| @@ -283,6 +283,7 @@ struct MomentarySwitch : virtual Switch { | |||||
| //////////////////// | //////////////////// | ||||
| struct AudioIO; | struct AudioIO; | ||||
| struct MidiIO; | |||||
| struct AudioWidget : OpaqueWidget { | struct AudioWidget : OpaqueWidget { | ||||
| /** Not owned */ | /** Not owned */ | ||||
| @@ -290,7 +291,10 @@ struct AudioWidget : OpaqueWidget { | |||||
| void onMouseDown(EventMouseDown &e) override; | void onMouseDown(EventMouseDown &e) override; | ||||
| }; | }; | ||||
| struct MIDIWidget : OpaqueWidget { | |||||
| struct MidiWidget : OpaqueWidget { | |||||
| /** Not owned */ | |||||
| MidiIO *midiIO = NULL; | |||||
| void onMouseDown(EventMouseDown &e) override; | |||||
| }; | }; | ||||
| //////////////////// | //////////////////// | ||||
| @@ -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"))); | setSVG(SVG::load(assetGlobal("res/ComponentLibrary/MIDI_DIN.svg"))); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -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 | |||||
| @@ -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>(&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<MenuEntry>()); | |||||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "MIDI channel")); | |||||
| MidiInput *midiInput = dynamic_cast<MidiInput*>(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 | |||||
| @@ -39,6 +39,11 @@ struct AudioInterfaceIO : AudioIO { | |||||
| maxInputs = MAX_INPUTS; | maxInputs = MAX_INPUTS; | ||||
| } | } | ||||
| ~AudioInterfaceIO() { | |||||
| // Wait until processStream() is finished | |||||
| std::lock_guard<std::mutex> lock(audioMutex); | |||||
| } | |||||
| void processStream(const float *input, float *output, int length) override { | void processStream(const float *input, float *output, int length) override { | ||||
| if (numInputs > 0) { | if (numInputs > 0) { | ||||
| // TODO Do we need to wait on the input to be consumed here? | // TODO Do we need to wait on the input to be consumed here? | ||||
| @@ -300,7 +305,4 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||||
| AudioWidget *audioWidget = construct<USB_B_AudioWidget>(); | AudioWidget *audioWidget = construct<USB_B_AudioWidget>(); | ||||
| audioWidget->audioIO = &module->audioIO; | audioWidget->audioIO = &module->audioIO; | ||||
| addChild(audioWidget); | addChild(audioWidget); | ||||
| // Widget *w = construct<DIN_MIDIWidget>(); | |||||
| // w->box.pos = Vec(100, 0); | |||||
| // addChild(w); | |||||
| } | } | ||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <list> | #include <list> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "core.hpp" | #include "core.hpp" | ||||
| @@ -324,3 +325,4 @@ void MIDICCToCVWidget::step() { | |||||
| ModuleWidget::step(); | ModuleWidget::step(); | ||||
| } | } | ||||
| #endif | |||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <list> | #include <list> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "core.hpp" | #include "core.hpp" | ||||
| @@ -369,3 +370,4 @@ void MIDIClockToCVWidget::step() { | |||||
| ModuleWidget::step(); | ModuleWidget::step(); | ||||
| } | } | ||||
| #endif | |||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <list> | #include <list> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "core.hpp" | #include "core.hpp" | ||||
| @@ -260,3 +261,4 @@ void ChannelChoice::onAction(EventAction &e) { | |||||
| void ChannelChoice::step() { | void ChannelChoice::step() { | ||||
| text = (midiModule->channel >= 0) ? stringf("%d", midiModule->channel + 1) : "All"; | text = (midiModule->channel >= 0) ? stringf("%d", midiModule->channel + 1) : "All"; | ||||
| } | } | ||||
| #endif | |||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <unordered_map> | #include <unordered_map> | ||||
| #include "rack.hpp" | #include "rack.hpp" | ||||
| @@ -201,3 +202,5 @@ struct ChannelChoice : ChoiceButton { | |||||
| void step() override; | void step() override; | ||||
| void onAction(EventAction &e) override; | void onAction(EventAction &e) override; | ||||
| }; | }; | ||||
| #endif | |||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <list> | #include <list> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "core.hpp" | #include "core.hpp" | ||||
| @@ -303,3 +304,4 @@ void MidiToCVWidget::step() { | |||||
| ModuleWidget::step(); | ModuleWidget::step(); | ||||
| } | } | ||||
| #endif | |||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <list> | #include <list> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "core.hpp" | #include "core.hpp" | ||||
| @@ -282,3 +283,4 @@ MIDITriggerToCVWidget::MIDITriggerToCVWidget() { | |||||
| void MIDITriggerToCVWidget::step() { | void MIDITriggerToCVWidget::step() { | ||||
| ModuleWidget::step(); | ModuleWidget::step(); | ||||
| } | } | ||||
| #endif | |||||
| @@ -1,3 +1,4 @@ | |||||
| #if 0 | |||||
| #include <list> | #include <list> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "core.hpp" | #include "core.hpp" | ||||
| @@ -416,3 +417,4 @@ void QuadMidiToCVWidget::step() { | |||||
| ModuleWidget::step(); | ModuleWidget::step(); | ||||
| } | } | ||||
| #endif | |||||
| @@ -8,12 +8,12 @@ void init(rack::Plugin *p) { | |||||
| #endif | #endif | ||||
| p->addModel(createModel<AudioInterfaceWidget>("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); | p->addModel(createModel<AudioInterfaceWidget>("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); | ||||
| p->addModel(createModel<MidiToCVWidget>("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
| // p->addModel(createModel<MidiToCVWidget>("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
| p->addModel(createModel<MIDICCToCVWidget>("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
| p->addModel(createModel<MIDIClockToCVWidget>("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); | |||||
| p->addModel(createModel<MIDITriggerToCVWidget>("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
| p->addModel(createModel<QuadMidiToCVWidget>("Core", "QuadMIDIToCVInterface", "Quad MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG)); | |||||
| // p->addModel(createModel<MIDICCToCVWidget>("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
| // p->addModel(createModel<MIDIClockToCVWidget>("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); | |||||
| // p->addModel(createModel<MIDITriggerToCVWidget>("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
| // p->addModel(createModel<QuadMidiToCVWidget>("Core", "QuadMIDIToCVInterface", "Quad MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG)); | |||||
| // p->addModel(createModel<BridgeWidget>("Core", "Bridge", "Bridge")); | // p->addModel(createModel<BridgeWidget>("Core", "Bridge", "Bridge")); | ||||
| p->addModel(createModel<BlankWidget>("Core", "Blank", "Blank", BLANK_TAG)); | p->addModel(createModel<BlankWidget>("Core", "Blank", "Blank", BLANK_TAG)); | ||||
| @@ -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<RtMidiIn*>(midi); | |||||
| } | |||||
| MidiOutput::MidiOutput() { | |||||
| midi = new RtMidiOut(); | |||||
| } | |||||
| MidiOutput::~MidiOutput() { | |||||
| delete dynamic_cast<RtMidiOut*>(midi); | |||||
| } | |||||
| } // namespace rack | |||||