diff --git a/source/backend/plugin/FluidSynthPlugin.cpp b/source/backend/plugin/FluidSynthPlugin.cpp index 8d5facac3..b3a6575b7 100644 --- a/source/backend/plugin/FluidSynthPlugin.cpp +++ b/source/backend/plugin/FluidSynthPlugin.cpp @@ -21,6 +21,8 @@ #include +#include + #if (FLUIDSYNTH_VERSION_MAJOR >= 1 && FLUIDSYNTH_VERSION_MINOR >= 1 && FLUIDSYNTH_VERSION_MICRO >= 4) # define FLUIDSYNTH_VERSION_NEW_API #endif @@ -38,7 +40,7 @@ class FluidSynthPlugin : public CarlaPlugin public: FluidSynthPlugin(CarlaEngine* const engine, const unsigned int id, const bool use16Outs) : CarlaPlugin(engine, id), - kUses16Outs(use16Outs), + fUses16Outs(use16Outs), fSettings(nullptr), fSynth(nullptr), fSynthId(-1), @@ -434,45 +436,48 @@ public: void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override { CARLA_SAFE_ASSERT_RETURN(fSynth != nullptr,); - CARLA_SAFE_ASSERT_RETURN(type != nullptr,); - CARLA_SAFE_ASSERT_RETURN(key != nullptr,); - CARLA_SAFE_ASSERT_RETURN(value != nullptr,); - carla_debug("DssiPlugin::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui)); + CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',); + CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); + CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',); + carla_debug("FluidSynthPlugin::setCustomData(%s, \"%s\", \"%s\", %s)", type, key, value, bool2str(sendGui)); if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0) - return carla_stderr2("DssiPlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); + return carla_stderr2("FluidSynthPlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); if (std::strcmp(key, "midiPrograms") != 0) - return carla_stderr2("DssiPlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); - -// QStringList midiProgramList(QString(value).split(":", QString::SkipEmptyParts)); -// -// if (midiProgramList.count() == MAX_MIDI_CHANNELS) -// { -// uint i = 0; -// foreach (const QString& midiProg, midiProgramList) -// { -// bool ok; -// uint index = midiProg.toUInt(&ok); -// -// if (ok && index < pData->midiprog.count) -// { -// const uint32_t bank = pData->midiprog.data[index].bank; -// const uint32_t program = pData->midiprog.data[index].program; -// -// fluid_synth_program_select(fSynth, i, fSynthId, bank, program); -// fCurMidiProgs[i] = index; -// -// if (pData->ctrlChannel == static_cast(i)) -// { -// pData->midiprog.current = index; -// pData->engine->callback(CALLBACK_MIDI_PROGRAM_CHANGED, pData->id, index, 0, 0.0f, nullptr); -// } -// } -// -// ++i; -// } -// } + return carla_stderr2("FluidSynthPlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); + + if (! fUses16Outs) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + + QStringList midiProgramList(QString(value).split(":", QString::SkipEmptyParts)); + + if (midiProgramList.count() == MAX_MIDI_CHANNELS) + { + uint i = 0; + foreach (const QString& midiProg, midiProgramList) + { + bool ok; + uint index = midiProg.toUInt(&ok); + + if (ok && index < pData->midiprog.count) + { + const uint32_t bank = pData->midiprog.data[index].bank; + const uint32_t program = pData->midiprog.data[index].program; + + fluid_synth_program_select(fSynth, i, fSynthId, bank, program); + fCurMidiProgs[i] = index; + + if (pData->ctrlChannel == static_cast(i)) + { + pData->midiprog.current = index; + pData->engine->callback(ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED, pData->id, index, 0, 0.0f, nullptr); + } + } + + ++i; + } + } CarlaPlugin::setCustomData(type, key, value, sendGui); } @@ -496,6 +501,7 @@ public: const uint32_t program = pData->midiprog.data[index].program; //const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback)); + fluid_synth_program_select(fSynth, pData->ctrlChannel, fSynthId, bank, program); fCurMidiProgs[pData->ctrlChannel] = index; } @@ -528,7 +534,7 @@ public: clearBuffers(); uint32_t aOuts, params, j; - aOuts = kUses16Outs ? 32 : 2; + aOuts = fUses16Outs ? 32 : 2; params = FluidSynthParametersMax; pData->audioOut.createNew(aOuts); @@ -540,7 +546,7 @@ public: // --------------------------------------- // Audio Outputs - if (kUses16Outs) + if (fUses16Outs) { for (j=0; j < 32; ++j) { @@ -879,7 +885,9 @@ public: // extra plugin hints pData->extraHints = 0x0; pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN; - pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; + + if (! fUses16Outs) + pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; bufferSizeChanged(pData->engine->getBufferSize()); reloadPrograms(true); @@ -1385,15 +1393,10 @@ public: // -------------------------------------------------------------------------------------------------------- // Fill plugin buffers and Run plugin - if (kUses16Outs) + if (fUses16Outs) { for (i=0; i < pData->audioOut.count; ++i) - { -#ifdef HAVE_JUCE - FloatVectorOperations::clear(fAudio16Buffers[i], frames); -#else -#endif - } + FLOAT_CLEAR(fAudio16Buffers[i], frames); fluid_synth_process(fSynth, frames, 0, nullptr, pData->audioOut.count, fAudio16Buffers); } @@ -1405,7 +1408,7 @@ public: // Post-processing (volume and balance) { - // note - balance not possible with kUses16Outs, so we can safely skip fAudioOutBuffers + // note - balance not possible with fUses16Outs, so we can safely skip fAudioOutBuffers const bool doVolume = (pData->hints & PLUGIN_CAN_VOLUME) > 0 && pData->postProc.volume != 1.0f; const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) > 0 && (pData->postProc.balanceLeft != -1.0f || pData->postProc.balanceRight != 1.0f); @@ -1417,12 +1420,7 @@ public: if (doBalance) { if (i % 2 == 0) - { -#ifdef HAVE_JUCE - FloatVectorOperations::copy(oldBufLeft, outBuffer[i]+timeOffset, frames); -#else -#endif - } + FLOAT_COPY(oldBufLeft, outBuffer[i]+timeOffset, frames); float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f; @@ -1445,7 +1443,7 @@ public: } // Volume - if (kUses16Outs) + if (fUses16Outs) { for (k=0; k < frames; ++k) outBuffer[i][k+timeOffset] = fAudio16Buffers[i][k] * pData->postProc.volume; @@ -1459,7 +1457,7 @@ public: } // End of Post-processing #else - if (kUses16Outs) + if (fUses16Outs) { for (i=0; i < pData->audioOut.count; ++i) { @@ -1477,7 +1475,7 @@ public: void bufferSizeChanged(const uint32_t newBufferSize) override { - if (! kUses16Outs) + if (! fUses16Outs) return; for (uint32_t i=0; i < pData->audioOut.count; ++i) @@ -1519,7 +1517,7 @@ public: const void* getExtraStuff() const noexcept override { - return kUses16Outs ? (const void*)0x1 : nullptr; + return fUses16Outs ? (const void*)0x1 : nullptr; } bool init(const char* const filename, const char* const name, const char* const label) @@ -1576,7 +1574,7 @@ public: CarlaString label2(label); - if (kUses16Outs && ! label2.endsWith(" (16 outs)")) + if (fUses16Outs && ! label2.endsWith(" (16 outs)")) label2 += " (16 outs)"; pData->filename = carla_strdup(filename); @@ -1647,7 +1645,7 @@ private: FluidSynthParametersMax = 14 }; - const bool kUses16Outs; + const bool fUses16Outs; fluid_settings_t* fSettings; fluid_synth_t* fSynth; diff --git a/source/backend/plugin/LadspaPlugin.cpp b/source/backend/plugin/LadspaPlugin.cpp index 7405a9b6f..fd17aee6f 100644 --- a/source/backend/plugin/LadspaPlugin.cpp +++ b/source/backend/plugin/LadspaPlugin.cpp @@ -1334,14 +1334,11 @@ public: bool init(const char* const filename, const char* const name, const char* const label, const LADSPA_RDF_Descriptor* const rdfDescriptor) { + CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false); + // --------------------------------------------------------------- // first checks - if (pData->engine == nullptr) - { - return false; - } - if (pData->client != nullptr) { pData->engine->setLastError("Plugin client is already registered"); diff --git a/source/backend/plugin/LinuxSamplerPlugin.cpp b/source/backend/plugin/LinuxSamplerPlugin.cpp index c106cccab..807471163 100644 --- a/source/backend/plugin/LinuxSamplerPlugin.cpp +++ b/source/backend/plugin/LinuxSamplerPlugin.cpp @@ -15,6 +15,12 @@ * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ +/* TODO + * - implement buffer size changes + * - implement sample rate changes + * - call outDev->ReconnectAll() after changing buffer size or sample rate + * - use CARLA_SAFE_ASSERT_RETURN with err + */ #include "CarlaPluginInternal.hpp" #ifdef WANT_LINUXSAMPLER @@ -22,6 +28,9 @@ #include "linuxsampler/EngineFactory.h" #include +#include +#include + namespace LinuxSampler { using CarlaBackend::CarlaEngine; @@ -30,8 +39,8 @@ using CarlaBackend::CarlaPlugin; // ----------------------------------------------------------------------- // LinuxSampler static values -static const float VOLUME_MAX = 3.16227766f; // +10 dB -static const float VOLUME_MIN = 0.0f; // -inf dB +static const float kVolumeMax = 3.16227766f; // +10 dB +static const float kVolumeMin = 0.0f; // -inf dB // ----------------------------------------------------------------------- // LinuxSampler AudioOutputDevice Plugin @@ -39,7 +48,7 @@ static const float VOLUME_MIN = 0.0f; // -inf dB class AudioOutputDevicePlugin : public AudioOutputDevice { public: - AudioOutputDevicePlugin(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin) + AudioOutputDevicePlugin(const CarlaEngine* const engine, const CarlaPlugin* const plugin) : AudioOutputDevice(std::map()), fEngine(engine), fPlugin(plugin) @@ -48,6 +57,8 @@ public: CARLA_ASSERT(plugin != nullptr); } + ~AudioOutputDevicePlugin() override {} + // ------------------------------------------------------------------- // LinuxSampler virtual methods @@ -71,7 +82,7 @@ public: uint SampleRate() override { - return (uint)fEngine->getSampleRate(); + return uint(fEngine->getSampleRate()); } String Driver() override @@ -92,9 +103,25 @@ public: return RenderAudio(samples); } + // ------------------------------------------------------------------- + private: - CarlaEngine* const fEngine; - CarlaPlugin* const fPlugin; + const CarlaEngine* const fEngine; + const CarlaPlugin* const fPlugin; +}; + +// ----------------------------------------------------------------------- +// LinuxSampler MidiInputPort Plugin + +class MidiInputPortPlugin : public MidiInputPort +{ +public: + MidiInputPortPlugin(MidiInputDevice* const device, const int portNumber) + : MidiInputPort(device, portNumber) + { + } + + ~MidiInputPortPlugin() override {} }; // ----------------------------------------------------------------------- @@ -126,28 +153,13 @@ public: MidiInputPort* CreateMidiPort() override { - return new MidiInputPortPlugin(this, (int)Ports.size()); + return new MidiInputPortPlugin(this, int(Ports.size())); } - // ------------------------------------------------------------------- - // Properly delete port (destructor is protected) - - void DeleteMidiPort(MidiInputPort* const port) + MidiInputPortPlugin* CreateMidiPortPlugin() { - delete (MidiInputPortPlugin*)port; + return new MidiInputPortPlugin(this, int(Ports.size())); } - - // ------------------------------------------------------------------- - // MIDI Port implementation for this plugin MIDI input driver - // (Constructor and destructor are protected) - - class MidiInputPortPlugin : public MidiInputPort - { - protected: - MidiInputPortPlugin(MidiInputDevicePlugin* const device, const int portNumber) - : MidiInputPort(device, portNumber) {} - friend class MidiInputDevicePlugin; - }; }; } // namespace LinuxSampler @@ -167,16 +179,20 @@ public: : CarlaPlugin(engine, id), fFormat(carla_strdup(format)), fUses16Outs(use16Outs), - fSampler(new LinuxSampler::Sampler()), - fSamplerChannel(nullptr), fEngine(nullptr), - fEngineChannel(nullptr), - fAudioOutputDevice(new LinuxSampler::AudioOutputDevicePlugin(engine, this)), - fMidiInputDevice(new LinuxSampler::MidiInputDevicePlugin(fSampler)), - fMidiInputPort(fMidiInputDevice->CreateMidiPort()), + fMidiInputDevice(nullptr), + fMidiInputPort(nullptr), fInstrument(nullptr) { - carla_debug("LinuxSamplerPlugin::LinuxSamplerPlugin(%p, %i, %s)", engine, id, bool2str(isGIG)); + carla_debug("LinuxSamplerPlugin::LinuxSamplerPlugin(%p, %i, %s, %s)", engine, id, format, bool2str(use16Outs)); + + for (int i=0; i < 16; ++i) + { + fCurMidiProgs[0] = 0; + fSamplerChannels[i] = nullptr; + fEngineChannels[i] = nullptr; + fAudioOutputDevices[i] = nullptr; + } } ~LinuxSamplerPlugin() override @@ -197,23 +213,46 @@ public: if (fEngine != nullptr) { - if (fSamplerChannel != nullptr) + if (fMidiInputDevice != nullptr) { - fMidiInputPort->Disconnect(fSamplerChannel->GetEngineChannel()); - fEngineChannel->DisconnectAudioOutputDevice(); - fSampler->RemoveSamplerChannel(fSamplerChannel); + if (fMidiInputPort != nullptr) + { + for (int i=0; i < 16; ++i) + { + if (fSamplerChannels[i] != nullptr) + { + if (fEngineChannels[i] != nullptr) + { + fMidiInputPort->Disconnect(fEngineChannels[i]); + fEngineChannels[i]->DisconnectAudioOutputDevice(); + fEngineChannels[i] = nullptr; + } + + fSampler.RemoveSamplerChannel(fSamplerChannels[i]); + fSamplerChannels[i] = nullptr; + + if (fAudioOutputDevices[i] != nullptr) + { + delete fAudioOutputDevices[i]; + fAudioOutputDevices[i] = nullptr; + } + } + } + + delete fMidiInputPort; + fMidiInputPort = nullptr; + } + + delete fMidiInputDevice; + fMidiInputDevice = nullptr; } + fInstrument = nullptr; + LinuxSampler::EngineFactory::Destroy(fEngine); + fEngine = nullptr; } - // destructor is private - fMidiInputDevice->DeleteMidiPort(fMidiInputPort); - - delete fMidiInputDevice; - delete fAudioOutputDevice; - delete fSampler; - fInstrumentIds.clear(); if (fFormat != nullptr) @@ -286,16 +325,89 @@ public: // ------------------------------------------------------------------- // Set data (state) - // nothing + void prepareForSave() override + { + char strBuf[STR_MAX+1]; + std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i", fCurMidiProgs[0], fCurMidiProgs[1], fCurMidiProgs[2], fCurMidiProgs[3], + fCurMidiProgs[4], fCurMidiProgs[5], fCurMidiProgs[6], fCurMidiProgs[7], + fCurMidiProgs[8], fCurMidiProgs[9], fCurMidiProgs[10], fCurMidiProgs[11], + fCurMidiProgs[12], fCurMidiProgs[13], fCurMidiProgs[14], fCurMidiProgs[15]); + + CarlaPlugin::setCustomData(CUSTOM_DATA_TYPE_STRING, "midiPrograms", strBuf, false); + } // ------------------------------------------------------------------- // Set data (internal stuff) - // nothing + void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) override + { + if (channel < MAX_MIDI_CHANNELS) + pData->midiprog.current = fCurMidiProgs[channel]; + + CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback); + } // ------------------------------------------------------------------- // Set data (plugin-specific stuff) + void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override + { + CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',); + CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); + CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',); + carla_debug("DssiPlugin::setCustomData(%s, \"%s\", \"%s\", %s)", type, key, value, bool2str(sendGui)); + + if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0) + return carla_stderr2("LinuxSamplerPlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); + + if (std::strcmp(key, "midiPrograms") != 0) + return carla_stderr2("LinuxSamplerPlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); + + if (! fUses16Outs) + return CarlaPlugin::setCustomData(type, key, value, sendGui); + + QStringList midiProgramList(QString(value).split(":", QString::SkipEmptyParts)); + + if (midiProgramList.count() == MAX_MIDI_CHANNELS) + { + uint i = 0; + foreach (const QString& midiProg, midiProgramList) + { + bool ok; + uint index = midiProg.toUInt(&ok); + + if (ok && index < pData->midiprog.count) + { + const uint32_t bank = pData->midiprog.data[index].bank; + const uint32_t program = pData->midiprog.data[index].program; + const uint32_t rIndex = bank*128 + program; + + if (pData->engine->isOffline()) + { + fEngineChannels[i]->PrepareLoadInstrument(pData->filename, rIndex); + fEngineChannels[i]->LoadInstrument(); + } + else + { + fInstrument->LoadInstrumentInBackground(fInstrumentIds[rIndex], fEngineChannels[i]); + } + + fCurMidiProgs[i] = index; + + if (pData->ctrlChannel == static_cast(i)) + { + pData->midiprog.current = index; + pData->engine->callback(ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED, pData->id, index, 0, 0.0f, nullptr); + } + } + + ++i; + } + } + + CarlaPlugin::setCustomData(type, key, value, sendGui); + } + void setMidiProgram(int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback) override { CARLA_ASSERT(index >= -1 && index < static_cast(pData->midiprog.count)); @@ -305,7 +417,7 @@ public: else if (index > static_cast(pData->midiprog.count)) return; - if (pData->ctrlChannel < 0 || pData->ctrlChannel >= 16) + if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS) return; if (index >= 0) @@ -314,17 +426,21 @@ public: const uint32_t program = pData->midiprog.data[index].program; const uint32_t rIndex = bank*128 + program; + LinuxSampler::EngineChannel* const engineChannel(fUses16Outs ? fEngineChannels[pData->ctrlChannel] : fEngineChannels[0]); + const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback)); if (pData->engine->isOffline()) { - fEngineChannel->PrepareLoadInstrument(pData->filename, rIndex); - fEngineChannel->LoadInstrument(); + engineChannel->PrepareLoadInstrument(pData->filename, rIndex); + engineChannel->LoadInstrument(); } else { - fInstrument->LoadInstrumentInBackground(fInstrumentIds[rIndex], fEngineChannel); + fInstrument->LoadInstrumentInBackground(fInstrumentIds[rIndex], engineChannel); } + + fCurMidiProgs[pData->ctrlChannel] = index; } CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback); @@ -350,7 +466,7 @@ public: clearBuffers(); uint32_t aOuts; - aOuts = 2; + aOuts = fUses16Outs ? 16 : 2; pData->audioOut.createNew(aOuts); @@ -360,6 +476,37 @@ public: // --------------------------------------- // Audio Outputs + if (fUses16Outs) + { + for (uint32_t i=0; i < 32; ++i) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + portName += "out-"; + + if ((i+2)/2 < 9) + portName += "0"; + + portName += CarlaString((i+2)/2); + + if (i % 2 == 0) + portName += "L"; + else + portName += "R"; + + portName.truncate(portNameSize); + + pData->audioOut.ports[i].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false); + pData->audioOut.ports[i].rindex = i; + } + } + else { // out-left portName.clear(); @@ -414,14 +561,16 @@ public: // plugin hints pData->hints = 0x0; - //pData->hints |= PLUGIN_IS_SYNTH; + pData->hints |= PLUGIN_IS_SYNTH; pData->hints |= PLUGIN_CAN_VOLUME; pData->hints |= PLUGIN_CAN_BALANCE; // extra plugin hints pData->extraHints = 0x0; pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN; - pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; + + if (! fUses16Outs) + pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; bufferSizeChanged(pData->engine->getBufferSize()); reloadPrograms(true); @@ -478,7 +627,16 @@ public: if (init) { - setMidiProgram(0, false, false, false); + for (int i=0; i < 16; ++i) + { + CARLA_SAFE_ASSERT_CONTINUE(fEngineChannels[i] != nullptr); + + fEngineChannels[i]->PrepareLoadInstrument(pData->filename, 0); + fEngineChannels[i]->LoadInstrument(); + fCurMidiProgs[i] = 0; + } + + pData->midiprog.current = 0; } else { @@ -491,16 +649,20 @@ public: void activate() override { - CARLA_ASSERT(fAudioOutputDevice != nullptr); - - fAudioOutputDevice->Play(); + for (int i=0; i < 16; ++i) + { + if (fAudioOutputDevices[i] != nullptr) + fAudioOutputDevices[i]->Play(); + } } void deactivate() override { - CARLA_ASSERT(fAudioOutputDevice != nullptr); - - fAudioOutputDevice->Stop(); + for (int i=0; i < 16; ++i) + { + if (fAudioOutputDevices[i] != nullptr) + fAudioOutputDevices[i]->Stop(); + } } void process(float** const, float** const outBuffer, const uint32_t frames) override @@ -514,13 +676,7 @@ public: { // disable any output sound for (i=0; i < pData->audioOut.count; ++i) - { -#ifdef HAVE_JUCE - FloatVectorOperations::clear(outBuffer[i], frames); -#else -#endif - } - + FLOAT_CLEAR(outBuffer[i], frames); return; } @@ -866,10 +1022,24 @@ public: // -------------------------------------------------------------------------------------------------------- // Run plugin - fAudioOutputDevice->Channel(0)->SetBuffer(outBuffer[0] + timeOffset); - fAudioOutputDevice->Channel(1)->SetBuffer(outBuffer[1] + timeOffset); - // QUESTION: Need to clear it before? - fAudioOutputDevice->Render(frames); + if (fUses16Outs) + { + for (int i=0; i < 16; ++i) + { + if (fAudioOutputDevices[i] != nullptr) + { + fAudioOutputDevices[i]->Channel(0)->SetBuffer(outBuffer[i*2 ] + timeOffset); + fAudioOutputDevices[i]->Channel(1)->SetBuffer(outBuffer[i*2+1] + timeOffset); + fAudioOutputDevices[i]->Render(frames); + } + } + } + else + { + fAudioOutputDevices[0]->Channel(0)->SetBuffer(outBuffer[0] + timeOffset); + fAudioOutputDevices[0]->Channel(1)->SetBuffer(outBuffer[1] + timeOffset); + fAudioOutputDevices[0]->Render(frames); + } #ifndef BUILD_BRIDGE // -------------------------------------------------------------------------------------------------------- @@ -887,12 +1057,7 @@ public: if (doBalance) { if (i % 2 == 0) - { -#ifdef HAVE_JUCE - FloatVectorOperations::copy(oldBufLeft, outBuffer[i], frames); -#else -#endif - } + FLOAT_COPY(oldBufLeft, outBuffer[i], frames); float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f; @@ -945,19 +1110,11 @@ public: bool init(const char* filename, const char* const name, const char* label) { - CARLA_ASSERT(pData->engine != nullptr); - CARLA_ASSERT(pData->client == nullptr); - CARLA_ASSERT(filename != nullptr); - CARLA_ASSERT(label != nullptr); + CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false); // --------------------------------------------------------------- // first checks - if (pData->engine == nullptr) - { - return false; - } - if (pData->client != nullptr) { pData->engine->setLastError("Plugin client is already registered"); @@ -977,25 +1134,17 @@ public: } // --------------------------------------------------------------- - // Check if file exists - { -// QFileInfo file(filename); -// -// if (! (file.exists() && file.isFile() && file.isReadable())) -// { -// pData->engine->setLastError("Requested file is not valid or does not exist"); -// return false; -// } - } + // Store format + + CarlaString cstype(fFormat); + cstype.toLower(); + const char* const ctype(cstype.getBuffer()); // --------------------------------------------------------------- // Create the LinuxSampler Engine - CarlaString stype(fFormat); - stype.toLower(); - try { - fEngine = LinuxSampler::EngineFactory::Create((const char*)stype); + fEngine = LinuxSampler::EngineFactory::Create(ctype); } catch (LinuxSampler::Exception& e) { @@ -1003,6 +1152,44 @@ public: return false; } + // --------------------------------------------------------------- + // Init LinuxSampler stuff + + fMidiInputDevice = new LinuxSampler::MidiInputDevicePlugin(&fSampler); + fMidiInputPort = fMidiInputDevice->CreateMidiPortPlugin(); + + // always needs at least 1 output device + fAudioOutputDevices[0] = new LinuxSampler::AudioOutputDevicePlugin(pData->engine, this); + + for (int i=0; i < 16; ++i) + { + fSamplerChannels[i] = fSampler.AddSamplerChannel(); + CARLA_SAFE_ASSERT_CONTINUE(fSamplerChannels[i] != nullptr); + + fEngineChannels[i] = fSamplerChannels[i]->GetEngineChannel(); + CARLA_SAFE_ASSERT_CONTINUE(fEngineChannels[i] != nullptr); + + LinuxSampler::AudioOutputDevicePlugin* outputDevice; + + if (fUses16Outs) + { + fAudioOutputDevices[i] = new LinuxSampler::AudioOutputDevicePlugin(pData->engine, this); + outputDevice = fAudioOutputDevices[i]; + } + else + { + outputDevice = fAudioOutputDevices[0]; + } + + fSamplerChannels[i]->SetEngineType(ctype); + fSamplerChannels[i]->SetAudioOutputDevice(outputDevice); + + fEngineChannels[i]->Connect(outputDevice); + fEngineChannels[i]->Volume(LinuxSampler::kVolumeMax); + + fMidiInputPort->Connect(fEngineChannels[i], static_cast(i)); + } + // --------------------------------------------------------------- // Get the Engine's Instrument Manager @@ -1011,8 +1198,6 @@ public: if (fInstrument == nullptr) { pData->engine->setLastError("Failed to get LinuxSampler instrument manager"); - LinuxSampler::EngineFactory::Destroy(fEngine); - fEngine = nullptr; return false; } @@ -1025,8 +1210,6 @@ public: catch (const LinuxSampler::InstrumentManagerException& e) { pData->engine->setLastError(e.what()); - LinuxSampler::EngineFactory::Destroy(fEngine); - fEngine = nullptr; return false; } @@ -1036,8 +1219,6 @@ public: if (fInstrumentIds.size() == 0) { pData->engine->setLastError("Failed to find any instruments"); - LinuxSampler::EngineFactory::Destroy(fEngine); - fEngine = nullptr; return false; } @@ -1049,14 +1230,13 @@ public: catch (const LinuxSampler::InstrumentManagerException& e) { pData->engine->setLastError(e.what()); - LinuxSampler::EngineFactory::Destroy(fEngine); - fEngine = nullptr; return false; } fRealName = info.InstrumentName.c_str(); fLabel = info.Product.c_str(); fMaker = info.Artists.c_str(); + pData->filename = carla_strdup(filename); if (fUses16Outs && ! fLabel.endsWith(" (16 outs)")) @@ -1076,23 +1256,11 @@ public: { pData->engine->setLastError("Failed to register plugin client"); LinuxSampler::EngineFactory::Destroy(fEngine); + fInstrument = nullptr; fEngine = nullptr; return false; } - // --------------------------------------------------------------- - // Init LinuxSampler stuff - - fSamplerChannel = fSampler->AddSamplerChannel(); - fSamplerChannel->SetEngineType((const char*)stype); - fSamplerChannel->SetAudioOutputDevice(fAudioOutputDevice); - - fEngineChannel = fSamplerChannel->GetEngineChannel(); - fEngineChannel->Connect(fAudioOutputDevice); - fEngineChannel->Volume(LinuxSampler::VOLUME_MAX); - - fMidiInputPort->Connect(fSamplerChannel->GetEngineChannel(), LinuxSampler::midi_chan_all); - // --------------------------------------------------------------- // load plugin settings @@ -1128,19 +1296,21 @@ private: const char* fFormat; const bool fUses16Outs; + int32_t fCurMidiProgs[16]; + CarlaString fRealName; CarlaString fLabel; CarlaString fMaker; - LinuxSampler::Sampler* fSampler; - LinuxSampler::SamplerChannel* fSamplerChannel; + LinuxSampler::Sampler fSampler; + LinuxSampler::Engine* fEngine; - LinuxSampler::Engine* fEngine; - LinuxSampler::EngineChannel* fEngineChannel; + LinuxSampler::SamplerChannel* fSamplerChannels[16]; + LinuxSampler::EngineChannel* fEngineChannels[16]; - LinuxSampler::AudioOutputDevicePlugin* fAudioOutputDevice; - LinuxSampler::MidiInputDevicePlugin* fMidiInputDevice; - LinuxSampler::MidiInputPort* fMidiInputPort; + LinuxSampler::AudioOutputDevicePlugin* fAudioOutputDevices[16]; + LinuxSampler::MidiInputDevicePlugin* fMidiInputDevice; + LinuxSampler::MidiInputPortPlugin* fMidiInputPort; LinuxSampler::InstrumentManager* fInstrument; std::vector fInstrumentIds; @@ -1154,17 +1324,44 @@ CARLA_BACKEND_END_NAMESPACE CARLA_BACKEND_START_NAMESPACE -CarlaPlugin* CarlaPlugin::newLinuxSampler(const Initializer& init, const char* const format, const bool use16Outs) +CarlaPlugin* CarlaPlugin::newLinuxSampler(const Initializer& init, const char* const format, const bool /*use16Outs*/) { + // TESTING + const bool use16Outs = true; + carla_debug("LinuxSamplerPlugin::newLinuxSampler({%p, \"%s\", \"%s\", \"%s\"}, %s, %s)", init.engine, init.filename, init.name, init.label, format, bool2str(use16Outs)); -#ifdef WANT_FLUIDSYNTH +#ifdef WANT_LINUXSAMPLER if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && use16Outs) { init.engine->setLastError("Carla's rack mode can only work with Stereo modules, please choose the 2-channel only sample-library version"); return nullptr; } + // ------------------------------------------------------------------- + // Check if file exists + { + QFileInfo file(init.filename); + + if (! file.exists()) + { + init.engine->setLastError("Requested file does not exist"); + return false; + } + + if (! file.isFile()) + { + init.engine->setLastError("Requested file is not valid"); + return false; + } + + if (! file.isReadable()) + { + init.engine->setLastError("Requested file is not readable"); + return false; + } + } + LinuxSamplerPlugin* const plugin(new LinuxSamplerPlugin(init.engine, init.id, format, use16Outs)); if (! plugin->init(init.filename, init.name, init.label)) diff --git a/source/bridges/Makefile b/source/bridges/Makefile index 05f001348..e569c5d55 100644 --- a/source/bridges/Makefile +++ b/source/bridges/Makefile @@ -382,7 +382,8 @@ OBJS_NATIVE += \ ../backend/plugin/DssiPlugin__native.o \ ../backend/plugin/Lv2Plugin__native.o \ ../backend/plugin/VstPlugin__native.o \ - ../backend/plugin/Vst3Plugin__native.o \ + ../backend/plugin/AuPlugin__native.o \ + ../backend/plugin/JucePlugin__native.o \ ../backend/plugin/FluidSynthPlugin__native.o \ ../backend/plugin/LinuxSamplerPlugin__native.o