From a6846272ff485ae9d2caf354377ed0839fff4361 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 5 May 2013 18:20:17 +0100 Subject: [PATCH] Continue last commit; ZynAddSubFX multi-program --- source/backend/native/zynaddsubfx.cpp | 60 +++++++++++--- source/backend/plugin/CarlaPlugin.cpp | 4 +- source/backend/plugin/FluidSynthPlugin.cpp | 5 +- source/backend/plugin/NativePlugin.cpp | 92 +++++++++++++++++++--- source/carla_shared.py | 4 +- 5 files changed, 139 insertions(+), 26 deletions(-) diff --git a/source/backend/native/zynaddsubfx.cpp b/source/backend/native/zynaddsubfx.cpp index 2a586b93b..8549056b0 100644 --- a/source/backend/native/zynaddsubfx.cpp +++ b/source/backend/native/zynaddsubfx.cpp @@ -104,11 +104,14 @@ public: : PluginDescriptorClass(host), kMaster(new Master()), kSampleRate(getSampleRate()), + fIsActive(false), fThread(kMaster, host) { fThread.start(); maybeInitPrograms(kMaster); - //fThread.waitForStarted(); + + for (int i = 0; i < NUM_MIDI_PARTS; ++i) + kMaster->partonoff(i, 1); } ~ZynAddSubFxPlugin() override @@ -229,13 +232,13 @@ protected: bool isOffline = false; - if (isOffline) + if (isOffline || ! fIsActive) loadProgram(kMaster, channel, bank, program); else fThread.loadLater(channel, bank, program); } - void setCustomData(const char* const key, const char* const value) + void setCustomData(const char* const key, const char* const value) override { CARLA_ASSERT(key != nullptr); CARLA_ASSERT(value != nullptr); @@ -254,6 +257,13 @@ protected: // broken //for (int i=0; i < NUM_MIDI_PARTS; i++) // kMaster->setController(0, MIDI_CONTROL_ALL_SOUND_OFF, 0); + + fIsActive = true; + } + + void deactivate() override + { + fIsActive = false; } void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents) override @@ -371,6 +381,7 @@ private: #endif fQuit(false), fChangeProgram(false), + fNextChannel(0), fNextBank(0), fNextProgram(0) { @@ -387,7 +398,7 @@ private: void loadLater(const uint8_t channel, const uint32_t bank, const uint32_t program) { - // TODO + fNextChannel = channel; fNextBank = bank; fNextProgram = program; fChangeProgram = true; @@ -396,6 +407,7 @@ private: void stopLoadLater() { fChangeProgram = false; + fNextChannel = 0; fNextBank = 0; fNextProgram = 0; } @@ -489,12 +501,17 @@ private: if (fChangeProgram) { fChangeProgram = false; - loadProgram(kMaster, 0, fNextBank, fNextProgram); // TODO + loadProgram(kMaster, fNextChannel, fNextBank, fNextProgram); + fNextChannel = 0; fNextBank = 0; fNextProgram = 0; - } - carla_msleep(15); + carla_msleep(15); + } + else + { + carla_msleep(30); + } } #ifdef WANT_ZYNADDSUBFX_UI @@ -533,12 +550,14 @@ private: bool fQuit; bool fChangeProgram; + uint8_t fNextChannel; uint32_t fNextBank; uint32_t fNextProgram; }; Master* const kMaster; const unsigned kSampleRate; + bool fIsActive; ZynThread fThread; @@ -601,26 +620,28 @@ public: return; doSearch = false; + sPrograms.append(new ProgramInfo(0, 0, "default")); + pthread_mutex_lock(&master->mutex); // refresh banks master->bank.rescanforbanks(); - for (uint32_t i=0, size = master->bank.banks.size(); i < size; i++) + for (uint32_t i=0, size = master->bank.banks.size(); i < size; ++i) { if (master->bank.banks[i].dir.empty()) continue; master->bank.loadbank(master->bank.banks[i].dir); - for (unsigned int instrument = 0; instrument < BANK_SIZE; instrument++) + for (unsigned int instrument = 0; instrument < BANK_SIZE; ++instrument) { const std::string insName(master->bank.getname(instrument)); if (insName.empty() || insName[0] == '\0' || insName[0] == ' ') continue; - sPrograms.append(new ProgramInfo(i, instrument, insName.c_str())); + sPrograms.append(new ProgramInfo(i+1, instrument, insName.c_str())); } } @@ -629,16 +650,31 @@ public: static void loadProgram(Master* const master, const uint8_t channel, const uint32_t bank, const uint32_t program) { - const std::string& bankdir(master->bank.banks[bank].dir); + if (bank == 0) + { + pthread_mutex_lock(&master->mutex); + + master->part[channel]->defaults(); + master->part[channel]->applyparameters(false); + master->partonoff(channel, 1); + + pthread_mutex_unlock(&master->mutex); + + return; + } + + const std::string& bankdir(master->bank.banks[bank-1].dir); if (! bankdir.empty()) { pthread_mutex_lock(&master->mutex); + master->partonoff(channel, 1); + master->bank.loadbank(bankdir); master->bank.loadfromslot(program, master->part[channel]); - master->applyparameters(false); + master->part[channel]->applyparameters(false); pthread_mutex_unlock(&master->mutex); } diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index 486b38fcc..109c00189 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -804,7 +804,9 @@ void CarlaPlugin::loadSaveState(const SaveState& saveState) // --------------------------------------------------------------------- // Part 3 - set midi program - if (saveState.currentMidiBank >= 0 && saveState.currentMidiProgram >= 0 && type() != PLUGIN_SF2) + const bool usesMultiProgs(type() == PLUGIN_SF2 || (type() == PLUGIN_INTERNAL && (fHints & PLUGIN_IS_SYNTH) != 0)); + + if (saveState.currentMidiBank >= 0 && saveState.currentMidiProgram >= 0 && ! usesMultiProgs) setMidiProgramById(saveState.currentMidiBank, saveState.currentMidiProgram, true, true, true); // --------------------------------------------------------------------- diff --git a/source/backend/plugin/FluidSynthPlugin.cpp b/source/backend/plugin/FluidSynthPlugin.cpp index 9f147ef7b..6c0d32f4e 100644 --- a/source/backend/plugin/FluidSynthPlugin.cpp +++ b/source/backend/plugin/FluidSynthPlugin.cpp @@ -451,7 +451,10 @@ public: fCurMidiProgs[i] = index; if (kData->ctrlChannel == static_cast(i)) + { + kData->midiprog.current = index; kData->engine->callback(CALLBACK_MIDI_PROGRAM_CHANGED, fId, index, 0, 0.0f, nullptr); + } } ++i; @@ -977,7 +980,7 @@ public: fCurMidiProgs[9] = 0; } - setMidiProgram(0, false, false, false); + kData->midiprog.current = 0; } else { diff --git a/source/backend/plugin/NativePlugin.cpp b/source/backend/plugin/NativePlugin.cpp index 762ca252f..3159df618 100644 --- a/source/backend/plugin/NativePlugin.cpp +++ b/source/backend/plugin/NativePlugin.cpp @@ -172,7 +172,8 @@ public: fIsUiVisible(false), fAudioInBuffers(nullptr), fAudioOutBuffers(nullptr), - fMidiEventCount(0) + fMidiEventCount(0), + fCurMidiProgs{0} { carla_debug("NativePlugin::NativePlugin(%p, %i)", engine, id); @@ -483,9 +484,19 @@ public: CARLA_ASSERT(fDescriptor != nullptr); CARLA_ASSERT(fHandle != nullptr); - if (fDescriptor->get_state == nullptr) - return; - if ((fDescriptor->hints & ::PLUGIN_USES_STATE) == 0) + if (kData->midiprog.count > 0 && (fHints & PLUGIN_IS_SYNTH) != 0) + { + 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_STRING, "midiPrograms", strBuf, false); + } + + if (fDescriptor->get_state == nullptr || (fDescriptor->hints & ::PLUGIN_USES_STATE) == 0) return; if (char* data = fDescriptor->get_state(fHandle)) @@ -514,6 +525,14 @@ public: CarlaPlugin::setName(newName); } + void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) override + { + if (channel < MAX_MIDI_CHANNELS) + kData->midiprog.current = fCurMidiProgs[channel]; + + CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback); + } + // ------------------------------------------------------------------- // Set data (plugin-specific stuff) @@ -569,6 +588,41 @@ public: fDescriptor->set_state(fHandle2, value); } } + else if (std::strcmp(key, "midiPrograms") == 0 && fDescriptor->set_midi_program != nullptr) + { + 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 < kData->midiprog.count) + { + const uint32_t bank = kData->midiprog.data[index].bank; + const uint32_t program = kData->midiprog.data[index].program; + + fDescriptor->set_midi_program(fHandle, i, bank, program); + + if (fHandle2 != nullptr) + fDescriptor->set_midi_program(fHandle2, i, bank, program); + + fCurMidiProgs[i] = index; + + if (kData->ctrlChannel == static_cast(i)) + { + kData->midiprog.current = index; + kData->engine->callback(CALLBACK_MIDI_PROGRAM_CHANGED, fId, index, 0, 0.0f, nullptr); + } + } + + ++i; + } + } + } else { if (fDescriptor->set_custom_data != nullptr) @@ -603,17 +657,23 @@ public: else if (index > static_cast(kData->midiprog.count)) return; + if ((fHints & PLUGIN_IS_SYNTH) != 0 && (kData->ctrlChannel < 0 || kData->ctrlChannel >= MAX_MIDI_CHANNELS)) + return; + if (index >= 0) { + const uint8_t channel = (kData->ctrlChannel >= 0 || kData->ctrlChannel < MAX_MIDI_CHANNELS) ? kData->ctrlChannel : 0; const uint32_t bank = kData->midiprog.data[index].bank; const uint32_t program = kData->midiprog.data[index].program; const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback)); - fDescriptor->set_midi_program(fHandle, 0, bank, program); // TODO + fDescriptor->set_midi_program(fHandle, channel, bank, program); if (fHandle2 != nullptr) - fDescriptor->set_midi_program(fHandle2, 0, bank, program); // TODO + fDescriptor->set_midi_program(fHandle2, channel, bank, program); + + fCurMidiProgs[channel] = index; } CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback); @@ -1072,7 +1132,7 @@ public: // Query new programs uint32_t count = 0; - if (fDescriptor->get_midi_program_count != nullptr && fDescriptor->get_midi_program_info != nullptr) + if (fDescriptor->get_midi_program_count != nullptr && fDescriptor->get_midi_program_info != nullptr && fDescriptor->set_midi_program != nullptr) count = fDescriptor->get_midi_program_count(fHandle); if (count > 0) @@ -1452,16 +1512,24 @@ public: break; case kEngineControlEventTypeMidiProgram: - if (event.channel == kData->ctrlChannel && (fOptions & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0) + if (event.channel < MAX_MIDI_CHANNELS && (fOptions & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0) { - const uint32_t nextProgramId = ctrlEvent.param; + const uint32_t nextProgramId(ctrlEvent.param); for (k=0; k < kData->midiprog.count; ++k) { if (kData->midiprog.data[k].bank == nextBankId && kData->midiprog.data[k].program == nextProgramId) { - setMidiProgram(k, false, false, false); - postponeRtEvent(kPluginPostRtEventMidiProgramChange, k, 0, 0.0f); + fDescriptor->set_midi_program(fHandle, event.channel, nextBankId, nextProgramId); + + if (fHandle2 != nullptr) + fDescriptor->set_midi_program(fHandle2, event.channel, nextBankId, nextProgramId); + + fCurMidiProgs[event.channel] = k; + + if (event.channel == kData->ctrlChannel) + postponeRtEvent(kPluginPostRtEventMidiProgramChange, k, 0, 0.0f); + break; } } @@ -2188,6 +2256,8 @@ private: uint32_t fMidiEventCount; ::MidiEvent fMidiEvents[MAX_MIDI_EVENTS*2]; + int32_t fCurMidiProgs[MAX_MIDI_CHANNELS]; + NativePluginMidiData fMidiIn; NativePluginMidiData fMidiOut; diff --git a/source/carla_shared.py b/source/carla_shared.py index 7ecf8dbba..6a10b927b 100644 --- a/source/carla_shared.py +++ b/source/carla_shared.py @@ -1900,7 +1900,9 @@ class PluginEdit(QDialog): self.fTabIconTimers.append(ICON_STATE_NULL) def _updateCtrlMidiProgram(self): - if self.fPluginInfo['type'] != PLUGIN_SF2: + if self.fPluginInfo['type'] not in (PLUGIN_INTERNAL, PLUGIN_SF2): + return + elif not self.fPluginInfo['hints'] & PLUGIN_IS_SYNTH: return if self.fControlChannel == -1: