@@ -430,7 +430,7 @@ public: | |||
* | |||
* \see getOptions() and getAvailableOptions() | |||
*/ | |||
void setOption(const uint option, const bool yesNo, const bool sendCallback); | |||
virtual void setOption(const uint option, const bool yesNo, const bool sendCallback); | |||
/*! | |||
* Enable or disable the plugin according to \a yesNo. \n | |||
@@ -499,6 +499,7 @@ public: | |||
* \note Force-Stereo plugins only! | |||
*/ | |||
void setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept; | |||
#endif | |||
/*! | |||
* Set the plugin's midi control channel. | |||
@@ -507,7 +508,6 @@ public: | |||
* \param sendCallback Send message change to registered callback | |||
*/ | |||
virtual void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept; | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Set data (plugin-specific stuff) | |||
@@ -500,6 +500,24 @@ public: | |||
break; | |||
} | |||
case kPluginBridgeNonRtSetCtrlChannel: { | |||
const int16_t channel(fShmNonRtControl.readShort()); | |||
CARLA_SAFE_ASSERT_BREAK(channel >= -1 && channel < MAX_MIDI_CHANNELS); | |||
if (plugin != nullptr && plugin->isEnabled()) | |||
plugin->setCtrlChannel(static_cast<int8_t>(channel), false, false); | |||
break; | |||
} | |||
case kPluginBridgeNonRtSetOption: { | |||
const uint32_t option(fShmNonRtControl.readUInt()); | |||
const bool yesNo(fShmNonRtControl.readBool()); | |||
if (plugin != nullptr && plugin->isEnabled()) | |||
plugin->setOption(option, yesNo, false); | |||
break; | |||
} | |||
case kPluginBridgeNonRtPrepareForSave: { | |||
if (plugin == nullptr || ! plugin->isEnabled()) break; | |||
@@ -638,25 +656,7 @@ protected: | |||
break; | |||
} | |||
case kPluginBridgeRtSetProgram: { | |||
const int32_t index(fShmRtControl.readInt()); | |||
CARLA_SAFE_ASSERT_BREAK(index >= -1); | |||
if (plugin != nullptr && plugin->isEnabled()) | |||
plugin->setProgram(index, false, false, false); | |||
break; | |||
} | |||
case kPluginBridgeRtSetMidiProgram: { | |||
const int32_t index(fShmRtControl.readInt()); | |||
CARLA_SAFE_ASSERT_BREAK(index >= -1); | |||
if (plugin != nullptr && plugin->isEnabled()) | |||
plugin->setMidiProgram(index, false, false, false); | |||
break; | |||
} | |||
case kPluginBridgeRtMidiEvent: { | |||
case kPluginBridgeRtMidiData: { | |||
const uint32_t time(fShmRtControl.readUInt()); | |||
const uint32_t size(fShmRtControl.readUInt()); | |||
CARLA_SAFE_ASSERT_BREAK(size > 0 && size <= 4); | |||
@@ -682,6 +682,56 @@ protected: | |||
break; | |||
} | |||
case kPluginBridgeRtMidiBank: { | |||
const uint32_t time(fShmRtControl.readUInt()); | |||
const uint8_t chnnl(fShmRtControl.readByte()); | |||
const uint16_t index(fShmRtControl.readUShort()); | |||
CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr); | |||
for (ushort i=0; i < kMaxEngineEventInternalCount; ++i) | |||
{ | |||
EngineEvent& event(pData->events.in[i]); | |||
if (event.type != kEngineEventTypeNull) | |||
continue; | |||
event.type = kEngineEventTypeControl; | |||
event.time = time; | |||
event.channel = chnnl; | |||
event.ctrl.type = kEngineControlEventTypeMidiProgram; | |||
event.ctrl.param = index; | |||
event.ctrl.value = 0.0f; | |||
break; | |||
} | |||
break; | |||
} | |||
case kPluginBridgeRtMidiProgram: { | |||
const uint32_t time(fShmRtControl.readUInt()); | |||
const uint8_t chnnl(fShmRtControl.readByte()); | |||
const uint16_t index(fShmRtControl.readUShort()); | |||
CARLA_SAFE_ASSERT_BREAK(pData->events.in != nullptr); | |||
for (ushort i=0; i < kMaxEngineEventInternalCount; ++i) | |||
{ | |||
EngineEvent& event(pData->events.in[i]); | |||
if (event.type != kEngineEventTypeNull) | |||
continue; | |||
event.type = kEngineEventTypeControl; | |||
event.time = time; | |||
event.channel = chnnl; | |||
event.ctrl.type = kEngineControlEventTypeMidiBank; | |||
event.ctrl.param = index; | |||
event.ctrl.value = 0.0f; | |||
break; | |||
} | |||
break; | |||
} | |||
case kPluginBridgeRtAllSoundOff: { | |||
const uint32_t time(fShmRtControl.readUInt()); | |||
@@ -516,7 +516,32 @@ public: | |||
// ------------------------------------------------------------------- | |||
// Set data (internal stuff) | |||
// nothing | |||
void setOption(const uint option, const bool yesNo, const bool sendCallback) override | |||
{ | |||
{ | |||
const CarlaMutexLocker _cml(fShmNonRtControl.mutex); | |||
fShmNonRtControl.writeOpcode(kPluginBridgeNonRtSetOption); | |||
fShmNonRtControl.writeInt(static_cast<int32_t>(option)); | |||
fShmNonRtControl.writeBool(yesNo); | |||
fShmNonRtControl.commitWrite(); | |||
} | |||
CarlaPlugin::setOption(option, yesNo, sendCallback); | |||
} | |||
void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override | |||
{ | |||
{ | |||
const CarlaMutexLocker _cml(fShmNonRtControl.mutex); | |||
fShmNonRtControl.writeOpcode(kPluginBridgeNonRtSetCtrlChannel); | |||
fShmNonRtControl.writeShort(channel); | |||
fShmNonRtControl.commitWrite(); | |||
} | |||
CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback); | |||
} | |||
// ------------------------------------------------------------------- | |||
// Set data (plugin-specific stuff) | |||
@@ -871,9 +896,9 @@ public: | |||
data2 = note.note; | |||
data3 = note.velo; | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiEvent); | |||
fShmRtControl.writeInt(0); | |||
fShmRtControl.writeInt(3); | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiData); | |||
fShmRtControl.writeInt(0); // time | |||
fShmRtControl.writeInt(3); // size | |||
fShmRtControl.writeByte(data1); | |||
fShmRtControl.writeByte(data2); | |||
fShmRtControl.writeByte(data3); | |||
@@ -890,15 +915,7 @@ public: | |||
bool allNotesOffSent = false; | |||
uint32_t numEvents = pData->event.portIn->getEventCount(); | |||
uint32_t nextBankId; | |||
if (pData->midiprog.current >= 0 && pData->midiprog.count > 0) | |||
nextBankId = pData->midiprog.data[pData->midiprog.current].bank; | |||
else | |||
nextBankId = 0; | |||
for (uint32_t i=0; i < numEvents; ++i) | |||
for (uint32_t i=0, numEvents = pData->event.portIn->getEventCount(); i < numEvents; ++i) | |||
{ | |||
const EngineEvent& event(pData->event.portIn->getEvent(i)); | |||
@@ -1010,7 +1027,7 @@ public: | |||
if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F) | |||
{ | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiEvent); | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiData); | |||
fShmRtControl.writeInt(static_cast<int32_t>(event.time)); | |||
fShmRtControl.writeInt(3); | |||
fShmRtControl.writeByte(static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + event.channel)); | |||
@@ -1023,35 +1040,24 @@ public: | |||
} // case kEngineControlEventTypeParameter | |||
case kEngineControlEventTypeMidiBank: | |||
if (event.channel == pData->ctrlChannel && (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0) | |||
nextBankId = ctrlEvent.param; | |||
if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) | |||
{ | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiBank); | |||
fShmRtControl.writeInt(static_cast<int32_t>(event.time)); | |||
fShmRtControl.writeByte(event.channel); | |||
fShmRtControl.writeShort(static_cast<int16_t>(ctrlEvent.param)); | |||
fShmRtControl.commitWrite(); | |||
} | |||
break; | |||
case kEngineControlEventTypeMidiProgram: | |||
if (event.channel == pData->ctrlChannel && (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0) | |||
if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) | |||
{ | |||
const uint32_t nextProgramId(ctrlEvent.param); | |||
if (pData->midiprog.count > 0) | |||
{ | |||
for (uint32_t k=0; k < pData->midiprog.count; ++k) | |||
{ | |||
if (pData->midiprog.data[k].bank == nextBankId && pData->midiprog.data[k].program == nextProgramId) | |||
{ | |||
const int32_t index(static_cast<int32_t>(k)); | |||
fShmRtControl.writeOpcode(kPluginBridgeRtSetMidiProgram); | |||
fShmRtControl.writeInt(index); | |||
fShmRtControl.commitWrite(); | |||
pData->postponeRtEvent(kPluginPostRtEventMidiProgramChange, index, 0, 0.0f); | |||
break; | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
} | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiProgram); | |||
fShmRtControl.writeInt(static_cast<int32_t>(event.time)); | |||
fShmRtControl.writeByte(event.channel); | |||
fShmRtControl.writeShort(static_cast<int16_t>(ctrlEvent.param)); | |||
fShmRtControl.commitWrite(); | |||
} | |||
break; | |||
@@ -1104,7 +1110,7 @@ public: | |||
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0) | |||
continue; | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiEvent); | |||
fShmRtControl.writeOpcode(kPluginBridgeRtMidiData); | |||
fShmRtControl.writeInt(static_cast<int32_t>(event.time)); | |||
fShmRtControl.writeInt(midiEvent.size); | |||
@@ -1032,10 +1032,13 @@ void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool s | |||
if (sendCallback) | |||
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_PANNING, 0, fixedValue, nullptr); | |||
} | |||
#endif | |||
void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept | |||
{ | |||
#ifndef BUILD_BRIDGE | |||
CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||
#endif | |||
CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,); | |||
if (pData->ctrlChannel == channel) | |||
@@ -1043,6 +1046,7 @@ void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const | |||
pData->ctrlChannel = channel; | |||
#ifndef BUILD_BRIDGE | |||
const float channelf(channel); | |||
if (sendOsc && pData->engine->isOscControlRegistered()) | |||
@@ -1050,8 +1054,11 @@ void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const | |||
if (sendCallback) | |||
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_CTRL_CHANNEL, 0, channelf, nullptr); | |||
} | |||
#else | |||
// unused | |||
return; (void)sendOsc; (void)sendCallback; | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
// Set data (plugin-specific stuff) | |||
@@ -373,7 +373,6 @@ public: | |||
// ------------------------------------------------------------------- | |||
// Set data (internal stuff) | |||
#ifndef BUILD_BRIDGE | |||
void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override | |||
{ | |||
if (channel >= 0 && channel < MAX_MIDI_CHANNELS) | |||
@@ -381,7 +380,6 @@ public: | |||
CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Set data (plugin-specific stuff) | |||
@@ -394,7 +394,6 @@ public: | |||
// ------------------------------------------------------------------- | |||
// Set data (internal stuff) | |||
#ifndef BUILD_BRIDGE | |||
void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override | |||
{ | |||
if (channel >= 0 && channel < MAX_MIDI_CHANNELS) | |||
@@ -402,7 +401,6 @@ public: | |||
CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Set data (plugin-specific stuff) | |||
@@ -546,7 +546,6 @@ public: | |||
CarlaPlugin::setName(newName); | |||
} | |||
#ifndef BUILD_BRIDGE | |||
void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override | |||
{ | |||
if (channel >= 0 && channel < MAX_MIDI_CHANNELS && pData->midiprog.count > 0) | |||
@@ -554,7 +553,6 @@ public: | |||
CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Set data (plugin-specific stuff) | |||
@@ -56,9 +56,9 @@ enum PluginBridgeRtOpcode { | |||
kPluginBridgeRtNull = 0, | |||
kPluginBridgeRtSetAudioPool, // ulong/ptr | |||
kPluginBridgeRtSetParameter, // uint, float | |||
kPluginBridgeRtSetProgram, // int | |||
kPluginBridgeRtSetMidiProgram, // int | |||
kPluginBridgeRtMidiEvent, // uint/frame, uint/size, char[] | |||
kPluginBridgeRtMidiData, // uint/frame, uint/size, char[] | |||
kPluginBridgeRtMidiBank, // uint/frame, byte/chan, ushort | |||
kPluginBridgeRtMidiProgram, // uint/frame, byte/chan, ushort | |||
kPluginBridgeRtAllSoundOff, // uint/frame | |||
kPluginBridgeRtAllNotesOff, // uint/frame | |||
kPluginBridgeRtProcess | |||
@@ -79,6 +79,8 @@ enum PluginBridgeNonRtOpcode { | |||
kPluginBridgeNonRtSetMidiProgram, // int | |||
kPluginBridgeNonRtSetCustomData, // uint/size, str, uint/size, str, uint/size, str | |||
kPluginBridgeNonRtSetChunkDataFile, // uint/size, str/file | |||
kPluginBridgeNonRtSetCtrlChannel, // short | |||
kPluginBridgeNonRtSetOption, // uint/option, bool | |||
kPluginBridgeNonRtPrepareForSave, | |||
kPluginBridgeNonRtShowUI, | |||
kPluginBridgeNonRtHideUI, | |||
@@ -203,12 +205,12 @@ const char* PluginBridgeRtOpcode2str(const PluginBridgeRtOpcode opcode) noexcept | |||
return "kPluginBridgeRtSetAudioPool"; | |||
case kPluginBridgeRtSetParameter: | |||
return "kPluginBridgeRtSetParameter"; | |||
case kPluginBridgeRtSetProgram: | |||
return "kPluginBridgeRtSetProgram"; | |||
case kPluginBridgeRtSetMidiProgram: | |||
return "kPluginBridgeRtSetMidiProgram"; | |||
case kPluginBridgeRtMidiEvent: | |||
return "kPluginBridgeRtMidiEvent"; | |||
case kPluginBridgeRtMidiData: | |||
return "kPluginBridgeRtMidiData"; | |||
case kPluginBridgeRtMidiBank: | |||
return "kPluginBridgeRtMidiBank"; | |||
case kPluginBridgeRtMidiProgram: | |||
return "kPluginBridgeRtMidiProgram"; | |||
case kPluginBridgeRtAllSoundOff: | |||
return "kPluginBridgeRtAllSoundOff"; | |||
case kPluginBridgeRtAllNotesOff: | |||
@@ -252,6 +254,10 @@ const char* PluginBridgeNonRtOpcode2str(const PluginBridgeNonRtOpcode opcode) no | |||
return "kPluginBridgeNonRtSetCustomData"; | |||
case kPluginBridgeNonRtSetChunkDataFile: | |||
return "kPluginBridgeNonRtSetChunkDataFile"; | |||
case kPluginBridgeNonRtSetCtrlChannel: | |||
return "kPluginBridgeNonRtSetCtrlChannel"; | |||
case kPluginBridgeNonRtSetOption: | |||
return "kPluginBridgeNonRtSetOption"; | |||
case kPluginBridgeNonRtPrepareForSave: | |||
return "kPluginBridgeNonRtPrepareForSave"; | |||
case kPluginBridgeNonRtShowUI: | |||