Browse Source

Cleanup input midi expander, add channel option

tags/22.02
falkTX 3 years ago
parent
commit
d0224fce14
3 changed files with 167 additions and 53 deletions
  1. +165
    -51
      plugins/Cardinal/src/ExpanderInputMIDI.cpp
  2. +1
    -1
      plugins/Cardinal/src/HostMIDI.cpp
  3. +1
    -1
      plugins/Makefile

plugins/Cardinal/src/Expanders.cpp → plugins/Cardinal/src/ExpanderInputMIDI.cpp View File

@@ -20,6 +20,16 @@


// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------


/**
* This class contains a substantial amount of code from VCVRack's dsp/midi.hpp
* Copyright (C) 2016-2021 VCV.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*/

struct CardinalExpanderForInputMIDI : CardinalExpanderFromCVToCarlaMIDI { struct CardinalExpanderForInputMIDI : CardinalExpanderFromCVToCarlaMIDI {
enum ParamIds { enum ParamIds {
NUM_PARAMS NUM_PARAMS
@@ -27,10 +37,10 @@ struct CardinalExpanderForInputMIDI : CardinalExpanderFromCVToCarlaMIDI {
enum InputIds { enum InputIds {
PITCH_INPUT, PITCH_INPUT,
GATE_INPUT, GATE_INPUT,
VEL_INPUT,
AFT_INPUT,
PW_INPUT,
MW_INPUT,
VELOCITY_INPUT,
AFTERTOUCH_INPUT,
PITCHBEND_INPUT,
MODWHEEL_INPUT,
NUM_INPUTS NUM_INPUTS
}; };
enum OutputIds { enum OutputIds {
@@ -45,112 +55,170 @@ struct CardinalExpanderForInputMIDI : CardinalExpanderFromCVToCarlaMIDI {
int8_t notes[CHANNELS]; int8_t notes[CHANNELS];
bool gates[CHANNELS]; bool gates[CHANNELS];
int8_t keyPressures[CHANNELS]; int8_t keyPressures[CHANNELS];
int8_t mw;
int16_t pw;
int8_t modwheel;
int16_t pitchbend;


uint8_t channel = 0;
Module* lastConnectedModule = nullptr; Module* lastConnectedModule = nullptr;


CardinalExpanderForInputMIDI() {
CardinalExpanderForInputMIDI()
{
static_assert(NUM_INPUTS == kNumInputs, "Invalid input configuration"); static_assert(NUM_INPUTS == kNumInputs, "Invalid input configuration");
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configInput(PITCH_INPUT, "1V/octave pitch"); configInput(PITCH_INPUT, "1V/octave pitch");
configInput(GATE_INPUT, "Gate"); configInput(GATE_INPUT, "Gate");
configInput(VEL_INPUT, "Velocity");
configInput(AFT_INPUT, "Aftertouch");
configInput(PW_INPUT, "Pitchbend");
configInput(MW_INPUT, "Mod wheel");
configInput(VELOCITY_INPUT, "Velocity");
configInput(AFTERTOUCH_INPUT, "Aftertouch");
configInput(PITCHBEND_INPUT, "Pitchbend");
configInput(MODWHEEL_INPUT, "Mod wheel");
onReset(); onReset();
} }


/** Must be called before setNoteGate(). */ /** Must be called before setNoteGate(). */
void setVelocity(int8_t vel, int c) {
void setVelocity(int8_t vel, int c)
{
vels[c] = vel; vels[c] = vel;
} }


void setNoteGate(int8_t note, bool gate, int c) {
if (midiEventCount == MAX_MIDI_EVENTS)
void setNoteGate(int8_t note, bool gate, int c)
{
if (midiEventCount == MAX_MIDI_EVENTS || frame == UINT_MAX)
return; return;
bool changedNote = gate && gates[c] && (note != notes[c]);
bool enabledGate = gate && !gates[c];
bool disabledGate = !gate && gates[c];
if (changedNote || disabledGate) {

const bool changedNote = gate && gates[c] && (note != notes[c]);
const bool enabledGate = gate && !gates[c];
const bool disabledGate = !gate && gates[c];

if (changedNote || disabledGate)
{
// Note off // Note off
NativeMidiEvent& m(midiEvents[midiEventCount++]); NativeMidiEvent& m(midiEvents[midiEventCount++]);
m.time = frame; m.time = frame;
m.port = 0; m.port = 0;
m.size = 3; m.size = 3;
m.data[0] = 0x80;
m.data[0] = 0x80 | channel;
m.data[1] = notes[c]; m.data[1] = notes[c];
m.data[2] = vels[c]; m.data[2] = vels[c];
} }
if (changedNote || enabledGate) {

if (changedNote || enabledGate)
{
// Note on // Note on
NativeMidiEvent& m(midiEvents[midiEventCount++]); NativeMidiEvent& m(midiEvents[midiEventCount++]);
m.time = frame; m.time = frame;
m.port = 0; m.port = 0;
m.size = 3; m.size = 3;
m.data[0] = 0x90;
m.data[0] = 0x90 | channel;
m.data[1] = note; m.data[1] = note;
m.data[2] = vels[c]; m.data[2] = vels[c];
} }

notes[c] = note; notes[c] = note;
gates[c] = gate; gates[c] = gate;
} }


void setKeyPressure(int8_t val, int c) {
if (keyPressures[c] == val || midiEventCount == MAX_MIDI_EVENTS)
void setKeyPressure(int8_t val, int c)
{
if (keyPressures[c] == val)
return; return;

keyPressures[c] = val; keyPressures[c] = val;

if (midiEventCount == MAX_MIDI_EVENTS || frame == UINT_MAX)
return;

// Polyphonic key pressure // Polyphonic key pressure
NativeMidiEvent& m(midiEvents[midiEventCount++]); NativeMidiEvent& m(midiEvents[midiEventCount++]);
m.time = frame; m.time = frame;
m.port = 0; m.port = 0;
m.size = 3; m.size = 3;
m.data[0] = 0xa0;
m.data[0] = 0xa0 | channel;
m.data[1] = notes[c]; m.data[1] = notes[c];
m.data[2] = val; m.data[2] = val;
} }


void setModWheel(int8_t mw) {
if (this->mw == mw || midiEventCount == MAX_MIDI_EVENTS)
void setModWheel(int8_t modwheel)
{
if (this->modwheel == modwheel)
return; return;
this->mw = mw;

this->modwheel = modwheel;

if (midiEventCount == MAX_MIDI_EVENTS || frame == UINT_MAX)
return;

// Modulation Wheel (CC1) // Modulation Wheel (CC1)
NativeMidiEvent& m(midiEvents[midiEventCount++]); NativeMidiEvent& m(midiEvents[midiEventCount++]);
m.time = frame; m.time = frame;
m.port = 0; m.port = 0;
m.size = 3; m.size = 3;
m.data[0] = 0xb0;
m.data[0] = 0xb0 | channel;
m.data[1] = 1; m.data[1] = 1;
m.data[2] = mw;
m.data[2] = modwheel;
} }


void setPitchWheel(int16_t pw) {
if (this->pw == pw || midiEventCount == MAX_MIDI_EVENTS)
void setPitchbend(int16_t pitchbend)
{
if (this->pitchbend == pitchbend)
return;

this->pitchbend = pitchbend;

if (midiEventCount == MAX_MIDI_EVENTS || frame == UINT_MAX)
return; return;
this->pw = pw;
// Pitch Wheel // Pitch Wheel
NativeMidiEvent& m(midiEvents[midiEventCount++]); NativeMidiEvent& m(midiEvents[midiEventCount++]);
m.time = frame; m.time = frame;
m.port = 0; m.port = 0;
m.size = 3; m.size = 3;
m.data[0] = 0xe0;
m.data[1] = pw & 0x7f;
m.data[2] = (pw >> 7) & 0x7f;
m.data[0] = 0xe0 | channel;
m.data[1] = pitchbend & 0x7f;
m.data[2] = (pitchbend >> 7) & 0x7f;
} }


void onReset() override
void panic()
{ {
for (uint c = 0; c < CHANNELS; c++) {
if (frame != UINT_MAX)
{
// Send all note off commands
for (int note = 0; note <= 127; ++note)
{
if (midiEventCount == MAX_MIDI_EVENTS)
break;
// Note off
NativeMidiEvent& m(midiEvents[midiEventCount++]);
m.time = frame;
m.port = 0;
m.size = 3;
m.data[0] = 0x80 | channel;
m.data[1] = note;
m.data[2] = 0;
}
}

reset();
}

void reset()
{
for (uint c = 0; c < CHANNELS; ++c)
{
vels[c] = 100; vels[c] = 100;
notes[c] = 60; notes[c] = 60;
gates[c] = false; gates[c] = false;
keyPressures[c] = -1; keyPressures[c] = -1;
} }
mw = -1;
pw = 0x2000;
modwheel = -1;
pitchbend = 0x2000;
midiEventCount = 0; midiEventCount = 0;
frame = UINT_MAX; frame = UINT_MAX;
}

void onReset() override
{
reset();
channel = 0;
lastConnectedModule = nullptr; lastConnectedModule = nullptr;
} }


@@ -178,7 +246,7 @@ struct CardinalExpanderForInputMIDI : CardinalExpanderFromCVToCarlaMIDI {
return; return;


for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); c++) { for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); c++) {
int vel = (int) std::round(inputs[VEL_INPUT].getNormalPolyVoltage(10.f * 100 / 127, c) / 10.f * 127);
int vel = (int) std::round(inputs[VELOCITY_INPUT].getNormalPolyVoltage(10.f * 100 / 127, c) / 10.f * 127);
vel = clamp(vel, 0, 127); vel = clamp(vel, 0, 127);
setVelocity(vel, c); setVelocity(vel, c);


@@ -187,21 +255,36 @@ struct CardinalExpanderForInputMIDI : CardinalExpanderFromCVToCarlaMIDI {
bool gate = inputs[GATE_INPUT].getPolyVoltage(c) >= 1.f; bool gate = inputs[GATE_INPUT].getPolyVoltage(c) >= 1.f;
setNoteGate(note, gate, c); setNoteGate(note, gate, c);


int aft = (int) std::round(inputs[AFT_INPUT].getPolyVoltage(c) / 10.f * 127);
int aft = (int) std::round(inputs[AFTERTOUCH_INPUT].getPolyVoltage(c) / 10.f * 127);
aft = clamp(aft, 0, 127); aft = clamp(aft, 0, 127);
setKeyPressure(aft, c); setKeyPressure(aft, c);
} }


int pw = (int) std::round((inputs[PW_INPUT].getVoltage() + 5.f) / 10.f * 0x4000);
pw = clamp(pw, 0, 0x3fff);
setPitchWheel(pw);
int pitchbend = (int) std::round((inputs[PITCHBEND_INPUT].getVoltage() + 5.f) / 10.f * 16383);
pitchbend = clamp(pitchbend, 0, 16383);
setPitchbend(pitchbend);


int mw = (int) std::round(inputs[MW_INPUT].getVoltage() / 10.f * 127);
mw = clamp(mw, 0, 127);
setModWheel(mw);
int modwheel = (int) std::round(inputs[MODWHEEL_INPUT].getVoltage() / 10.f * 127);
modwheel = clamp(modwheel, 0, 127);
setModWheel(modwheel);


++frame; ++frame;
} }

json_t* dataToJson() override
{
json_t* const rootJ = json_object();
DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr);

json_object_set_new(rootJ, "channel", json_integer(channel));
return rootJ;
}

void dataFromJson(json_t* const rootJ) override
{
if (json_t* const channelJ = json_object_get(rootJ, "channel"))
channel = json_integer_value(channelJ) & 0x0F;
}
}; };


// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
@@ -211,16 +294,19 @@ struct CardinalExpanderForInputMIDIWidget : ModuleWidgetWith3HP {
static constexpr const float startY = 90.0f; static constexpr const float startY = 90.0f;
static constexpr const float padding = 49.0f; static constexpr const float padding = 49.0f;


CardinalExpanderForInputMIDIWidget(CardinalExpanderForInputMIDI* const module)
CardinalExpanderForInputMIDI* const module;

CardinalExpanderForInputMIDIWidget(CardinalExpanderForInputMIDI* const m)
: module(m)
{ {
setModule(module);
setModule(m);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ExpanderMIDI.svg"))); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ExpanderMIDI.svg")));


addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0))); addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));


