From 2b68057cb7a5469fd059cd577875bf68b9a36c86 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 13 Jan 2018 03:51:06 -0500 Subject: [PATCH] Add midi.cpp with MidiIO class --- include/app.hpp | 6 +++- include/componentlibrary.hpp | 4 +-- include/midi.hpp | 41 ++++++++++++++++++++++ src/app/MidiWidget.cpp | 66 ++++++++++++++++++++++++++++++++++++ src/core/AudioInterface.cpp | 8 +++-- src/core/MidiCCToCV.cpp | 2 ++ src/core/MidiClockToCV.cpp | 2 ++ src/core/MidiIO.cpp | 2 ++ src/core/MidiIO.hpp | 3 ++ src/core/MidiToCV.cpp | 2 ++ src/core/MidiTriggerToCV.cpp | 2 ++ src/core/QuadMidiToCV.cpp | 2 ++ src/core/core.cpp | 10 +++--- src/midi.cpp | 42 +++++++++++++++++++++++ 14 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 include/midi.hpp create mode 100644 src/app/MidiWidget.cpp create mode 100644 src/midi.cpp diff --git a/include/app.hpp b/include/app.hpp index 1e1550c0..81812647 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -283,6 +283,7 @@ struct MomentarySwitch : virtual Switch { //////////////////// struct AudioIO; +struct MidiIO; struct AudioWidget : OpaqueWidget { /** Not owned */ @@ -290,7 +291,10 @@ struct AudioWidget : OpaqueWidget { void onMouseDown(EventMouseDown &e) override; }; -struct MIDIWidget : OpaqueWidget { +struct MidiWidget : OpaqueWidget { + /** Not owned */ + MidiIO *midiIO = NULL; + void onMouseDown(EventMouseDown &e) override; }; //////////////////// diff --git a/include/componentlibrary.hpp b/include/componentlibrary.hpp index 5ae6c671..4bc68fe9 100644 --- a/include/componentlibrary.hpp +++ b/include/componentlibrary.hpp @@ -346,8 +346,8 @@ struct USB_B_AudioWidget : AudioWidget, SVGWidget { } }; -struct DIN_MIDIWidget : MIDIWidget, SVGWidget { - DIN_MIDIWidget() { +struct MIDI_DIN_MidiWidget : MidiWidget, SVGWidget { + MIDI_DIN_MidiWidget() { setSVG(SVG::load(assetGlobal("res/ComponentLibrary/MIDI_DIN.svg"))); } }; diff --git a/include/midi.hpp b/include/midi.hpp new file mode 100644 index 00000000..a55d4ac5 --- /dev/null +++ b/include/midi.hpp @@ -0,0 +1,41 @@ +#pragma once + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsuggest-override" +#include "rtmidi/RtMidi.h" +#pragma GCC diagnostic pop + + +namespace rack { + + +struct MidiIO { + RtMidi *midi; + int port = -1; + /* For MIDI output, the channel to output messages. + For MIDI input, the channel to filter. + Set to -1 to allow all MIDI channels (for input). + Zero indexed. + */ + int channel = -1; + + virtual ~MidiIO() {} + virtual int getPortCount(); + virtual std::string getPortName(int port); + virtual void openPort(int port); +}; + + +struct MidiInput : MidiIO { + MidiInput(); + ~MidiInput(); +}; + + +struct MidiOutput : MidiIO { + MidiOutput(); + ~MidiOutput(); +}; + + +} // namespace rack diff --git a/src/app/MidiWidget.cpp b/src/app/MidiWidget.cpp new file mode 100644 index 00000000..5f832278 --- /dev/null +++ b/src/app/MidiWidget.cpp @@ -0,0 +1,66 @@ +#include "app.hpp" +#include "midi.hpp" + + +namespace rack { + + +struct MidiPortItem : MenuItem { + MidiIO *midiIO; + int port; + void onAction(EventAction &e) override { + midiIO->openPort(port); + } +}; + + +struct MidiChannelItem : MenuItem { + MidiIO *midiIO; + int channel; + void onAction(EventAction &e) override { + midiIO->channel = channel; + } +}; + + +void MidiWidget::onMouseDown(EventMouseDown &e) { + OpaqueWidget::onMouseDown(e); + + if (!midiIO) + return; + + Menu *menu = gScene->createMenu(); + + menu->addChild(construct(&MenuLabel::text, "MIDI port")); + for (int port = 0; port < midiIO->getPortCount(); port++) { + MidiPortItem *item = new MidiPortItem(); + item->midiIO = midiIO; + item->port = port; + item->text = midiIO->getPortName(port); + item->rightText = CHECKMARK(item->port == midiIO->port); + menu->addChild(item); + } + menu->addChild(construct()); + + menu->addChild(construct(&MenuLabel::text, "MIDI channel")); + MidiInput *midiInput = dynamic_cast(midiIO); + if (midiInput) { + MidiChannelItem *item = new MidiChannelItem(); + item->midiIO = midiIO; + item->channel = -1; + item->text = "All"; + item->rightText = CHECKMARK(item->channel == midiIO->channel); + menu->addChild(item); + } + for (int channel = 0; channel < 16; channel++) { + MidiChannelItem *item = new MidiChannelItem(); + item->midiIO = midiIO; + item->channel = channel; + item->text = stringf("%d", channel + 1); + item->rightText = CHECKMARK(item->channel == midiIO->channel); + menu->addChild(item); + } +} + + +} // namespace rack diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index d990f8bb..fe90229c 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -39,6 +39,11 @@ struct AudioInterfaceIO : AudioIO { maxInputs = MAX_INPUTS; } + ~AudioInterfaceIO() { + // Wait until processStream() is finished + std::lock_guard lock(audioMutex); + } + void processStream(const float *input, float *output, int length) override { if (numInputs > 0) { // TODO Do we need to wait on the input to be consumed here? @@ -300,7 +305,4 @@ AudioInterfaceWidget::AudioInterfaceWidget() { AudioWidget *audioWidget = construct(); audioWidget->audioIO = &module->audioIO; addChild(audioWidget); - // Widget *w = construct(); - // w->box.pos = Vec(100, 0); - // addChild(w); } diff --git a/src/core/MidiCCToCV.cpp b/src/core/MidiCCToCV.cpp index 6e60e5f3..c9aa2be4 100644 --- a/src/core/MidiCCToCV.cpp +++ b/src/core/MidiCCToCV.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include "core.hpp" @@ -324,3 +325,4 @@ void MIDICCToCVWidget::step() { ModuleWidget::step(); } +#endif \ No newline at end of file diff --git a/src/core/MidiClockToCV.cpp b/src/core/MidiClockToCV.cpp index 1b5186c7..eda9a413 100644 --- a/src/core/MidiClockToCV.cpp +++ b/src/core/MidiClockToCV.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include "core.hpp" @@ -369,3 +370,4 @@ void MIDIClockToCVWidget::step() { ModuleWidget::step(); } +#endif \ No newline at end of file diff --git a/src/core/MidiIO.cpp b/src/core/MidiIO.cpp index 74f71bfb..1a2f726e 100644 --- a/src/core/MidiIO.cpp +++ b/src/core/MidiIO.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include "core.hpp" @@ -260,3 +261,4 @@ void ChannelChoice::onAction(EventAction &e) { void ChannelChoice::step() { text = (midiModule->channel >= 0) ? stringf("%d", midiModule->channel + 1) : "All"; } +#endif \ No newline at end of file diff --git a/src/core/MidiIO.hpp b/src/core/MidiIO.hpp index 756822d6..ed4db49e 100644 --- a/src/core/MidiIO.hpp +++ b/src/core/MidiIO.hpp @@ -1,3 +1,4 @@ +#if 0 #include #include "rack.hpp" @@ -201,3 +202,5 @@ struct ChannelChoice : ChoiceButton { void step() override; void onAction(EventAction &e) override; }; + +#endif \ No newline at end of file diff --git a/src/core/MidiToCV.cpp b/src/core/MidiToCV.cpp index df8accd9..67d8b865 100644 --- a/src/core/MidiToCV.cpp +++ b/src/core/MidiToCV.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include "core.hpp" @@ -303,3 +304,4 @@ void MidiToCVWidget::step() { ModuleWidget::step(); } +#endif \ No newline at end of file diff --git a/src/core/MidiTriggerToCV.cpp b/src/core/MidiTriggerToCV.cpp index 3fb0f1c1..0936468f 100644 --- a/src/core/MidiTriggerToCV.cpp +++ b/src/core/MidiTriggerToCV.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include "core.hpp" @@ -282,3 +283,4 @@ MIDITriggerToCVWidget::MIDITriggerToCVWidget() { void MIDITriggerToCVWidget::step() { ModuleWidget::step(); } +#endif \ No newline at end of file diff --git a/src/core/QuadMidiToCV.cpp b/src/core/QuadMidiToCV.cpp index 84c7335b..70b8f7ae 100644 --- a/src/core/QuadMidiToCV.cpp +++ b/src/core/QuadMidiToCV.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include "core.hpp" @@ -416,3 +417,4 @@ void QuadMidiToCVWidget::step() { ModuleWidget::step(); } +#endif \ No newline at end of file diff --git a/src/core/core.cpp b/src/core/core.cpp index 416b3ca6..09a50a01 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -8,12 +8,12 @@ void init(rack::Plugin *p) { #endif p->addModel(createModel("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); - p->addModel(createModel("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); + // p->addModel(createModel("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); - p->addModel(createModel("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); - p->addModel(createModel("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); - p->addModel(createModel("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); - p->addModel(createModel("Core", "QuadMIDIToCVInterface", "Quad MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG)); + // p->addModel(createModel("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); + // p->addModel(createModel("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); + // p->addModel(createModel("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); + // p->addModel(createModel("Core", "QuadMIDIToCVInterface", "Quad MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG)); // p->addModel(createModel("Core", "Bridge", "Bridge")); p->addModel(createModel("Core", "Blank", "Blank", BLANK_TAG)); diff --git a/src/midi.cpp b/src/midi.cpp new file mode 100644 index 00000000..e30b3163 --- /dev/null +++ b/src/midi.cpp @@ -0,0 +1,42 @@ +#include "midi.hpp" + + +namespace rack { + + +int MidiIO::getPortCount() { + return midi->getPortCount(); +} + +std::string MidiIO::getPortName(int port) { + return midi->getPortName(port); +} + +void MidiIO::openPort(int port) { + midi->closePort(); + + if (port >= 0) { + midi->openPort(port); + } + this->port = port; +} + +MidiInput::MidiInput() { + midi = new RtMidiIn(); +} + +MidiInput::~MidiInput() { + delete dynamic_cast(midi); +} + + +MidiOutput::MidiOutput() { + midi = new RtMidiOut(); +} + +MidiOutput::~MidiOutput() { + delete dynamic_cast(midi); +} + + +} // namespace rack