kopia lustrzana https://gitlab.com/eliggett/wfview
666 wiersze
20 KiB
C++
666 wiersze
20 KiB
C++
#include "audioplugin.h"
|
|
|
|
//#include <lilv-0/lilv/lilv.h>
|
|
|
|
//#include <lv2.h>
|
|
#include "logcategories.h"
|
|
|
|
|
|
|
|
audioPlugin::audioPlugin(int maxBufferSizeNeeded, pluginPathType path,
|
|
unsigned char chainPosition, QObject *parent) : QObject(parent)
|
|
{
|
|
// Note: the size is for "interlaced" 2-channel 8-bit data, as is used outside of this plugin.
|
|
// Please do not set this to an odd number.
|
|
|
|
// We need each of our 16-bit one-channel buffers to be four times smaller in size.
|
|
|
|
if(maxBufferSizeNeeded==0)
|
|
{
|
|
bufferSize = 2728/2; // seems like an acceptable default value
|
|
} else {
|
|
bufferSize = maxBufferSizeNeeded/4;
|
|
}
|
|
|
|
this->audioChain = path;
|
|
this->chainPosition = chainPosition;
|
|
|
|
instanceId = (uint64_t)this;
|
|
instanceString = QString("0x%1").arg(instanceId, 16, 16, QChar('0'));
|
|
|
|
inBypassMode = false;
|
|
|
|
info.chainPosition = chainPosition;
|
|
info.instanceID = instanceId;
|
|
info.path = audioChain;
|
|
|
|
pluginURIAsQString = QString("unset");
|
|
|
|
externalSourceBuffer = NULL;
|
|
externalSinkBuffer = NULL;
|
|
|
|
sampleRate = 48000;
|
|
|
|
makeByteTable();
|
|
allocateBuffers();
|
|
initPluginWorld();
|
|
}
|
|
|
|
audioPlugin::~audioPlugin()
|
|
{
|
|
// free plugin helpers
|
|
unloadPlugin();
|
|
// TODO: consider locking the runPlugin carefully
|
|
|
|
// free buffers
|
|
deallocateBuffers();
|
|
}
|
|
|
|
void audioPlugin::setInputBuffer(char *stereoInterlacedInputBuffer)
|
|
{
|
|
if(stereoInterlacedInputBuffer == NULL)
|
|
{
|
|
emit pluginErrorMessage("Could not use NULL input buffer.");
|
|
haveExternalSourceBuffer = false;
|
|
externalSourceBuffer = NULL;
|
|
} else {
|
|
this->externalSourceBuffer = (int16_t*)stereoInterlacedInputBuffer;
|
|
haveExternalSourceBuffer = true;
|
|
}
|
|
}
|
|
|
|
void audioPlugin::setOutputBuffer(char *stereoInterlacedOutputBuffer)
|
|
{
|
|
if(stereoInterlacedOutputBuffer == NULL)
|
|
{
|
|
emit pluginErrorMessage("Could not use NULL output buffer.");
|
|
haveExternalSinkBuffer = false;
|
|
externalSinkBuffer = NULL;
|
|
} else {
|
|
this->externalSinkBuffer = (int16_t*)stereoInterlacedOutputBuffer;
|
|
haveExternalSinkBuffer = true;
|
|
}
|
|
}
|
|
|
|
int16_t* audioPlugin::getInputBuffer()
|
|
{
|
|
return externalSourceBuffer;
|
|
}
|
|
|
|
int16_t* audioPlugin::getOutputBuffer()
|
|
{
|
|
return externalSinkBuffer;
|
|
}
|
|
|
|
void audioPlugin::selectPluginByID(int pluginId)
|
|
{
|
|
(void)pluginId;
|
|
}
|
|
|
|
void audioPlugin::selectPluginByLabel(QString pluginLabel)
|
|
{
|
|
(void)pluginLabel;
|
|
}
|
|
|
|
void audioPlugin::selectPluginByName(QString pluginName)
|
|
{
|
|
(void)pluginName;
|
|
}
|
|
|
|
void audioPlugin::allocateBuffers()
|
|
{
|
|
// Internal use float buffers for audio
|
|
// These buffers may be larger than required, but must not be smaller.
|
|
// They will be accessed based on the size of the audio samples passing through.
|
|
if(haveAllocatedInternalBuffers)
|
|
{
|
|
// realloc?
|
|
emit pluginErrorMessage("WARNING: asked to reallocate buffer memory! This feature has not been implemented yet.");
|
|
} else {
|
|
inputBuffer[0]= (float*)malloc(sizeof(float) * bufferSize);
|
|
inputBuffer[1]= (float*)malloc(sizeof(float) * bufferSize);
|
|
|
|
outputBuffer[0]= (float*)malloc(sizeof(float) * bufferSize);
|
|
outputBuffer[1]= (float*)malloc(sizeof(float) * bufferSize);
|
|
|
|
haveAllocatedInternalBuffers = true;
|
|
}
|
|
}
|
|
|
|
void audioPlugin::deallocateBuffers()
|
|
{
|
|
if(haveAllocatedInternalBuffers)
|
|
{
|
|
haveAllocatedInternalBuffers = false;
|
|
free(inputBuffer);
|
|
free(outputBuffer);
|
|
} else {
|
|
emit pluginErrorMessage("WARNING: asked to deallocate memory that has not been allocated!");
|
|
}
|
|
}
|
|
|
|
void audioPlugin::initPluginWorld()
|
|
{
|
|
// Setup the "world" for the plugin functions:
|
|
world = lilv_world_new();
|
|
lilv_world_load_all(world);
|
|
plugins = lilv_world_get_all_plugins(world);
|
|
gControlPortClass = lilv_new_uri(world, LV2_CORE__ControlPort);
|
|
// TODO: if thing == NULL... emit fail
|
|
}
|
|
|
|
bool audioPlugin::activatePlugin()
|
|
{
|
|
// TODO: unactivate and unload reset bools
|
|
if(haveLoadedPlugin && !haveActivatedPlugin)
|
|
{
|
|
lilv_instance_activate(instance);
|
|
haveActivatedPlugin = true;
|
|
emit pluginStatusMessage(QString("[%1] activated plugin.").arg(instanceString));
|
|
return true;
|
|
} else {
|
|
emit pluginErrorMessage(QString("Cannot activate plugin that has not been loaded."));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void audioPlugin::setupPlugin(char *pluginURI)
|
|
{
|
|
// This function loads exactly the URI it is told to load.
|
|
// Future versions might include other, easier methods.
|
|
bool loadedOk = false;
|
|
bool activatedOk = false;
|
|
this->pluginURIAsQString = QString("%1").arg(pluginURI);
|
|
loadedOk = loadPlugin(pluginURI);
|
|
haveLoadedPlugin = loadedOk;
|
|
|
|
activatedOk = activatePlugin();
|
|
|
|
info.isLoaded = loadedOk && activatedOk;
|
|
info.pluginName = pluginNameAsQString;
|
|
info.plugin = this;
|
|
info.pluginURI = this->pluginURIAsQString;
|
|
emit pluginLoaded(info);
|
|
}
|
|
|
|
bool audioPlugin::loadPlugin(char *pluginURI)
|
|
{
|
|
bool success = false;
|
|
lilv_plugins_get_by_uri(plugins, uri);
|
|
|
|
uri = lilv_new_uri(world, pluginURI);
|
|
plugin = lilv_plugins_get_by_uri(plugins, uri);
|
|
if(plugin == NULL)
|
|
{
|
|
success = false;
|
|
this->info.isLoaded = false;
|
|
emit pluginLoaded(this->info);
|
|
emit pluginErrorMessage(QString("Could not find plugin by URI [%1]").arg(pluginURI));
|
|
pluginNameAsQString = "";
|
|
haveLoadedPlugin = false;
|
|
return success;
|
|
}
|
|
|
|
pluginName = lilv_plugin_get_name(plugin);
|
|
pluginNameAsQString = QString("%1").arg(lilv_node_as_string(pluginName));
|
|
emit pluginStatusMessage(QString("Loaded plugin named [%1] from URI [%2]").arg(lilv_node_as_string(pluginName)).arg(pluginURI));
|
|
success = true;
|
|
|
|
success = createPorts();
|
|
|
|
if(n_audio_in == 0 || n_audio_in > 2)
|
|
{
|
|
success = false;
|
|
this->info.isLoaded = false;
|
|
emit pluginLoaded(this->info);
|
|
emit pluginErrorMessage(QString("Number of audio input ports (%1) for plugin [%2] is not compatible.")\
|
|
.arg(n_audio_in).arg(lilv_node_as_string(pluginName)));
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
const uint32_t n_portsLoop = lilv_plugin_get_num_ports(plugin);
|
|
;
|
|
feature_uri_map_data = { this, audioPlugin::urid_map };
|
|
feature_uri_map = { LV2_URID__map, &feature_uri_map_data };
|
|
|
|
feature_uri_unmap_data = { this, audioPlugin::urid_unmap };
|
|
feature_uri_unmap = { LV2_URID__unmap, &feature_uri_unmap_data };
|
|
|
|
feature_worker = { LV2_WORKER__schedule, (LV2_Worker_Schedule*)malloc(sizeof(LV2_Worker_Schedule)) };
|
|
|
|
features[0] = &feature_uri_map;
|
|
features[1] = &feature_uri_unmap;
|
|
features[2] = &feature_worker;
|
|
|
|
instance = lilv_plugin_instantiate(plugin, sampleRate, features);
|
|
// The NULL is "features" ??
|
|
|
|
if(instance == NULL)
|
|
{
|
|
success = false;
|
|
emit pluginErrorMessage(QString("Plugin instance could not be created for plugin with name [%1]").arg(pluginNameAsQString));
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
// This is where the controls, input buffer, and output buffer, are connected
|
|
// into the plugin instance using pointers.
|
|
|
|
for (uint32_t p = 0, i = 0, o = 0; p < n_portsLoop; ++p) {
|
|
if (ports[p].type == TYPE_CONTROL) {
|
|
lilv_instance_connect_port(instance, p, &ports[p].value);
|
|
} else if (ports[p].type == TYPE_AUDIO) {
|
|
if (ports[p].is_input) {
|
|
lilv_instance_connect_port(instance, p, inputBuffer[ i++ ]);
|
|
} else {
|
|
lilv_instance_connect_port(instance, p, outputBuffer[ o++ ]);
|
|
}
|
|
} else {
|
|
lilv_instance_connect_port(instance, p, NULL);
|
|
}
|
|
}
|
|
|
|
success = true;
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
bool audioPlugin::createPorts()
|
|
{
|
|
bool success = false;
|
|
|
|
n_ports = lilv_plugin_get_num_ports(plugin);
|
|
n_audio_in = 0;
|
|
n_audio_out = 0;
|
|
|
|
emit pluginStatusMessage(QString("Creating ports, number of ports returned: %1").arg(n_ports));
|
|
ports = (Port*)calloc(n_ports, sizeof(Port));
|
|
float *values = (float*)calloc(n_ports, sizeof(float)); // default values actually
|
|
float *minValues = (float*)calloc(n_ports, sizeof(float));
|
|
float *maxValues = (float*)calloc(n_ports, sizeof(float));
|
|
controlsType singleControl;
|
|
controls.clear();
|
|
unsigned int controlNumber = 0;
|
|
|
|
lilv_plugin_get_port_ranges_float(plugin, minValues, maxValues, values);
|
|
// The two NULL above contain pointers to float arrays holding max and min values for the controls.
|
|
|
|
LilvNode* lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
|
|
LilvNode* lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
|
|
LilvNode* lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
|
|
LilvNode* lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
|
|
LilvNode* lv2_EventPort = lilv_new_uri(world, LV2_EVENT__EventPort);
|
|
LilvNode* lv2_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
|
|
LilvNode* lv2_connectionOptional = lilv_new_uri(world, LV2_CORE__connectionOptional);
|
|
LilvNode* lv2_urid_map = lilv_new_uri(world, LV2_URID__map);
|
|
LilvNode* lv2_urid_unmap = lilv_new_uri(world, LV2_URID__unmap);
|
|
LilvNode* lv2_worker_schedule = lilv_new_uri(world, LV2_WORKER__schedule);
|
|
|
|
|
|
for (uint32_t i = 0; i < n_ports; ++i) {
|
|
Port *port = &ports[i];
|
|
const LilvPort *lport = lilv_plugin_get_port_by_index(plugin, i);
|
|
port->lilv_port = lport;
|
|
port->index = i;
|
|
port->value = isnan(values[i]) ? 0.0f : values[i];
|
|
port->optional = lilv_port_has_property(plugin, lport, lv2_connectionOptional);
|
|
|
|
// Check if input or output:
|
|
if (lilv_port_is_a(plugin, lport, lv2_InputPort)) {
|
|
port->is_input = true;
|
|
} else if (!lilv_port_is_a(plugin, lport, lv2_OutputPort) && !port->optional)
|
|
{
|
|
success = false;
|
|
emit pluginErrorMessage(QString("Port %1 is neither input nor output").arg(i));
|
|
return success;
|
|
}
|
|
|
|
// Check if port is audio or control:
|
|
if (lilv_port_is_a(plugin, lport, lv2_ControlPort)) {
|
|
port->type = TYPE_CONTROL;
|
|
singleControl.instanceId = instanceId;
|
|
singleControl.portIndex = i;
|
|
singleControl.controlsIndex = controlNumber++;
|
|
singleControl.def = isnan(values[i]) ? 0.0f : values[i];
|
|
singleControl.min = isnan(minValues[i]) ? 0.0f : minValues[i];
|
|
singleControl.max = isnan(maxValues[i]) ? 0.0f : maxValues[i];
|
|
singleControl.value = singleControl.def; // start at default value
|
|
singleControl.label = QString("%1").arg(lilv_node_as_string(lilv_port_get_name(plugin, lport)));
|
|
controls.push_back(singleControl);
|
|
}
|
|
else if (lilv_port_is_a(plugin, lport, lv2_AudioPort)) {
|
|
port->type = TYPE_AUDIO;
|
|
if (port->is_input) {
|
|
++n_audio_in;
|
|
}
|
|
else {
|
|
++n_audio_out;
|
|
}
|
|
}
|
|
else if (lilv_port_is_a(plugin, lport, lv2_EventPort)) {
|
|
emit pluginStatusMessage(QString("[%1] is an event port").arg(i));
|
|
port->type = TYPE_EVENT;
|
|
}
|
|
else if (lilv_port_is_a(plugin, lport, lv2_AtomPort)) {
|
|
emit pluginStatusMessage(QString("[%1] is an atom port").arg(i));
|
|
port->type = TYPE_ATOM;
|
|
}
|
|
else if (!port->optional)
|
|
{
|
|
success = false;
|
|
emit pluginErrorMessage(QString("Port %1 has an unsupported type.").arg(i));
|
|
return success;
|
|
}
|
|
}
|
|
|
|
if (lilv_plugin_has_feature(plugin, lv2_urid_map)) {
|
|
emit pluginStatusMessage(QString("Plugin is requesting urid_map feature"));
|
|
}
|
|
if (lilv_plugin_has_feature(plugin, lv2_urid_unmap)) {
|
|
emit pluginStatusMessage(QString("Plugin is requesting urid_unmap feature"));
|
|
}
|
|
if (lilv_plugin_has_feature(plugin, lv2_worker_schedule)) {
|
|
emit pluginStatusMessage(QString("Plugin is requesting worker_schedule feature"));
|
|
}
|
|
|
|
// At this point, the plugin is "discovered" and the temporary variables can be free'd:
|
|
|
|
lilv_node_free(lv2_connectionOptional);
|
|
lilv_node_free(lv2_ControlPort);
|
|
lilv_node_free(lv2_AudioPort);
|
|
lilv_node_free(lv2_OutputPort);
|
|
lilv_node_free(lv2_InputPort);
|
|
lilv_node_free(lv2_AtomPort);
|
|
|
|
free(values);
|
|
free(minValues);
|
|
free(maxValues);
|
|
|
|
// What persists is the "ports" holder, which is now populated,
|
|
// as well as the counters for input and output ports.
|
|
|
|
success = true;
|
|
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
void audioPlugin::unloadPlugin()
|
|
{
|
|
haveActivatedPlugin = false;
|
|
haveLoadedPlugin = false;
|
|
|
|
lilv_instance_deactivate(instance);
|
|
lilv_world_free(world);
|
|
emit pluginStatusMessage(QString("[%1] unloaded plugin [%2]")\
|
|
.arg(instanceString)\
|
|
.arg(pluginNameAsQString));
|
|
}
|
|
|
|
void audioPlugin::runPlugin(int samples)
|
|
{
|
|
// samples is the number of samples *at 8-8 bit stereo interlaced*
|
|
// The interface here is designed so that one can call it with the QByteArray.length() number.
|
|
|
|
if(inBypassMode)
|
|
return;
|
|
|
|
if(haveActivatedPlugin && haveExternalSinkBuffer && haveExternalSourceBuffer)
|
|
{
|
|
// Let's make these calculations only at one location in the code:
|
|
externalSampleCount = samples;
|
|
sourceBufferSampleCount = samples / 2; // 16-bit is half as many
|
|
inputBufferSampleCount = samples / 4; // 16-bit per-channel is 1/4 as many per channel.
|
|
|
|
// You can safely comment out any of these functions to determine where the crash is:
|
|
convertInputBuffer(); // seems ok
|
|
copyControlsToPluginInterface(); // seems ok
|
|
lilv_instance_run(instance, inputBufferSampleCount);
|
|
|
|
convertOutputBuffer(); // seems ok
|
|
|
|
} else {
|
|
emit pluginErrorMessage(QString("[%1] Tried to run without complete plugin activation.").arg(instanceString));
|
|
emit pluginErrorMessage(QString("[%1] has the following data: activated: %2, have sink: %3, have source: %4")\
|
|
.arg(instanceString)\
|
|
.arg(haveActivatedPlugin)\
|
|
.arg(haveExternalSinkBuffer)\
|
|
.arg(haveExternalSourceBuffer));
|
|
}
|
|
}
|
|
|
|
void audioPlugin::getPluginControlPorts(pluginInstanceInfoType info)
|
|
{
|
|
// For this, we should only be returning control ports, not audio or other ports,
|
|
// and we should be sending a copy of the port data, not pointers.
|
|
|
|
// We need to do this with an array of ports...
|
|
|
|
uint64_t instanceRequested = info.instanceID;
|
|
|
|
if(instanceRequested != this->instanceId)
|
|
{
|
|
emit pluginErrorMessage(QString("Plugin Controls Query received for instance 0x%1 but this is instance 0x%2.")\
|
|
.arg(instanceRequested, 16, 16, QChar('0'))\
|
|
.arg(instanceId, 16, 16, QChar('0')));
|
|
return;
|
|
}
|
|
|
|
if(haveActivatedPlugin)
|
|
{
|
|
emit haveControlPorts(controls);
|
|
} else {
|
|
emit pluginErrorMessage(QString("Cannot return plugin ports of unactivated plugin"));
|
|
}
|
|
}
|
|
|
|
void audioPlugin::handleAdjustedPluginControls(controlsType control)
|
|
{
|
|
// Access the local vector of controls, called "controls".
|
|
// Alter the control->controlsIndex member to have equal value.
|
|
|
|
if(control.controlsIndex <= (unsigned int)controls.size())
|
|
{
|
|
controls[control.controlsIndex].value = control.value;
|
|
} else {
|
|
emit pluginErrorMessage(QString("Error in plugin [%1][%4]: Asked to adjust control at index %2 when the max index is %3.")\
|
|
.arg(pluginNameAsQString)\
|
|
.arg(control.controlsIndex)\
|
|
.arg(controls.size())\
|
|
.arg(instanceString));
|
|
}
|
|
}
|
|
|
|
void audioPlugin::setBypass(bool bypass)
|
|
{
|
|
this->inBypassMode = bypass;
|
|
}
|
|
|
|
void audioPlugin::copyControlsToPluginInterface()
|
|
{
|
|
// Haven't figured out exactly how to do this one yet. Something like this:
|
|
// Loop across all ports, modify if matching index.
|
|
|
|
// Should I have used the n_params variable here instead of portIndex?
|
|
|
|
// I have assumed that "value" is the control value.
|
|
|
|
controlsType c;
|
|
|
|
for(int i=0; i < controls.size(); i++)
|
|
{
|
|
c = controls.at(i);
|
|
this->ports[ c.portIndex ].value = c.value;
|
|
}
|
|
}
|
|
|
|
void audioPlugin::convertInputBuffer()
|
|
{
|
|
// Copy from the interleaved uint16 buffer
|
|
// into the float buffer for the plugin to process
|
|
// Includes amplitude scaling into -1 to +1
|
|
|
|
// externalSourceBuffer --> scale --> inputBuffer
|
|
|
|
float max = 65535.0f;
|
|
float mid = max / 2.0f;
|
|
float scalingFactor = 1.0f / max;
|
|
|
|
// Note, we have already cast the 8MSB, 8LSB type data into a 16-bit holder
|
|
// So accessing one member should result in a full 16-bit number.
|
|
|
|
for (int n = 0; n < sourceBufferSampleCount; n += 2) {
|
|
inputBuffer[0][n/2] = ( externalSourceBuffer[n] - mid) * scalingFactor;
|
|
inputBuffer[1][n/2] = ( externalSourceBuffer[n+1] - mid) * scalingFactor;
|
|
|
|
// inputBuffer[0][n/2] = (externalSourceBuffer[n] - mid) * scalingFactor;
|
|
// inputBuffer[1][n/2] = (externalSourceBuffer[n+1] - mid) * scalingFactor;
|
|
}
|
|
}
|
|
|
|
void audioPlugin::convertOutputBuffer()
|
|
{
|
|
// Copy from the plugin float output
|
|
// to the interleaved uint16 buffer for the audioHandler.
|
|
// Includes amplitude scaling back to uint16 levels.
|
|
// Also converts to "dual mono" if so requested, copying
|
|
// the channel 0 data over to channel 1.
|
|
// Useful for mono plugins that do not create a second output stream.
|
|
|
|
// outputBuffer --> scale --> externalSinkBuffer
|
|
|
|
float max = 65535.0f;
|
|
float mid = max / 2.0f; // set to zero for muted testing
|
|
|
|
// copy through test:
|
|
|
|
// Copy input to output:
|
|
// for (int n = 0; n+1 < sourceBufferSampleCount; n += 1) {
|
|
// externalSinkBuffer[n] = externalSourceBuffer[n];
|
|
// }
|
|
|
|
// Copy float of input to output:
|
|
// for (int n = 0; n+1 < sourceBufferSampleCount; n += 2) {
|
|
// externalSinkBuffer[n] = (inputBuffer[0][n/2] + 1) * mid; // L
|
|
// externalSinkBuffer[n+1] = (inputBuffer[0][n/2] + 1) * mid; // Copy L
|
|
// }
|
|
|
|
if(forceOutputMono)
|
|
{
|
|
for (int n = 0; n+1 < sourceBufferSampleCount; n += 2) {
|
|
externalSinkBuffer[n] = (outputBuffer[0][n/2] + 1) * mid; // L
|
|
externalSinkBuffer[n+1] = (outputBuffer[0][n/2] + 1) * mid; // Copy L
|
|
}
|
|
} else {
|
|
|
|
for (int n = 0; n+1 < sourceBufferSampleCount; n += 2) {
|
|
externalSinkBuffer[n] = (outputBuffer[0][n/2] + 1) * mid; // L
|
|
externalSinkBuffer[n+1] = (outputBuffer[1][n/2] + 1) * mid; // R
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void audioPlugin::makeByteTable()
|
|
{
|
|
for(unsigned int i=0; i < 65535; i++)
|
|
{
|
|
byteTable[i] = ((i&0x00ff) << 8) | ( (i&0xff00) >> 8 ) ;
|
|
}
|
|
}
|
|
|
|
QString audioPlugin::getPLuginControlInfo()
|
|
{
|
|
QString info = QString("Plugin controls information for plugin named [%1] on instance [%2]: \n")\
|
|
.arg(pluginNameAsQString)\
|
|
.arg(instanceString);
|
|
controlsType c;
|
|
|
|
for(int i = 0; i < controls.size(); i ++)
|
|
{
|
|
c = controls.at(i);
|
|
info.append(QString("Control %1: port index: %7, min: %2, max: %3, default: %4, current value: %5, name: [%6] \n")\
|
|
.arg(c.controlsIndex)
|
|
.arg(c.min)\
|
|
.arg(c.max)\
|
|
.arg(c.def)\
|
|
.arg(c.value)\
|
|
.arg(c.label)\
|
|
.arg(c.portIndex));
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
LV2_URID audioPlugin::urid_map(LV2_URID_Map_Handle handle, const char* uri)
|
|
{
|
|
audioPlugin* lv2 = (audioPlugin*)handle;
|
|
LV2_URID urid;
|
|
|
|
std::string key = uri;
|
|
|
|
if (lv2->urid_map_data.find(key) == lv2->urid_map_data.end()) {
|
|
urid = lv2->current_urid++;
|
|
lv2->urid_map_data[key] = urid;
|
|
}
|
|
else {
|
|
urid = lv2->urid_map_data[key];
|
|
}
|
|
|
|
return urid;
|
|
}
|
|
|
|
const char* audioPlugin::urid_unmap(void* handle, LV2_URID urid)
|
|
{
|
|
audioPlugin* lv2 = (audioPlugin*)handle;
|
|
const char* value = nullptr;
|
|
|
|
for (auto const& p : lv2->urid_map_data) {
|
|
if (p.second == urid) {
|
|
value = p.first.c_str();
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void audioPlugin::debugThis()
|
|
{
|
|
qDebug() << __PRETTY_FUNCTION__ << "Reached plugin debug function for instance" << instanceString;
|
|
emit pluginStatusMessage(getPLuginControlInfo());
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|