MIDI plugins -- partial implemetnation, temporarily disabled.

This commit is contained in:
Robin E. R. Davies
2024-12-05 10:52:34 -05:00
parent 2989309728
commit 9d64cf1f92
24 changed files with 892 additions and 84 deletions
+3 -2
View File
@@ -1862,8 +1862,9 @@ public:
VuUpdate v;
v.instanceId_ = instanceId;
// Display mono VUs if a stereo device is being fed identical L/R inputs.
v.isStereoInput_ = effect->GetNumberOfInputAudioPorts() != 1 && effect->GetAudioInputBuffer(0) != effect->GetAudioInputBuffer(1);
v.isStereoOutput_ = effect->GetNumberOfOutputAudioPorts() != 1;
v.isStereoInput_ = effect->GetNumberOfInputAudioBuffers() >= 2
&& effect->GetAudioInputBuffer(0) != effect->GetAudioInputBuffer(1);
v.isStereoOutput_ = effect->GetNumberOfOutputAudioBuffers() >= 2;
vuConfig->vuUpdateWorkingData.push_back(v);
vuConfig->vuUpdateResponseData.push_back(v);
+4 -1
View File
@@ -41,7 +41,7 @@ namespace macaron
public:
static std::string Encode(const std::vector<uint8_t> &data)
{
return Encode(data.size(),&(data[0]));
return Encode(data.size(),data.data());
}
static std::string Encode(size_t size, const uint8_t *data)
{
@@ -112,6 +112,9 @@ namespace macaron
if (in_len % 4 != 0)
throw std::invalid_argument("Input data size is not a multiple of 4");
if (in_len < 4) {
return std::vector<uint8_t>();
}
size_t out_len = in_len / 4 * 3;
if (input[in_len - 1] == '=')
out_len--;
+5 -2
View File
@@ -49,8 +49,11 @@ namespace pipedal {
virtual void SetBypass(bool enable) = 0;
virtual float GetOutputControlValue(int controlIndex) const = 0;
virtual int GetNumberOfInputAudioPorts() const = 0;
virtual int GetNumberOfOutputAudioPorts() const = 0;
virtual int GetNumberOfInputAudioPorts() const = 0; // as declared
virtual int GetNumberOfOutputAudioPorts() const = 0; // as declared.
virtual int GetNumberOfInputAudioBuffers() const = 0; // may be different if plugin has zero inputs.
virtual int GetNumberOfOutputAudioBuffers() const = 0; // may be different if plugin has zero inputs.
virtual float *GetAudioInputBuffer(int index) const = 0;
virtual float *GetAudioOutputBuffer(int index) const = 0;
virtual void ResetAtomBuffers() = 0;
+4 -4
View File
@@ -414,12 +414,12 @@ void Lv2Effect::SetAudioInputBuffer(int index, float *buffer)
void Lv2Effect::SetAudioInputBuffer(float *left)
{
if (GetNumberOfInputAudioPorts() > 1)
if (GetNumberOfInputAudioBuffers() > 1)
{
SetAudioInputBuffer(0, left);
SetAudioInputBuffer(1, left);
}
else if (GetNumberOfInputAudioPorts() != 0) /// yyx MIXING!
else if (GetNumberOfInputAudioBuffers() != 0)
{
SetAudioInputBuffer(0, left);
}
@@ -427,11 +427,11 @@ void Lv2Effect::SetAudioInputBuffer(float *left)
void Lv2Effect::SetAudioInputBuffers(float *left, float *right)
{
if (GetNumberOfInputAudioPorts() == 1)
if (GetNumberOfInputAudioBuffers() == 1)
{
SetAudioInputBuffer(0, left);
}
else if (GetNumberOfInputAudioPorts() > 1)
else if (GetNumberOfInputAudioBuffers() > 1)
{
SetAudioInputBuffer(0, left);
SetAudioInputBuffer(1, right);
+6
View File
@@ -252,16 +252,22 @@ namespace pipedal
virtual uint64_t GetInstanceId() const { return instanceId; }
virtual int GetNumberOfInputAudioPorts() const { return inputAudioPortIndices.size(); }
virtual int GetNumberOfOutputAudioPorts() const { return outputAudioPortIndices.size(); }
virtual int GetNumberOfInputAtomPorts() const { return inputAtomPortIndices.size(); }
virtual int GetNumberOfOutputAtomPorts() const { return outputAtomPortIndices.size(); }
virtual int GetNumberOfMidiInputPorts() const { return inputMidiPortIndices.size(); }
virtual int GetNumberOfMidiOutputPorts() const { return outputMidiPortIndices.size(); }
virtual int GetNumberOfInputAudioBuffers() const { return this->inputAudioBuffers.size(); }
virtual int GetNumberOfOutputAudioBuffers() const {return this->outputAudioBuffers.size(); }
virtual void SetAudioInputBuffer(int index, float *buffer);
virtual float *GetAudioInputBuffer(int index) const { return this->inputAudioBuffers[index]; }
virtual void SetAudioInputBuffer(float *buffer);
virtual void SetAudioInputBuffers(float *left, float *right);
+10 -32
View File
@@ -136,11 +136,11 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
if (inputBuffers.size() == 1)
{
if (pLv2Effect->GetNumberOfInputAudioPorts() == 1)
if (pLv2Effect->GetNumberOfInputAudioBuffers() == 1)
{
pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]);
}
else
else if (pLv2Effect->GetNumberOfInputAudioBuffers() >= 2)
{
pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]);
pLv2Effect->SetAudioInputBuffer(1, inputBuffers[0]);
@@ -148,13 +148,13 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
}
else
{
if (pLv2Effect->GetNumberOfInputAudioPorts() == 1)
if (pLv2Effect->GetNumberOfInputAudioBuffers() == 1)
{
pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]);
auto inputBuffer = inputBuffers[0];
}
else
else if (pLv2Effect->GetNumberOfInputAudioBuffers() >= 2)
{
pLv2Effect->SetAudioInputBuffer(0, inputBuffers[0]);
pLv2Effect->SetAudioInputBuffer(1, inputBuffers[1]);
@@ -178,37 +178,15 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
std::vector<float *> effectOutput;
#ifdef RECYCLE_AUDIO_BUFFERS
// can't do this anymore if we're going to do pop-less bypbass.
if (pEffect->GetNumberOfOutputAudioPorts() == 1)
{
float *pLeft = inputBuffers[0];
effectOutput.push_back(pLeft);
}
else
{
if (inputBuffers.size() == 1)
{
effectOutput.push_back(inputBuffers[0]);
effectOutput.push_back(CreateNewAudioBuffer());
}
else
{
effectOutput.push_back(inputBuffers[0]);
effectOutput.push_back(inputBuffers[1]);
}
}
#else
if (pEffect->GetNumberOfOutputAudioPorts() == 1)
if (pEffect->GetNumberOfOutputAudioBuffers() == 1)
{
effectOutput.push_back(CreateNewAudioBuffer());
}
else
else if (pEffect->GetNumberOfOutputAudioBuffers() >= 2)
{
effectOutput.push_back(CreateNewAudioBuffer());
effectOutput.push_back(CreateNewAudioBuffer());
}
#endif
for (size_t i = 0; i < effectOutput.size(); ++i)
{
pEffect->SetAudioOutputBuffer(i, effectOutput[i]);
@@ -475,21 +453,21 @@ void Lv2Pedalboard::ComputeVus(RealtimeVuBuffers *vuConfiguration, uint32_t samp
{
auto effect = this->realtimeEffects[index];
if (effect->GetNumberOfInputAudioPorts() == 1)
if (effect->GetNumberOfInputAudioBuffers() == 1)
{
pUpdate->AccumulateInputs(effect->GetAudioInputBuffer(0), samples);
}
else
else if (effect->GetNumberOfInputAudioBuffers() >= 2)
{
pUpdate->AccumulateInputs(
effect->GetAudioInputBuffer(0),
effect->GetAudioInputBuffer(1), samples);
}
if (effect->GetNumberOfOutputAudioPorts() == 1)
if (effect->GetNumberOfOutputAudioBuffers() == 1)
{
pUpdate->AccumulateOutputs(effect->GetAudioOutputBuffer(0), samples);
}
else
else if (effect->GetNumberOfOutputAudioBuffers() >= 2)
{
pUpdate->AccumulateOutputs(
effect->GetAudioOutputBuffer(0),
+30 -1
View File
@@ -17,12 +17,41 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "pch.h"
#include "MidiBinding.hpp"
#include "MapFeature.hpp"
using namespace pipedal;
MidiChannelBinding MidiChannelBinding::DefaultForMissingValue()
{
MidiChannelBinding result {};
return result;
}
void MidiChannelBinding::Prepare(MapFeature &mapFeature)
{
midiDeviceUrids.resize(0);
midiDeviceUrids.reserve(midiDevices_.size());
for (const auto&midiDevice: midiDevices_)
{
midiDeviceUrids.push_back(mapFeature.GetUrid(midiDevice.c_str()));
}
}
JSON_MAP_BEGIN(MidiChannelBinding)
JSON_MAP_REFERENCE(MidiChannelBinding,deviceSelection)
JSON_MAP_REFERENCE(MidiChannelBinding,midiDevices)
JSON_MAP_REFERENCE(MidiChannelBinding,channel)
JSON_MAP_REFERENCE(MidiChannelBinding,acceptProgramChanges)
JSON_MAP_REFERENCE(MidiChannelBinding,acceptCommonMessages)
JSON_MAP_END()
JSON_MAP_BEGIN(MidiBinding)
JSON_MAP_REFERENCE(MidiBinding,channel)
JSON_MAP_REFERENCE(MidiBinding,symbol)
+88
View File
@@ -20,10 +20,16 @@
#pragma once
#include "json.hpp"
#include <cstdint>
#include <string>
#include <vector>
#include <lv2/urid/urid.h>
namespace pipedal {
class MapFeature;
#define GETTER_SETTER_REF(name) \
const decltype(name##_)& name() const { return name##_;} \
@@ -33,6 +39,9 @@ namespace pipedal {
decltype(name##_)& name() { return name##_;} \
const decltype(name##_)& name() const { return name##_;}
//void name(decltype(const name##_) &value) { name##_ = value; }
//void name(decltype(const name##_) &&value) { name##_ = std::move(value); }
#define GETTER_SETTER(name) \
@@ -102,6 +111,85 @@ public:
};
enum class MidiDeviceSelection {
DeviceAny = 0,
DeviceNone = 1,
DeviceList = 2
};
class MidiChannelBinding {
public:
static constexpr std::int32_t CHANNEL_OMNI = -1;
private:
int32_t deviceSelection_ = (int32_t)(MidiDeviceSelection::DeviceAny);
std::vector<std::string> midiDevices_;
std::vector<LV2_URID> midiDeviceUrids;
std::int32_t channel_ = CHANNEL_OMNI;
bool acceptProgramChanges_ = true;
bool acceptCommonMessages_ = true;
public:
MidiDeviceSelection deviceSelection() const { return (MidiDeviceSelection)deviceSelection_; }
void deviceSelection(MidiDeviceSelection value) { deviceSelection_ = (int32_t)value; }
GETTER_SETTER_VEC(midiDevices);
GETTER_SETTER(channel);
GETTER_SETTER(acceptProgramChanges);
GETTER_SETTER(acceptCommonMessages);
void Prepare(MapFeature &mapFeature);
static MidiChannelBinding DefaultForMissingValue();
bool WantsMidiMessage(uint8_t midi_cc0,uint8_t midi_cc1, uint8_t midi_cc2);
bool WantProgramChange(uint8_t midi_cc0,uint8_t midi_cc1);
// must call Prepare first.
bool WantsDevice(LV2_URID deviceUrid);
DECLARE_JSON_MAP(MidiChannelBinding);
};
///////////////////////////////////////
inline bool MidiChannelBinding::WantsMidiMessage(uint8_t midi_cc0,uint8_t midi_cc1, uint8_t midi_cc2)
{
if (midi_cc0 < 0xF0)
{
if (channel_ < 0) return true;
return midi_cc0 & 0x0F == channel_;
} else {
return acceptCommonMessages_;
}
}
inline bool MidiChannelBinding::WantProgramChange(uint8_t midi_cc0,uint8_t midi_cc1)
{
if (!acceptProgramChanges_)
{
return false;
}
if (channel_ < 0) return true;
return midi_cc0 & 0x0F == channel_;
}
inline bool MidiChannelBinding::WantsDevice(LV2_URID deviceUrid)
{
if (this->midiDeviceUrids.size() == 0) return true;
for (LV2_URID urid: midiDeviceUrids)
{
if (urid == deviceUrid) return true;
}
return false;
}
//////////////////////////////////////////
#undef GETTER_SETTER_REF
#undef GETTER_SETTER_VEC
#undef GETTER_SETTER
+2
View File
@@ -92,6 +92,7 @@ public:
std::vector<PedalboardItem> topChain_;
std::vector<PedalboardItem> bottomChain_;
std::vector<MidiBinding> midiBindings_;
std::optional<MidiChannelBinding> midiChannelBinding_;
std::string vstState_;
uint32_t stateUpdateCount_ = 0;
Lv2PluginState lv2State_;
@@ -122,6 +123,7 @@ public:
GETTER_SETTER_VEC(topChain)
GETTER_SETTER_VEC(bottomChain)
GETTER_SETTER_VEC(midiBindings)
GETTER_SETTER_REF(midiChannelBinding)
GETTER_SETTER(stateUpdateCount)
GETTER_SETTER_REF(lv2State)
Lv2PluginState&lv2State() { return lv2State_; } // non-const version.
+12
View File
@@ -1876,6 +1876,18 @@ void PiPedalModel::UpdateDefaults(PedalboardItem *pedalboardItem, std::unordered
}
if (pPlugin)
{
if (pPlugin->hasMidiInput())
{
if (!pedalboardItem->midiChannelBinding())
{
pedalboardItem->midiChannelBinding(MidiChannelBinding::DefaultForMissingValue());
}
} else {
if (pedalboardItem->midiChannelBinding())
{
pedalboardItem->midiChannelBinding(std::optional<MidiChannelBinding>()); // clear it.
}
}
for (size_t i = 0; i < pPlugin->ports().size(); ++i)
{
auto port = pPlugin->ports()[i];
+4 -3
View File
@@ -495,6 +495,10 @@ void PluginHost::Load(const char *lv2Path)
{
Lv2Log::debug("Plugin %s (%s) skipped. No audio i/o.", plugin->name().c_str(), plugin->uri().c_str());
} else if (info.audio_inputs() == 0)
{
// temporarily disable this feature.
Lv2Log::debug("Plugin %s (%s) skipped. No inputs.", plugin->name().c_str(), plugin->uri().c_str());
}
#elif SUPPORT_MIDI
if (info.audio_inputs() == 0 && !info.has_midi_input())
@@ -520,9 +524,6 @@ void PluginHost::Load(const char *lv2Path)
if (info.audio_inputs() == 0) {
Lv2Log::debug("************* ZERO INPUTS: %s (%s) skipped. No audio outputs.", plugin->name().c_str(), plugin->uri().c_str());
}
if (info.audio_outputs() == 0) {
Lv2Log::debug("************* ZERO OUTPUTS: %s (%s) skipped. No audio outputs.", plugin->name().c_str(), plugin->uri().c_str());
}
ui_plugins_.push_back(std::move(info));
}
}
+1
View File
@@ -432,6 +432,7 @@ namespace pipedal
return true;
}
}
return false;
}
bool hasMidiOutput() const
{
+5
View File
@@ -381,10 +381,15 @@ namespace pipedal
{
return (int)this->inputs.size();
}
virtual int GetNumberOfInputAudioBuffers() const { return this->inputs.size(); }
virtual float *GetAudioInputBuffer(int index) const
{
return inputs[index];
}
virtual int GetNumberOfOutputAudioBuffers() const {return this->outputBuffers.size(); }
virtual float *GetAudioOutputBuffer(int index) const
{
return this->outputBuffers[index];
+1 -1
View File
@@ -199,7 +199,7 @@ const void *StateInterface::StateRetrieveFunction(
*size = entry.value_.size();
*type = map.GetUrid(entry.atomType_.c_str());
*flags = entry.flags_;
return (void*)&entry.value_[0];
return entry.value_.data();
}
+13
View File
@@ -126,8 +126,21 @@ namespace pipedal
{
return info.pluginInfo_.audio_outputs();
}
virtual int GetNumberOfInputAudioBuffers() const { return buffers.inputs.size(); }
virtual int GetNumberOfOutputAudioPorts() const {return buffers.outputs.size(); }
virtual float *GetAudioInputBuffer(int index) const { return buffers.inputs[index]; }
virtual float *GetAudioOutputBuffer(int index) const { return buffers.outputs[index]; }
virtual int GetNumberOfInputAudioBuffers() const {
return buffers.inputs.size();
}
virtual int GetNumberOfInputAudioBuffers() const {
return buffers.outputs.size();
}
virtual void ResetAtomBuffers() {}
virtual void RequestParameter(LV2_URID uridUri) {} // no vst equivalent.
virtual void GatherPatchProperties(RealtimePatchPropertyRequest *pRequest) {} // no vst equivalent.