| @@ -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') | ||||