for (int i=0; i<CardinalExpanderForInputMIDI::NUM_INPUTS; ++i) for (int i=0; i<CardinalExpanderForInputMIDI::NUM_INPUTS; ++i)
addInput(createInput<PJ301MPort>(Vec(startX + 4.0f, startY + padding * i), module, i));
addInput(createInput<PJ301MPort>(Vec(startX + 4.0f, startY + padding * i), m, i));
} }


void draw(const DrawArgs& args) override void draw(const DrawArgs& args) override
@@ -261,7 +347,35 @@ struct CardinalExpanderForInputMIDIWidget : ModuleWidgetWith3HP {
nvgText(args.vg, box.size.x * 0.666f, startY + padding * 4 - 4.0f, "Pb", nullptr); nvgText(args.vg, box.size.x * 0.666f, startY + padding * 4 - 4.0f, "Pb", nullptr);
nvgText(args.vg, box.size.x * 0.666f, startY + padding * 5 - 4.0f, "MW", nullptr); nvgText(args.vg, box.size.x * 0.666f, startY + padding * 5 - 4.0f, "MW", nullptr);


ModuleWidgetWithSideScrews::draw(args);
ModuleWidgetWith3HP::draw(args);
}

void appendContextMenu(Menu* const menu) override
{
menu->addChild(new MenuSeparator);

struct ChannelItem : MenuItem {
CardinalExpanderForInputMIDI* module;
Menu* createChildMenu() override {
Menu* menu = new Menu;
for (uint8_t c = 0; c < 16; c++) {
menu->addChild(createCheckMenuItem(string::f("%d", c+1), "",
[=]() {return module->channel == c;},
[=]() {module->channel = c;}
));
}
return menu;
}
};
ChannelItem* const channelItem = new ChannelItem;
channelItem->text = "MIDI channel";
channelItem->rightText = string::f("%d", module->channel+1) + " " + RIGHT_ARROW;
channelItem->module = module;
menu->addChild(channelItem);

menu->addChild(createMenuItem("Panic", "",
[=]() { module->panic(); }
));
} }
}; };



