@@ -0,0 +1,143 @@ | |||||
#include "core.hpp" | |||||
#include "midi.hpp" | |||||
#include "dsp/filter.hpp" | |||||
struct CcChoice : LedDisplayChoice { | |||||
CcChoice() { | |||||
box.size.y = mm2px(6.666); | |||||
textOffset.y -= 4; | |||||
} | |||||
}; | |||||
struct CcMidiWidget : MidiWidget { | |||||
LedDisplaySeparator *hSeparators[4]; | |||||
LedDisplaySeparator *vSeparators[4]; | |||||
LedDisplayChoice *ccChoices[4][4]; | |||||
CcMidiWidget() { | |||||
Vec pos = channelChoice->box.getBottomLeft(); | |||||
for (int x = 1; x < 4; x++) { | |||||
vSeparators[x] = Widget::create<LedDisplaySeparator>(pos); | |||||
addChild(vSeparators[x]); | |||||
} | |||||
for (int y = 0; y < 4; y++) { | |||||
hSeparators[y] = Widget::create<LedDisplaySeparator>(pos); | |||||
addChild(hSeparators[y]); | |||||
for (int x = 0; x < 4; x++) { | |||||
CcChoice *ccChoice = Widget::create<CcChoice>(pos); | |||||
ccChoice->text = stringf("%d", x*4+y); | |||||
ccChoices[x][y] = ccChoice; | |||||
addChild(ccChoice); | |||||
} | |||||
pos = ccChoices[0][y]->box.getBottomLeft(); | |||||
} | |||||
for (int x = 1; x < 4; x++) { | |||||
vSeparators[x]->box.size.y = pos.y - vSeparators[x]->box.pos.y; | |||||
} | |||||
} | |||||
void step() override { | |||||
MidiWidget::step(); | |||||
for (int x = 1; x < 4; x++) { | |||||
vSeparators[x]->box.pos.x = box.size.x / 4 * x; | |||||
} | |||||
for (int y = 0; y < 4; y++) { | |||||
hSeparators[y]->box.size.x = box.size.x; | |||||
for (int x = 0; x < 4; x++) { | |||||
ccChoices[x][y]->box.size.x = box.size.x / 4; | |||||
ccChoices[x][y]->box.pos.x = box.size.x / 4 * x; | |||||
} | |||||
} | |||||
} | |||||
}; | |||||
struct MIDITriggerToCVInterface : Module { | |||||
enum ParamIds { | |||||
NUM_PARAMS | |||||
}; | |||||
enum InputIds { | |||||
NUM_INPUTS | |||||
}; | |||||
enum OutputIds { | |||||
ENUMS(TRIG_OUTPUT, 16), | |||||
NUM_OUTPUTS | |||||
}; | |||||
enum LightIds { | |||||
NUM_LIGHTS | |||||
}; | |||||
MidiInputQueue midiInput; | |||||
MIDITriggerToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||||
void step() override { | |||||
MidiMessage msg; | |||||
while (midiInput.shift(&msg)) { | |||||
processMessage(msg); | |||||
} | |||||
for (int i = 0; i < 16; i++) { | |||||
outputs[TRIG_OUTPUT + i].value = 0.f; | |||||
} | |||||
} | |||||
void processMessage(MidiMessage msg) { | |||||
// debug("MIDI: %01x %01x %02x %02x", msg.status(), msg.channel(), msg.data1, msg.data2); | |||||
switch (msg.status()) { | |||||
default: break; | |||||
} | |||||
} | |||||
json_t *toJson() override { | |||||
json_t *rootJ = json_object(); | |||||
json_object_set_new(rootJ, "midi", midiInput.toJson()); | |||||
return rootJ; | |||||
} | |||||
void fromJson(json_t *rootJ) override { | |||||
json_t *midiJ = json_object_get(rootJ, "midi"); | |||||
midiInput.fromJson(midiJ); | |||||
} | |||||
}; | |||||
struct MIDITriggerToCVInterfaceWidget : ModuleWidget { | |||||
MIDITriggerToCVInterfaceWidget(MIDITriggerToCVInterface *module) : ModuleWidget(module) { | |||||
setPanel(SVG::load(assetGlobal("res/Core/MIDICCToCVInterface.svg"))); | |||||
addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||||
addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 0)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 1)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094982, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 2)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 3)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.8943355, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 4)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.49466, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 5)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.094982, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 6)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 7)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.8943343, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 8)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.494659, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 9)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.09498, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 10)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 11)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(3.894335, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 12)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(15.49466, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 13)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 14)); | |||||
addOutput(Port::create<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 15)); | |||||
MidiWidget *midiWidget = Widget::create<CcMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | |||||
midiWidget->box.size = mm2px(Vec(44, 54.667)); | |||||
midiWidget->midiIO = &module->midiInput; | |||||
addChild(midiWidget); | |||||
} | |||||
}; | |||||
Model *modelMIDITriggerToCVInterface = Model::create<MIDITriggerToCVInterface, MIDITriggerToCVInterfaceWidget>("Core", "MIDITriggerToCVInterface", "MIDI-TRIG", MIDI_TAG, EXTERNAL_TAG); |
@@ -1,286 +0,0 @@ | |||||
#if 0 | |||||
#include <list> | |||||
#include <algorithm> | |||||
#include "core.hpp" | |||||
#include "MidiIO.hpp" | |||||
#include "dsp/digital.hpp" | |||||
using namespace rack; | |||||
struct TriggerValue { | |||||
int val = 0; | |||||
int num; | |||||
bool numInited = false; | |||||
bool onFocus = false; | |||||
}; | |||||
struct MIDITriggerToCVInterface : MidiIO, Module { | |||||
enum ParamIds { | |||||
NUM_PARAMS | |||||
}; | |||||
enum InputIds { | |||||
NUM_INPUTS | |||||
}; | |||||
enum OutputIds { | |||||
NUM_OUTPUTS = 16 | |||||
}; | |||||
TriggerValue trigger[NUM_OUTPUTS]; | |||||
MIDITriggerToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
trigger[i].num = i; | |||||
} | |||||
} | |||||
~MIDITriggerToCVInterface() { | |||||
} | |||||
void step() override; | |||||
void processMidi(std::vector<unsigned char> msg); | |||||
void resetMidi() override; | |||||
virtual json_t *toJson() override { | |||||
json_t *rootJ = json_object(); | |||||
addBaseJson(rootJ); | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
json_object_set_new(rootJ, std::to_string(i).c_str(), json_integer(trigger[i].num)); | |||||
} | |||||
return rootJ; | |||||
} | |||||
void fromJson(json_t *rootJ) override { | |||||
baseFromJson(rootJ); | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
json_t *ccNumJ = json_object_get(rootJ, std::to_string(i).c_str()); | |||||
if (ccNumJ) { | |||||
trigger[i].num = json_integer_value(ccNumJ); | |||||
trigger[i].numInited = true; | |||||
} | |||||
} | |||||
} | |||||
void onReset() override { | |||||
resetMidi(); | |||||
} | |||||
}; | |||||
void MIDITriggerToCVInterface::step() { | |||||
if (isPortOpen()) { | |||||
std::vector<unsigned char> message; | |||||
// midiIn->getMessage returns empty vector if there are no messages in the queue | |||||
getMessage(&message); | |||||
if (message.size() > 0) { | |||||
processMidi(message); | |||||
} | |||||
} | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
// Note: Could have an option to select between gate and velocity | |||||
// but trigger seams more useful | |||||
// outputs[i].value = trigger[i] / 127.0 * 10; | |||||
outputs[i].value = trigger[i].val > 0 ? 10.0 : 0.0; | |||||
} | |||||
} | |||||
void MIDITriggerToCVInterface::resetMidi() { | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
trigger[i].val = 0; | |||||
} | |||||
}; | |||||
void MIDITriggerToCVInterface::processMidi(std::vector<unsigned char> msg) { | |||||
int channel = msg[0] & 0xf; | |||||
int status = (msg[0] >> 4) & 0xf; | |||||
int data1 = msg[1]; | |||||
int data2 = msg[2]; | |||||
//fprintf(stderr, "channel %d status %d data1 %d data2 %d\n", channel, status, data1,data2); | |||||
// Filter channels | |||||
if (this->channel >= 0 && this->channel != channel) | |||||
return; | |||||
if (status == 0x8) { // note off | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
if (data1 == trigger[i].num) { | |||||
trigger[i].val = 0; | |||||
} | |||||
} | |||||
return; | |||||
} | |||||
if (status == 0x9) { // note on | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | |||||
if (trigger[i].onFocus && data2 > 0) { | |||||
trigger[i].num = data1; | |||||
} | |||||
if (data1 == trigger[i].num) { | |||||
trigger[i].val = data2; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
struct TriggerTextField : TextField { | |||||
void onTextChange() override; | |||||
void draw(NVGcontext *vg) override; | |||||
void onMouseDown(EventMouseDown &e) override; | |||||
void onMouseUp(EventMouseUp &e) override; | |||||
void onMouseLeave(EventMouseLeave &e) override; | |||||
int outNum; | |||||
MIDITriggerToCVInterface *module; | |||||
}; | |||||
void TriggerTextField::draw(NVGcontext *vg) { | |||||
/* This is necessary, since the save | |||||
* file is loaded after constructing the widget*/ | |||||
if (module->trigger[outNum].numInited) { | |||||
module->trigger[outNum].numInited = false; | |||||
text = std::to_string(module->trigger[outNum].num); | |||||
} | |||||
if (module->trigger[outNum].onFocus) { | |||||
text = std::to_string(module->trigger[outNum].num); | |||||
} | |||||
TextField::draw(vg); | |||||
} | |||||
void TriggerTextField::onTextChange() { | |||||
if (text.size() > 0) { | |||||
try { | |||||
int num = std::stoi(text); | |||||
// Only allow valid cc numbers | |||||
if (num < 0 || num > 127 || text.size() > 3) { | |||||
text = ""; | |||||
begin = end = 0; | |||||
module->trigger[outNum].num = -1; | |||||
} | |||||
else { | |||||
module->trigger[outNum].num = num; | |||||
} | |||||
} | |||||
catch (...) { | |||||
text = ""; | |||||
begin = end = 0; | |||||
module->trigger[outNum].num = -1; | |||||
} | |||||
}; | |||||
} | |||||
void TriggerTextField::onMouseUp(EventMouseUp &e) { | |||||
if (e.button == 1) { | |||||
module->trigger[outNum].onFocus = false; | |||||
e.consumed = true; | |||||
} | |||||
TextField::onMouseUp(e); | |||||
} | |||||
void TriggerTextField::onMouseDown(EventMouseDown &e) { | |||||
if (e.button == 1) { | |||||
module->trigger[outNum].onFocus = true; | |||||
e.consumed = true; | |||||
} | |||||
TextField::onMouseDown(e); | |||||
} | |||||
void TriggerTextField::onMouseLeave(EventMouseLeave &e) { | |||||
module->trigger[outNum].onFocus = false; | |||||
e.consumed = true; | |||||
} | |||||
MIDITriggerToCVWidget::MIDITriggerToCVWidget() { | |||||
MIDITriggerToCVInterface *module = new MIDITriggerToCVInterface(); | |||||
setModule(module); | |||||
box.size = Vec(16 * 15, 380); | |||||
{ | |||||
Panel *panel = new LightPanel(); | |||||
panel->box.size = box.size; | |||||
addChild(panel); | |||||
} | |||||
float margin = 5; | |||||
float labelHeight = 15; | |||||
float yPos = margin; | |||||
addChild(createScrew<ScrewSilver>(Vec(15, 0))); | |||||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0))); | |||||
addChild(createScrew<ScrewSilver>(Vec(15, 365))); | |||||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365))); | |||||
{ | |||||
Label *label = new Label(); | |||||
label->box.pos = Vec(box.size.x - margin - 11 * 15, margin); | |||||
label->text = "MIDI Trigger to CV"; | |||||
addChild(label); | |||||
yPos = labelHeight * 2; | |||||
} | |||||
{ | |||||
Label *label = new Label(); | |||||
label->box.pos = Vec(margin, yPos); | |||||
label->text = "MIDI Interface"; | |||||
addChild(label); | |||||
MidiChoice *midiChoice = new MidiChoice(); | |||||
midiChoice->midiModule = dynamic_cast<MidiIO *>(module); | |||||
midiChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos); | |||||
midiChoice->box.size.x = (box.size.x / 2.0) - margin; | |||||
addChild(midiChoice); | |||||
yPos += midiChoice->box.size.y + margin; | |||||
} | |||||
{ | |||||
Label *label = new Label(); | |||||
label->box.pos = Vec(margin, yPos); | |||||
label->text = "Channel"; | |||||
addChild(label); | |||||
ChannelChoice *channelChoice = new ChannelChoice(); | |||||
channelChoice->midiModule = dynamic_cast<MidiIO *>(module); | |||||
channelChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos); | |||||
channelChoice->box.size.x = (box.size.x / 2.0) - margin; | |||||
addChild(channelChoice); | |||||
yPos += channelChoice->box.size.y + margin * 3; | |||||
} | |||||
for (int i = 0; i < MIDITriggerToCVInterface::NUM_OUTPUTS; i++) { | |||||
TriggerTextField *triggerNumChoice = new TriggerTextField(); | |||||
triggerNumChoice->module = module; | |||||
triggerNumChoice->outNum = i; | |||||
triggerNumChoice->text = std::to_string(module->trigger[i].num); | |||||
triggerNumChoice->box.pos = Vec(11 + (i % 4) * (63), yPos); | |||||
triggerNumChoice->box.size.x = 29; | |||||
addChild(triggerNumChoice); | |||||
yPos += labelHeight + margin; | |||||
addOutput(createOutput<PJ3410Port>(Vec((i % 4) * (63) + 10, yPos + 5), module, i)); | |||||
if ((i + 1) % 4 == 0) { | |||||
yPos += 47 + margin; | |||||
} | |||||
else { | |||||
yPos -= labelHeight + margin; | |||||
} | |||||
} | |||||
} | |||||
void MIDITriggerToCVWidget::step() { | |||||
ModuleWidget::step(); | |||||
} | |||||
#endif |
@@ -9,6 +9,7 @@ void init(rack::Plugin *p) { | |||||
p->addModel(modelMIDIToCVInterface); | p->addModel(modelMIDIToCVInterface); | ||||
p->addModel(modelQuadMIDIToCVInterface); | p->addModel(modelQuadMIDIToCVInterface); | ||||
p->addModel(modelMIDICCToCVInterface); | p->addModel(modelMIDICCToCVInterface); | ||||
p->addModel(modelMIDITriggerToCVInterface); | |||||
p->addModel(modelBlank); | p->addModel(modelBlank); | ||||
p->addModel(modelNotes); | p->addModel(modelNotes); | ||||
} | } |
@@ -8,5 +8,6 @@ extern Model *modelAudioInterface; | |||||
extern Model *modelMIDIToCVInterface; | extern Model *modelMIDIToCVInterface; | ||||
extern Model *modelQuadMIDIToCVInterface; | extern Model *modelQuadMIDIToCVInterface; | ||||
extern Model *modelMIDICCToCVInterface; | extern Model *modelMIDICCToCVInterface; | ||||
extern Model *modelMIDITriggerToCVInterface; | |||||
extern Model *modelBlank; | extern Model *modelBlank; | ||||
extern Model *modelNotes; | extern Model *modelNotes; |