diff options
Diffstat (limited to 'pluginvst.cc')
-rw-r--r-- | pluginvst.cc | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/pluginvst.cc b/pluginvst.cc new file mode 100644 index 0000000..700a19d --- /dev/null +++ b/pluginvst.cc @@ -0,0 +1,391 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * pluginvst.cc + * + * Mon Feb 8 19:24:40 CET 2016 + * Copyright 2016 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of PluginGizmo. + * + * PluginGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * PluginGizmo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with PluginGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "pluginvst.h" + +#include "midievent.h" + +#include <public.sdk/source/vst2.x/audioeffectx.h> +#include <public.sdk/source/vst2.x/aeffeditor.h> + +bool PluginVST::getFreeWheel() const +{ + return free_wheel; +} + +float PluginVST::getSamplerate() +{ + return AudioEffectX::getSampleRate(); +} + + +std::size_t PluginVST::getFramesize() +{ + return AudioEffectX::getBlockSize(); +} + +bool PluginVST::getActive() +{ + return active; +} + +float PluginVST::getLatency() +{ + return current_latency; +} + +void PluginVST::setLatency(float latency) +{ + update_latency = latency; +} + +void PluginVST::updateLatency() +{ + if(update_latency != current_latency) + { + AudioEffectX::setInitialDelay(current_latency); + AudioEffectX::ioChanged(); + current_latency = update_latency; + } +} + +// +// VST AudioEffectX implementation: +// +PluginVST::PluginVST(audioMasterCallback audioMaster) + : AudioEffectX(audioMaster, 0, 0) +{ +} + +PluginVST::~PluginVST() +{ +} + +static uint32_t sdbm_hash(std::string input) +{ + unsigned long hash = 0; + + for(auto& cha : input) + { + hash = (unsigned char)cha + (hash << 6) + (hash << 16) - hash; + } + + return hash; +} + +void PluginVST::open() +{ + // Called when plug-in is initialized. + + // virtual void setUniqueID (VstInt32 iD) + // Must be called to set the plug-ins unique ID! + uint32_t hash = sdbm_hash(getId()); + AudioEffect::setUniqueID(hash); + + // virtual void setNumInputs (VstInt32 inputs) + // Set the number of inputs the plug-in will handle. For a plug-in which + // could change its IO configuration, this number is the maximun available + // inputs. + AudioEffect::setNumInputs(getNumberOfAudioInputs()); + + // virtual void setNumOutputs (VstInt32 outputs) + // Set the number of outputs the plug-in will handle. For a plug-in which + // could change its IO configuration, this number is the maximun available + // ouputs. + AudioEffect::setNumOutputs(getNumberOfAudioOutputs()); + + // virtual void canProcessReplacing (bool state=true) + // Tells that processReplacing() could be used. Mandatory in VST 2.4! + AudioEffect::canProcessReplacing(true); + + // virtual void canDoubleReplacing (bool state=true) + // Tells that processDoubleReplacing() is implemented. + AudioEffect::canDoubleReplacing(false); + + // virtual void programsAreChunks (bool state=true) + // Program data is handled in formatless chunks (using getChunk-setChunks). + AudioEffect::programsAreChunks(true); // for generic config string support. + + // virtual void setInitialDelay (VstInt32 delay) + // Use to report the plug-in's latency (Group Delay). + AudioEffect::setInitialDelay(0); + + AudioEffectX::isSynth(getNumberOfMidiInputs() > 0); + + if(hasGUI()) + { + editor = std::make_shared<UI>(*this); + setEditor(editor.get()); + } +} + +void PluginVST::close() +{ + // Called when plug-in will be released. + setEditor(nullptr); + editor = nullptr; +} + +void PluginVST::suspend() +{ + // Called when plug-in is switched to off. + active = false; + onActiveChange(active); + updateLatency(); +} + +void PluginVST::resume() +{ + updateLatency(); + + // Called when plug-in is switched to on. + active = true; + onActiveChange(active); +} + +void PluginVST::setSampleRate(float sampleRate) +{ + // Called when the sample rate changes (always in a suspend state). + onSamplerateChange(sampleRate); +} + +void PluginVST::setBlockSize(VstInt32 blockSize) +{ + // Called when the Maximun block size changes (always in a suspend state). + // Note that the sampleFrames in Process Calls could be smaller than this + // block size, but NOT bigger. + onFramesizeChange(blockSize); +} + +VstInt32 PluginVST::processEvents(VstEvents* events) +{ + // For each process cycle, processEvents() is called once before a + // processReplacing() call. + + for(VstInt32 i = 0; i < events->numEvents; ++i) + { + auto event = events->events[i]; + if(event->type != kVstMidiType) + { + continue; + } + + auto midi_event = (VstMidiEvent*)event; + input_events.emplace_back(midi_event->deltaFrames, + midi_event->midiData, + midi_event->byteSize); + } + + return 0; +} + +void PluginVST::processReplacing(float** inputs, float** outputs, + VstInt32 sampleFrames) +{ + // Process 32 bit (single precision) floats (always in a resume state). + + // 0 = realtime/normal + // 1 = non-realtime/rendering + // 2 = offline processing + long lvl = AudioEffectX::getCurrentProcessLevel(); + bool last_free_wheel = free_wheel; + free_wheel = (lvl != 0); + if(last_free_wheel != free_wheel) + { + onFreeWheelChange(free_wheel); + } + + std::vector<const float*> input_audio_ports; + for(std::size_t i = 0; i < getNumberOfAudioInputs(); ++i) + { + input_audio_ports.emplace_back(inputs[i]); + } + + std::vector<float*> output_audio_ports; + output_audio_ports.resize(getNumberOfAudioOutputs()); + + for(std::size_t i = 0; i < getNumberOfAudioOutputs(); ++i) + { + output_audio_ports[i] = outputs[i]; + } + + std::vector<MidiEvent> output_events; + + // Process events and audio + process(pos, + input_events, + output_events, + input_audio_ports, + output_audio_ports, + (std::size_t)sampleFrames); + + input_events.clear(); + + if(getNumberOfMidiOutputs()) + { + // Translate output_events to VST midi events. + std::vector<VstMidiEvent> vst_output_event_list; + vst_output_event_list.resize(output_events.size()); + for(std::size_t i = 0; i < output_events.size(); ++i) + { + vst_output_event_list[i].deltaFrames = output_events[i].getTime(); + vst_output_event_list[i].type = kVstMidiType; + const char* data = output_events[i].getData(); + for(std::size_t j = 0; j < output_events[i].getSize(); ++j) + { + vst_output_event_list[i].midiData[j] = data[j]; + } + vst_output_event_list[i].byteSize = output_events[i].getSize(); + } + + if(!vst_output_event_list.empty()) + { + // Dispatch output events to host + VstEvents vst_output_events; + vst_output_events.numEvents = vst_output_event_list.size(); + vst_output_events.events[0] = (VstEvent*)vst_output_event_list.data(); + sendVstEventsToHost(&vst_output_events); + } + } + + pos += sampleFrames; +} + +VstInt32 PluginVST::getChunk(void **data, bool isPreset) +{ + std::string state = onStateSave(); + char* chunk = (char*)malloc(state.size() + 1); + memcpy(chunk, state.data(), state.size()); + *data = chunk; + return state.size(); +} + +VstInt32 PluginVST::setChunk(void *data, VstInt32 byteSize, bool isPreset) +{ + std::string state; + state.append((const char*)data, (std::size_t)byteSize); + onStateRestore(state); + return 0; +} + +VstInt32 PluginVST::canDo(char* text) +{ + std::string feature = text; + + // Midi input + if((feature == "receiveVstMidiEvent") &&//PlugCanDos::canDoReceiveVstMidiEvent + (getNumberOfMidiInputs() > 0)) + { + return 1; + } + + // Midi output + if((feature == "sendVstMidiEvent") && // PlugCanDos::canDoSendVstMidiEvent + (getNumberOfMidiOutputs() > 0)) + { + return 1; + } + + // For FreeWheel functionality. + if(feature == "offline") // PlugCanDos::canDoOffline + { + return 1; + } + + // TODO: For soft-bypass state. + //if(feature == "bypass") // PlugCanDos::canDoBypass) + //{ + // return 1; + //} + + // TODO: For receiving metronome ticks? + //if(feature == "receiveVstTimeInfo") // PlugCanDos::canDoReceiveVstTimeInfo) + //{ + // return 1; + //} + + return 0; +} + +void PluginVST::resizeWindow(std::size_t width, std::size_t height) +{ + if(editor) + { + editor->rect.top = 0; + editor->rect.left = 0; + editor->rect.right = width; + editor->rect.bottom = height; + } +} + +void PluginVST::closeWindow() +{ +} + +PluginVST::UI::UI(PluginVST& plugin_vst) + : AEffEditor(&plugin_vst) + , plugin_vst(plugin_vst) +{ +} + +bool PluginVST::UI::open(void* ptr) +{ + plugin_vst.createWindow(ptr); + + AEffEditor::open(ptr); + + is_open = true; + return true; +} + +void PluginVST::UI::close() +{ + is_open = false; + plugin_vst.onDestroyWindow(); + + AEffEditor::close(); +} + +bool PluginVST::UI::isOpen() +{ + return is_open; +} + +void PluginVST::UI::idle() +{ + if(is_open) + { + plugin_vst.onIdle(); + } + + AEffEditor::idle(); +} + +bool PluginVST::UI::getRect(ERect** rect) +{ + *rect = &this->rect; + return true; +} |