summaryrefslogtreecommitdiff
path: root/pluginvst.cc
diff options
context:
space:
mode:
Diffstat (limited to 'pluginvst.cc')
-rw-r--r--pluginvst.cc391
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;
+}