@@ -798,8 +798,8 @@ public: | |||||
static CarlaPlugin* newLV2(const Initializer& init); | static CarlaPlugin* newLV2(const Initializer& init); | ||||
static CarlaPlugin* newVST(const Initializer& init); | static CarlaPlugin* newVST(const Initializer& init); | ||||
static CarlaPlugin* newGIG(const Initializer& init); | static CarlaPlugin* newGIG(const Initializer& init); | ||||
static CarlaPlugin* newSF2(const Initializer& init, const bool use16Outs); | |||||
static CarlaPlugin* newSFZ(const Initializer& init); | static CarlaPlugin* newSFZ(const Initializer& init); | ||||
static CarlaPlugin* newSF2(const Initializer& init); | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -713,7 +713,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, cons | |||||
break; | break; | ||||
case PLUGIN_SF2: | case PLUGIN_SF2: | ||||
plugin = CarlaPlugin::newSF2(init); | |||||
plugin = CarlaPlugin::newSF2(init, (extra != nullptr)); | |||||
break; | break; | ||||
case PLUGIN_SFZ: | case PLUGIN_SFZ: | ||||
@@ -49,7 +49,7 @@ public: | |||||
kClient(client), | kClient(client), | ||||
kPort(port) | kPort(port) | ||||
{ | { | ||||
qDebug("CarlaEngineJackAudioPort::CarlaEngineJackAudioPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port); | |||||
carla_debug("CarlaEngineJackAudioPort::CarlaEngineJackAudioPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port); | |||||
if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | ||||
{ | { | ||||
@@ -63,7 +63,7 @@ public: | |||||
~CarlaEngineJackAudioPort() | ~CarlaEngineJackAudioPort() | ||||
{ | { | ||||
qDebug("CarlaEngineJackAudioPort::~CarlaEngineJackAudioPort()"); | |||||
carla_debug("CarlaEngineJackAudioPort::~CarlaEngineJackAudioPort()"); | |||||
if (kClient != nullptr && kPort != nullptr) | if (kClient != nullptr && kPort != nullptr) | ||||
jackbridge_port_unregister(kClient, kPort); | jackbridge_port_unregister(kClient, kPort); | ||||
@@ -111,7 +111,7 @@ public: | |||||
kPort(port), | kPort(port), | ||||
fJackBuffer(nullptr) | fJackBuffer(nullptr) | ||||
{ | { | ||||
qDebug("CarlaEngineJackEventPort::CarlaEngineJackEventPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port); | |||||
carla_debug("CarlaEngineJackEventPort::CarlaEngineJackEventPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port); | |||||
if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | ||||
{ | { | ||||
@@ -125,7 +125,7 @@ public: | |||||
~CarlaEngineJackEventPort() | ~CarlaEngineJackEventPort() | ||||
{ | { | ||||
qDebug("CarlaEngineJackEventPort::~CarlaEngineJackEventPort()"); | |||||
carla_debug("CarlaEngineJackEventPort::~CarlaEngineJackEventPort()"); | |||||
if (kClient != nullptr && kPort != nullptr) | if (kClient != nullptr && kPort != nullptr) | ||||
jackbridge_port_unregister(kClient, kPort); | jackbridge_port_unregister(kClient, kPort); | ||||
@@ -368,7 +368,7 @@ public: | |||||
kClient(client), | kClient(client), | ||||
kUseClient(processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | kUseClient(processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | ||||
{ | { | ||||
qDebug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", EngineType2Str(engineType), ProcessMode2Str(processMode), client); | |||||
carla_debug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", EngineType2Str(engineType), ProcessMode2Str(processMode), client); | |||||
if (kUseClient) | if (kUseClient) | ||||
{ | { | ||||
@@ -382,7 +382,7 @@ public: | |||||
~CarlaEngineJackClient() | ~CarlaEngineJackClient() | ||||
{ | { | ||||
qDebug("CarlaEngineClient::~CarlaEngineClient()"); | |||||
carla_debug("CarlaEngineClient::~CarlaEngineClient()"); | |||||
if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | ||||
{ | { | ||||
@@ -393,7 +393,7 @@ public: | |||||
void activate() | void activate() | ||||
{ | { | ||||
qDebug("CarlaEngineJackClient::activate()"); | |||||
carla_debug("CarlaEngineJackClient::activate()"); | |||||
if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | ||||
{ | { | ||||
@@ -408,7 +408,7 @@ public: | |||||
void deactivate() | void deactivate() | ||||
{ | { | ||||
qDebug("CarlaEngineJackClient::deactivate()"); | |||||
carla_debug("CarlaEngineJackClient::deactivate()"); | |||||
if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | if (kProcessMode == PROCESS_MODE_MULTIPLE_CLIENTS) | ||||
{ | { | ||||
@@ -423,7 +423,7 @@ public: | |||||
bool isOk() const | bool isOk() const | ||||
{ | { | ||||
qDebug("CarlaEngineJackClient::isOk()"); | |||||
carla_debug("CarlaEngineJackClient::isOk()"); | |||||
if (kUseClient) | if (kUseClient) | ||||
return bool(kClient); | return bool(kClient); | ||||
@@ -441,7 +441,7 @@ public: | |||||
const CarlaEnginePort* addPort(const EnginePortType portType, const char* const name, const bool isInput) | const CarlaEnginePort* addPort(const EnginePortType portType, const char* const name, const bool isInput) | ||||
{ | { | ||||
qDebug("CarlaEngineJackClient::addPort(%s, \"%s\", %s)", EnginePortType2Str(portType), name, bool2str(isInput)); | |||||
carla_debug("CarlaEngineJackClient::addPort(%s, \"%s\", %s)", EnginePortType2Str(portType), name, bool2str(isInput)); | |||||
jack_port_t* port = nullptr; | jack_port_t* port = nullptr; | ||||
@@ -500,7 +500,7 @@ public: | |||||
#endif | #endif | ||||
fFreewheel(false) | fFreewheel(false) | ||||
{ | { | ||||
qDebug("CarlaEngineJack::CarlaEngineJack()"); | |||||
carla_debug("CarlaEngineJack::CarlaEngineJack()"); | |||||
#ifdef BUILD_BRIDGE | #ifdef BUILD_BRIDGE | ||||
fOptions.processMode = PROCESS_MODE_MULTIPLE_CLIENTS; | fOptions.processMode = PROCESS_MODE_MULTIPLE_CLIENTS; | ||||
@@ -511,7 +511,7 @@ public: | |||||
~CarlaEngineJack() | ~CarlaEngineJack() | ||||
{ | { | ||||
qDebug("CarlaEngineJack::~CarlaEngineJack()"); | |||||
carla_debug("CarlaEngineJack::~CarlaEngineJack()"); | |||||
CARLA_ASSERT(fClient == nullptr); | CARLA_ASSERT(fClient == nullptr); | ||||
} | } | ||||
@@ -539,7 +539,7 @@ public: | |||||
bool init(const char* const clientName) | bool init(const char* const clientName) | ||||
{ | { | ||||
qDebug("CarlaEngineJack::init(\"%s\")", clientName); | |||||
carla_debug("CarlaEngineJack::init(\"%s\")", clientName); | |||||
fFreewheel = false; | fFreewheel = false; | ||||
fTransportState = JackTransportStopped; | fTransportState = JackTransportStopped; | ||||
@@ -607,7 +607,7 @@ public: | |||||
bool close() | bool close() | ||||
{ | { | ||||
qDebug("CarlaEngineJack::close()"); | |||||
carla_debug("CarlaEngineJack::close()"); | |||||
CarlaEngine::close(); | CarlaEngine::close(); | ||||
#ifdef BUILD_BRIDGE | #ifdef BUILD_BRIDGE | ||||
@@ -53,10 +53,10 @@ public: | |||||
{ | { | ||||
showGui(false); | showGui(false); | ||||
// Wait a bit first, try safe quit, then force kill | |||||
// Wait a bit first, then force kill | |||||
if (kData->osc.thread.isRunning() && ! kData->osc.thread.stop(kData->engine->getOptions().oscUiTimeout)) | if (kData->osc.thread.isRunning() && ! kData->osc.thread.stop(kData->engine->getOptions().oscUiTimeout)) | ||||
{ | { | ||||
carla_stderr("Failed to properly stop DSSI GUI thread"); | |||||
carla_stderr("DSSI GUI thread still running, forcing termination now"); | |||||
kData->osc.thread.terminate(); | kData->osc.thread.terminate(); | ||||
} | } | ||||
} | } | ||||
@@ -1170,7 +1170,7 @@ public: | |||||
const EngineMidiEvent& midiEvent = event.midi; | const EngineMidiEvent& midiEvent = event.midi; | ||||
uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); | uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); | ||||
uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data); | |||||
uint8_t channel = event.channel; | |||||
// Fix bad note-off (per DSSI spec) | // Fix bad note-off (per DSSI spec) | ||||
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) | if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) | ||||
@@ -28,15 +28,22 @@ CARLA_BACKEND_START_NAMESPACE | |||||
class FluidSynthPlugin : public CarlaPlugin | class FluidSynthPlugin : public CarlaPlugin | ||||
{ | { | ||||
public: | public: | ||||
FluidSynthPlugin(CarlaEngine* const engine, const unsigned int id) | |||||
: CarlaPlugin(engine, id) | |||||
FluidSynthPlugin(CarlaEngine* const engine, const unsigned int id, const bool use16Outs) | |||||
: CarlaPlugin(engine, id), | |||||
kUses16Outs(use16Outs), | |||||
fSettings(nullptr), | |||||
fSynth(nullptr), | |||||
fSynthId(-1), | |||||
fAudio16Buffers(nullptr) | |||||
{ | { | ||||
carla_debug("FluidSynthPlugin::FluidSynthPlugin()"); | |||||
carla_debug("FluidSynthPlugin::FluidSynthPlugin(%p, %i, %s)", engine, id, bool2str(use16Outs)); | |||||
// create settings | // create settings | ||||
fSettings = new_fluid_settings(); | fSettings = new_fluid_settings(); | ||||
// define settings | // define settings | ||||
fluid_settings_setint(fSettings, "synth.audio-channels", use16Outs ? 16 : 1); | |||||
fluid_settings_setint(fSettings, "synth.audio-groups", use16Outs ? 16 : 1); | |||||
fluid_settings_setnum(fSettings, "synth.sample-rate", kData->engine->getSampleRate()); | fluid_settings_setnum(fSettings, "synth.sample-rate", kData->engine->getSampleRate()); | ||||
fluid_settings_setint(fSettings, "synth.threadsafe-api ", 0); | fluid_settings_setint(fSettings, "synth.threadsafe-api ", 0); | ||||
@@ -66,6 +73,8 @@ public: | |||||
delete_fluid_synth(fSynth); | delete_fluid_synth(fSynth); | ||||
delete_fluid_settings(fSettings); | delete_fluid_settings(fSettings); | ||||
deleteBuffers(); | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -400,7 +409,7 @@ public: | |||||
deleteBuffers(); | deleteBuffers(); | ||||
uint32_t aOuts, params, j; | uint32_t aOuts, params, j; | ||||
aOuts = 2; | |||||
aOuts = kUses16Outs ? 32 : 2; | |||||
params = FluidSynthParametersMax; | params = FluidSynthParametersMax; | ||||
kData->audioOut.createNew(aOuts); | kData->audioOut.createNew(aOuts); | ||||
@@ -412,7 +421,44 @@ public: | |||||
// --------------------------------------- | // --------------------------------------- | ||||
// Audio Outputs | // Audio Outputs | ||||
if (kUses16Outs) | |||||
{ | |||||
for (j=0; j < 32; j++) | |||||
{ | |||||
portName.clear(); | |||||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||||
{ | |||||
portName = fName; | |||||
portName += ":"; | |||||
} | |||||
portName += "out-"; | |||||
if ((j+2)/2 < 9) | |||||
portName += "0"; | |||||
portName += CarlaString((j+2)/2); | |||||
if (j % 2 == 0) | |||||
portName += "L"; | |||||
else | |||||
portName += "R"; | |||||
portName.truncate(portNameSize); | |||||
kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); | |||||
kData->audioOut.ports[j].rindex = j; | |||||
} | |||||
fAudio16Buffers = new float*[aOuts]; | |||||
for (j=0; j < aOuts; j++) | |||||
fAudio16Buffers[j] = nullptr; | |||||
} | |||||
else | |||||
{ | { | ||||
// out-left | |||||
portName.clear(); | portName.clear(); | ||||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | if (processMode == PROCESS_MODE_SINGLE_CLIENT) | ||||
@@ -426,9 +472,8 @@ public: | |||||
kData->audioOut.ports[0].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); | kData->audioOut.ports[0].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); | ||||
kData->audioOut.ports[0].rindex = 0; | kData->audioOut.ports[0].rindex = 0; | ||||
} | |||||
{ | |||||
// out-right | |||||
portName.clear(); | portName.clear(); | ||||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | if (processMode == PROCESS_MODE_SINGLE_CLIENT) | ||||
@@ -714,6 +759,7 @@ public: | |||||
fHints |= PLUGIN_CAN_BALANCE; | fHints |= PLUGIN_CAN_BALANCE; | ||||
fHints |= PLUGIN_CAN_FORCE_STEREO; | fHints |= PLUGIN_CAN_FORCE_STEREO; | ||||
bufferSizeChanged(kData->engine->getBufferSize()); | |||||
reloadPrograms(true); | reloadPrograms(true); | ||||
kData->client->activate(); | kData->client->activate(); | ||||
@@ -819,7 +865,6 @@ public: | |||||
void process(float** const, float** const outBuffer, const uint32_t frames, const uint32_t framesOffset) | void process(float** const, float** const outBuffer, const uint32_t frames, const uint32_t framesOffset) | ||||
{ | { | ||||
uint32_t i, k; | uint32_t i, k; | ||||
uint32_t midiEventCount = 0; | |||||
// -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
// Check if active | // Check if active | ||||
@@ -871,8 +916,6 @@ public: | |||||
fluid_synth_noteon(fSynth, note.channel, note.note, note.velo); | fluid_synth_noteon(fSynth, note.channel, note.note, note.velo); | ||||
else | else | ||||
fluid_synth_noteoff(fSynth,note.channel, note.note); | fluid_synth_noteoff(fSynth,note.channel, note.note); | ||||
midiEventCount += 1; | |||||
} | } | ||||
kData->extNotes.mutex.unlock(); | kData->extNotes.mutex.unlock(); | ||||
@@ -905,7 +948,11 @@ public: | |||||
if (time > timeOffset) | if (time > timeOffset) | ||||
{ | { | ||||
fluid_synth_write_float(fSynth, time - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1); | |||||
if (kUses16Outs) | |||||
processSingle(outBuffer, time - timeOffset, timeOffset); | |||||
else | |||||
fluid_synth_write_float(fSynth, time - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1); | |||||
timeOffset = time; | timeOffset = time; | ||||
} | } | ||||
@@ -1011,7 +1058,7 @@ public: | |||||
} | } | ||||
case kEngineControlEventTypeMidiBank: | case kEngineControlEventTypeMidiBank: | ||||
if (event.channel < 16 && event.channel != 9) // FIXME | |||||
if (event.channel < 16) | |||||
nextBankIds[event.channel] = ctrlEvent.param; | nextBankIds[event.channel] = ctrlEvent.param; | ||||
break; | break; | ||||
@@ -1068,13 +1115,10 @@ public: | |||||
case kEngineEventTypeMidi: | case kEngineEventTypeMidi: | ||||
{ | { | ||||
if (midiEventCount >= MAX_MIDI_EVENTS) | |||||
continue; | |||||
const EngineMidiEvent& midiEvent = event.midi; | const EngineMidiEvent& midiEvent = event.midi; | ||||
uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); | uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); | ||||
uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data); | |||||
uint8_t channel = event.channel; | |||||
// Fix bad note-off | // Fix bad note-off | ||||
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) | if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) | ||||
@@ -1103,8 +1147,18 @@ public: | |||||
const uint8_t pressure = midiEvent.data[2]; | const uint8_t pressure = midiEvent.data[2]; | ||||
// TODO, not in fluidsynth API? | // TODO, not in fluidsynth API? | ||||
Q_UNUSED(note); | |||||
Q_UNUSED(pressure); | |||||
continue; | |||||
// unused | |||||
(void)note; | |||||
(void)pressure; | |||||
} | |||||
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fHints & PLUGIN_OPTION_SELF_AUTOMATION) != 0) | |||||
{ | |||||
const uint8_t control = midiEvent.data[1]; | |||||
const uint8_t value = midiEvent.data[2]; | |||||
fluid_synth_cc(fSynth, channel, control, value); | |||||
} | } | ||||
else if (MIDI_IS_STATUS_AFTERTOUCH(status)) | else if (MIDI_IS_STATUS_AFTERTOUCH(status)) | ||||
{ | { | ||||
@@ -1122,8 +1176,6 @@ public: | |||||
else | else | ||||
continue; | continue; | ||||
midiEventCount += 1; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -1132,7 +1184,12 @@ public: | |||||
kData->postRtEvents.trySplice(); | kData->postRtEvents.trySplice(); | ||||
if (frames > timeOffset) | if (frames > timeOffset) | ||||
fluid_synth_write_float(fSynth, frames - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1); | |||||
{ | |||||
if (kUses16Outs) | |||||
processSingle(outBuffer, frames - timeOffset, timeOffset); | |||||
else | |||||
fluid_synth_write_float(fSynth, frames - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1); | |||||
} | |||||
} // End of Event Input and Processing | } // End of Event Input and Processing | ||||
@@ -1208,6 +1265,60 @@ public: | |||||
kData->activeBefore = kData->active; | kData->activeBefore = kData->active; | ||||
} | } | ||||
void processSingle(float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) | |||||
{ | |||||
for (uint32_t i=0; i < kData->audioOut.count; i++) | |||||
carla_zeroFloat(fAudio16Buffers[i], frames); | |||||
fluid_synth_process(fSynth, frames, 0, nullptr, kData->audioOut.count, fAudio16Buffers); | |||||
for (uint32_t i=0, k; i < kData->audioOut.count; i++) | |||||
{ | |||||
for (k=0; k < frames; k++) | |||||
outBuffer[i][k+timeOffset] = fAudio16Buffers[i][k]; | |||||
} | |||||
} | |||||
void bufferSizeChanged(const uint32_t newBufferSize) | |||||
{ | |||||
if (! kUses16Outs) | |||||
return; | |||||
for (uint32_t i=0; i < kData->audioOut.count; i++) | |||||
{ | |||||
if (fAudio16Buffers[i] != nullptr) | |||||
delete[] fAudio16Buffers[i]; | |||||
fAudio16Buffers[i] = new float[newBufferSize]; | |||||
} | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Cleanup | |||||
void deleteBuffers() | |||||
{ | |||||
carla_debug("FluidSynthPlugin::deleteBuffers() - start"); | |||||
if (fAudio16Buffers != nullptr) | |||||
{ | |||||
for (uint32_t i=0; i < kData->audioOut.count; i++) | |||||
{ | |||||
if (fAudio16Buffers[i] != nullptr) | |||||
{ | |||||
delete[] fAudio16Buffers[i]; | |||||
fAudio16Buffers[i] = nullptr; | |||||
} | |||||
} | |||||
delete[] fAudio16Buffers; | |||||
fAudio16Buffers = nullptr; | |||||
} | |||||
CarlaPlugin::deleteBuffers(); | |||||
carla_debug("FluidSynthPlugin::deleteBuffers() - end"); | |||||
} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
bool init(const char* const filename, const char* const name, const char* const label) | bool init(const char* const filename, const char* const name, const char* const label) | ||||
@@ -1271,13 +1382,16 @@ private: | |||||
FluidSynthParametersMax = 14 | FluidSynthParametersMax = 14 | ||||
}; | }; | ||||
const bool kUses16Outs; | |||||
CarlaString fLabel; | CarlaString fLabel; | ||||
fluid_settings_t* fSettings; | fluid_settings_t* fSettings; | ||||
fluid_synth_t* fSynth; | fluid_synth_t* fSynth; | ||||
int fSynthId; | int fSynthId; | ||||
double fParamBuffers[FluidSynthParametersMax]; | |||||
float** fAudio16Buffers; | |||||
double fParamBuffers[FluidSynthParametersMax]; | |||||
}; | }; | ||||
/**@}*/ | /**@}*/ | ||||
@@ -1290,19 +1404,24 @@ CARLA_BACKEND_END_NAMESPACE | |||||
CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
CarlaPlugin* CarlaPlugin::newSF2(const Initializer& init) | |||||
CarlaPlugin* CarlaPlugin::newSF2(const Initializer& init, const bool use16Outs) | |||||
{ | { | ||||
carla_debug("CarlaPlugin::newSF2({%p, \"%s\", \"%s\", \"%s\"})", init.engine, init.filename, init.name, init.label); | carla_debug("CarlaPlugin::newSF2({%p, \"%s\", \"%s\", \"%s\"})", init.engine, init.filename, init.name, init.label); | ||||
#ifdef WANT_FLUIDSYNTH | #ifdef WANT_FLUIDSYNTH | ||||
if (! fluid_is_soundfont(init.filename)) | if (! fluid_is_soundfont(init.filename)) | ||||
{ | { | ||||
init.engine->setLastError("Requested file is not a valid SoundFont"); | init.engine->setLastError("Requested file is not a valid SoundFont"); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
FluidSynthPlugin* const plugin = new FluidSynthPlugin(init.engine, init.id); | |||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && use16Outs) | |||||
{ | |||||
init.engine->setLastError("Carla's rack mode can only work with Stereo modules, please choose the 2-channel only SoundFont version"); | |||||
return nullptr; | |||||
} | |||||
FluidSynthPlugin* const plugin = new FluidSynthPlugin(init.engine, init.id, use16Outs); | |||||
if (! plugin->init(init.filename, init.name, init.label)) | if (! plugin->init(init.filename, init.name, init.label)) | ||||
{ | { | ||||
@@ -509,7 +509,7 @@ public: | |||||
if (max - min == 0.0f) | if (max - min == 0.0f) | ||||
{ | { | ||||
carla_stderr2("Broken plugin parameter: max - min == 0"); | |||||
carla_stderr2("WARNING - Broken plugin parameter '%s': max - min == 0.0f", fDescriptor->PortNames[i]); | |||||
max = min + 0.1f; | max = min + 0.1f; | ||||
} | } | ||||
@@ -1069,7 +1069,6 @@ public: | |||||
#endif | #endif | ||||
} // End of Post-processing | } // End of Post-processing | ||||
CARLA_PROCESS_CONTINUE_CHECK; | CARLA_PROCESS_CONTINUE_CHECK; | ||||
// -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
@@ -1075,6 +1075,14 @@ class CarlaMainW(QMainWindow): | |||||
if gui: | if gui: | ||||
return gui.encode("utf-8") | return gui.encode("utf-8") | ||||
elif ptype == PLUGIN_SF2: | |||||
if plugin['name'].endswith(" (16 outputs)"): | |||||
# return a dummy non-null pointer | |||||
INTPOINTER = POINTER(c_int) | |||||
ptr = c_int(0x1) | |||||
addr = addressof(ptr) | |||||
return cast(addr, INTPOINTER) | |||||
return c_nullptr | return c_nullptr | ||||
def loadRDFs(self): | def loadRDFs(self): | ||||
@@ -86,3 +86,8 @@ carla-discovery-win64.exe: $(OBJS) ../libs/lilv_win64.a | |||||
clean: | clean: | ||||
rm -f carla-discovery-* | rm -f carla-discovery-* | ||||
# -------------------------------------------------------------- | |||||
debug: | |||||
$(MAKE) DEBUG=true |
@@ -1291,9 +1291,21 @@ void do_fluidsynth_check(const char* const filename, const bool init) | |||||
delete_fluid_settings(f_settings); | delete_fluid_settings(f_settings); | ||||
} | } | ||||
#if CARLA_OS_WIN | |||||
int sep = '\\'; | |||||
#else | |||||
int sep = '/'; | |||||
#endif | |||||
CarlaString name(std::strrchr(filename, sep)+1); | |||||
name.truncate(name.rfind('.')); | |||||
CarlaString label(name); | |||||
// 2 channels | |||||
DISCOVERY_OUT("init", "-----------"); | DISCOVERY_OUT("init", "-----------"); | ||||
DISCOVERY_OUT("name", ""); | |||||
DISCOVERY_OUT("label", ""); | |||||
DISCOVERY_OUT("name", (const char*)name); | |||||
DISCOVERY_OUT("label", (const char*)label); | |||||
DISCOVERY_OUT("maker", ""); | DISCOVERY_OUT("maker", ""); | ||||
DISCOVERY_OUT("copyright", ""); | DISCOVERY_OUT("copyright", ""); | ||||
DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH); | DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH); | ||||
@@ -1307,6 +1319,26 @@ void do_fluidsynth_check(const char* const filename, const bool init) | |||||
DISCOVERY_OUT("parameters.total", 14); | DISCOVERY_OUT("parameters.total", 14); | ||||
DISCOVERY_OUT("build", BINARY_NATIVE); | DISCOVERY_OUT("build", BINARY_NATIVE); | ||||
DISCOVERY_OUT("end", "------------"); | DISCOVERY_OUT("end", "------------"); | ||||
// 16 channels | |||||
if (name.isNotEmpty()) | |||||
name += " (16 outputs)"; | |||||
DISCOVERY_OUT("init", "-----------"); | |||||
DISCOVERY_OUT("name", ""); | |||||
DISCOVERY_OUT("name", (const char*)name); | |||||
DISCOVERY_OUT("label", (const char*)label); | |||||
DISCOVERY_OUT("copyright", ""); | |||||
DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH); | |||||
DISCOVERY_OUT("audio.outs", 32); | |||||
DISCOVERY_OUT("audio.total", 32); | |||||
DISCOVERY_OUT("midi.ins", 1); | |||||
DISCOVERY_OUT("midi.total", 1); | |||||
DISCOVERY_OUT("programs.total", programs); | |||||
DISCOVERY_OUT("parameters.ins", 13); // defined in Carla | |||||
DISCOVERY_OUT("parameters.outs", 1); | |||||
DISCOVERY_OUT("parameters.total", 14); | |||||
DISCOVERY_OUT("build", BINARY_NATIVE); | |||||
DISCOVERY_OUT("end", "------------"); | |||||
#else | #else | ||||
DISCOVERY_OUT("error", "SF2 support not available"); | DISCOVERY_OUT("error", "SF2 support not available"); | ||||
Q_UNUSED(filename); | Q_UNUSED(filename); | ||||
@@ -187,6 +187,30 @@ public: | |||||
truncate(0); | truncate(0); | ||||
} | } | ||||
size_t find(const char c) | |||||
{ | |||||
for (size_t i=0; i < bufferLen; i++) | |||||
{ | |||||
if (buffer[i] == c) | |||||
return i; | |||||
} | |||||
return 0; | |||||
} | |||||
size_t rfind(const char c) | |||||
{ | |||||
size_t pos = 0; | |||||
for (size_t i=0; i < bufferLen; i++) | |||||
{ | |||||
if (buffer[i] == c) | |||||
pos = i; | |||||
} | |||||
return pos; | |||||
} | |||||
void replace(const char before, const char after) | void replace(const char before, const char after) | ||||
{ | { | ||||
if (after == '\0') | if (after == '\0') | ||||