ladspa-pitchshift/mengubah_ladspa.cpp

251 lines
7.1 KiB
C++

#include <cstdint>
#include "ladspa.h"
#include <array>
#include "common.h"
#include "effect.h"
#include "pitchshifter.h"
#include "formantshifter.h"
#include "timestretcher.h"
#define PORT_COUNT 6
#define ML_INPUT 0
#define ML_OUTPUT 1
#define ML_PITCH_CHANGE 3
#define ML_TIMBRE_CHANGE 5
#define ML_TIMBRE_IND 4
#define ML_PITCH_IND 2
using namespace Mengu;
using namespace dsp;
struct PluginHandler {
std::array<PitchShifter *, 3> pitch_shifters;
std::array<Effect *, 2> formant_shifters;
const float *in_buffer;
float *out_buffer;
const float *pitch_shifter_ind;
const float *pitch_shift;
const float *formant_shifter_ind;
const float *formant_shift;
};
enum PitchShiftInd {
WSOLAPitch = 0,
PhaseVocoderPitch = 1,
PhaseVocoderDoneRightPitch = 2,
};
enum FormantShiftInd {
LPCFormant = 0,
PSOLAFormant = 1,
};
/* internal core methods */
static LADSPA_Handle instantiate(const LADSPA_Descriptor *descriptor, unsigned long sample_rate) {
PluginHandler *plugin = new PluginHandler;
plugin->pitch_shifters = {
new TimeStretchPitchShifter(new WSOLATimeStretcher(), 1),
new TimeStretchPitchShifter(new PhaseVocoderTimeStretcher(), 1),
new TimeStretchPitchShifter(new PhaseVocoderDoneRightTimeStretcher(), 1),
};
plugin->formant_shifters = {
new LPCFormantShifter(),
new TimeStretchPitchShifter(new PSOLATimeStretcher(), 1),
};
return plugin;
}
static void connect_port(LADSPA_Handle instance, unsigned long port, LADSPA_Data *data_location) {
PluginHandler* plugin = (PluginHandler*) instance;
if (plugin == nullptr) return;
switch (port)
{
case 0:
plugin->in_buffer = (const float*) data_location;
break;
case 1:
plugin->out_buffer = (float*) data_location;
break;
case 2:
plugin->pitch_shifter_ind = (const float*) data_location;
case 3:
plugin->pitch_shift = (const float*) data_location;
break;
case 4:
plugin->formant_shifter_ind = (const float*) data_location;
break;
case 5:
plugin->formant_shift = (const float*) data_location;
break;
default:
break;
}
}
static void activate (LADSPA_Handle instance)
{
/* not needed here */
}
static void run (LADSPA_Handle instance, unsigned long sample_count)
{
PluginHandler* plugin = (PluginHandler*) instance;
if (plugin == nullptr) return;
if ((!plugin->in_buffer) || (!plugin->out_buffer) || (!plugin->pitch_shift)) return;
// apply effects
Effect *pitch_shifter = plugin->pitch_shifters[static_cast<PitchShiftInd>(*plugin->pitch_shifter_ind)];
Effect *formant_shifter = plugin->formant_shifters[static_cast<FormantShiftInd>(*plugin->formant_shifter_ind)];
pitch_shifter->set_property(0, EffectPropPayload {
.type = Slider,
.value = *plugin->pitch_shift,
});
formant_shifter->set_property(0, EffectPropPayload {
.type = Slider,
.value = *plugin->formant_shift,
});
static constexpr uint32_t ProcSize = 1 << 10;
Complex cbuffer[ProcSize];
uint32_t num_processed = 0;
while (num_processed < sample_count) {
uint32_t num_this_pass = MIN(ProcSize, sample_count - num_processed);
for (uint32_t i = 0; i < num_this_pass; i++) {
cbuffer[i] = (Complex) plugin->in_buffer[num_processed + i];
}
pitch_shifter->push_signal(cbuffer, num_this_pass);
pitch_shifter->pop_transformed_signal(cbuffer, num_this_pass);
formant_shifter->push_signal(cbuffer, num_this_pass);
formant_shifter->pop_transformed_signal(cbuffer, num_this_pass);
for (uint32_t i = 0; i < num_this_pass; i++) {
plugin->out_buffer[num_processed + i] = cbuffer[i].real();
}
num_processed += num_this_pass;
}
}
static void deactivate (LADSPA_Handle instance)
{
/* not needed here */
}
static void cleanup (LADSPA_Handle instance) {
PluginHandler *plugin = (PluginHandler *) instance;
if (plugin == nullptr) {
return;
}
for (auto pitch_shifter: plugin->pitch_shifters) {
delete pitch_shifter;
}
for (auto formant_shifter: plugin->formant_shifters) {
delete formant_shifter;
}
delete plugin;
}
static LADSPA_Descriptor *descriptor = NULL;
// On plugin load
static void __attribute__ ((constructor)) init() {
LADSPA_PortDescriptor * portDescriptors;
LADSPA_PortRangeHint * portRangeHints;
char ** portNames;
descriptor = (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
if (!descriptor) {
return;
}
descriptor->UniqueID = 109124; // should be unique
descriptor->Label = "pitcher";
descriptor->Name = "pitchplug";
descriptor->Maker = "Rysertio";
descriptor->Copyright = "(c) 2023, Rysertio";
descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
descriptor->PortCount = PORT_COUNT;
portDescriptors = (LADSPA_PortDescriptor *) calloc(PORT_COUNT, sizeof(LADSPA_PortDescriptor));
portDescriptors[ML_PITCH_CHANGE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
portDescriptors[ML_TIMBRE_CHANGE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
portDescriptors[ML_INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
portDescriptors[ML_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
portDescriptors[ML_PITCH_IND] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
portDescriptors[ML_TIMBRE_IND] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
descriptor->PortDescriptors = portDescriptors;
portNames = (char **) calloc(PORT_COUNT, sizeof(char *));
portNames[ML_PITCH_CHANGE] = "pitch change factor";
portNames[ML_TIMBRE_CHANGE] = "timbre change factor";
portNames[ML_INPUT] = "Input";
portNames[ML_OUTPUT] = "Output";
portNames[ML_PITCH_IND] = "pitch change algorithm";
portNames[ML_TIMBRE_IND] = "timbre change algorithm";
descriptor->PortNames = (const char * const *) portNames;
portRangeHints = (LADSPA_PortRangeHint *) calloc(PORT_COUNT, sizeof(LADSPA_PortRangeHint));
portRangeHints[ML_PITCH_CHANGE].HintDescriptor = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_1;
portRangeHints[ML_PITCH_CHANGE].LowerBound = 1;
portRangeHints[ML_TIMBRE_CHANGE].HintDescriptor = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_1;
portRangeHints[ML_TIMBRE_CHANGE].LowerBound = 1;
portRangeHints[ML_INPUT].HintDescriptor = 0;
portRangeHints[ML_OUTPUT].HintDescriptor = 0;
descriptor->PortRangeHints = portRangeHints;
descriptor->instantiate = instantiate;
descriptor->connect_port = connect_port;
descriptor->activate = activate;
descriptor->run = run;
descriptor->run_adding = NULL;
descriptor->set_run_adding_gain = NULL;
descriptor->deactivate = NULL;
descriptor->cleanup = cleanup;
}
// On plugin unload
static void __attribute__ ((destructor)) fini() {
return;
}
// we only have one type of plugin
const LADSPA_Descriptor * ladspa_descriptor(unsigned long index) {
if (index != 0) {
return NULL;
}
return descriptor;
}