@@ -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 |