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