diff --git a/csound b/csound
index 958aaf5..4612119 160000
--- a/csound
+++ b/csound
@@ -1 +1 @@
-Subproject commit 958aaf5b93a973445ea0edeed6073069ad0b6fc2
+Subproject commit 4612119213a4626033101e8bb11a5e9da2b86839
diff --git a/examples/CollidingComb.csd b/examples/CollidingComb.csd
index 6731db0..88d282f 100644
--- a/examples/CollidingComb.csd
+++ b/examples/CollidingComb.csd
@@ -18,7 +18,7 @@ This Csound piece demonstrates how to use the following vst3 opcodes:
--m195 --opcode-lib="/home/mkg/csound-vst3-opcodes/build/lib/Debug/libvst3_plugins.so" -z1
+-dm162 -odac --sample-accurate
@@ -36,10 +36,10 @@ alwayson "CollidingCombSynth_Output"
alwayson "Piano_Output"
alwayson "Master_Output"
-gi_vst3_handle_CollidingCombSynth vst3init "/usr/lib/vst3/CollidingCombSynth.vst3", "CollidingCombSynth", 1
+gi_vst3_handle_CollidingCombSynth vst3init "/Users/michaelgogins/code/vst/VSTPlugins/build/VST3/Release/CollidingCombSynth.vst3", "CollidingCombSynth", 1
vst3info gi_vst3_handle_CollidingCombSynth
-gi_vst3_handle_piano vst3init "/home/mkg/csound-vst3-opcodes/build/VST3/Debug/mda-vst3.vst3", "mda Piano", 1
+gi_vst3_handle_piano vst3init "/Library/Audio/Plug-Ins/VST3/mda-vst3.vst3", "mda Piano", 1
vst3info gi_vst3_handle_piano
// Array of instrument plugins indexed by instrument number, for sending
diff --git a/examples/pianoteq8_macos_test.csd b/examples/pianoteq8_macos_test.csd
index b178eb5..e223099 100644
--- a/examples/pianoteq8_macos_test.csd
+++ b/examples/pianoteq8_macos_test.csd
@@ -16,7 +16,7 @@ connect "Piano_Output", "outright", "Master_Output", "inright"
alwayson "Piano_Output"
alwayson "Master_Output"
-gi_vst3_handle_piano vst3init "/Library/Audio/Plug-Ins/VST3/Pianoteq 8.vst3", "Pianoteq 8", 1
+gi_vst3_handle_piano vst3init "/Library/Audio/Plug-Ins/VST3/Pianoteq 8.vst3", "Pianoteq 8", "", 1
vst3info gi_vst3_handle_piano
// Score generating instrument.
diff --git a/examples/vst3-opcodes-minimal.csd b/examples/vst3-opcodes-minimal.csd
index 8d448e8..7055233 100644
--- a/examples/vst3-opcodes-minimal.csd
+++ b/examples/vst3-opcodes-minimal.csd
@@ -24,7 +24,7 @@ several other plugins in the VST3 SDK. Parameters and presets also are used.
--m195 --opcode-lib="~/csound-vst3-opcodes/build/lib/Release/libvst3_plugins.so" -z1
+-m162
@@ -38,10 +38,10 @@ connect "JX10_Output", "outright", "Master_Output", "inright"
connect "Piano_Output", "outleft", "Master_Output", "inleft"
connect "Piano_Output", "outright", "Master_Output", "inright"
-gi_vst3_handle_jx10 vst3init "/Users/michaelgogins/csound-vst3-opcodes/build-macos/VST3/Debug/mda-vst3.vst3", "mda JX10", 1
+gi_vst3_handle_jx10 vst3init "/Users/michaelgogins/csound-vst3-opcodes/build-macos/VST3/Debug/mda-vst3.vst3", "mda JX10", "", 1
;vst3info gi_vst3_handle_jx10
-gi_vst3_handle_piano vst3init "/Users/michaelgogins/csound-vst3-opcodes/build-macos/VST3/Debug/mda-vst3.vst3", "mda Piano", 1
+gi_vst3_handle_piano vst3init "/Users/michaelgogins/csound-vst3-opcodes/build-macos/VST3/Debug/mda-vst3.vst3", "mda Piano", "", 1
;vst3info gi_vst3_handle_piano
// Array of instrument plugins indexed by instrument number, for sending
diff --git a/examples/vst3-opcodes-test-macos.csd b/examples/vst3-opcodes-test-macos.csd
index 20d3e6a..21822a5 100644
--- a/examples/vst3-opcodes-test-macos.csd
+++ b/examples/vst3-opcodes-test-macos.csd
@@ -32,7 +32,7 @@ to run this piece from the `csound-vst3/vst3-opcodes` subdirectory.
--m195 -odac ; --opcode-lib="../../build-macos/lib/Debug/libvst3_plugins.dylib" -z1
+-m162 -odac
@@ -56,16 +56,16 @@ alwayson "Delay"
alwayson "Reverb"
alwayson "Master_Output"
-gi_vst3_handle_jx10 vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda JX10", 1
+gi_vst3_handle_jx10 vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda JX10", "", 1
vst3info gi_vst3_handle_jx10
-gi_vst3_handle_piano vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda Piano", 1
+gi_vst3_handle_piano vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda Piano", "", 1
vst3info gi_vst3_handle_piano
-gi_vst3_handle_delay vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda Delay", 1
+gi_vst3_handle_delay vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda Delay", "", 1
vst3info gi_vst3_handle_delay
-gi_vst3_handle_ambience vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda Ambience", 1
+gi_vst3_handle_ambience vst3init "../build-macos/VST3/Debug/mda-vst3.vst3", "mda Ambience", "", 1
vst3info gi_vst3_handle_ambience
// Array of instrument plugins indexed by instrument number, for sending
@@ -146,14 +146,14 @@ endin
instr Save_Preset
i_target_plugin = p4
S_preset_name init p5
-i_vst3_plugin init gi_plugins[p4]
+i_vst3_plugin init gi_plugins[i_target_plugin]
vst3presetsave i_vst3_plugin, S_preset_name
prints "%-24s i %9.4f t %9.4f d %9.4f target: %3d preset: %s #%3d\n", nstrstr(p1), p1, p2, p3, i_target_plugin, S_preset_name, active(p1)
endin
instr Program_Change
i_target_plugin = p4
-i_vst3_plugin init gi_plugins[p4]
+i_vst3_plugin init gi_plugins[i_target_plugin]
; May only be relevant to the MDA example plugins.
k_parameter_id init p5
k_parameter_value init p6
@@ -165,7 +165,7 @@ endin
instr Load_Preset
i_target_plugin = p4
S_preset_name init p5
-i_vst3_plugin init gi_plugins[p4]
+i_vst3_plugin init gi_plugins[i_target_plugin]
vst3presetload i_vst3_plugin, S_preset_name
prints "%-24s i %9.4f t %9.4f d %9.4f target: %3d preset: %s #%3d\n", nstrstr(p1), p1, p2, p3, i_target_plugin, S_preset_name, active(p1)
endin
@@ -216,10 +216,10 @@ i "Print_Info" 10.5 1 4
; Restores original parameter state.
i "Load_Preset" 25 1 4 "jx10.vstpreset"
i "Print_Info" 25.5 1 4
-i "Program_Change" 25 1 4 0 12
-i "Print_Info" 30.0 1 4
-i "Program_Change" 30.1 4 0 5
-i "Print_Info" 30.2 1 3
+;i "Program_Change" 25 1 4 0 12
+;i "Print_Info" 30.0 1 4
+;i "Program_Change" 30.1 4 0 5
+;i "Print_Info" 30.2 1 3
diff --git a/vst3-opcodes/vst3-opcodes.cpp b/vst3-opcodes/vst3-opcodes.cpp
index 632b4bc..4c04e18 100644
--- a/vst3-opcodes/vst3-opcodes.cpp
+++ b/vst3-opcodes/vst3-opcodes.cpp
@@ -15,7 +15,7 @@
#define DEBUGGING 0
#define TUNING_DEBUGGING 0
-#define PARAMETER_DEBUGGING 0
+#define PARAMETER_DEBUGGING 1
#define PROCESS_DEBUGGING 0
#define EDITOR_IMPLEMENTED 0
@@ -81,7 +81,72 @@
* user, who must pass it to all other vst3 opcodes.
* (7) When Csound calls csoundModuleDestroy, the vst3_host_t instance
* terminates all plugins and deallocates all state.
- */
+ *
+ * The sequence for initializing the processor in the SDK documentation,
+ * omitting steps for connection points, is as follows. I do not know why some
+ * calls are repeated. I do not know which calls are actually required, though
+ * that can be inferred to some extent from the samples. I will also examine
+ * some other open source hosts.
+ *
+ * I will try to match this as best I can, and enumerate the calling sequence
+ * in my log messages.
+
+# Created
+// Optional, not using.
+// Component->setIoMode
+IComponent->getControllerClassID (S1)
+# Setup
+// I have provided a preset filepath argument, which is allowed to be blank,
+// for `vst3init`.
+IComponent->setState (S2)
+// IComponent->getState
+// Samples don't do this.
+// IAudioProcessor->setBusArrangement
+// IAudioProcessor->getBusArrangement
+IAudioProcessor->canProcessSampleSize (S2.1)
+# Setup Done
+IComponent->getBusCount (S3)
+IComponent->getBusInfo
+// For one input bus, returns in the argument its matching output bus.
+// The samples don't do this.
+// IComponent->getRoutingInfo
+IComponent->activateBus
+// Again, I have provided an optional preset file in `vst3init`.
+// IComponent->setState
+// IComponent->getState
+// Not needed here.
+// IAudioProcessor->getLatencySamples
+// IAudioProcessor->getTailSamples
+// Samples don't do this.
+// IAudioProcessor->setBusArrangement
+// IAudioProcessor->getBusArrangement
+IAudioProcessor->canProcessSampleSize
+IAudioProcessor->setupProcessing
+IProcessContextRequirements->getProcessContextRequirements
+# Activated -- why is this repeated? The samples only do this once.
+IComponent->getBusCount (S3)
+IComponent->getBusInfo (S4)
+// For one input bus, returns in the argument its matching output bus.
+// The samples don't do this.
+// IComponent->getRoutingInfo
+// The following returns no errors or assertions, but doesn't work.
+IComponent->setState
+// IComponent->getState
+// Not needed here.
+// IAudioProcessor->getLatencySamples
+// IAudioProcessor->getTailSamples
+// The samples don't do this.
+// IAudioProcessor->getBusArrangement
+// Why is this repeated?
+IAudioProcessor->canProcessSampleSize
+// I don't think this is needed.
+// IAudioPresentationLatency->setAudioPresentationLatency
+# Processing
+// There's an implication that only the UI thread can call
+// IComponent::setState during processing.
+IAudioProcessor->process
+
+*/
namespace csound {
@@ -283,36 +348,7 @@ namespace csound {
//~ static Steinberg::Vst::EditorHost::AppInit gInit (std::make_unique ());
- // Does this do any good? I dunno.
-
- class ComponentHandler : public Steinberg::Vst::IComponentHandler
- {
- public:
- Steinberg::tresult PLUGIN_API beginEdit (Steinberg::Vst::ParamID id) override {
- SMTG_DBPRT1 ("beginEdit called (%d)\n", id);
- return Steinberg::kNotImplemented;
- }
- Steinberg::tresult PLUGIN_API performEdit (Steinberg::Vst::ParamID id, Steinberg::Vst::ParamValue valueNormalized) override {
- SMTG_DBPRT2 ("performEdit called (%d, %f)\n", id, valueNormalized);
- return Steinberg::kNotImplemented;
- }
- Steinberg::tresult PLUGIN_API endEdit (Steinberg::Vst::ParamID id) override {
- SMTG_DBPRT1 ("endEdit called (%d)\n", id);
- return Steinberg::kNotImplemented;
- }
- Steinberg::tresult PLUGIN_API restartComponent (Steinberg::int32 flags) override {
- SMTG_DBPRT1 ("restartComponent called (%d)\n", flags);
- return Steinberg::kNotImplemented;
- }
- private:
- Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID /*_iid*/, void** /*obj*/) override {
- return Steinberg::kNoInterface;
- }
- Steinberg::uint32 PLUGIN_API addRef () override { return 1000; }
- Steinberg::uint32 PLUGIN_API release () override { return 1000; }
- };
-
-#endif
+ #endif
// This currently is a dummy implementation.
@@ -424,10 +460,10 @@ namespace csound {
}
return updateProcessSetup();
}
- bool setBlockSize(int32 value) {
- if (blockSize == value) {
- return true;
- }
+ /**
+ * Here the host (this) creates buffers for hostProcessData.
+ */
+ bool setBlockSize(Steinberg::int32 value) {
blockSize = value;
if (sampleRate == 0) {
return true;
@@ -437,9 +473,12 @@ namespace csound {
} else {
plugin_sample_size = Steinberg::Vst::kSample32;
}
+ // This is what actually allocates the audio buffers.
+ // HostProcessData looks up the Component's BusInfos and creates
+ // buffers accordingly.
hostProcessData.prepare(*component, blockSize, plugin_sample_size);
auto result = updateProcessSetup();
- csound->Message(csound, "vst3_plugin::setBlockSize: plugin_sample_size: %9d\n", plugin_sample_size);
+ csound->Message(csound, "vst3_plugin::setBlockSize: plugin_sample_size: %s (S2.1)\n", plugin_sample_size ? "64 bits" : "32 bits");
csound->Message(csound, "vst3_plugin::setBlockSize: sampleRate: %9.3f\n", sampleRate);
csound->Message(csound, "vst3_plugin::setBlockSize: blockSize: %9d\n", blockSize);
return result;
@@ -448,7 +487,7 @@ namespace csound {
// such must be normalized. Note that `id` is `id`, and not an index.
// Note also that many parameters one might think are not normalized,
// _are_ normalized (legacy code).
- void setParameter(uint32 id, double value, int32 sampleOffset) {
+ void setParameter(int32 id, double value, int32 sampleOffset) {
double normalized_value = controller->plainParamToNormalized(id, value);
#if PARAMETER_DEBUGGING
csound->Message(csound, "vst3_plugin_t::setParameter: id: %9d value: %9.4f normalized: %9.4f offset: %d\n",
@@ -561,7 +600,8 @@ namespace csound {
}
}
Steinberg::Vst::ProcessSetup setup;
- if (processor->canProcessSampleSize(Steinberg::Vst::kSample64) == Steinberg::kResultTrue) {
+ csound->Message(csound, "vst3_plugin_t::updateProcessSetup: canProcessSampleSize (S2.2).\n");
+ if (processor->canProcessSampleSize(Steinberg::Vst::kSample64) == Steinberg::kResultTrue) {
plugin_sample_size = Steinberg::Vst::kSample64;
csound->Message(csound, "vst3_plugin_t::updateProcessSetup: processing 64 bit samples.\n");
setup.symbolicSampleSize = Steinberg::Vst::kSample64;
@@ -570,6 +610,7 @@ namespace csound {
csound->Message(csound, "vst3_plugin_t::updateProcessSetup: processing 32 bit samples.\n");
setup.symbolicSampleSize = Steinberg::Vst::kSample32;
}
+ // TBool has the same values as bool.
component->activateBus(Steinberg::Vst::kEvent, Steinberg::Vst::kInput, 0, false);
component->activateBus(Steinberg::Vst::kEvent, Steinberg::Vst::kOutput, 0, false);
component->activateBus(Steinberg::Vst::kAudio, Steinberg::Vst::kInput, 0, false);
@@ -582,9 +623,10 @@ namespace csound {
return false;
}
if (component->setActive(true) != Steinberg::kResultOk) {
- csound->Message(csound, "vst3_plugin_t::updateProcessSetup: setActive returned 'false'.\n");
+ csound->Message(csound, "vst3_plugin_t::updateProcessSetup: setActive returned not OK.\n");
return false;
}
+ csound->Message(csound, "vst3_plugin_t::updateProcessSetup: activateBus (S3).\n");
component->activateBus(Steinberg::Vst::kEvent, Steinberg::Vst::kInput, 0, true);
component->activateBus(Steinberg::Vst::kEvent, Steinberg::Vst::kOutput, 0, true);
component->activateBus(Steinberg::Vst::kAudio, Steinberg::Vst::kInput, 0, true);
@@ -641,15 +683,18 @@ namespace csound {
if (controllerClassUID.isValid() == false) {
csound->Message(csound, "vst3_plugin_t: The edit controller class has no valid UID!\n");
}
- char cidString[50];
- controllerClassUID.toString(cidString);
char iidString[50];
component->iid.toString(iidString);
+ char pidString[50];
+ processor->iid.toString(pidString);
+ char cidString[50];
+ controller->iid.toString(cidString);
// Class information.
if (print == true) {
csound->Message(csound, "vst3_plugin_t: class: module classinfo id: %s\n", classInfo.ID().toString().c_str());
csound->Message(csound, " class: component class id: %s\n", iidString);
- csound->Message(csound, " class: controller class id: %s\n", cidString);
+ csound->Message(csound, " class: processor class id: %s\n", pidString);
+ csound->Message(csound, " class: controller class id: %s (S1)\n", cidString);
csound->Message(csound, " class: cardinality: %i\n", classInfo.cardinality());
csound->Message(csound, " class: category: %s\n", classInfo.category().c_str());
csound->Message(csound, " class: name: %s\n", classInfo.name().c_str());
@@ -658,8 +703,8 @@ namespace csound {
csound->Message(csound, " class: sdkVersion: %s\n", classInfo.sdkVersion().c_str());
csound->Message(csound, " class: subCategoriesString: %s\n", classInfo.subCategoriesString().c_str());
csound->Message(csound, " class: classFlags: %i\n", classInfo.classFlags());
- csound->Message(csound, " can process 32 bit samples: %d\n", processor->canProcessSampleSize(Steinberg::Vst::kSample32) == Steinberg::kResultTrue);
- csound->Message(csound, " can process 64 bit samples: %d\n", processor->canProcessSampleSize(Steinberg::Vst::kSample64) == Steinberg::kResultTrue);
+ csound->Message(csound, " can process 32 bit samples: %s (S2.3)\n", processor->canProcessSampleSize(Steinberg::Vst::kSample32) == Steinberg::kResultTrue ? "yes" : "no");
+ csound->Message(csound, " can process 64 bit samples: %s (S2.3)\n", processor->canProcessSampleSize(Steinberg::Vst::kSample64) == Steinberg::kResultTrue ? "yes" : "no");
csound->Message(csound, " Csound samples: %d bits\n", int((sizeof(MYFLT) * 8)));
// Input and output busses.
// There is no ID in a BusInfo.
@@ -668,7 +713,7 @@ namespace csound {
Steinberg::Vst::BusInfo busInfo = {};
auto result = component->getBusInfo(Steinberg::Vst::MediaTypes::kAudio, Steinberg::Vst::kInput, i, busInfo);
auto name = VST3::StringConvert::convert(busInfo.name);
- csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s \n",
+ csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s (S3 S4)\n",
i,
busInfo.direction == 0 ? "Input " : "Output",
busInfo.mediaType == 0 ? "Audio" : "Event",
@@ -682,7 +727,7 @@ namespace csound {
Steinberg::Vst::BusInfo busInfo = {};
auto result = component->getBusInfo(Steinberg::Vst::MediaTypes::kEvent, Steinberg::Vst::kInput, i, busInfo);
auto name = VST3::StringConvert::convert(busInfo.name);
- csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s \n",
+ csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s (S3 S4)\n",
i,
busInfo.direction == 0 ? "Input " : "Output",
busInfo.mediaType == 0 ? "Audio" : "Event",
@@ -696,7 +741,7 @@ namespace csound {
Steinberg::Vst::BusInfo busInfo = {};
auto result = component->getBusInfo(Steinberg::Vst::MediaTypes::kAudio, Steinberg::Vst::kOutput, i, busInfo);
auto name = VST3::StringConvert::convert(busInfo.name);
- csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s \n",
+ csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s (S3 S4)\n",
i,
busInfo.direction == 0 ? "Input " : "Output",
busInfo.mediaType == 0 ? "Audio" : "Event",
@@ -710,7 +755,7 @@ namespace csound {
Steinberg::Vst::BusInfo busInfo = {};
auto result = component->getBusInfo(Steinberg::Vst::MediaTypes::kEvent, Steinberg::Vst::kOutput, i, busInfo);
auto name = VST3::StringConvert::convert(busInfo.name);
- csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s \n",
+ csound->Message(csound, " Buss[%3d]: direction: %s media: %s channels: %3d bus type: %s flags: %d name: %-32s (S3 S4)\n",
i,
busInfo.direction == 0 ? "Input " : "Output",
busInfo.mediaType == 0 ? "Audio" : "Event",
@@ -814,6 +859,57 @@ namespace csound {
static ComponentHandler component_handler_;
return &component_handler_;
}
+ int load_preset(const std::string &preset_filepath) {
+ csound->Message(csound, "load_preset: preset_filepath: %s\n", preset_filepath.c_str());
+ std::fstream input_stream(preset_filepath.c_str(), std::fstream::in | std::fstream::binary);
+ Steinberg::MemoryStream memory_stream;
+ char c;
+ Steinberg::int32 bytes_to_write = 1;
+ Steinberg::int32 bytes_written = 0;
+ while (input_stream.get(c)) {
+ memory_stream.write(&c, sizeof(c), &bytes_written);
+ }
+ auto stream_size = memory_stream.getSize();
+ input_stream.close();
+ csound->Message(csound, "load_preset: stream_size: %d\n", stream_size);
+ if (stream_size <= 0) {
+ csound->Message(csound, "load_preset::init: no file or no data: %s\n", preset_filepath.c_str());
+ return NOTOK;
+ }
+ Steinberg::int64 position = 0;
+ auto result = memory_stream.seek (0, Steinberg::IBStream::kIBSeekSet, &position);
+ if (result != Steinberg::kResultOk) {
+ csound->Message(csound, "load_preset::init: could not seek in IBStream.\n");
+ return NOTOK;
+ }
+ char iidString[50];
+ const auto uid = classInfo.ID();
+ auto tuid = classInfo.ID().data();
+ auto module_class_id = Steinberg::FUID::fromTUID(tuid);
+ module_class_id.toString(iidString);
+ component->iid.toString(iidString);
+ csound->Message(csound, "load_preset: component class ID: %s\n", iidString);
+ if (processor->setProcessing(false) != Steinberg::kResultOk) {
+ csound->Message(csound, "load_preset::init: failed to turn Processor off.\n");
+ }
+ if (component->setActive(false) != Steinberg::kResultOk) {
+ csound->Message(csound, "load_preset::init: failed to deactivate Component.\n");
+ }
+ result = Steinberg::Vst::PresetFile::loadPreset(&memory_stream, component->iid, component);
+ if (result == Steinberg::kResultOk) {
+ csound->Message(csound, "load_preset::init: loaded preset file: %s\n", preset_filepath.c_str());
+ return OK;
+ } else {
+ csound->Message(csound, "load_preset::init: failed to load preset file: %s\n", preset_filepath.c_str());
+ return NOTOK;
+ }
+ if (component->setActive(true) != Steinberg::kResultOk) {
+ csound->Message(csound, "load_preset::init: failed to reactivate Component.\n");
+ }
+ if (processor->setProcessing(true) != Steinberg::kResultOk) {
+ csound->Message(csound, "load_preset::init: failed to turn Processor back on.\n");
+ }
+ }
CSOUND* csound = nullptr;
Steinberg::IPtr provider;
VST3::Hosting::ClassInfo classInfo;
@@ -865,8 +961,8 @@ namespace csound {
/**
* Loads a VST3 Module and obtains all plugins in it.
*/
- int load_module(CSOUND *csound, const std::string& module_pathname, const std::string &plugin_name, bool verbose) {
- int handle = -1;
+ MYFLT load_module(CSOUND *csound, const std::string& module_pathname, const std::string &plugin_name, bool verbose) {
+ size_t handle = 0;
if (verbose == true) {
csound->Message(csound, "vst3_host_t::load_module: loading: \"%s\"\n", module_pathname.c_str());
}
@@ -878,7 +974,7 @@ namespace csound {
reason += "\nError: ";
reason += error;
csound->Message(csound, "vst3_host_t::load_module: error: %s\n", reason.c_str());
- return handle;
+ return -1;
}
modules_for_pathnames[module_pathname] = module;
auto factory = module->getFactory();
@@ -909,7 +1005,7 @@ namespace csound {
std::string error = "No VST3 Audio Module class found in file ";
error += module_pathname;
csound->Message(csound, "vst3_host_t::load_module: error: %s\n", error.c_str());
- return -1;;
+ return -1;
}
auto vst3_plugin = std::make_shared();
vst3_plugin->initialize(csound, classInfo_, plugProvider);
@@ -926,7 +1022,8 @@ namespace csound {
controllerClassUID.toString(cidString);
handle = vst3_plugins_for_handles.size();
vst3_plugins_for_handles.push_back(vst3_plugin);
- return handle;
+ MYFLT result = std::floor(static_cast(handle));
+ return result;
}
vst3_plugin_t *plugin_for_handle(MYFLT *handle) {
auto handle_value = *handle;
@@ -1030,30 +1127,37 @@ namespace csound {
log(csound, "vst3audio::audio: warning! current_time_in_frames is less than 0: %d\n", current_time_in_frames);
return NOTOK;
}
+ if (frame_count != vst3_plugin->hostProcessData.numSamples) {
+ log(csound, "vst3audio::audio: error! ksmps (%d) != numSamples: %d\n", ksmps(), vst3_plugin->hostProcessData.numSamples);
+ }
// Because this opcode should always be on, and because the plugins
// _themselves_ are actually responsible for scheduling by sample
// frame, ksmps_offset and ksmps_no_end have no effect and are not
// used.
if (plugin_sample_size == Steinberg::Vst::kSample32) {
- for (Steinberg::int32 channel_index = 0; channel_index < input_channel_count; ++channel_index) {
+ for (Steinberg::int32 channel_index_in = 0; channel_index_in < input_channel_count; ++channel_index_in) {
for (Steinberg::int32 frame_index = 0; frame_index < frame_count; ++frame_index) {
- plugin_input_channels_32[channel_index][frame_index] = a_input_channels[channel_index][frame_index];
- }
+ plugin_input_channels_32[channel_index_in][frame_index] = static_cast(a_input_channels[channel_index_in][frame_index]);
+#if PROCESS_DEBUGGING
+ log(csound, "vst3audio::audio in for 32 bits: sample[%4d][%4d]: opcode: %f plugin: %f\n",
+ channel_index_in, frame_index, a_input_channels[channel_index_in][frame_index], plugin_input_channels_32[channel_index_in][frame_index]);
+#endif
+ }
}
vst3_plugin->process(current_time_in_frames);
for (Steinberg::int32 channel_index = 0; channel_index < output_channel_count; ++channel_index) {
for (Steinberg::int32 frame_index = 0; frame_index < frame_count; ++frame_index) {
+ a_output_channels[channel_index][frame_index] = static_cast(plugin_output_channels_32[channel_index][frame_index]);
#if PROCESS_DEBUGGING
- log(csound, "vst3audio::audio for 32 bits: sample[%4d][%4d]: opcode: %f plugin: %f\n",
+ log(csound, "vst3audio::audio out for 32 bits: sample[%4d][%4d]: opcode: %f plugin: %f\n",
channel_index, frame_index, a_output_channels[channel_index][frame_index], plugin_output_channels_32[channel_index][frame_index]);
#endif
- a_output_channels[channel_index][frame_index] = plugin_output_channels_32[channel_index][frame_index];
}
}
} else {
- for (Steinberg::int32 channel_index = 0; channel_index < input_channel_count; ++channel_index) {
+ for (Steinberg::int32 channel_index_in = 0; channel_index_in < input_channel_count; ++channel_index_in) {
for (Steinberg::int32 frame_index = 0; frame_index < frame_count; ++frame_index) {
- plugin_input_channels_64[channel_index][frame_index] = a_input_channels[channel_index][frame_index];
+ plugin_input_channels_64[channel_index_in][frame_index] = a_input_channels[channel_index_in][frame_index];
}
}
vst3_plugin->process(current_time_in_frames);
@@ -1061,7 +1165,7 @@ namespace csound {
for (Steinberg::int32 frame_index = 0; frame_index < frame_count; ++frame_index) {
a_output_channels[channel_index][frame_index] = plugin_output_channels_64[channel_index][frame_index];
#if PROCESS_DEBUGGING
- log(csound, "vst3audio::audio for 64 bits: sample[%4d][%4d]: opcode: %f plugin: %f\n",
+ log(csound, "vst3audio::audio out for 64 bits: sample[%4d][%4d]: opcode: %f plugin: %f\n",
channel_index, frame_index, a_output_channels[channel_index][frame_index], plugin_output_channels_64[channel_index][frame_index]);
#endif
}
@@ -1091,19 +1195,25 @@ namespace csound {
// Inputs.
MYFLT *i_module_pathname;
MYFLT *i_plugin_name;
+ MYFLT *i_preset_filepath;
MYFLT *i_verbose;
int init(CSOUND *csound) {
int result = OK;
log(csound, "\nvst3init::init...\n");
auto host = vst3_host_for_csound(csound);
log(csound, "vst3init::init: host: %p\n", host);
- std::string module_pathname =((STRINGDAT *)i_module_pathname)->data;
- std::string plugin_name =((STRINGDAT *)i_plugin_name)->data;
+ std::string module_pathname =((STRINGDAT *)i_module_pathname)->data;
+ std::string plugin_name = ((STRINGDAT *)i_plugin_name)->data;
log(csound, "vst3init::init: loading module: \"%s\", \"%s\"...\n", module_pathname.c_str(), plugin_name.c_str());
*i_vst3_handle = host->load_module(csound, module_pathname, plugin_name,(bool)*i_verbose);
log(csound, "vst3init::init: loaded module: \"%s\", \"%s\" i_vst3_handle: %ld...\n", module_pathname.c_str(), plugin_name.c_str(), (size_t)*i_vst3_handle);
auto vst3_plugin = get_plugin(csound, static_cast(*i_vst3_handle));
log(csound, "vst3init::init: created plugin: \"%s\": address: %p handle: %ld\n", plugin_name.c_str(), vst3_plugin,(size_t) *i_vst3_handle);
+ std::string preset_filepath = ((STRINGDAT *)i_preset_filepath)->data;
+ if (preset_filepath.length() > 0) {
+ log(csound, "vst3init::init: loading preset \"%s\" (S2)\n", preset_filepath.c_str());
+ result = vst3_plugin->load_preset(preset_filepath);
+ }
return result;
};
};
@@ -1365,6 +1475,8 @@ namespace csound {
int result = OK;
vst3_plugin = get_plugin(csound, static_cast(*i_vst3_handle));
frames_per_kperiod = csound->GetKsmps(csound);
+ prior_parameter_id = -1;
+ prior_parameter_value = -1;
return result;
};
int kontrol(CSOUND *csound) {
@@ -1376,7 +1488,7 @@ namespace csound {
if (parameter_id != prior_parameter_id || parameter_value != prior_parameter_value) {
int64_t block_start_frames = opds.insdshead->kcounter * frames_per_kperiod;
int64_t current_time_frames = csound->GetCurrentTimeSamples(csound);
- Steinberg::int32 delta_frames = current_time_frames - block_start_frames;
+ Steinberg::int32 delta_frames = static_cast(current_time_frames - block_start_frames);
vst3_plugin->setParameter(parameter_id, parameter_value, delta_frames);
#if PARAMETER_DEBUGGING
log(csound, "vst3paramset::kontrol: id: %4d value: %9.4f delta_frames: %4d\n", parameter_id, parameter_value, delta_frames);
@@ -1391,48 +1503,13 @@ namespace csound {
struct VST3PRESETLOAD : public csound::OpcodeBase {
// Inputs.
MYFLT *i_vst3_handle;
- MYFLT *S_preset_filepath;
+ MYFLT *i_preset_filepath;
// State.
vst3_plugin_t *vst3_plugin;
int init(CSOUND *csound) {
vst3_plugin = get_plugin(csound, static_cast(*i_vst3_handle));
- std::string preset_filepath = ((STRINGDAT *)S_preset_filepath)->data;
- log(csound, "vst3presetload: preset_filepath: %s\n", preset_filepath.c_str());
- std::fstream input_stream(preset_filepath.c_str(), std::fstream::in | std::fstream::binary);
- Steinberg::MemoryStream memory_stream;
- char c;
- Steinberg::int32 bytes_to_write = 1;
- Steinberg::int32 bytes_written = 0;
- while (input_stream.get(c)) {
- memory_stream.write(&c, sizeof(c), &bytes_written);
- }
- auto stream_size = memory_stream.getSize();
- input_stream.close();
- Steinberg::int64 position = 0;
- auto result = memory_stream.seek (0, Steinberg::IBStream::kIBSeekSet, &position);
- char iidString[50];
- vst3_plugin->component->iid.toString(iidString);
- log(csound, "vst3presetload: component class ID: %s\n", iidString);
- if (result == Steinberg::kResultOk) {
- log(csound, "vst3presetload: stream_size: %d\n", stream_size);
- // In the PresetFile source code, the class ID is definitely the _Component_ ID.
- result = Steinberg::Vst::PresetFile::loadPreset(&memory_stream, vst3_plugin->component->iid, vst3_plugin->component);
- if (result == Steinberg::kResultOk) {
- log(csound, "vst3presetload::init: loaded from preset file: %s\n", preset_filepath.c_str());
- return OK;
- } else {
- log(csound, "vst3presetload: failed to load from preset file: %s\n", preset_filepath.c_str());
- }
- }
- // If that doesn't work, assume it's a "simple plugin" and see if
- // the component can simply read the file.
- result = memory_stream.seek (0, Steinberg::IBStream::kIBSeekSet, &position);
- result = vst3_plugin->component->setState(&memory_stream);
- if (result == false) {
- log(csound, "vst3presetload: failed to set loaded state: %s\n", preset_filepath.c_str());
- return NOTOK;
- }
- log(csound, "vst3presetload::init: set loaded state: %s\n", preset_filepath.c_str());
+ std::string preset_filepath = ((STRINGDAT *)i_preset_filepath)->data;
+ vst3_plugin->load_preset(preset_filepath);
return OK;
};
};
@@ -1440,18 +1517,17 @@ namespace csound {
struct VST3PRESETSAVE : public csound::OpcodeBase {
// Inputs.
MYFLT *i_vst3_handle;
- MYFLT *S_preset_filepath;
+ MYFLT *i_preset_filepath;
// State.
vst3_plugin_t *vst3_plugin;
int init(CSOUND *csound) {
vst3_plugin = get_plugin(csound, static_cast(*i_vst3_handle));
- std::string preset_filepath = ((STRINGDAT *)S_preset_filepath)->data;
+ std::string preset_filepath = ((STRINGDAT *)i_preset_filepath)->data;
log(csound, "vst3presetsave: preset_filepath: %s\n", preset_filepath.c_str());
auto tuid = vst3_plugin->classInfo.ID().data();
auto classid = Steinberg::FUID::fromTUID(tuid);
Steinberg::MemoryStream memory_stream;
- auto result = Steinberg::Vst::PresetFile::savePreset(&memory_stream, classid, vst3_plugin->component,
- vst3_plugin->controller);
+ auto result = Steinberg::Vst::PresetFile::savePreset(&memory_stream, classid, vst3_plugin->component); // , vst3_plugin->controller);
if (result == false) {
log(csound, "vst3presetsave::init: failed to save preset: %s\n", preset_filepath.c_str());
return NOTOK;
@@ -1489,7 +1565,7 @@ namespace csound {
static OENTRY localops[] = {
{"vst3audio", sizeof(VST3AUDIO), 0, 3, "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", "M", &VST3AUDIO::init_, &VST3AUDIO::audio_, 0},
{"vst3info", sizeof(VST3INFO), 0, 1, "", "i", &VST3INFO::init_, 0, 0},
- {"vst3init", sizeof(VST3INIT), 0, 1, "i", "TTo", &VST3INIT::init_, 0, 0},
+ {"vst3init", sizeof(VST3INIT), 0, 1, "i", "TTTo", &VST3INIT::init_, 0, 0},
#if EDITOR_IMPLEMENTED
{"vst3edit", sizeof(VST3EDIT), 0, 1, "", "i", &VST3EDIT::init_, 0, 0},
#endif
@@ -1543,9 +1619,8 @@ extern "C" {
PUBLIC int csoundModuleDestroy(CSOUND *csound) {
//#if DEBUGGING
- csound->Message(csound, "csoundModuleDestroy (vst3_opcodes): csound: %p thread: %ld...\n",
- csound,
- std::this_thread::get_id());
+ csound->Message(csound, "csoundModuleDestroy (vst3_opcodes): csound: %p...\n",
+ csound);
//#endif
csound::vst3hosts::instance().module_destroy(csound);
csound->Message(csound, "csoundModuleDestroy (vst3_opcodes): csound: %p.\n", csound);