+ 1
- 1
plugins/Cardinal/src/HostMIDI.cpp View File

@@ -635,7 +635,7 @@ struct HostMIDI : Module {
return rootJ; return rootJ;
} }


void dataFromJson(json_t* rootJ) override
void dataFromJson(json_t* const rootJ) override
{ {
if (json_t* const smoothJ = json_object_get(rootJ, "smooth")) if (json_t* const smoothJ = json_object_get(rootJ, "smooth"))
midiInput.smooth = json_boolean_value(smoothJ); midiInput.smooth = json_boolean_value(smoothJ);


+ 1
- 1
plugins/Makefile View File

@@ -187,7 +187,7 @@ PLUGIN_FILES = plugins.cpp
# Cardinal (built-in) # Cardinal (built-in)


PLUGIN_FILES += Cardinal/src/Blank.cpp PLUGIN_FILES += Cardinal/src/Blank.cpp
PLUGIN_FILES += Cardinal/src/Expanders.cpp
PLUGIN_FILES += Cardinal/src/ExpanderInputMIDI.cpp
PLUGIN_FILES += Cardinal/src/glBars.cpp PLUGIN_FILES += Cardinal/src/glBars.cpp
PLUGIN_FILES += Cardinal/src/HostAudio.cpp PLUGIN_FILES += Cardinal/src/HostAudio.cpp
PLUGIN_FILES += Cardinal/src/HostCV.cpp PLUGIN_FILES += Cardinal/src/HostCV.cpp


Loading…
Cancel
Save