DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 8368f132201f57487987b9408aabeee2591a3fe9
parent 7fb4d014e8db06e7171446824255f1cfeb7cb173
Author: falkTX <falktx@falktx.com>
Date:   Sun,  7 Aug 2022 03:56:05 +0100

Start dealing with VST3 buses

Diffstat:
Mdistrho/src/DistrhoPluginVST3.cpp | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 195 insertions(+), 55 deletions(-)

diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -264,11 +264,10 @@ class PluginVst3 { /* Buses: count possible buses we can provide to the host, in case they are not yet defined by the developer. * These values are only used if port groups aren't set. - * We count the number of used port groups in `numGroups`. * * When port groups are not in use, we fill in appropriately. - * 1 bus is provided for the main audio (if there is any) plus 1 for each sidechain or cv port. - * Main audio comes first, if available. + * 1 bus is provided for the main audio (if there is any) plus 1 for sidechain and 1 for each cv port. + * Main audio is used as first bus, if available. * Then sidechain, also if available. * And finally each CV port individually. * @@ -277,18 +276,20 @@ class PluginVst3 struct BusInfo { uint8_t audio; // either 0 or 1 uint8_t sidechain; // either 0 or 1 - uint32_t numMainAudio; - uint32_t numSidechain; - uint32_t numCV; - uint32_t numGroups; + uint32_t groups; + uint32_t audioPorts; + uint32_t sidechainPorts; + uint32_t groupPorts; + uint32_t cvPorts; BusInfo() : audio(0), sidechain(0), - numMainAudio(0), - numSidechain(0), - numCV(0), - numGroups(0) {} + groups(0), + audioPorts(0), + sidechainPorts(0), + groupPorts(0), + cvPorts(0) {} } inputBuses, outputBuses; #if DISTRHO_PLUGIN_WANT_MIDI_INPUT @@ -608,9 +609,11 @@ public: { #if DISTRHO_PLUGIN_NUM_INPUTS > 0 fillInBusInfoDetails<true>(); + std::memset(fEnabledInputs, 0, sizeof(fEnabledInputs)); #endif #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 fillInBusInfoDetails<false>(); + std::memset(fEnabledOutputs, 0, sizeof(fEnabledOutputs)); #endif if (const uint32_t extraParameterCount = fParameterCount + kVst3InternalParameterBaseCount) @@ -731,9 +734,9 @@ public: { case V3_AUDIO: if (busDirection == V3_INPUT) - return inputBuses.audio + inputBuses.sidechain + inputBuses.numCV + inputBuses.numGroups; + return inputBuses.audio + inputBuses.sidechain + inputBuses.groups + inputBuses.cvPorts; if (busDirection == V3_OUTPUT) - return outputBuses.audio + outputBuses.sidechain + outputBuses.numCV + outputBuses.numGroups; + return outputBuses.audio + outputBuses.sidechain + outputBuses.groups + outputBuses.cvPorts; break; case V3_EVENT: #if DISTRHO_PLUGIN_WANT_MIDI_INPUT @@ -1166,11 +1169,30 @@ public: // ---------------------------------------------------------------------------------------------------------------- // v3_audio_processor interface calls - v3_result setBusArrangements(v3_speaker_arrangement* /*inputs*/, const int32_t /*numInputs*/, - v3_speaker_arrangement* /*outputs*/, const int32_t /*numOutputs*/) + v3_result setBusArrangements(v3_speaker_arrangement* const inputs, const int32_t numInputs, + v3_speaker_arrangement* const outputs, const int32_t numOutputs) { - // TODO - return V3_NOT_IMPLEMENTED; + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(numInputs >= 0, V3_INVALID_ARG); + if (!setAudioBusArrangement<true>(inputs, static_cast<uint32_t>(numInputs))) + return V3_INTERNAL_ERR; + #else + DISTRHO_SAFE_ASSERT_RETURN(numInputs == 0, V3_INVALID_ARG); + // unused + (void)inputs; + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(numOutputs >= 0, V3_INVALID_ARG); + if (!setAudioBusArrangement<false>(outputs, static_cast<uint32_t>(numOutputs))) + return V3_INTERNAL_ERR; + #else + DISTRHO_SAFE_ASSERT_RETURN(numOutputs == 0, V3_INVALID_ARG); + // unused + (void)outputs; + #endif + + return V3_OK; } v3_result getBusArrangement(const int32_t busDirection, const int32_t busIndex, v3_speaker_arrangement* const speaker) const noexcept @@ -1268,7 +1290,7 @@ public: if (! fPlugin.isActive()) fPlugin.activate(); -#if DISTRHO_PLUGIN_WANT_TIMEPOS + #if DISTRHO_PLUGIN_WANT_TIMEPOS if (v3_process_context* const ctx = data->ctx) { fTimePosition.playing = ctx->state & V3_PROCESS_CTX_PLAYING; @@ -1323,7 +1345,7 @@ public: fPlugin.setTimePosition(fTimePosition); } -#endif + #endif if (data->nframes <= 0) { @@ -2304,6 +2326,12 @@ private: float* fCachedParameterValues; // basic offset + real float* fDummyAudioBuffer; bool* fParameterValuesChangedDuringProcessing; // basic offset + real + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + bool fEnabledInputs[DISTRHO_PLUGIN_NUM_INPUTS]; + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + bool fEnabledOutputs[DISTRHO_PLUGIN_NUM_OUTPUTS]; + #endif #if DISTRHO_PLUGIN_HAS_UI bool* fParameterValueChangesForUI; // basic offset + real bool fConnectedToUI; @@ -2339,12 +2367,23 @@ private: void fillInBusInfoDetails() { constexpr const uint32_t numPorts = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS; - BusInfo& bufInfo(isInput ? inputBuses : outputBuses); + BusInfo& busInfo(isInput ? inputBuses : outputBuses); + bool* const enabledPorts = isInput + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + ? fEnabledInputs + #else + ? nullptr + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + : fEnabledOutputs; + #else + : nullptr; + #endif std::vector<uint32_t> visitedPortGroups; for (uint32_t i=0; i<numPorts; ++i) { - AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); + const AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); if (port.groupId != kPortGroupNone) { @@ -2352,45 +2391,55 @@ private: if (std::find(visitedPortGroups.begin(), end, port.groupId) == end) { visitedPortGroups.push_back(port.groupId); - ++bufInfo.numGroups; + ++busInfo.groups; } + ++busInfo.groupPorts; continue; } if (port.hints & kAudioPortIsCV) - ++bufInfo.numCV; + ++busInfo.cvPorts; + else if (port.hints & kAudioPortIsSidechain) + ++busInfo.sidechainPorts; else - ++bufInfo.numMainAudio; - - if (port.hints & kAudioPortIsSidechain) - ++bufInfo.numSidechain; + ++busInfo.audioPorts; } - if (bufInfo.numMainAudio != 0) - bufInfo.audio = 1; - if (bufInfo.numSidechain != 0) - bufInfo.sidechain = 1; + if (busInfo.audioPorts != 0) + busInfo.audio = 1; + if (busInfo.sidechainPorts != 0) + busInfo.sidechain = 1; uint32_t busIdFromGroup = 0; uint32_t busIdForCV = 0; - for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i) + for (uint32_t i=0; i<numPorts; ++i) { AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); if (port.groupId != kPortGroupNone) { port.busId = busIdFromGroup++; + + if (busInfo.audio == 0 && (port.hints & kAudioPortIsSidechain) == 0x0) + enabledPorts[i] = true; } else { if (port.hints & kAudioPortIsCV) - port.busId = bufInfo.audio + bufInfo.sidechain + busIdForCV++; + { + port.busId = busInfo.audio + busInfo.sidechain + busIdForCV++; + } else if (port.hints & kAudioPortIsSidechain) - port.busId = bufInfo.audio; + { + port.busId = busInfo.audio; + } else + { port.busId = 0; + enabledPorts[i] = true; + } - port.busId += bufInfo.numGroups; + port.busId += busInfo.groups; } } } @@ -2399,14 +2448,14 @@ private: v3_result getAudioBusInfo(uint32_t busId, v3_bus_info* const info) const { constexpr const uint32_t numPorts = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS; - const BusInfo& bufInfo(isInput ? inputBuses : outputBuses); + const BusInfo& busInfo(isInput ? inputBuses : outputBuses); int32_t numChannels; uint32_t flags; v3_bus_types busType; v3_str_128 busName = {}; - if (busId < bufInfo.numGroups) + if (busId < busInfo.groups) { numChannels = fPlugin.getAudioPortCountWithGroupId(isInput, busId); busType = V3_AUX; @@ -2422,8 +2471,10 @@ private: switch (port.groupId) { - case kPortGroupMono: case kPortGroupStereo: + numChannels = 2; + // fall-through + case kPortGroupMono: strncpy_utf16(busName, isInput ? "Audio Input" : "Audio Output", 128); break; default: @@ -2434,7 +2485,7 @@ private: break; } - if (bufInfo.audio == 0 && (port.hints & kAudioPortIsSidechain) == 0x0) + if (busInfo.audio == 0 && (port.hints & kAudioPortIsSidechain) == 0x0) { busType = V3_MAIN; flags = V3_DEFAULT_ACTIVE; @@ -2445,23 +2496,23 @@ private: } else { - busId -= bufInfo.numGroups; + busId -= busInfo.groups; switch (busId) { case 0: - if (bufInfo.audio) + if (busInfo.audio) { - numChannels = bufInfo.numMainAudio; + numChannels = busInfo.audioPorts; busType = V3_MAIN; flags = V3_DEFAULT_ACTIVE; break; } // fall-through case 1: - if (bufInfo.sidechain) + if (busInfo.sidechain) { - numChannels = bufInfo.numSidechain; + numChannels = busInfo.sidechainPorts; busType = V3_AUX; flags = 0; break; @@ -2499,6 +2550,7 @@ private: } } + // d_stdout("getAudioBusInfo %d %d", busId, numChannels); std::memset(info, 0, sizeof(v3_bus_info)); info->media_type = V3_AUDIO; info->direction = isInput ? V3_INPUT : V3_OUTPUT; @@ -2513,18 +2565,36 @@ private: bool getAudioBusArrangement(uint32_t busId, v3_speaker_arrangement* const speaker) const { constexpr const uint32_t numPorts = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS; - const BusInfo& bufInfo(isInput ? inputBuses : outputBuses); + const BusInfo& busInfo(isInput ? inputBuses : outputBuses); + const bool* const enabledPorts = isInput + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + ? fEnabledInputs + #else + ? nullptr + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + : fEnabledOutputs; + #else + : nullptr; + #endif for (uint32_t i=0; i<numPorts; ++i) { - AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); + const AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); if (port.busId != busId) { - d_stdout("port.busId != busId: %d %d", port.busId, busId); + // d_stdout("port.busId != busId: %d %d", port.busId, busId); continue; } + if (!enabledPorts[i]) + { + *speaker = 0; + // d_stdout("getAudioBusArrangement %d %lx", busId, 0); + return true; + } + v3_speaker_arrangement arr; switch (port.groupId) @@ -2536,7 +2606,7 @@ private: arr = V3_SPEAKER_L | V3_SPEAKER_R; break; default: - if (busId < bufInfo.numGroups) + if (busId < busInfo.groups) { const uint32_t numPortsInBus = fPlugin.getAudioPortCountWithGroupId(isInput, busId); arr = 0x0; @@ -2545,34 +2615,104 @@ private: } else { - busId -= bufInfo.numGroups; + busId -= busInfo.groups; - if (bufInfo.audio != 0 && busId == 0) + if (busInfo.audio != 0 && busId == 0) { arr = 0x0; - for (uint32_t j=0; j<bufInfo.numMainAudio; ++j) + for (uint32_t j=0; j<busInfo.audioPorts; ++j) arr |= 1ull << (j + 33ull); } - else if (bufInfo.sidechain != 0 && busId == bufInfo.audio) + else if (busInfo.sidechain != 0 && busId == busInfo.audio) { arr = 0x0; - for (uint32_t j=0; j<bufInfo.numSidechain; ++j) - arr |= 1ull << (bufInfo.numMainAudio + j + 33ull); + for (uint32_t j=0; j<busInfo.sidechainPorts; ++j) + arr |= 1ull << (busInfo.audioPorts + j + 33ull); } else { - arr = 1ull << (bufInfo.numMainAudio + bufInfo.numSidechain + busId + 33ull); + arr = 1ull << (busInfo.audioPorts + busInfo.sidechainPorts + busId + 33ull); } } break; } *speaker = arr; + // d_stdout("getAudioBusArrangement %d %lx", busId, arr); return true; } return false; } + + template<bool isInput> + bool setAudioBusArrangement(v3_speaker_arrangement* const speakers, const uint32_t numBuses) + { + constexpr const uint32_t numPorts = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS; + BusInfo& busInfo(isInput ? inputBuses : outputBuses); + bool* const enabledPorts = isInput + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + ? fEnabledInputs + #else + ? nullptr + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + : fEnabledOutputs; + #else + : nullptr; + #endif + + for (uint32_t busId=0; busId<numBuses; ++busId) + { + const v3_speaker_arrangement arr = speakers[busId]; + + // d_stdout("setAudioBusArrangement %d %d | %d %lx", (int)isInput, numBuses, busId, arr); + + for (uint32_t i=0; i<numPorts; ++i) + { + AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); + + if (port.busId != busId) + { + d_stdout("setAudioBusArrangement port.busId != busId: %d %d", port.busId, busId); + continue; + } + + // special case for turning mono into "stereo" + /* + if (arr == (V3_SPEAKER_L|V3_SPEAKER_R)) + { + if (port.groupId == kPortGroupMono) + port.groupId = kPortGroupStereo; + else if (busId == 0 && busInfo.audioPorts == 1) + busInfo.audioPorts = 2; + } + */ + + enabledPorts[i] = arr != 0; + break; + } + } + + // disable any buses outside of the requested arrangement + const uint32_t totalBuses = busInfo.audio + busInfo.sidechain + busInfo.groups + busInfo.cvPorts; + + for (uint32_t busId=numBuses; busId<totalBuses; ++busId) + { + for (uint32_t i=0; i<numPorts; ++i) + { + const AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i)); + + if (port.busId == busId) + { + enabledPorts[i] = false; + break; + } + } + } + + return true; + } #endif // ----------------------------------------------------------------------------------------------------------------