Implement midi channel filtering in host midi
Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
ecc8b00a9f
commit
e3b9858994
4 changed files with 93 additions and 52 deletions
|
|
@ -82,6 +82,7 @@ struct HostMIDI : Module {
|
|||
uint32_t midiEventFrame;
|
||||
int64_t lastBlockFrame;
|
||||
bool wasPlaying;
|
||||
uint8_t channel;
|
||||
|
||||
// stuff from Rack
|
||||
bool smooth;
|
||||
|
|
@ -138,6 +139,7 @@ struct HostMIDI : Module {
|
|||
midiEventFrame = 0;
|
||||
lastBlockFrame = -1;
|
||||
wasPlaying = false;
|
||||
channel = 0;
|
||||
smooth = true;
|
||||
channels = 1;
|
||||
polyMode = ROTATE_MODE;
|
||||
|
|
@ -194,7 +196,7 @@ struct HostMIDI : Module {
|
|||
}
|
||||
}
|
||||
|
||||
for (uint32_t i=0; i<midiEventsLeft; ++i)
|
||||
while (midiEventsLeft != 0)
|
||||
{
|
||||
const MidiEvent& midiEvent(*midiEvents);
|
||||
|
||||
|
|
@ -216,6 +218,12 @@ struct HostMIDI : Module {
|
|||
data = midiEvent.data;
|
||||
}
|
||||
|
||||
if (channel != 0 && data[0] < 0xF0)
|
||||
{
|
||||
if ((data[0] & 0x0F) != (channel - 1))
|
||||
continue;
|
||||
}
|
||||
|
||||
converterMsg.frame = midiEventFrame;
|
||||
std::memcpy(converterMsg.bytes.data(), data, midiEvent.size);
|
||||
|
||||
|
|
@ -509,6 +517,7 @@ struct HostMIDI : Module {
|
|||
|
||||
struct MidiOutput : dsp::MidiGenerator<PORT_MAX_CHANNELS> {
|
||||
CardinalPluginContext* const pcontext;
|
||||
uint8_t channel = 0;
|
||||
dsp::Timer rateLimiterTimer;
|
||||
|
||||
MidiOutput(CardinalPluginContext* const pc)
|
||||
|
|
@ -516,7 +525,7 @@ struct HostMIDI : Module {
|
|||
|
||||
void onMessage(const midi::Message& message) override
|
||||
{
|
||||
pcontext->writeMidiMessage(message);
|
||||
pcontext->writeMidiMessage(message, channel);
|
||||
}
|
||||
} midiOutput;
|
||||
|
||||
|
|
@ -555,6 +564,13 @@ struct HostMIDI : Module {
|
|||
configOutput(CONTINUE_OUTPUT, "Continue trigger");
|
||||
}
|
||||
|
||||
void onReset() override
|
||||
{
|
||||
midiInput.reset();
|
||||
midiOutput.reset();
|
||||
midiOutput.channel = 0;
|
||||
}
|
||||
|
||||
void process(const ProcessArgs& args) override
|
||||
{
|
||||
if (midiInput.process(args, outputs))
|
||||
|
|
@ -622,39 +638,48 @@ struct HostMIDI : Module {
|
|||
|
||||
json_t* dataToJson() override
|
||||
{
|
||||
json_t* rootJ = json_object();
|
||||
json_t* const rootJ = json_object();
|
||||
DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr);
|
||||
|
||||
json_object_set_new(rootJ, "smooth", json_boolean(midiInput.smooth));
|
||||
json_object_set_new(rootJ, "channels", json_integer(midiInput.channels));
|
||||
json_object_set_new(rootJ, "polyMode", json_integer(midiInput.polyMode));
|
||||
|
||||
// Saving/restoring pitch and mod doesn't make much sense for MPE.
|
||||
if (midiInput.polyMode != MidiInput::MPE_MODE) {
|
||||
if (midiInput.polyMode != MidiInput::MPE_MODE)
|
||||
{
|
||||
json_object_set_new(rootJ, "lastPitch", json_integer(midiInput.pws[0]));
|
||||
json_object_set_new(rootJ, "lastMod", json_integer(midiInput.mods[0]));
|
||||
}
|
||||
|
||||
json_object_set_new(rootJ, "inputChannel", json_integer(midiInput.channel));
|
||||
json_object_set_new(rootJ, "outputChannel", json_integer(midiOutput.channel));
|
||||
|
||||
return rootJ;
|
||||
}
|
||||
|
||||
void dataFromJson(json_t* rootJ) override
|
||||
{
|
||||
json_t* smoothJ = json_object_get(rootJ, "smooth");
|
||||
if (smoothJ)
|
||||
if (json_t* const smoothJ = json_object_get(rootJ, "smooth"))
|
||||
midiInput.smooth = json_boolean_value(smoothJ);
|
||||
|
||||
json_t* channelsJ = json_object_get(rootJ, "channels");
|
||||
if (channelsJ)
|
||||
if (json_t* const channelsJ = json_object_get(rootJ, "channels"))
|
||||
midiInput.setChannels(json_integer_value(channelsJ));
|
||||
|
||||
json_t* polyModeJ = json_object_get(rootJ, "polyMode");
|
||||
if (polyModeJ)
|
||||
if (json_t* const polyModeJ = json_object_get(rootJ, "polyMode"))
|
||||
midiInput.polyMode = (MidiInput::PolyMode) json_integer_value(polyModeJ);
|
||||
|
||||
json_t* lastPitchJ = json_object_get(rootJ, "lastPitch");
|
||||
if (lastPitchJ)
|
||||
if (json_t* const lastPitchJ = json_object_get(rootJ, "lastPitch"))
|
||||
midiInput.pws[0] = json_integer_value(lastPitchJ);
|
||||
|
||||
json_t* lastModJ = json_object_get(rootJ, "lastMod");
|
||||
if (lastModJ)
|
||||
if (json_t* const lastModJ = json_object_get(rootJ, "lastMod"))
|
||||
midiInput.mods[0] = json_integer_value(lastModJ);
|
||||
|
||||
if (json_t* const inputChannelJ = json_object_get(rootJ, "inputChannel"))
|
||||
midiInput.channel = json_integer_value(inputChannelJ);
|
||||
|
||||
if (json_t* const outputChannelJ = json_object_get(rootJ, "outputChannel"))
|
||||
midiOutput.channel = json_integer_value(outputChannelJ) & 0x0F;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -742,12 +767,31 @@ struct HostMIDIWidget : ModuleWidget {
|
|||
void appendContextMenu(Menu* const menu) override
|
||||
{
|
||||
menu->addChild(new MenuSeparator);
|
||||
|
||||
menu->addChild(createMenuLabel("MIDI Input"));
|
||||
|
||||
menu->addChild(createBoolPtrMenuItem("Smooth pitch/mod wheel", "", &module->midiInput.smooth));
|
||||
|
||||
struct ChannelItem : MenuItem {
|
||||
struct InputChannelItem : MenuItem {
|
||||
HostMIDI* module;
|
||||
Menu* createChildMenu() override {
|
||||
Menu* menu = new Menu;
|
||||
for (int c = 0; c <= 16; c++) {
|
||||
menu->addChild(createCheckMenuItem((c == 0) ? "All" : string::f("%d", c), "",
|
||||
[=]() {return module->midiInput.channel == c;},
|
||||
[=]() {module->midiInput.channel = c;}
|
||||
));
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
};
|
||||
InputChannelItem* const inputChannelItem = new InputChannelItem;
|
||||
inputChannelItem->text = "MIDI channel";
|
||||
inputChannelItem->rightText = (module->midiInput.channel ? string::f("%d", module->midiInput.channel) : "All")
|
||||
+ " " + RIGHT_ARROW;
|
||||
inputChannelItem->module = module;
|
||||
menu->addChild(inputChannelItem);
|
||||
|
||||
struct PolyphonyChannelItem : MenuItem {
|
||||
HostMIDI* module;
|
||||
Menu* createChildMenu() override {
|
||||
Menu* menu = new Menu;
|
||||
|
|
@ -760,11 +804,11 @@ struct HostMIDIWidget : ModuleWidget {
|
|||
return menu;
|
||||
}
|
||||
};
|
||||
ChannelItem* channelItem = new ChannelItem;
|
||||
channelItem->text = "Polyphony channels";
|
||||
channelItem->rightText = string::f("%d", module->midiInput.channels) + " " + RIGHT_ARROW;
|
||||
channelItem->module = module;
|
||||
menu->addChild(channelItem);
|
||||
PolyphonyChannelItem* const polyphonyChannelItem = new PolyphonyChannelItem;
|
||||
polyphonyChannelItem->text = "Polyphony channels";
|
||||
polyphonyChannelItem->rightText = string::f("%d", module->midiInput.channels) + " " + RIGHT_ARROW;
|
||||
polyphonyChannelItem->module = module;
|
||||
menu->addChild(polyphonyChannelItem);
|
||||
|
||||
menu->addChild(createIndexPtrSubmenuItem("Polyphony mode", {
|
||||
"Rotate",
|
||||
|
|
@ -774,7 +818,28 @@ struct HostMIDIWidget : ModuleWidget {
|
|||
}, &module->midiInput.polyMode));
|
||||
|
||||
menu->addChild(new MenuSeparator);
|
||||
menu->addChild(createMenuLabel("MIDI Output"));
|
||||
|
||||
struct OutputChannelItem : MenuItem {
|
||||
HostMIDI* module;
|
||||
Menu* createChildMenu() override {
|
||||
Menu* menu = new Menu;
|
||||
for (uint8_t c = 0; c < 15; c++) {
|
||||
menu->addChild(createCheckMenuItem(string::f("%d", c+1), "",
|
||||
[=]() {return module->midiOutput.channel == c;},
|
||||
[=]() {module->midiOutput.channel = c;}
|
||||
));
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
};
|
||||
OutputChannelItem* const outputChannelItem = new OutputChannelItem;
|
||||
outputChannelItem->text = "MIDI channel";
|
||||
outputChannelItem->rightText = string::f("%d", module->midiOutput.channel+1) + " " + RIGHT_ARROW;
|
||||
outputChannelItem->module = module;
|
||||
menu->addChild(outputChannelItem);
|
||||
|
||||
menu->addChild(new MenuSeparator);
|
||||
menu->addChild(createMenuLabel("MIDI Input & Output"));
|
||||
|
||||
menu->addChild(createMenuItem("Panic", "",
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ struct CardinalPluginContext : rack::Context {
|
|||
UI* ui;
|
||||
#endif
|
||||
CardinalPluginContext(Plugin* const p);
|
||||
void writeMidiMessage(const rack::midi::Message& message);
|
||||
void writeMidiMessage(const rack::midi::Message& message, uint8_t channel);
|
||||
#ifndef HEADLESS
|
||||
bool addIdleCallback(IdleCallback* cb) const;
|
||||
void removeIdleCallback(IdleCallback* cb) const;
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ struct Initializer
|
|||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message)
|
||||
void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel)
|
||||
{
|
||||
const size_t size = message.bytes.size();
|
||||
DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
|
||||
|
|
@ -367,6 +367,9 @@ void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message)
|
|||
|
||||
std::memcpy(event.data, message.bytes.data(), event.size);
|
||||
|
||||
if (channel != 0 && event.data[0] < 0xF0)
|
||||
event.data[0] |= channel & 0x0F;
|
||||
|
||||
plugin->writeMidiEvent(event);
|
||||
}
|
||||
|
||||
|
|
@ -831,34 +834,7 @@ protected:
|
|||
{
|
||||
const TimePosition& timePos(getTimePosition());
|
||||
|
||||
bool reset = false;
|
||||
|
||||
if (timePos.playing)
|
||||
{
|
||||
if (timePos.frame == 0 || fPreviousFrame + frames != timePos.frame)
|
||||
reset = true;
|
||||
|
||||
/*
|
||||
if (! context->playing)
|
||||
{
|
||||
if (timePos.frame == 0)
|
||||
{
|
||||
singleTimeMidiEvent.data[0] = 0xFA; // start
|
||||
sendSingleSimpleMidiMessage(singleTimeMidiEvent);
|
||||
}
|
||||
|
||||
singleTimeMidiEvent.data[0] = 0xFB; // continue
|
||||
sendSingleSimpleMidiMessage(singleTimeMidiEvent);
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (context->playing)
|
||||
{
|
||||
/*
|
||||
singleTimeMidiEvent.data[0] = 0xFC; // stop
|
||||
sendSingleSimpleMidiMessage(singleTimeMidiEvent);
|
||||
*/
|
||||
}
|
||||
const bool reset = timePos.playing && (timePos.frame == 0 || fPreviousFrame + frames != timePos.frame);
|
||||
|
||||
context->playing = timePos.playing;
|
||||
context->bbtValid = timePos.bbt.valid;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ struct CardinalPluginContext : rack::Context {
|
|||
std::memset(parameters, 0, sizeof(parameters));
|
||||
}
|
||||
|
||||
void writeMidiMessage(const rack::midi::Message& message);
|
||||
void writeMidiMessage(const rack::midi::Message& message, uint8_t channel);
|
||||
|
||||
#ifndef HEADLESS
|
||||
bool addIdleCallback(IdleCallback* cb) const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue