diff --git a/source/backend/Makefile.mk b/source/backend/Makefile.mk index a10fb96e7..28178823c 100644 --- a/source/backend/Makefile.mk +++ b/source/backend/Makefile.mk @@ -32,7 +32,7 @@ BUILD_CXX_FLAGS += -DWANT_JACK endif ifeq ($(HAVE_FLUIDSYNTH),true) -# BUILD_CXX_FLAGS += -DWANT_FLUIDSYNTH +BUILD_CXX_FLAGS += -DWANT_FLUIDSYNTH endif ifeq ($(HAVE_LINUXSAMPLER),true) diff --git a/source/backend/engine/jack.cpp b/source/backend/engine/jack.cpp index 156eb6fb2..0886fd916 100644 --- a/source/backend/engine/jack.cpp +++ b/source/backend/engine/jack.cpp @@ -1044,8 +1044,10 @@ private: float inPeaks[inCount]; float outPeaks[outCount]; - carla_zeroFloat(inPeaks, inCount); - carla_zeroFloat(outPeaks, outCount); + if (inCount > 0) + carla_zeroFloat(inPeaks, inCount); + if (outCount > 0) + carla_zeroFloat(outPeaks, outCount); for (uint32_t i=0; i < inCount; i++) { diff --git a/source/backend/plugin/carla_plugin.pro b/source/backend/plugin/carla_plugin.pro index bf5fe1b23..e2a53b41b 100644 --- a/source/backend/plugin/carla_plugin.pro +++ b/source/backend/plugin/carla_plugin.pro @@ -11,7 +11,8 @@ DEFINES += WANT_LADSPA WANT_DSSI # WANT_LV2 WANT_VST # Samplers -#DEFINES += WANT_FLUIDSYNTH WANT_LINUXSAMPLER +DEFINES += WANT_FLUIDSYNTH +# WANT_LINUXSAMPLER # ZynAddSubFX DEFINES += WANT_ZYNADDSUBFX diff --git a/source/backend/plugin/dssi.cpp b/source/backend/plugin/dssi.cpp index 725adaf99..ff6f00499 100644 --- a/source/backend/plugin/dssi.cpp +++ b/source/backend/plugin/dssi.cpp @@ -98,7 +98,7 @@ public: // ------------------------------------------------------------------- // Information (base) - virtual PluginType type() const + PluginType type() const { return PLUGIN_DSSI; } @@ -891,13 +891,81 @@ public: } // -------------------------------------------------------------------------------------------------------- - // Event Input + // Check if active before - if (kData->event.portIn != nullptr && kData->activeBefore) + if (! kData->activeBefore) { + if (kData->event.portIn != nullptr) + { + for (k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; k++) + { + carla_zeroStruct(fMidiEvents[k]); + carla_zeroStruct(fMidiEvents[k+i]); + + fMidiEvents[k].type = SND_SEQ_EVENT_CONTROLLER; + fMidiEvents[k].data.control.channel = k; + fMidiEvents[k].data.control.param = MIDI_CONTROL_ALL_SOUND_OFF; + + fMidiEvents[k+i].type = SND_SEQ_EVENT_CONTROLLER; + fMidiEvents[k+i].data.control.channel = k; + fMidiEvents[k+i].data.control.param = MIDI_CONTROL_ALL_NOTES_OFF; + } + + midiEventCount = MAX_MIDI_CHANNELS*2; + } + + if (kData->latency > 0) + { + for (i=0; i < kData->audioIn.count; i++) + carla_zeroFloat(kData->latencyBuffers[i], kData->latency); + } + + if (fDescriptor->activate != nullptr) + { + fDescriptor->activate(fHandle); + + if (fHandle2 != nullptr) + fDescriptor->activate(fHandle2); + } + } + + // -------------------------------------------------------------------------------------------------------- + // Event Input and Processing + + else if (kData->event.portIn != nullptr) + { + // ---------------------------------------------------------------------------------------------------- + // MIDI Input (External) + + if (kData->extNotes.mutex.tryLock()) + { + while (midiEventCount < MAX_MIDI_EVENTS && ! kData->extNotes.data.isEmpty()) + { + const ExternalMidiNote& note = kData->extNotes.data.getFirst(true); + + CARLA_ASSERT(note.channel >= 0); + + carla_zeroStruct(fMidiEvents[midiEventCount]); + + fMidiEvents[midiEventCount].type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF; + fMidiEvents[midiEventCount].data.note.channel = note.channel; + fMidiEvents[midiEventCount].data.note.note = note.note; + fMidiEvents[midiEventCount].data.note.velocity = note.velo; + + midiEventCount += 1; + } + + kData->extNotes.mutex.unlock(); + + } // End of MIDI Input (External) + + // ---------------------------------------------------------------------------------------------------- + // Event Input (System) + bool allNotesOffSent = false; uint32_t time, nEvents = kData->event.portIn->getEventCount(); + uint32_t timeOffset = 0; uint32_t nextBankId = 0; if (kData->midiprog.current >= 0 && kData->midiprog.count > 0) @@ -912,6 +980,15 @@ public: if (time >= frames) continue; + CARLA_ASSERT(time >= timeOffset); + + if (time > timeOffset) + { + processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset, midiEventCount); + midiEventCount = 0; + timeOffset = time; + } + // Control change switch (event.type) { @@ -1021,7 +1098,7 @@ public: case kEngineControlEventTypeMidiProgram: if (event.channel == kData->ctrlInChannel) { - uint32_t nextProgramId = ctrlEvent.param; + const uint32_t nextProgramId = ctrlEvent.param; for (k=0; k < kData->midiprog.count; k++) { @@ -1038,7 +1115,7 @@ public: case kEngineControlEventTypeAllSoundOff: if (event.channel == kData->ctrlInChannel) { - if (/*midi.portMin &&*/ ! allNotesOffSent) + if (! allNotesOffSent) sendMidiAllNotesOff(); if (fDescriptor->deactivate != nullptr) @@ -1067,7 +1144,7 @@ public: case kEngineControlEventTypeAllNotesOff: if (event.channel == kData->ctrlInChannel) { - if (/*midi.portMin &&*/ ! allNotesOffSent) + if (! allNotesOffSent) sendMidiAllNotesOff(); allNotesOffSent = true; @@ -1157,39 +1234,26 @@ public: kData->postRtEvents.trySplice(); - // ---------------------------------------------------------------------------------------------------- - // MIDI Input (External) - - if (kData->extNotes.mutex.tryLock()) - { - while (midiEventCount < MAX_MIDI_EVENTS && ! kData->extNotes.data.isEmpty()) - { - const ExternalMidiNote& note = kData->extNotes.data.getFirst(true); - - CARLA_ASSERT(note.channel >= 0); - - carla_zeroStruct(fMidiEvents[midiEventCount]); - - fMidiEvents[midiEventCount].type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF; - fMidiEvents[midiEventCount].data.note.channel = note.channel; - fMidiEvents[midiEventCount].data.note.note = note.note; - fMidiEvents[midiEventCount].data.note.velocity = note.velo; - - midiEventCount += 1; - } + if (frames > timeOffset) + processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset, midiEventCount); - kData->extNotes.mutex.unlock(); + } // End of Event Input and Processing - } // End of MIDI Input (External) + // -------------------------------------------------------------------------------------------------------- + // Plugin processing (no events) - } // End of Event Input + else + { + processSingle(inBuffer, outBuffer, frames, 0, 0); - CARLA_PROCESS_CONTINUE_CHECK; + } // End of Plugin processing (no events) // -------------------------------------------------------------------------------------------------------- // Special Parameters #if 0 + CARLA_PROCESS_CONTINUE_CHECK; + for (k=0; k < param.count; k++) { if (param.data[k].type == PARAMETER_LATENCY) @@ -1201,98 +1265,6 @@ public: CARLA_PROCESS_CONTINUE_CHECK; #endif - // -------------------------------------------------------------------------------------------------------- - // Plugin processing - - { - if (! kData->activeBefore) - { -#if 0 - if (midi.portMin) - { - for (k=0; k < MAX_MIDI_CHANNELS; k++) - { - memset(&midiEvents[k], 0, sizeof(snd_seq_event_t)); //FIXME - midiEvents[k].type = SND_SEQ_EVENT_CONTROLLER; - midiEvents[k].data.control.channel = k; - midiEvents[k].data.control.param = MIDI_CONTROL_ALL_SOUND_OFF; - - memset(&midiEvents[k*2], 0, sizeof(snd_seq_event_t)); //FIXME - midiEvents[k*2].type = SND_SEQ_EVENT_CONTROLLER; - midiEvents[k*2].data.control.channel = k; - midiEvents[k*2].data.control.param = MIDI_CONTROL_ALL_NOTES_OFF; - } - - midiEventCount = MAX_MIDI_CHANNELS; - } -#endif - - if (kData->latency > 0) - { - for (i=0; i < kData->audioIn.count; i++) - carla_zeroFloat(kData->latencyBuffers[i], kData->latency); - } - - if (fDescriptor->activate != nullptr) - { - fDescriptor->activate(fHandle); - - if (fHandle2 != nullptr) - fDescriptor->activate(fHandle2); - } - } - - if (fHandle2 == nullptr) - { - for (i=0; i < kData->audioIn.count; i++) - fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]); - - for (i=0; i < kData->audioOut.count; i++) - fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]); - } - else - { - if (kData->audioIn.count > 0) - { - CARLA_ASSERT(kData->audioIn.count == 2); - - fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]); - fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]); - } - - if (kData->audioOut.count > 0) - { - CARLA_ASSERT(kData->audioOut.count == 2); - - fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]); - fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]); - } - } - - if (fDssiDescriptor->run_synth != nullptr) - { - fDssiDescriptor->run_synth(fHandle, frames, fMidiEvents, midiEventCount); - - if (fHandle2) - fDssiDescriptor->run_synth(fHandle2, frames, fMidiEvents, midiEventCount); - } - else if (fDssiDescriptor->run_multiple_synths != nullptr) - { - LADSPA_Handle handlePtr[2] = { fHandle, fHandle2 }; - snd_seq_event_t* midiEventsPtr[2] = { fMidiEvents, fMidiEvents }; - unsigned long midiEventCountPtr[2] = { midiEventCount, midiEventCount }; - fDssiDescriptor->run_multiple_synths((fHandle2 != nullptr) ? 2 : 1, handlePtr, frames, midiEventsPtr, midiEventCountPtr); - } - else - { - fDescriptor->run(fHandle, frames); - - if (fHandle2) - fDescriptor->run(fHandle2, frames); - } - - } // End of Plugin processing - CARLA_PROCESS_CONTINUE_CHECK; // -------------------------------------------------------------------------------------------------------- @@ -1411,6 +1383,58 @@ public: kData->activeBefore = kData->active; } + void processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset, const uint32_t midiEventCount) + { + if (fHandle2 == nullptr) + { + for (uint32_t i=0; i < kData->audioIn.count; i++) + fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]+timeOffset); + + for (uint32_t i=0; i < kData->audioOut.count; i++) + fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]+timeOffset); + } + else + { + if (kData->audioIn.count > 0) + { + CARLA_ASSERT(kData->audioIn.count == 2); + + fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]+timeOffset); + fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]+timeOffset); + } + + if (kData->audioOut.count > 0) + { + CARLA_ASSERT(kData->audioOut.count == 2); + + fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]+timeOffset); + fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]+timeOffset); + } + } + + if (fDssiDescriptor->run_synth != nullptr) + { + fDssiDescriptor->run_synth(fHandle, frames, fMidiEvents, midiEventCount); + + if (fHandle2) + fDssiDescriptor->run_synth(fHandle2, frames, fMidiEvents, midiEventCount); + } + else if (fDssiDescriptor->run_multiple_synths != nullptr) + { + LADSPA_Handle handlePtr[2] = { fHandle, fHandle2 }; + snd_seq_event_t* midiEventsPtr[2] = { fMidiEvents, fMidiEvents }; + unsigned long midiEventCountPtr[2] = { midiEventCount, midiEventCount }; + fDssiDescriptor->run_multiple_synths((fHandle2 != nullptr) ? 2 : 1, handlePtr, frames, midiEventsPtr, midiEventCountPtr); + } + else + { + fDescriptor->run(fHandle, frames); + + if (fHandle2) + fDescriptor->run(fHandle2, frames); + } + } + // ------------------------------------------------------------------- // Post-poned events diff --git a/source/backend/plugin/fluidsynth.cpp b/source/backend/plugin/fluidsynth.cpp index 804514c14..5707fdbdb 100644 --- a/source/backend/plugin/fluidsynth.cpp +++ b/source/backend/plugin/fluidsynth.cpp @@ -25,68 +25,58 @@ CARLA_BACKEND_START_NAMESPACE - -/*! - * @defgroup CarlaBackendFluidSynthPlugin Carla Backend FluidSynth Plugin - * - * The Carla Backend FluidSynth Plugin.\n - * http://www.fluidsynth.org/ - * @{ - */ - class FluidSynthPlugin : public CarlaPlugin { public: - FluidSynthPlugin(CarlaEngine* const engine, const unsigned short id) + FluidSynthPlugin(CarlaEngine* const engine, const unsigned int id) : CarlaPlugin(engine, id) { qDebug("FluidSynthPlugin::FluidSynthPlugin()"); - m_type = PLUGIN_SF2; - m_label = nullptr; - // create settings - f_settings = new_fluid_settings(); + fSettings = new_fluid_settings(); // define settings - fluid_settings_setnum(f_settings, "synth.sample-rate", x_engine->getSampleRate()); - fluid_settings_setint(f_settings, "synth.threadsafe-api ", 0); + fluid_settings_setnum(fSettings, "synth.sample-rate", kData->engine->getSampleRate()); + fluid_settings_setint(fSettings, "synth.threadsafe-api ", 0); // create synth - f_synth = new_fluid_synth(f_settings); + fSynth = new_fluid_synth(fSettings); #ifdef FLUIDSYNTH_VERSION_NEW_API - fluid_synth_set_sample_rate(f_synth, x_engine->getSampleRate()); + fluid_synth_set_sample_rate(fSynth, kData->engine->getSampleRate()); #endif // set default values - fluid_synth_set_reverb_on(f_synth, 0); - fluid_synth_set_reverb(f_synth, FLUID_REVERB_DEFAULT_ROOMSIZE, FLUID_REVERB_DEFAULT_DAMP, FLUID_REVERB_DEFAULT_WIDTH, FLUID_REVERB_DEFAULT_LEVEL); + fluid_synth_set_reverb_on(fSynth, 0); + fluid_synth_set_reverb(fSynth, FLUID_REVERB_DEFAULT_ROOMSIZE, FLUID_REVERB_DEFAULT_DAMP, FLUID_REVERB_DEFAULT_WIDTH, FLUID_REVERB_DEFAULT_LEVEL); - fluid_synth_set_chorus_on(f_synth, 0); - fluid_synth_set_chorus(f_synth, FLUID_CHORUS_DEFAULT_N, FLUID_CHORUS_DEFAULT_LEVEL, FLUID_CHORUS_DEFAULT_SPEED, FLUID_CHORUS_DEFAULT_DEPTH, FLUID_CHORUS_DEFAULT_TYPE); + fluid_synth_set_chorus_on(fSynth, 0); + fluid_synth_set_chorus(fSynth, FLUID_CHORUS_DEFAULT_N, FLUID_CHORUS_DEFAULT_LEVEL, FLUID_CHORUS_DEFAULT_SPEED, FLUID_CHORUS_DEFAULT_DEPTH, FLUID_CHORUS_DEFAULT_TYPE); - fluid_synth_set_polyphony(f_synth, 64); + fluid_synth_set_polyphony(fSynth, 64); for (int i=0; i < 16; i++) - fluid_synth_set_interp_method(f_synth, i, FLUID_INTERP_DEFAULT); + fluid_synth_set_interp_method(fSynth, i, FLUID_INTERP_DEFAULT); } ~FluidSynthPlugin() { qDebug("FluidSynthPlugin::~FluidSynthPlugin()"); - if (m_label) - free((void*)m_label); - - delete_fluid_synth(f_synth); - delete_fluid_settings(f_settings); + delete_fluid_synth(fSynth); + delete_fluid_settings(fSettings); } // ------------------------------------------------------------------- // Information (base) - PluginCategory category() + PluginType type() const + { + return PLUGIN_SF2; + } + + PluginCategory category() const { return PLUGIN_CATEGORY_SYNTH; } @@ -94,9 +84,9 @@ public: // ------------------------------------------------------------------- // Information (count) - uint32_t parameterScalePointCount(const uint32_t parameterId) + uint32_t parameterScalePointCount(const uint32_t parameterId) const { - CARLA_ASSERT(parameterId < param.count); + CARLA_ASSERT(parameterId < kData->param.count); switch (parameterId) { @@ -112,16 +102,16 @@ public: // ------------------------------------------------------------------- // Information (per-plugin data) - double getParameterValue(const uint32_t parameterId) + float getParameterValue(const uint32_t parameterId) { - CARLA_ASSERT(parameterId < param.count); + CARLA_ASSERT(parameterId < kData->param.count); - return paramBuffers[parameterId]; + return fParamBuffers[parameterId]; } - double getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) + float getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) { - CARLA_ASSERT(parameterId < param.count); + CARLA_ASSERT(parameterId < kData->param.count); CARLA_ASSERT(scalePointId < parameterScalePointCount(parameterId)); switch (parameterId) @@ -151,26 +141,26 @@ public: return FLUID_INTERP_DEFAULT; } default: - return 0.0; + return 0.0f; } } void getLabel(char* const strBuf) { - if (m_label) - strncpy(strBuf, m_label, STR_MAX); + if (fLabel.isNotEmpty()) + std::strncpy(strBuf, (const char*)fLabel, STR_MAX); else CarlaPlugin::getLabel(strBuf); } void getMaker(char* const strBuf) { - strncpy(strBuf, "FluidSynth SF2 engine", STR_MAX); + std::strncpy(strBuf, "FluidSynth SF2 engine", STR_MAX); } void getCopyright(char* const strBuf) { - strncpy(strBuf, "GNU GPL v2+", STR_MAX); + std::strncpy(strBuf, "GNU GPL v2+", STR_MAX); } void getRealName(char* const strBuf) @@ -180,51 +170,51 @@ public: void getParameterName(const uint32_t parameterId, char* const strBuf) { - CARLA_ASSERT(parameterId < param.count); + CARLA_ASSERT(parameterId < kData->param.count); switch (parameterId) { case FluidSynthReverbOnOff: - strncpy(strBuf, "Reverb On/Off", STR_MAX); + std::strncpy(strBuf, "Reverb On/Off", STR_MAX); break; case FluidSynthReverbRoomSize: - strncpy(strBuf, "Reverb Room Size", STR_MAX); + std::strncpy(strBuf, "Reverb Room Size", STR_MAX); break; case FluidSynthReverbDamp: - strncpy(strBuf, "Reverb Damp", STR_MAX); + std::strncpy(strBuf, "Reverb Damp", STR_MAX); break; case FluidSynthReverbLevel: - strncpy(strBuf, "Reverb Level", STR_MAX); + std::strncpy(strBuf, "Reverb Level", STR_MAX); break; case FluidSynthReverbWidth: - strncpy(strBuf, "Reverb Width", STR_MAX); + std::strncpy(strBuf, "Reverb Width", STR_MAX); break; case FluidSynthChorusOnOff: - strncpy(strBuf, "Chorus On/Off", STR_MAX); + std::strncpy(strBuf, "Chorus On/Off", STR_MAX); break; case FluidSynthChorusNr: - strncpy(strBuf, "Chorus Voice Count", STR_MAX); + std::strncpy(strBuf, "Chorus Voice Count", STR_MAX); break; case FluidSynthChorusLevel: - strncpy(strBuf, "Chorus Level", STR_MAX); + std::strncpy(strBuf, "Chorus Level", STR_MAX); break; case FluidSynthChorusSpeedHz: - strncpy(strBuf, "Chorus Speed", STR_MAX); + std::strncpy(strBuf, "Chorus Speed", STR_MAX); break; case FluidSynthChorusDepthMs: - strncpy(strBuf, "Chorus Depth", STR_MAX); + std::strncpy(strBuf, "Chorus Depth", STR_MAX); break; case FluidSynthChorusType: - strncpy(strBuf, "Chorus Type", STR_MAX); + std::strncpy(strBuf, "Chorus Type", STR_MAX); break; case FluidSynthPolyphony: - strncpy(strBuf, "Polyphony", STR_MAX); + std::strncpy(strBuf, "Polyphony", STR_MAX); break; case FluidSynthInterpolation: - strncpy(strBuf, "Interpolation", STR_MAX); + std::strncpy(strBuf, "Interpolation", STR_MAX); break; case FluidSynthVoiceCount: - strncpy(strBuf, "Voice Count", STR_MAX); + std::strncpy(strBuf, "Voice Count", STR_MAX); break; default: CarlaPlugin::getParameterName(parameterId, strBuf); @@ -234,15 +224,15 @@ public: void getParameterUnit(const uint32_t parameterId, char* const strBuf) { - CARLA_ASSERT(parameterId < param.count); + CARLA_ASSERT(parameterId < kData->param.count); switch (parameterId) { case FluidSynthChorusSpeedHz: - strncpy(strBuf, "Hz", STR_MAX); + std::strncpy(strBuf, "Hz", STR_MAX); break; case FluidSynthChorusDepthMs: - strncpy(strBuf, "ms", STR_MAX); + std::strncpy(strBuf, "ms", STR_MAX); break; default: CarlaPlugin::getParameterUnit(parameterId, strBuf); @@ -252,7 +242,7 @@ public: void getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) { - CARLA_ASSERT(parameterId < param.count); + CARLA_ASSERT(parameterId < kData->param.count); CARLA_ASSERT(scalePointId < parameterScalePointCount(parameterId)); switch (parameterId) @@ -261,26 +251,26 @@ public: switch (scalePointId) { case 0: - strncpy(strBuf, "Sine wave", STR_MAX); + std::strncpy(strBuf, "Sine wave", STR_MAX); return; case 1: - strncpy(strBuf, "Triangle wave", STR_MAX); + std::strncpy(strBuf, "Triangle wave", STR_MAX); return; } case FluidSynthInterpolation: switch (scalePointId) { case 0: - strncpy(strBuf, "None", STR_MAX); + std::strncpy(strBuf, "None", STR_MAX); return; case 1: - strncpy(strBuf, "Straight-line", STR_MAX); + std::strncpy(strBuf, "Straight-line", STR_MAX); return; case 2: - strncpy(strBuf, "Fourth-order", STR_MAX); + std::strncpy(strBuf, "Fourth-order", STR_MAX); return; case 3: - strncpy(strBuf, "Seventh-order", STR_MAX); + std::strncpy(strBuf, "Seventh-order", STR_MAX); return; } } @@ -291,30 +281,31 @@ public: // ------------------------------------------------------------------- // Set data (plugin-specific stuff) - void setParameterValue(const uint32_t parameterId, double value, const bool sendGui, const bool sendOsc, const bool sendCallback) + void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) { - CARLA_ASSERT(parameterId < param.count); - paramBuffers[parameterId] = fixParameterValue(value, param.ranges[parameterId]); + CARLA_ASSERT(parameterId < kData->param.count); + + const float fixedValue = kData->param.fixValue(parameterId, value); + fParamBuffers[parameterId] = fixedValue; switch (parameterId) { case FluidSynthReverbOnOff: - value = value > 0.5 ? 1 : 0; - fluid_synth_set_reverb_on(f_synth, value); + fluid_synth_set_reverb_on(fSynth, (fixedValue > 0.5f) ? 1 : 0); break; case FluidSynthReverbRoomSize: case FluidSynthReverbDamp: case FluidSynthReverbLevel: case FluidSynthReverbWidth: - fluid_synth_set_reverb(f_synth, paramBuffers[FluidSynthReverbRoomSize], paramBuffers[FluidSynthReverbDamp], paramBuffers[FluidSynthReverbWidth], paramBuffers[FluidSynthReverbLevel]); + fluid_synth_set_reverb(fSynth, fParamBuffers[FluidSynthReverbRoomSize], fParamBuffers[FluidSynthReverbDamp], fParamBuffers[FluidSynthReverbWidth], fParamBuffers[FluidSynthReverbLevel]); break; case FluidSynthChorusOnOff: { - const ScopedDisabler m(this, ! x_engine->isOffline()); - value = value > 0.5 ? 1 : 0; - fluid_synth_set_chorus_on(f_synth, value); + // FIXME + //const ScopedDisabler m(this, ! kData->engine->isOffline()); + fluid_synth_set_chorus_on(fSynth, (value > 0.5f) ? 1 : 0); break; } @@ -324,23 +315,28 @@ public: case FluidSynthChorusDepthMs: case FluidSynthChorusType: { - const ScopedDisabler m(this, ! x_engine->isOffline()); - fluid_synth_set_chorus(f_synth, rint(paramBuffers[FluidSynthChorusNr]), paramBuffers[FluidSynthChorusLevel], paramBuffers[FluidSynthChorusSpeedHz], paramBuffers[FluidSynthChorusDepthMs], rint(paramBuffers[FluidSynthChorusType])); + //FIXME + //const ScopedDisabler m(this, ! kData->engine->isOffline()); + fluid_synth_set_chorus(fSynth, fParamBuffers[FluidSynthChorusNr], fParamBuffers[FluidSynthChorusLevel], fParamBuffers[FluidSynthChorusSpeedHz], fParamBuffers[FluidSynthChorusDepthMs], fParamBuffers[FluidSynthChorusType]); break; } case FluidSynthPolyphony: { - const ScopedDisabler m(this, ! x_engine->isOffline()); - fluid_synth_set_polyphony(f_synth, rint(value)); + //FIXME + //const ScopedDisabler m(this, ! kData->engine->isOffline()); + fluid_synth_set_polyphony(fSynth, value); break; } case FluidSynthInterpolation: { - const ScopedDisabler m(this, ! x_engine->isOffline()); + //FIXME + //const ScopedDisabler m(this, ! kData->engine->isOffline()); + for (int i=0; i < 16; i++) - fluid_synth_set_interp_method(f_synth, i, rint(value)); + fluid_synth_set_interp_method(fSynth, i, value); + break; } @@ -353,27 +349,31 @@ public: void setMidiProgram(int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool block) { - CARLA_ASSERT(index >= -1 && index < (int32_t)midiprog.count); + CARLA_ASSERT(index >= -1 && index < static_cast(kData->midiprog.count)); if (index < -1) index = -1; - else if (index > (int32_t)midiprog.count) + else if (index > static_cast(kData->midiprog.count)) return; - if (m_ctrlInChannel < 0 || m_ctrlInChannel > 15) + if (kData->ctrlInChannel < 0 || kData->ctrlInChannel >= 16) return; + // FIXME if (index >= 0) { - if (x_engine->isOffline()) + const uint32_t bank = kData->midiprog.data[index].bank; + const uint32_t program = kData->midiprog.data[index].program; + + if (kData->engine->isOffline()) { - const CarlaEngine::ScopedLocker m(x_engine, block); - fluid_synth_program_select(f_synth, m_ctrlInChannel, f_id, midiprog.data[index].bank, midiprog.data[index].program); + //const CarlaEngine::ScopedLocker m(x_engine, block); + fluid_synth_program_select(fSynth, kData->ctrlInChannel, fSynthId, bank, program); } else { - const ScopedDisabler m(this, block); - fluid_synth_program_select(f_synth, m_ctrlInChannel, f_id, midiprog.data[index].bank, midiprog.data[index].program); + //const ScopedDisabler m(this, block); + fluid_synth_program_select(fSynth, kData->ctrlInChannel, fSynthId, bank, program); } } @@ -386,33 +386,27 @@ public: void reload() { qDebug("FluidSynthPlugin::reload() - start"); - CARLA_ASSERT(f_synth); + CARLA_ASSERT(kData->engine != nullptr); + CARLA_ASSERT(fSynth != nullptr); - const ProcessMode processMode(x_engine->getOptions().processMode); + const ProcessMode processMode(kData->engine->getProccessMode()); // Safely disable plugin for reload - const ScopedDisabler m(this); - - if (x_client->isActive()) - x_client->deactivate(); + const ScopedDisabler sd(this); - // Remove client ports - removeClientPorts(); + if (kData->client->isActive()) + kData->client->deactivate(); - // Delete old data deleteBuffers(); uint32_t aOuts, params, j; aOuts = 2; params = FluidSynthParametersMax; - aOut.ports = new CarlaEngineAudioPort*[aOuts]; - aOut.rindexes = new uint32_t[aOuts]; - - param.data = new ParameterData[params]; - param.ranges = new ParameterRanges[params]; + kData->audioOut.createNew(aOuts); + kData->param.createNew(params); - const int portNameSize = x_engine->maxPortNameSize(); + const int portNameSize = kData->engine->maxPortNameSize(); CarlaString portName; // --------------------------------------- @@ -423,15 +417,15 @@ public: if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } portName += "out-left"; portName.truncate(portNameSize); - aOut.ports[0] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false); - aOut.rindexes[0] = 0; + kData->audioOut.ports[0].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); + kData->audioOut.ports[0].rindex = 0; } { @@ -439,308 +433,290 @@ public: if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } portName += "out-right"; portName.truncate(portNameSize); - aOut.ports[1] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false); - aOut.rindexes[1] = 1; + kData->audioOut.ports[1].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); + kData->audioOut.ports[1].rindex = 1; } // --------------------------------------- - // MIDI Input + // Event Input { portName.clear(); if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } - portName += "midi-in"; + portName += "event-in"; portName.truncate(portNameSize); - midi.portMin = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, true); + kData->event.portIn = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, true); } // --------------------------------------- - // Parameters + // Event Output { portName.clear(); if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } - portName += "control-in"; + portName += "event-out"; portName.truncate(portNameSize); - param.portCin = (CarlaEngineControlPort*)x_client->addPort(CarlaEnginePortTypeControl, portName, true); - } - - { - portName.clear(); - - if (processMode == PROCESS_MODE_SINGLE_CLIENT) - { - portName = m_name; - portName += ":"; - } - - portName += "control-out"; - portName.truncate(portNameSize); - - param.portCout = (CarlaEngineControlPort*)x_client->addPort(CarlaEnginePortTypeControl, portName, false); + kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); } // ---------------------- j = FluidSynthReverbOnOff; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE | PARAMETER_IS_BOOLEAN; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 1.0; - param.ranges[j].def = 0.0; // off - param.ranges[j].step = 1.0; - param.ranges[j].stepSmall = 1.0; - param.ranges[j].stepLarge = 1.0; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE | PARAMETER_IS_BOOLEAN; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 1.0f; + kData->param.ranges[j].def = 0.0f; // off + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 1.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthReverbRoomSize; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 1.2; - param.ranges[j].def = FLUID_REVERB_DEFAULT_ROOMSIZE; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 1.2f; + kData->param.ranges[j].def = FLUID_REVERB_DEFAULT_ROOMSIZE; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthReverbDamp; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 1.0; - param.ranges[j].def = FLUID_REVERB_DEFAULT_DAMP; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 1.0f; + kData->param.ranges[j].def = FLUID_REVERB_DEFAULT_DAMP; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthReverbLevel; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; - param.data[j].midiChannel = 0; - param.data[j].midiCC = MIDI_CONTROL_REVERB_SEND_LEVEL; - param.ranges[j].min = 0.0; - param.ranges[j].max = 1.0; - param.ranges[j].def = FLUID_REVERB_DEFAULT_LEVEL; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = MIDI_CONTROL_REVERB_SEND_LEVEL; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 1.0f; + kData->param.ranges[j].def = FLUID_REVERB_DEFAULT_LEVEL; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthReverbWidth; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 10.0; // should be 100, but that sounds too much - param.ranges[j].def = FLUID_REVERB_DEFAULT_WIDTH; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 10.0f; // should be 100, but that sounds too much + kData->param.ranges[j].def = FLUID_REVERB_DEFAULT_WIDTH; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthChorusOnOff; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_BOOLEAN; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 1.0; - param.ranges[j].def = 0.0; // off - param.ranges[j].step = 1.0; - param.ranges[j].stepSmall = 1.0; - param.ranges[j].stepLarge = 1.0; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_BOOLEAN; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 1.0f; + kData->param.ranges[j].def = 0.0f; // off + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 1.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthChorusNr; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 99.0; - param.ranges[j].def = FLUID_CHORUS_DEFAULT_N; - param.ranges[j].step = 1.0; - param.ranges[j].stepSmall = 1.0; - param.ranges[j].stepLarge = 10.0; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 99.0f; + kData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_N; + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 10.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthChorusLevel; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED; - param.data[j].midiChannel = 0; - param.data[j].midiCC = 0; //MIDI_CONTROL_CHORUS_SEND_LEVEL; - param.ranges[j].min = 0.0; - param.ranges[j].max = 10.0; - param.ranges[j].def = FLUID_CHORUS_DEFAULT_LEVEL; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = 0; //MIDI_CONTROL_CHORUS_SEND_LEVEL; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 10.0f; + kData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_LEVEL; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthChorusSpeedHz; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.29; - param.ranges[j].max = 5.0; - param.ranges[j].def = FLUID_CHORUS_DEFAULT_SPEED; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.29f; + kData->param.ranges[j].max = 5.0f; + kData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_SPEED; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthChorusDepthMs; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0.0; - param.ranges[j].max = 2048000.0 / x_engine->getSampleRate(); - param.ranges[j].def = FLUID_CHORUS_DEFAULT_DEPTH; - param.ranges[j].step = 0.01; - param.ranges[j].stepSmall = 0.0001; - param.ranges[j].stepLarge = 0.1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 2048000.0 / kData->engine->getSampleRate(); + kData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_DEPTH; + kData->param.ranges[j].step = 0.01f; + kData->param.ranges[j].stepSmall = 0.0001f; + kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthChorusType; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER | PARAMETER_USES_SCALEPOINTS; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = FLUID_CHORUS_MOD_SINE; - param.ranges[j].max = FLUID_CHORUS_MOD_TRIANGLE; - param.ranges[j].def = FLUID_CHORUS_DEFAULT_TYPE; - param.ranges[j].step = 1; - param.ranges[j].stepSmall = 1; - param.ranges[j].stepLarge = 1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER | PARAMETER_USES_SCALEPOINTS; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = FLUID_CHORUS_MOD_SINE; + kData->param.ranges[j].max = FLUID_CHORUS_MOD_TRIANGLE; + kData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_TYPE; + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 1.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthPolyphony; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 1; - param.ranges[j].max = 512; // max theoric is 65535 - param.ranges[j].def = fluid_synth_get_polyphony(f_synth); - param.ranges[j].step = 1; - param.ranges[j].stepSmall = 1; - param.ranges[j].stepLarge = 10; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 1.0f; + kData->param.ranges[j].max = 512.0f; // max theoric is 65535 + kData->param.ranges[j].def = fluid_synth_get_polyphony(fSynth); + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 10.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthInterpolation; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_INPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER | PARAMETER_USES_SCALEPOINTS; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = FLUID_INTERP_NONE; - param.ranges[j].max = FLUID_INTERP_HIGHEST; - param.ranges[j].def = FLUID_INTERP_DEFAULT; - param.ranges[j].step = 1; - param.ranges[j].stepSmall = 1; - param.ranges[j].stepLarge = 1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_INTEGER | PARAMETER_USES_SCALEPOINTS; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = FLUID_INTERP_NONE; + kData->param.ranges[j].max = FLUID_INTERP_HIGHEST; + kData->param.ranges[j].def = FLUID_INTERP_DEFAULT; + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 1.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // ---------------------- j = FluidSynthVoiceCount; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].type = PARAMETER_OUTPUT; - param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE | PARAMETER_IS_INTEGER; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; - param.ranges[j].min = 0; - param.ranges[j].max = 65535; - param.ranges[j].def = 0; - param.ranges[j].step = 1; - param.ranges[j].stepSmall = 1; - param.ranges[j].stepLarge = 1; - paramBuffers[j] = param.ranges[j].def; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].type = PARAMETER_OUTPUT; + kData->param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE | PARAMETER_IS_INTEGER; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].max = 65535.0f; + kData->param.ranges[j].def = 0.0f; + kData->param.ranges[j].step = 1.0f; + kData->param.ranges[j].stepSmall = 1.0f; + kData->param.ranges[j].stepLarge = 1.0f; + fParamBuffers[j] = kData->param.ranges[j].def; // --------------------------------------- - aOut.count = aOuts; - param.count = params; - // plugin checks - m_hints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); + fHints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); - m_hints |= PLUGIN_IS_SYNTH; - m_hints |= PLUGIN_CAN_VOLUME; - m_hints |= PLUGIN_CAN_BALANCE; - m_hints |= PLUGIN_CAN_FORCE_STEREO; + fHints |= PLUGIN_IS_SYNTH; + fHints |= PLUGIN_CAN_VOLUME; + fHints |= PLUGIN_CAN_BALANCE; + fHints |= PLUGIN_CAN_FORCE_STEREO; reloadPrograms(true); - x_client->activate(); + kData->client->activate(); qDebug("FluidSynthPlugin::reload() - end"); } @@ -750,46 +726,41 @@ public: qDebug("FluidSynthPlugin::reloadPrograms(%s)", bool2str(init)); // Delete old programs - if (midiprog.count > 0) - { - for (uint32_t i=0; i < midiprog.count; i++) - free((void*)midiprog.data[i].name); - - delete[] midiprog.data; - } - - midiprog.count = 0; - midiprog.data = nullptr; + kData->midiprog.clear(); // Query new programs + uint32_t count = 0; fluid_sfont_t* f_sfont; fluid_preset_t f_preset; bool hasDrums = false; - f_sfont = fluid_synth_get_sfont_by_id(f_synth, f_id); + f_sfont = fluid_synth_get_sfont_by_id(fSynth, fSynthId); // initial check to know how much midi-programs we have f_sfont->iteration_start(f_sfont); while (f_sfont->iteration_next(f_sfont, &f_preset)) - midiprog.count += 1; + count += 1; // soundfonts must always have at least 1 midi-program - CARLA_ASSERT(midiprog.count > 0); + CARLA_ASSERT(count > 0); + + if (count == 0) + return; - if (midiprog.count > 0) - midiprog.data = new MidiProgramData[midiprog.count]; + kData->midiprog.createNew(count); // Update data uint32_t i = 0; f_sfont->iteration_start(f_sfont); + while (f_sfont->iteration_next(f_sfont, &f_preset)) { - CARLA_ASSERT(i < midiprog.count); - midiprog.data[i].bank = f_preset.get_banknum(&f_preset); - midiprog.data[i].program = f_preset.get_num(&f_preset); - midiprog.data[i].name = strdup(f_preset.get_name(&f_preset)); + CARLA_ASSERT(i < kData->midiprog.count); + kData->midiprog.data[i].bank = f_preset.get_banknum(&f_preset); + kData->midiprog.data[i].program = f_preset.get_num(&f_preset); + kData->midiprog.data[i].name = carla_strdup(f_preset.get_name(&f_preset)); - if (midiprog.data[i].bank == 128) + if (kData->midiprog.data[i].bank == 128) hasDrums = true; i++; @@ -798,38 +769,39 @@ public: //f_sfont->free(f_sfont); // Update OSC Names - if (x_engine->isOscControlRegistered()) + if (kData->engine->isOscControlRegistered()) { - x_engine->osc_send_control_set_midi_program_count(m_id, midiprog.count); + kData->engine->osc_send_control_set_midi_program_count(fId, kData->midiprog.count); - for (i=0; i < midiprog.count; i++) - x_engine->osc_send_control_set_midi_program_data(m_id, i, midiprog.data[i].bank, midiprog.data[i].program, midiprog.data[i].name); + for (i=0; i < kData->midiprog.count; i++) + kData->engine->osc_send_control_set_midi_program_data(fId, i, kData->midiprog.data[i].bank, kData->midiprog.data[i].program, kData->midiprog.data[i].name); } if (init) { - fluid_synth_program_reset(f_synth); + fluid_synth_program_reset(fSynth); + // select first program, or 128 for ch10 for (i=0; i < 16 && i != 9; i++) { - fluid_synth_program_select(f_synth, i, f_id, midiprog.data[0].bank, midiprog.data[0].program); + fluid_synth_program_select(fSynth, i, fSynthId, kData->midiprog.data[0].bank, kData->midiprog.data[0].program); #ifdef FLUIDSYNTH_VERSION_NEW_API - fluid_synth_set_channel_type(f_synth, i, CHANNEL_TYPE_MELODIC); + fluid_synth_set_channel_type(fSynth, i, CHANNEL_TYPE_MELODIC); #endif } if (hasDrums) { - fluid_synth_program_select(f_synth, 9, f_id, 128, 0); + fluid_synth_program_select(fSynth, 9, fSynthId, 128, 0); #ifdef FLUIDSYNTH_VERSION_NEW_API - fluid_synth_set_channel_type(f_synth, 9, CHANNEL_TYPE_DRUM); + fluid_synth_set_channel_type(fSynth, 9, CHANNEL_TYPE_DRUM); #endif } else { - fluid_synth_program_select(f_synth, 9, f_id, midiprog.data[0].bank, midiprog.data[0].program); + fluid_synth_program_select(fSynth, 9, fSynthId, kData->midiprog.data[0].bank, kData->midiprog.data[0].program); #ifdef FLUIDSYNTH_VERSION_NEW_API - fluid_synth_set_channel_type(f_synth, 9, CHANNEL_TYPE_MELODIC); + fluid_synth_set_channel_type(fSynth, 9, CHANNEL_TYPE_MELODIC); #endif } @@ -837,7 +809,7 @@ public: } else { - x_engine->callback(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0, nullptr); + kData->engine->callback(CALLBACK_RELOAD_PROGRAMS, fId, 0, 0, 0.0f, nullptr); } } @@ -849,370 +821,367 @@ public: uint32_t i, k; uint32_t midiEventCount = 0; - double aOutsPeak[2] = { 0.0 }; + // -------------------------------------------------------------------------------------------------------- + // Check if active - CARLA_PROCESS_CONTINUE_CHECK; + if (! kData->active) + { + // disable any output sound + for (i=0; i < kData->audioOut.count; i++) + carla_zeroFloat(outBuffer[i], frames); + + kData->activeBefore = kData->active; + return; + } + + // -------------------------------------------------------------------------------------------------------- + // Check if active before + + if (! kData->activeBefore) + { + for (int c=0; c < MAX_MIDI_CHANNELS; c++) + { +#ifdef FLUIDSYNTH_VERSION_NEW_API + fluid_synth_all_notes_off(fSynth, c); + fluid_synth_all_sounds_off(fSynth, c); +#else + fluid_synth_cc(f_synth, c, MIDI_CONTROL_ALL_SOUND_OFF, 0); + fluid_synth_cc(f_synth, c, MIDI_CONTROL_ALL_NOTES_OFF, 0); +#endif + } + } // -------------------------------------------------------------------------------------------------------- - // Parameters Input [Automation] + // Event Input and Processing - if (m_active && m_activeBefore) + else { + // ---------------------------------------------------------------------------------------------------- + // MIDI Input (External) + + if (kData->extNotes.mutex.tryLock()) + { + while (! kData->extNotes.data.isEmpty()) + { + const ExternalMidiNote& note = kData->extNotes.data.getFirst(true); + + CARLA_ASSERT(note.channel >= 0); + + if (note.velo > 0) + fluid_synth_noteon(fSynth, note.channel, note.note, note.velo); + else + fluid_synth_noteoff(fSynth,note.channel, note.note); + + midiEventCount += 1; + } + + kData->extNotes.mutex.unlock(); + + } // End of MIDI Input (External) + + // ---------------------------------------------------------------------------------------------------- + // Event Input (System) + bool allNotesOffSent = false; - const CarlaEngineControlEvent* cinEvent; - uint32_t time, nEvents = param.portCin->getEventCount(); + uint32_t time, nEvents = kData->event.portIn->getEventCount(); + uint32_t timeOffset = 0; - unsigned char nextBankIds[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0 }; + uint32_t nextBankIds[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0 }; - if (midiprog.current >= 0 && midiprog.count > 0 && m_ctrlInChannel >= 0 && m_ctrlInChannel < 16) - nextBankIds[m_ctrlInChannel] = midiprog.data[midiprog.current].bank; + if (kData->midiprog.current >= 0 && kData->midiprog.count > 0 && kData->ctrlInChannel >= 0 && kData->ctrlInChannel < 16) + nextBankIds[kData->ctrlInChannel] = kData->midiprog.data[kData->midiprog.current].bank; for (i=0; i < nEvents; i++) { - cinEvent = param.portCin->getEvent(i); - - if (! cinEvent) - continue; + const EngineEvent& event = kData->event.portIn->getEvent(i); - time = cinEvent->time - framesOffset; + time = event.time - framesOffset; if (time >= frames) continue; + CARLA_ASSERT(time >= timeOffset); + + if (time > timeOffset) + { + fluid_synth_write_float(fSynth, time - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1); + timeOffset = time; + } + // Control change - switch (cinEvent->type) + switch (event.type) { - case CarlaEngineNullEvent: + case kEngineEventTypeNull: break; - case CarlaEngineParameterChangeEvent: + case kEngineEventTypeControl: { - double value; + const EngineControlEvent& ctrlEvent = event.ctrl; - // Control backend stuff - if (cinEvent->channel == m_ctrlInChannel) + switch (ctrlEvent.type) { - if (MIDI_IS_CONTROL_BREATH_CONTROLLER(cinEvent->parameter) && (m_hints & PLUGIN_CAN_DRYWET) > 0) - { - value = cinEvent->value; - setDryWet(value, false, false); - postponeEvent(PluginPostEventParameterChange, PARAMETER_DRYWET, 0, value); - continue; - } - - if (MIDI_IS_CONTROL_CHANNEL_VOLUME(cinEvent->parameter) && (m_hints & PLUGIN_CAN_VOLUME) > 0) - { - value = cinEvent->value*127/100; - setVolume(value, false, false); - postponeEvent(PluginPostEventParameterChange, PARAMETER_VOLUME, 0, value); - continue; - } + case kEngineControlEventTypeNull: + break; - if (MIDI_IS_CONTROL_BALANCE(cinEvent->parameter) && (m_hints & PLUGIN_CAN_BALANCE) > 0) + case kEngineControlEventTypeParameter: + { + // Control backend stuff + if (event.channel == kData->ctrlInChannel) { - double left, right; - value = cinEvent->value/0.5 - 1.0; + double value; - if (value < 0.0) + if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (fHints & PLUGIN_CAN_DRYWET) > 0) { - left = -1.0; - right = (value*2)+1.0; + value = ctrlEvent.value; + setDryWet(value, false, false); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_DRYWET, 0, value); + continue; } - else if (value > 0.0) + + if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (fHints & PLUGIN_CAN_VOLUME) > 0) { - left = (value*2)-1.0; - right = 1.0; + value = ctrlEvent.value*127/100; + setVolume(value, false, false); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_VOLUME, 0, value); + continue; } - else + + if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (fHints & PLUGIN_CAN_BALANCE) > 0) { - left = -1.0; - right = 1.0; - } + double left, right; + value = ctrlEvent.value/0.5 - 1.0; + + if (value < 0.0) + { + left = -1.0; + right = (value*2)+1.0; + } + else if (value > 0.0) + { + left = (value*2)-1.0; + right = 1.0; + } + else + { + left = -1.0; + right = 1.0; + } - setBalanceLeft(left, false, false); - setBalanceRight(right, false, false); - postponeEvent(PluginPostEventParameterChange, PARAMETER_BALANCE_LEFT, 0, left); - postponeEvent(PluginPostEventParameterChange, PARAMETER_BALANCE_RIGHT, 0, right); - continue; + setBalanceLeft(left, false, false); + setBalanceRight(right, false, false); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_BALANCE_LEFT, 0, left); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_BALANCE_RIGHT, 0, right); + continue; + } } - } - // Control plugin parameters - for (k=0; k < param.count; k++) - { - if (param.data[k].midiChannel != cinEvent->channel) - continue; - if (param.data[k].midiCC != cinEvent->parameter) - continue; - if (param.data[k].type != PARAMETER_INPUT) - continue; - - if (param.data[k].hints & PARAMETER_IS_AUTOMABLE) + // Control plugin parameters + for (k=0; k < kData->param.count; k++) { - if (param.data[k].hints & PARAMETER_IS_BOOLEAN) + if (kData->param.data[k].midiChannel != event.channel) + continue; + if (kData->param.data[k].midiCC != ctrlEvent.param) + continue; + if (kData->param.data[k].type != PARAMETER_INPUT) + continue; + if ((kData->param.data[k].hints & PARAMETER_IS_AUTOMABLE) == 0) + continue; + + double value; + + if (kData->param.data[k].hints & PARAMETER_IS_BOOLEAN) { - value = cinEvent->value < 0.5 ? param.ranges[k].min : param.ranges[k].max; + value = (ctrlEvent.value < 0.5) ? kData->param.ranges[k].min : kData->param.ranges[k].max; } else { - value = cinEvent->value * (param.ranges[k].max - param.ranges[k].min) + param.ranges[k].min; + // FIXME - ranges call for this + value = ctrlEvent.value * (kData->param.ranges[k].max - kData->param.ranges[k].min) + kData->param.ranges[k].min; - if (param.data[k].hints & PARAMETER_IS_INTEGER) - value = rint(value); + if (kData->param.data[k].hints & PARAMETER_IS_INTEGER) + value = std::rint(value); } setParameterValue(k, value, false, false, false); - postponeEvent(PluginPostEventParameterChange, k, 0, value); + postponeRtEvent(kPluginPostRtEventParameterChange, k, 0, value); } - } - - break; - } - case CarlaEngineMidiBankChangeEvent: - if (cinEvent->channel < 16) - nextBankIds[cinEvent->channel] = rint(cinEvent->value); - break; + break; + } - case CarlaEngineMidiProgramChangeEvent: - if (cinEvent->channel < 16) - { - uint32_t bankId = nextBankIds[cinEvent->channel]; - uint32_t progId = rint(cinEvent->value); + case kEngineControlEventTypeMidiBank: + if (event.channel < 16) + nextBankIds[event.channel] = ctrlEvent.param; + break; - for (k=0; k < midiprog.count; k++) + case kEngineControlEventTypeMidiProgram: + if (event.channel < 16) { - if (midiprog.data[k].bank == bankId && midiprog.data[k].program == progId) + const uint32_t bankId = nextBankIds[event.channel]; + const uint32_t progId = ctrlEvent.param; + + for (k=0; k < kData->midiprog.count; k++) { - if (cinEvent->channel == m_ctrlInChannel) + if (kData->midiprog.data[k].bank == bankId && kData->midiprog.data[k].program == progId) { - setMidiProgram(k, false, false, false, false); - postponeEvent(PluginPostEventMidiProgramChange, k, 0, 0.0); + if (event.channel == kData->ctrlInChannel) + { + setMidiProgram(k, false, false, false, false); + postponeRtEvent(kPluginPostRtEventMidiProgramChange, k, 0, 0.0); + } + else + fluid_synth_program_select(fSynth, event.channel, fSynthId, bankId, progId); + + break; } - else - fluid_synth_program_select(f_synth, cinEvent->channel, f_id, bankId, progId); - - break; } } - } - break; - - case CarlaEngineAllSoundOffEvent: - if (cinEvent->channel == m_ctrlInChannel) - { - if (! allNotesOffSent) - sendMidiAllNotesOff(); - - postponeEvent(PluginPostEventParameterChange, PARAMETER_ACTIVE, 0, 0.0); - postponeEvent(PluginPostEventParameterChange, PARAMETER_ACTIVE, 0, 1.0); - - allNotesOffSent = true; - } - break; - - case CarlaEngineAllNotesOffEvent: - if (cinEvent->channel == m_ctrlInChannel) - { - if (! allNotesOffSent) - sendMidiAllNotesOff(); - - allNotesOffSent = true; - } - break; - } - } - } // End of Parameters Input + break; - CARLA_PROCESS_CONTINUE_CHECK; + case kEngineControlEventTypeAllSoundOff: + if (event.channel == kData->ctrlInChannel) + { + if (! allNotesOffSent) + sendMidiAllNotesOff(); - // -------------------------------------------------------------------------------------------------------- - // MIDI Input + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_ACTIVE, 0, 0.0); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_ACTIVE, 0, 1.0); - if (m_active && m_activeBefore) - { - // ---------------------------------------------------------------------------------------------------- - // MIDI Input (External) + allNotesOffSent = true; + } + break; - { - engineMidiLock(); + case kEngineControlEventTypeAllNotesOff: + if (event.channel == kData->ctrlInChannel) + { + if (! allNotesOffSent) + sendMidiAllNotesOff(); - for (i=0; i < MAX_MIDI_EVENTS && midiEventCount < MAX_MIDI_EVENTS; i++) - { - if (extMidiNotes[i].channel < 0) + allNotesOffSent = true; + } break; + } - if (extMidiNotes[i].velo) - fluid_synth_noteon(f_synth, m_ctrlInChannel, extMidiNotes[i].note, extMidiNotes[i].velo); - else - fluid_synth_noteoff(f_synth, m_ctrlInChannel, extMidiNotes[i].note); - - extMidiNotes[i].channel = -1; // mark as invalid - midiEventCount += 1; + break; } - engineMidiUnlock(); - - } // End of MIDI Input (External) - - CARLA_PROCESS_CONTINUE_CHECK; - - // ---------------------------------------------------------------------------------------------------- - // MIDI Input (System) - - { - const CarlaEngineMidiEvent* minEvent; - uint32_t time, nEvents = midi.portMin->getEventCount(); - - for (i=0; i < nEvents && midiEventCount < MAX_MIDI_EVENTS; i++) + case kEngineEventTypeMidi: { - minEvent = midi.portMin->getEvent(i); - - if (! minEvent) + if (midiEventCount >= MAX_MIDI_EVENTS) continue; - time = minEvent->time - framesOffset; - - if (time >= frames) - continue; + const EngineMidiEvent& midiEvent = event.midi; - uint8_t status = minEvent->data[0]; - uint8_t channel = status & 0x0F; + uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); + uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data); // Fix bad note-off - if (MIDI_IS_STATUS_NOTE_ON(status) && minEvent->data[2] == 0) + if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) status -= 0x10; if (MIDI_IS_STATUS_NOTE_OFF(status)) { - uint8_t note = minEvent->data[1]; + const uint8_t note = midiEvent.data[1]; - fluid_synth_noteoff(f_synth, channel, note); + fluid_synth_noteoff(fSynth, channel, note); - postponeEvent(PluginPostEventNoteOff, channel, note, 0.0); + postponeRtEvent(kPluginPostRtEventNoteOff, channel, note, 0.0); } else if (MIDI_IS_STATUS_NOTE_ON(status)) { - uint8_t note = minEvent->data[1]; - uint8_t velo = minEvent->data[2]; + const uint8_t note = midiEvent.data[1]; + const uint8_t velo = midiEvent.data[2]; - fluid_synth_noteon(f_synth, channel, note, velo); + fluid_synth_noteon(fSynth, channel, note, velo); - postponeEvent(PluginPostEventNoteOn, channel, note, velo); + postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); } else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status)) { + const uint8_t note = midiEvent.data[1]; + const uint8_t pressure = midiEvent.data[2]; + // TODO, not in fluidsynth API? + Q_UNUSED(note); + Q_UNUSED(pressure); } else if (MIDI_IS_STATUS_AFTERTOUCH(status)) { - uint8_t pressure = minEvent->data[1]; + const uint8_t pressure = midiEvent.data[1]; - fluid_synth_channel_pressure(f_synth, channel, pressure); + fluid_synth_channel_pressure(fSynth, channel, pressure);; } else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status)) { - uint8_t lsb = minEvent->data[1]; - uint8_t msb = minEvent->data[2]; + const uint8_t lsb = midiEvent.data[1]; + const uint8_t msb = midiEvent.data[2]; - fluid_synth_pitch_bend(f_synth, channel, (msb << 7) | lsb); + fluid_synth_pitch_bend(fSynth, channel, (msb << 7) | lsb); } else continue; midiEventCount += 1; - } - } // End of MIDI Input (System) - - } // End of MIDI Input - - CARLA_PROCESS_CONTINUE_CHECK; - - // -------------------------------------------------------------------------------------------------------- - // Plugin processing - if (m_active) - { - if (! m_activeBefore) - { - for (int c=0; c < MAX_MIDI_CHANNELS; c++) - { -#ifdef FLUIDSYNTH_VERSION_NEW_API - fluid_synth_all_notes_off(f_synth, c); - fluid_synth_all_sounds_off(f_synth, c); -#else - fluid_synth_cc(f_synth, c, MIDI_CONTROL_ALL_SOUND_OFF, 0); - fluid_synth_cc(f_synth, c, MIDI_CONTROL_ALL_NOTES_OFF, 0); -#endif + break; + } } } - fluid_synth_process(f_synth, frames, 0, nullptr, 2, outBuffer); - } + kData->postRtEvents.trySplice(); + + if (frames > timeOffset) + fluid_synth_write_float(fSynth, frames - timeOffset, outBuffer[0] + timeOffset, 0, 1, outBuffer[1] + timeOffset, 0, 1); + + } // End of Event Input and Processing CARLA_PROCESS_CONTINUE_CHECK; // -------------------------------------------------------------------------------------------------------- - // Post-processing (balance and volume) + // Post-processing (volume and balance) - if (m_active) { - bool do_balance = (x_balanceLeft != -1.0 || x_balanceRight != 1.0); + const bool doVolume = (fHints & PLUGIN_CAN_VOLUME) > 0 && kData->postProc.volume != 1.0f; + const bool doBalance = (fHints & PLUGIN_CAN_BALANCE) > 0 && (kData->postProc.balanceLeft != -1.0f || kData->postProc.balanceRight != 1.0f); - double bal_rangeL, bal_rangeR; - float oldBufLeft[do_balance ? frames : 0]; + float oldBufLeft[doBalance ? frames : 1]; - for (i=0; i < aOut.count; i++) + for (i=0; i < kData->audioOut.count; i++) { // Balance - if (do_balance) + if (doBalance) { - if (i%2 == 0) - memcpy(&oldBufLeft, outBuffer[i], sizeof(float)*frames); + if (i % 2 == 0) + std::memcpy(oldBufLeft, outBuffer[i], sizeof(float)*frames); - bal_rangeL = (x_balanceLeft+1.0)/2; - bal_rangeR = (x_balanceRight+1.0)/2; + float balRangeL = (kData->postProc.balanceLeft + 1.0f)/2.0f; + float balRangeR = (kData->postProc.balanceRight + 1.0f)/2.0f; for (k=0; k < frames; k++) { - if (i%2 == 0) + if (i % 2 == 0) { - // left output - outBuffer[i][k] = oldBufLeft[k]*(1.0-bal_rangeL); - outBuffer[i][k] += outBuffer[i+1][k]*(1.0-bal_rangeR); + // left + outBuffer[i][k] = oldBufLeft[k] * (1.0f - balRangeL); + outBuffer[i][k] += outBuffer[i+1][k] * (1.0f - balRangeR); } else { // right - outBuffer[i][k] = outBuffer[i][k]*bal_rangeR; - outBuffer[i][k] += oldBufLeft[k]*bal_rangeL; + outBuffer[i][k] = outBuffer[i][k] * balRangeR; + outBuffer[i][k] += oldBufLeft[k] * balRangeL; } } } - // Volume, using fluidsynth internals - fluid_synth_set_gain(f_synth, x_volume); - - // Output VU - if (x_engine->getOptions().processMode != PROCESS_MODE_CONTINUOUS_RACK) + // Volume + if (doVolume) { - for (k=0; i < 2 && k < frames; k++) - { - if (std::abs(outBuffer[i][k]) > aOutsPeak[i]) - aOutsPeak[i] = std::abs(outBuffer[i][k]); - } + for (k=0; k < frames; k++) + outBuffer[i][k] *= kData->postProc.volume; } } - } - else - { - // disable any output sound if not active - for (i=0; i < aOut.count; i++) - carla_zeroF(outBuffer[i], frames); - - aOutsPeak[0] = 0.0; - aOutsPeak[1] = 0.0; } // End of Post-processing @@ -1221,64 +1190,62 @@ public: // -------------------------------------------------------------------------------------------------------- // Control Output - if (m_active) { k = FluidSynthVoiceCount; - paramBuffers[k] = fluid_synth_get_active_voice_count(f_synth); - fixParameterValue(paramBuffers[k], param.ranges[k]); + fParamBuffers[k] = fluid_synth_get_active_voice_count(fSynth); + kData->param.ranges[k].fixValue(fParamBuffers[k]); - if (param.data[k].midiCC > 0) + if (kData->param.data[k].midiCC > 0) { - double value = (paramBuffers[k] - param.ranges[k].min) / (param.ranges[k].max - param.ranges[k].min); - param.portCout->writeEvent(CarlaEngineParameterChangeEvent, framesOffset, param.data[k].midiChannel, param.data[k].midiCC, value); + double value = kData->param.ranges[k].normalizeValue(fParamBuffers[k]); + kData->event.portOut->writeControlEvent(framesOffset, kData->param.data[k].midiChannel, kEngineControlEventTypeParameter, kData->param.data[k].midiCC, value); } - } // End of Control Output - CARLA_PROCESS_CONTINUE_CHECK; + } // End of Control Output // -------------------------------------------------------------------------------------------------------- - // Peak Values - - x_engine->setOutputPeak(m_id, 0, aOutsPeak[0]); - x_engine->setOutputPeak(m_id, 1, aOutsPeak[1]); - m_activeBefore = m_active; + kData->activeBefore = kData->active; } // ------------------------------------------------------------------- bool init(const char* const filename, const char* const name, const char* const label) { + CARLA_ASSERT(fSynth != nullptr); + CARLA_ASSERT(filename != nullptr); + CARLA_ASSERT(label != nullptr); + // --------------------------------------------------------------- // open soundfont - f_id = fluid_synth_sfload(f_synth, filename, 0); + fSynthId = fluid_synth_sfload(fSynth, filename, 0); - if (f_id < 0) + if (fSynthId < 0) { - x_engine->setLastError("Failed to load SoundFont file"); + kData->engine->setLastError("Failed to load SoundFont file"); return false; } // --------------------------------------------------------------- // get info - m_filename = strdup(filename); - m_label = strdup(label); + fFilename = filename; + fLabel = label; - if (name) - m_name = x_engine->getUniquePluginName(name); + if (name != nullptr) + fName = kData->engine->getNewUniquePluginName(name); else - m_name = x_engine->getUniquePluginName(label); + fName = kData->engine->getNewUniquePluginName(label); // --------------------------------------------------------------- // register client - x_client = x_engine->addClient(this); + kData->client = kData->engine->addClient(this); - if (! x_client->isOk()) + if (kData->client == nullptr || ! kData->client->isOk()) { - x_engine->setLastError("Failed to register plugin client"); + kData->engine->setLastError("Failed to register plugin client"); return false; } @@ -1304,13 +1271,13 @@ private: FluidSynthParametersMax = 14 }; - fluid_settings_t* f_settings; - fluid_synth_t* f_synth; - int f_id; + CarlaString fLabel; - double paramBuffers[FluidSynthParametersMax]; + fluid_settings_t* fSettings; + fluid_synth_t* fSynth; + int fSynthId; - const char* m_label; + double fParamBuffers[FluidSynthParametersMax]; }; /**@}*/ @@ -1318,23 +1285,16 @@ private: CARLA_BACKEND_END_NAMESPACE #else // WANT_FLUIDSYNTH -//# warning fluidsynth not available (no SF2 support) +# warning fluidsynth not available (no SF2 support) #endif CARLA_BACKEND_START_NAMESPACE CarlaPlugin* CarlaPlugin::newSF2(const Initializer& init) { - qDebug("CarlaPlugin::newSF2(%p, \"%s\", \"%s\", \"%s\")", init.engine, init.filename, init.name, init.label); + qDebug("CarlaPlugin::newSF2({%p, \"%s\", \"%s\", \"%s\"})", init.engine, init.filename, init.name, init.label); #ifdef WANT_FLUIDSYNTH - short id = init.engine->getNewPluginId(); - - if (id < 0 || id > init.engine->maxPluginNumber()) - { - init.engine->setLastError("Maximum number of plugins reached"); - return nullptr; - } if (! fluid_is_soundfont(init.filename)) { @@ -1342,7 +1302,7 @@ CarlaPlugin* CarlaPlugin::newSF2(const Initializer& init) return nullptr; } - FluidSynthPlugin* const plugin = new FluidSynthPlugin(init.engine, id); + FluidSynthPlugin* const plugin = new FluidSynthPlugin(init.engine, init.id); if (! plugin->init(init.filename, init.name, init.label)) { diff --git a/source/backend/plugin/ladspa.cpp b/source/backend/plugin/ladspa.cpp index ddf0462f3..f59599a23 100644 --- a/source/backend/plugin/ladspa.cpp +++ b/source/backend/plugin/ladspa.cpp @@ -82,7 +82,7 @@ public: // ------------------------------------------------------------------- // Information (base) - virtual PluginType type() const + PluginType type() const { return PLUGIN_LADSPA; } @@ -762,11 +762,35 @@ public: } // -------------------------------------------------------------------------------------------------------- - // Parameters Input [Automation] + // Check if active before - if (kData->event.portIn != nullptr && kData->activeBefore) + if (! kData->activeBefore) { + if (kData->latency > 0) + { + for (i=0; i < kData->audioIn.count; i++) + carla_zeroFloat(kData->latencyBuffers[i], kData->latency); + } + + if (fDescriptor->activate != nullptr) + { + fDescriptor->activate(fHandle); + + if (fHandle2 != nullptr) + fDescriptor->activate(fHandle2); + } + } + + // -------------------------------------------------------------------------------------------------------- + // Event Input and Processing + + else if (kData->event.portIn != nullptr) + { + // ---------------------------------------------------------------------------------------------------- + // Event Input (System) + uint32_t time, nEvents = kData->event.portIn->getEventCount(); + uint32_t timeOffset = 0; for (i=0; i < nEvents; i++) { @@ -777,6 +801,14 @@ public: if (time >= frames) continue; + CARLA_ASSERT(time >= timeOffset); + + if (time > timeOffset) + { + processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset); + timeOffset = time; + } + // Control change switch (event.type) { @@ -921,64 +953,36 @@ public: kData->postRtEvents.trySplice(); - } // End of Parameters Input + if (frames > timeOffset) + processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset); - CARLA_PROCESS_CONTINUE_CHECK; + } // End of Event Input and Processing // -------------------------------------------------------------------------------------------------------- - // Plugin processing + // Plugin processing (no events) + else { - if (! kData->activeBefore) - { - if (kData->latency > 0) - { - for (i=0; i < kData->audioIn.count; i++) - carla_zeroFloat(kData->latencyBuffers[i], kData->latency); - } + processSingle(inBuffer, outBuffer, frames, 0); - if (fDescriptor->activate != nullptr) - { - fDescriptor->activate(fHandle); + } // End of Plugin processing (no events) - if (fHandle2 != nullptr) - fDescriptor->activate(fHandle2); - } - } + // -------------------------------------------------------------------------------------------------------- + // Special Parameters - if (fHandle2 == nullptr) - { - for (i=0; i < kData->audioIn.count; i++) - fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]); +#if 0 + CARLA_PROCESS_CONTINUE_CHECK; - for (i=0; i < kData->audioOut.count; i++) - fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]); - } - else + for (k=0; k < param.count; k++) + { + if (param.data[k].type == PARAMETER_LATENCY) { - if (kData->audioIn.count > 0) - { - CARLA_ASSERT(kData->audioIn.count == 2); - - fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]); - fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]); - } - - if (kData->audioOut.count > 0) - { - CARLA_ASSERT(kData->audioOut.count == 2); - - fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]); - fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]); - } + // TODO } + } - fDescriptor->run(fHandle, frames); - - if (fHandle2 != nullptr) - fDescriptor->run(fHandle2, frames); - - } // End of Plugin processing + CARLA_PROCESS_CONTINUE_CHECK; +#endif CARLA_PROCESS_CONTINUE_CHECK; @@ -1088,6 +1092,41 @@ public: kData->activeBefore = kData->active; } + void processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) + { + if (fHandle2 == nullptr) + { + for (uint32_t i=0; i < kData->audioIn.count; i++) + fDescriptor->connect_port(fHandle, kData->audioIn.ports[i].rindex, inBuffer[i]+timeOffset); + + for (uint32_t i=0; i < kData->audioOut.count; i++) + fDescriptor->connect_port(fHandle, kData->audioOut.ports[i].rindex, outBuffer[i]+timeOffset); + } + else + { + if (kData->audioIn.count > 0) + { + CARLA_ASSERT(kData->audioIn.count == 2); + + fDescriptor->connect_port(fHandle, kData->audioIn.ports[0].rindex, inBuffer[0]+timeOffset); + fDescriptor->connect_port(fHandle2, kData->audioIn.ports[1].rindex, inBuffer[1]+timeOffset); + } + + if (kData->audioOut.count > 0) + { + CARLA_ASSERT(kData->audioOut.count == 2); + + fDescriptor->connect_port(fHandle, kData->audioOut.ports[0].rindex, outBuffer[0]+timeOffset); + fDescriptor->connect_port(fHandle2, kData->audioOut.ports[1].rindex, outBuffer[1]+timeOffset); + } + } + + fDescriptor->run(fHandle, frames); + + if (fHandle2 != nullptr) + fDescriptor->run(fHandle2, frames); + } + // ------------------------------------------------------------------- // Cleanup diff --git a/source/carla_shared.py b/source/carla_shared.py index ccd9cf79c..92ede0523 100644 --- a/source/carla_shared.py +++ b/source/carla_shared.py @@ -1462,6 +1462,8 @@ class PluginEdit(QDialog): self.connect(self.ui.keyboard, SIGNAL("noteOn(int)"), SLOT("slot_noteOn(int)")) self.connect(self.ui.keyboard, SIGNAL("noteOff(int)"), SLOT("slot_noteOff(int)")) + self.connect(self.ui.keyboard, SIGNAL("notesOn()"), SLOT("slot_notesOn()")) + self.connect(self.ui.keyboard, SIGNAL("notesOff()"), SLOT("slot_notesOff()")) self.connect(self.ui.cb_programs, SIGNAL("currentIndexChanged(int)"), SLOT("slot_programIndexChanged(int)")) self.connect(self.ui.cb_midi_programs, SIGNAL("currentIndexChanged(int)"), SLOT("slot_midiProgramIndexChanged(int)")) @@ -1724,7 +1726,7 @@ class PluginEdit(QDialog): mpData = Carla.host.get_midi_program_data(self.fPluginId, i) mpBank = int(mpData['bank']) mpProg = int(mpData['program']) - mpLabel = cString(mpData['label']) + mpLabel = cString(mpData['name']) self.ui.cb_midi_programs.addItem("%03i:%03i - %s" % (mpBank, mpProg, mpLabel)) self.fCurrentMidiProgram = Carla.host.get_current_midi_program_index(self.fPluginId) @@ -1753,7 +1755,7 @@ class PluginEdit(QDialog): mpData = Carla.host.get_midi_program_data(self.fPluginId, mpIndex) mpBank = int(mpData['bank']) mpProg = int(mpData['program']) - mpLabel = cString(mpData['label']) + mpLabel = cString(mpData['name']) self.ui.cb_midi_programs.setItemText(mpIndex, "%03i:%03i - %s" % (mpBank, mpProg, mpLabel)) # Update all parameter values @@ -1948,12 +1950,12 @@ class PluginEdit(QDialog): @pyqtSlot() def slot_notesOn(self): if self.fRealParent: - self.fRealParent.led_midi.setChecked(True) + self.fRealParent.ui.led_midi.setChecked(True) @pyqtSlot() def slot_notesOff(self): if self.fRealParent: - self.fRealParent.led_midi.setChecked(False) + self.fRealParent.ui.led_midi.setChecked(False) @pyqtSlot() def slot_finished(self):