Download Source/Plugin/PluginBridgeProcessor.cpp from RAM2118/pluginbridge: direct link, hf CLI and curl.
- Browser
- Download file 7.5 kB
-
https://huggingface.co/RAM2118/pluginbridge/resolve/1dd0405171bf6efd5a8dfd67bc5b5d3a24dc7aee/Source/Plugin/PluginBridgeProcessor.cpp
- Command line
-
hf download hf://RAM2118/pluginbridge@1dd0405171bf6efd5a8dfd67bc5b5d3a24dc7aee/Source/Plugin/PluginBridgeProcessor.cpp
-
curl -L -o PluginBridgeProcessor.cpp https://huggingface.co/RAM2118/pluginbridge/resolve/1dd0405171bf6efd5a8dfd67bc5b5d3a24dc7aee/Source/Plugin/PluginBridgeProcessor.cpp
7.5 kB
| using json = nlohmann::json; | |
| PluginBridgeProcessor::PluginBridgeProcessor() | |
| : AudioProcessor(BusesProperties() | |
| .withInput("Input", juce::AudioChannelSet::stereo(), true) | |
| .withOutput("Output", juce::AudioChannelSet::stereo(), true)), | |
| mcpServer(PluginBridgeConstants::kDefaultMcpPort, helper) | |
| { | |
| helper.onHelperCrashed = [this]() | |
| { | |
| pluginLoaded = false; | |
| pluginName.clear(); | |
| pluginParamCount = 0; | |
| DBG("PluginBridgeProcessor: Helper crashed — plugin unloaded"); | |
| }; | |
| mcpServer.start(); | |
| } | |
| PluginBridgeProcessor::~PluginBridgeProcessor() | |
| { | |
| mcpServer.stop(); | |
| helper.killHelper(); | |
| } | |
| void PluginBridgeProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) | |
| { | |
| currentSampleRate = sampleRate; | |
| currentBlockSize = samplesPerBlock; | |
| if (helper.isHelperRunning()) | |
| { | |
| json cmd = {{"cmd", "configure"}, | |
| {"sampleRate", sampleRate}, | |
| {"blockSize", samplesPerBlock}, | |
| {"channels", 2}}; | |
| helper.sendCommand(cmd.dump()); | |
| auto* header = helper.getSharedAudio().getHeader(); | |
| if (header) | |
| { | |
| header->sampleRate.store((uint32_t)sampleRate); | |
| header->blockSize.store((uint32_t)samplesPerBlock); | |
| header->numChannels.store(2); | |
| } | |
| } | |
| } | |
| void PluginBridgeProcessor::releaseResources() | |
| { | |
| } | |
| void PluginBridgeProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer&) | |
| { | |
| juce::ScopedNoDenormals noDenormals; | |
| auto totalNumInputChannels = getTotalNumInputChannels(); | |
| auto totalNumOutputChannels = getTotalNumOutputChannels(); | |
| for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) | |
| buffer.clear(i, 0, buffer.getNumSamples()); | |
| if (!pluginLoaded || !helper.isHelperRunning()) | |
| return; | |
| auto& shm = helper.getSharedAudio(); | |
| if (!shm.isValid()) return; | |
| int numChannels = buffer.getNumChannels(); | |
| int numSamples = buffer.getNumSamples(); | |
| const float* inputPtrs[2] = { | |
| buffer.getReadPointer(0), | |
| numChannels > 1 ? buffer.getReadPointer(1) : buffer.getReadPointer(0) | |
| }; | |
| shm.writeInput(inputPtrs, numChannels, numSamples); | |
| auto* header = shm.getHeader(); | |
| header->blockSize.store((uint32_t)numSamples); | |
| header->numChannels.store((uint32_t)numChannels); | |
| header->state.store(kStateInputReady); | |
| helper.getInputSem().signal(); | |
| if (helper.getOutputSem().wait(IPC::kProcessBlockTimeoutMs)) | |
| { | |
| float* outputPtrs[2] = { | |
| buffer.getWritePointer(0), | |
| numChannels > 1 ? buffer.getWritePointer(1) : buffer.getWritePointer(0) | |
| }; | |
| shm.readOutput(outputPtrs, numChannels, numSamples); | |
| header->state.store(kStateIdle); | |
| } | |
| } | |
| juce::AudioProcessorEditor* PluginBridgeProcessor::createEditor() | |
| { | |
| return new PluginBridgeEditor(*this); | |
| } | |
| void PluginBridgeProcessor::getStateInformation(juce::MemoryBlock& destData) | |
| { | |
| juce::ValueTree state("PluginBridgeState"); | |
| state.setProperty("pluginPath", pluginPath, nullptr); | |
| if (pluginLoaded && helper.isHelperRunning()) | |
| { | |
| auto response = helper.sendCommand("{\"cmd\":\"get_state\"}"); | |
| try { | |
| auto j = json::parse(response); | |
| if (j.value("ok", false)) | |
| state.setProperty("pluginState", juce::String(j["state"].get<std::string>()), nullptr); | |
| } catch (...) {} | |
| } | |
| juce::MemoryOutputStream stream(destData, false); | |
| state.writeToStream(stream); | |
| } | |
| void PluginBridgeProcessor::setStateInformation(const void* data, int sizeInBytes) | |
| { | |
| auto state = juce::ValueTree::readFromData(data, (size_t)sizeInBytes); | |
| if (state.isValid()) | |
| { | |
| auto path = state.getProperty("pluginPath").toString(); | |
| if (path.isNotEmpty()) | |
| { | |
| loadPlugin(path); | |
| auto pluginState = state.getProperty("pluginState").toString(); | |
| if (pluginState.isNotEmpty() && helper.isHelperRunning()) | |
| { | |
| json cmd = {{"cmd", "set_state"}, {"state", pluginState.toStdString()}}; | |
| helper.sendCommand(cmd.dump()); | |
| } | |
| } | |
| } | |
| } | |
| bool PluginBridgeProcessor::isMcpServerRunning() const | |
| { | |
| return mcpServer.isRunning(); | |
| } | |
| int PluginBridgeProcessor::getMcpServerPort() const | |
| { | |
| return mcpServer.getPort(); | |
| } | |
| void PluginBridgeProcessor::loadPlugin(const juce::String& path) | |
| { | |
| if (!helper.isHelperRunning()) | |
| { | |
| if (!helper.spawnHelper()) | |
| { | |
| DBG("PluginBridgeProcessor: Failed to spawn helper"); | |
| return; | |
| } | |
| json configCmd = {{"cmd", "configure"}, | |
| {"sampleRate", currentSampleRate}, | |
| {"blockSize", currentBlockSize}, | |
| {"channels", 2}}; | |
| helper.sendCommand(configCmd.dump()); | |
| } | |
| json loadCmd = {{"cmd", "load"}, | |
| {"path", path.toStdString()}, | |
| {"sampleRate", currentSampleRate}, | |
| {"blockSize", currentBlockSize}}; | |
| auto response = helper.sendCommand(loadCmd.dump()); | |
| try | |
| { | |
| auto j = json::parse(response); | |
| if (j.value("ok", false)) | |
| { | |
| pluginLoaded = true; | |
| pluginName = juce::String(j["name"].get<std::string>()); | |
| pluginParamCount = j.value("params", 0); | |
| pluginPath = path; | |
| DBG("PluginBridgeProcessor: Loaded " + pluginName + " (" + juce::String(pluginParamCount) + " params)"); | |
| } | |
| else | |
| { | |
| pluginLoaded = false; | |
| DBG("PluginBridgeProcessor: Failed to load: " + juce::String(j.value("error", "unknown"))); | |
| } | |
| } | |
| catch (...) | |
| { | |
| pluginLoaded = false; | |
| } | |
| } | |
| void PluginBridgeProcessor::unloadPlugin() | |
| { | |
| if (helper.isHelperRunning()) | |
| helper.sendCommand("{\"cmd\":\"unload\"}"); | |
| pluginLoaded = false; | |
| pluginName.clear(); | |
| pluginPath.clear(); | |
| pluginParamCount = 0; | |
| } | |
| void PluginBridgeProcessor::showPluginGui() | |
| { | |
| if (helper.isHelperRunning()) | |
| helper.sendCommand("{\"cmd\":\"show_gui\"}"); | |
| } | |
| void PluginBridgeProcessor::hidePluginGui() | |
| { | |
| if (helper.isHelperRunning()) | |
| helper.sendCommand("{\"cmd\":\"hide_gui\"}"); | |
| } | |
| juce::Array<juce::File> PluginBridgeProcessor::getInstalledPluginFiles() const | |
| { | |
| juce::Array<juce::File> results; | |
| juce::Array<juce::File> dirs = { | |
| juce::File("/Library/Audio/Plug-Ins/VST3"), | |
| juce::File::getSpecialLocation(juce::File::userHomeDirectory) | |
| .getChildFile("Library/Audio/Plug-Ins/VST3"), | |
| juce::File("/Library/Audio/Plug-Ins/Components"), | |
| juce::File::getSpecialLocation(juce::File::userHomeDirectory) | |
| .getChildFile("Library/Audio/Plug-Ins/Components") | |
| }; | |
| for (auto& dir : dirs) | |
| { | |
| if (dir.isDirectory()) | |
| { | |
| auto vst3s = dir.findChildFiles(juce::File::findDirectories, false, "*.vst3"); | |
| auto aus = dir.findChildFiles(juce::File::findDirectories, false, "*.component"); | |
| results.addArray(vst3s); | |
| results.addArray(aus); | |
| } | |
| } | |
| results.sort(); | |
| return results; | |
| } | |
| juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() | |
| { | |
| return new PluginBridgeProcessor(); | |
| } | |