Browse Source

Finish CV-MIDI, CV-CC, and CV-Gate. Clean up MIDI-CV, MIDI-CC, and MIDI-Gate. Make Grid16MidiWidget generic and reusable.

tags/v1.0.0
Andrew Belt 6 years ago
parent
commit
c13c967b26
7 changed files with 318 additions and 257 deletions
  1. +53
    -19
      src/Core/CV_CC.cpp
  2. +75
    -49
      src/Core/CV_Gate.cpp
  3. +18
    -0
      src/Core/CV_MIDI.cpp
  4. +150
    -19
      src/Core/Core.hpp
  5. +9
    -94
      src/Core/MIDI_CC.cpp
  6. +0
    -1
      src/Core/MIDI_CV.cpp
  7. +13
    -75
      src/Core/MIDI_Gate.cpp

+ 53
- 19
src/Core/CV_CC.cpp View File

@@ -1,34 +1,27 @@
#include "Core.hpp" #include "Core.hpp"




template <int N>
struct CCMidiOutput : midi::Output { struct CCMidiOutput : midi::Output {
int ccs[N];
int lastValues[N];
int lastValues[128];


CCMidiOutput() { CCMidiOutput() {
reset(); reset();
} }


void reset() { void reset() {
for (int n = 0; n < N; n++) {
ccs[n] = n;
for (int n = 0; n < 128; n++) {
lastValues[n] = -1; lastValues[n] = -1;
} }
} }


void setCC(int cc, int n) {
ccs[n] = cc;
}

void setValue(int value, int n) {
if (value == lastValues[n])
void setValue(int value, int cc) {
if (value == lastValues[cc])
return; return;
lastValues[n] = value;
lastValues[cc] = value;
// CC // CC
midi::Message m; midi::Message m;
m.setStatus(0xb); m.setStatus(0xb);
m.setNote(ccs[n]);
m.setNote(cc);
m.setValue(value); m.setValue(value);
sendMessage(m); sendMessage(m);
} }
@@ -50,11 +43,23 @@ struct CV_CC : Module {
NUM_LIGHTS NUM_LIGHTS
}; };


CCMidiOutput<16> midiOutput;
CCMidiOutput midiOutput;
float rateLimiterPhase = 0.f; float rateLimiterPhase = 0.f;
int learningId = -1;
int learnedCcs[16] = {};


CV_CC() { CV_CC() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
onReset();
}

void onReset() override {
for (int i = 0; i < 16; i++) {
learnedCcs[i] = i;
}
learningId = -1;
midiOutput.reset();
midiOutput.midi::Output::reset();
} }


void step() override { void step() override {
@@ -67,11 +72,39 @@ struct CV_CC : Module {
return; return;
} }


for (int n = 0; n < 16; n++) {
int value = (int) std::round(inputs[CC_INPUTS + n].getVoltage() / 10.f * 127);
for (int i = 0; i < 16; i++) {
int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127);
value = clamp(value, 0, 127); value = clamp(value, 0, 127);
midiOutput.setValue(value, n);
midiOutput.setValue(value, learnedCcs[i]);
}
}

json_t *dataToJson() override {
json_t *rootJ = json_object();

json_t *ccsJ = json_array();
for (int i = 0; i < 16; i++) {
json_array_append_new(ccsJ, json_integer(learnedCcs[i]));
} }
json_object_set_new(rootJ, "ccs", ccsJ);

json_object_set_new(rootJ, "midi", midiOutput.toJson());
return rootJ;
}

void dataFromJson(json_t *rootJ) override {
json_t *ccsJ = json_object_get(rootJ, "ccs");
if (ccsJ) {
for (int i = 0; i < 16; i++) {
json_t *ccJ = json_array_get(ccsJ, i);
if (ccJ)
learnedCcs[i] = json_integer_value(ccJ);
}
}

json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ)
midiOutput.fromJson(midiJ);
} }
}; };


@@ -103,11 +136,12 @@ struct CV_CCWidget : ModuleWidget {
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 112)), module, CV_CC::CC_INPUTS + 14)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 112)), module, CV_CC::CC_INPUTS + 14));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 112)), module, CV_CC::CC_INPUTS + 15)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 112)), module, CV_CC::CC_INPUTS + 15));


MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.4, 14.839)));
typedef Grid16MidiWidget<CcChoice<CV_CC>> TMidiWidget;
TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->box.size = mm2px(Vec(44, 54.667)); midiWidget->box.size = mm2px(Vec(44, 54.667));
if (module) if (module)
midiWidget->midiIO = &module->midiOutput; midiWidget->midiIO = &module->midiOutput;
// midiWidget->createGridChoices();
midiWidget->setModule(module);
addChild(midiWidget); addChild(midiWidget);
} }
}; };


+ 75
- 49
src/Core/CV_Gate.cpp View File

@@ -1,28 +1,25 @@
#include "Core.hpp" #include "Core.hpp"




template <int N>
struct GateMidiOutput : midi::Output { struct GateMidiOutput : midi::Output {
int vels[N];
bool lastGates[N];
int notes[N];
int vels[128];
bool lastGates[128];


GateMidiOutput() { GateMidiOutput() {
reset(); reset();
} }


void reset() { void reset() {
for (int n = 0; n < N; n++) {
vels[n] = 100;
lastGates[n] = false;
notes[n] = 60 + n;
for (int note = 0; note < 128; note++) {
vels[note] = 100;
lastGates[note] = false;
} }
} }


void panic() { void panic() {
reset(); reset();
// Send all note off commands // Send all note off commands
for (int note = 0; note <= 127; note++) {
for (int note = 0; note < 128; note++) {
// Note off // Note off
midi::Message m; midi::Message m;
m.setStatus(0x8); m.setStatus(0x8);
@@ -32,48 +29,28 @@ struct GateMidiOutput : midi::Output {
} }
} }


void setVelocity(int vel, int n) {
vels[n] = vel;
void setVelocity(int vel, int note) {
vels[note] = vel;
} }


void setGate(bool gate, int n) {
if (gate && !lastGates[n]) {
void setGate(bool gate, int note) {
if (gate && !lastGates[note]) {
// Note on // Note on
midi::Message m; midi::Message m;
m.setStatus(0x9); m.setStatus(0x9);
m.setNote(notes[n]);
m.setValue(vels[n]);
m.setNote(note);
m.setValue(vels[note]);
sendMessage(m); sendMessage(m);
} }
else if (!gate && lastGates[n]) {
else if (!gate && lastGates[note]) {
// Note off // Note off
midi::Message m; midi::Message m;
m.setStatus(0x8); m.setStatus(0x8);
m.setNote(notes[n]);
m.setValue(vels[n]);
m.setNote(note);
m.setValue(vels[note]);
sendMessage(m); sendMessage(m);
} }
lastGates[n] = gate;
}

void setNote(int note, int n) {
if (note == notes[n])
return;
if (lastGates[n]) {
// Note off
midi::Message m1;
m1.setStatus(0x8);
m1.setNote(notes[n]);
m1.setValue(vels[n]);
sendMessage(m1);
// Note on
midi::Message m2;
m2.setStatus(0x9);
m2.setNote(note);
m2.setValue(vels[n]);
sendMessage(m2);
}
notes[n] = note;
lastGates[note] = gate;
} }
}; };


@@ -93,27 +70,75 @@ struct CV_Gate : Module {
NUM_LIGHTS NUM_LIGHTS
}; };


GateMidiOutput<16> midiOutput;
GateMidiOutput midiOutput;
bool velocityMode = false; bool velocityMode = false;
int learningId = -1;
uint8_t learnedNotes[16] = {};


CV_Gate() { CV_Gate() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
onReset();
}

void onReset() override {
for (int i = 0; i < 16; i++) {
learnedNotes[i] = i + 36;
}
learningId = -1;
midiOutput.reset();
midiOutput.midi::Output::reset();
} }


void step() override { void step() override {
for (int n = 0; n < 16; n++) {
for (int i = 0; i < 16; i++) {
int note = learnedNotes[i];
if (velocityMode) { if (velocityMode) {
int vel = (int) std::round(inputs[GATE_INPUTS + n].getVoltage() / 10.f * 127);
int vel = (int) std::round(inputs[GATE_INPUTS + i].getVoltage() / 10.f * 127);
vel = clamp(vel, 0, 127); vel = clamp(vel, 0, 127);
midiOutput.setVelocity(vel, n);
midiOutput.setGate(vel > 0, n);
midiOutput.setVelocity(vel, note);
midiOutput.setGate(vel > 0, note);
} }
else { else {
bool gate = inputs[GATE_INPUTS + n].getVoltage() >= 1.f;
midiOutput.setVelocity(100, n);
midiOutput.setGate(gate, n);
bool gate = inputs[GATE_INPUTS + i].getVoltage() >= 1.f;
midiOutput.setVelocity(100, note);
midiOutput.setGate(gate, note);
}
}
}

json_t *dataToJson() override {
json_t *rootJ = json_object();

json_t *notesJ = json_array();
for (int i = 0; i < 16; i++) {
json_t *noteJ = json_integer(learnedNotes[i]);
json_array_append_new(notesJ, noteJ);
}
json_object_set_new(rootJ, "notes", notesJ);

json_object_set_new(rootJ, "velocity", json_boolean(velocityMode));

json_object_set_new(rootJ, "midi", midiOutput.toJson());
return rootJ;
}

void dataFromJson(json_t *rootJ) override {
json_t *notesJ = json_object_get(rootJ, "notes");
if (notesJ) {
for (int i = 0; i < 16; i++) {
json_t *noteJ = json_array_get(notesJ, i);
if (noteJ)
learnedNotes[i] = json_integer_value(noteJ);
} }
} }

json_t *velocityJ = json_object_get(rootJ, "velocity");
if (velocityJ)
velocityMode = json_boolean_value(velocityJ);

json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ)
midiOutput.fromJson(midiJ);
} }
}; };


@@ -145,11 +170,12 @@ struct CV_GateWidget : ModuleWidget {
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 112)), module, CV_Gate::GATE_INPUTS + 14)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(31, 112)), module, CV_Gate::GATE_INPUTS + 14));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 112)), module, CV_Gate::GATE_INPUTS + 15)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(43, 112)), module, CV_Gate::GATE_INPUTS + 15));


MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.4, 14.839)));
typedef Grid16MidiWidget<NoteChoice<CV_Gate>> TMidiWidget;
TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->box.size = mm2px(Vec(44, 54.667)); midiWidget->box.size = mm2px(Vec(44, 54.667));
if (module) if (module)
midiWidget->midiIO = &module->midiOutput; midiWidget->midiIO = &module->midiOutput;
// midiWidget->createGridChoices();
midiWidget->setModule(module);
addChild(midiWidget); addChild(midiWidget);
} }
}; };


+ 18
- 0
src/Core/CV_MIDI.cpp View File

@@ -233,6 +233,12 @@ struct CV_MIDI : Module {


CV_MIDI() { CV_MIDI() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
onReset();
}

void onReset() override {
midiOutput.reset();
midiOutput.midi::Output::reset();
} }


void step() override { void step() override {
@@ -292,6 +298,18 @@ struct CV_MIDI : Module {
bool cont = inputs[CONTINUE_INPUT].value >= 1.f; bool cont = inputs[CONTINUE_INPUT].value >= 1.f;
midiOutput.setContinue(cont); midiOutput.setContinue(cont);
} }

json_t *dataToJson() override {
json_t *rootJ = json_object();
json_object_set_new(rootJ, "midi", midiOutput.toJson());
return rootJ;
}

void dataFromJson(json_t *rootJ) override {
json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ)
midiOutput.fromJson(midiJ);
}
}; };






+ 150
- 19
src/Core/Core.hpp View File

@@ -16,40 +16,36 @@ extern Model *modelBlank;
extern Model *modelNotes; extern Model *modelNotes;





struct GridChoice : LedDisplayChoice {
virtual void setId(int id) {}
};


template <class TChoice>
struct Grid16MidiWidget : MidiWidget { struct Grid16MidiWidget : MidiWidget {
LedDisplaySeparator *hSeparators[4]; LedDisplaySeparator *hSeparators[4];
LedDisplaySeparator *vSeparators[4]; LedDisplaySeparator *vSeparators[4];
GridChoice *gridChoices[4][4];
TChoice *choices[4][4];


void createGridChoices() {
Grid16MidiWidget() {
Vec pos = channelChoice->box.getBottomLeft(); Vec pos = channelChoice->box.getBottomLeft();
// Add vSeparators
for (int x = 1; x < 4; x++) { for (int x = 1; x < 4; x++) {
vSeparators[x] = createWidget<LedDisplaySeparator>(pos); vSeparators[x] = createWidget<LedDisplaySeparator>(pos);
addChild(vSeparators[x]); addChild(vSeparators[x]);
} }
// Add hSeparators and choice widgets
for (int y = 0; y < 4; y++) { for (int y = 0; y < 4; y++) {
hSeparators[y] = createWidget<LedDisplaySeparator>(pos); hSeparators[y] = createWidget<LedDisplaySeparator>(pos);
addChild(hSeparators[y]); addChild(hSeparators[y]);
for (int x = 0; x < 4; x++) { for (int x = 0; x < 4; x++) {
GridChoice *gridChoice = createGridChoice();
assert(gridChoice);
gridChoice->box.pos = pos;
gridChoice->setId(4*y + x);
gridChoices[x][y] = gridChoice;
addChild(gridChoice);
choices[x][y] = new TChoice;
choices[x][y]->box.pos = pos;
choices[x][y]->setId(4*y + x);
addChild(choices[x][y]);
} }
pos = gridChoices[0][y]->box.getBottomLeft();
pos = choices[0][y]->box.getBottomLeft();
} }
for (int x = 1; x < 4; x++) { for (int x = 1; x < 4; x++) {
vSeparators[x]->box.size.y = pos.y - vSeparators[x]->box.pos.y; vSeparators[x]->box.size.y = pos.y - vSeparators[x]->box.pos.y;
} }
} }

void step() override { void step() override {
MidiWidget::step(); MidiWidget::step();
for (int x = 1; x < 4; x++) { for (int x = 1; x < 4; x++) {
@@ -58,10 +54,145 @@ struct Grid16MidiWidget : MidiWidget {
for (int y = 0; y < 4; y++) { for (int y = 0; y < 4; y++) {
hSeparators[y]->box.size.x = box.size.x; hSeparators[y]->box.size.x = box.size.x;
for (int x = 0; x < 4; x++) { for (int x = 0; x < 4; x++) {
gridChoices[x][y]->box.size.x = box.size.x / 4;
gridChoices[x][y]->box.pos.x = box.size.x / 4 * x;
choices[x][y]->box.size.x = box.size.x / 4;
choices[x][y]->box.pos.x = box.size.x / 4 * x;
}
}
}

template <class TModule>
void setModule(TModule *module) {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
choices[x][y]->module = module;
} }
} }
} }
virtual GridChoice *createGridChoice() {return NULL;}
};
};


template <class TModule>
struct CcChoice : LedDisplayChoice {
TModule *module;
int id;
int focusCc;

CcChoice() {
box.size.y = mm2px(6.666);
textOffset.y -= 4;
}

void setId(int id) {
this->id = id;
}

void step() override {
if (!module) {
text = "";
return;
}
if (module->learningId == id) {
if (0 <= focusCc)
text = string::f("%d", focusCc);
else
text = "LRN";
color.a = 0.5;
}
else {
text = string::f("%d", module->learnedCcs[id]);
color.a = 1.0;
if (app()->event->selectedWidget == this)
app()->event->selectedWidget = NULL;
}
}

void onSelect(const event::Select &e) override {
e.consume(this);
if (!module)
return;
module->learningId = id;
focusCc = -1;
}

void onDeselect(const event::Deselect &e) override {
if (!module)
return;
if (0 <= focusCc && focusCc < 128) {
module->learnedCcs[id] = focusCc;
}
module->learningId = -1;
}

void onSelectText(const event::SelectText &e) override {
int c = e.codepoint - '0';
if (0 <= c && c <= 9) {
if (focusCc < 0)
focusCc = 0;
focusCc = focusCc * 10 + c;
}
if (focusCc >= 128)
focusCc = 0;
e.consume(this);
}

void onSelectKey(const event::SelectKey &e) override {
if ((e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) && e.action == GLFW_PRESS && (e.mods & WINDOW_MOD_MASK) == 0) {
event::Deselect eDeselect;
onDeselect(eDeselect);
app()->event->selectedWidget = NULL;
e.consume(this);
}
}
};


template <class TModule>
struct NoteChoice : LedDisplayChoice {
TModule *module;
int id;

NoteChoice() {
box.size.y = mm2px(6.666);
textOffset.y -= 4;
textOffset.x -= 4;
}

void setId(int id) {
this->id = id;
}

void step() override {
if (!module)
return;
if (module->learningId == id) {
text = "LRN";
color.a = 0.5;
}
else {
uint8_t note = module->learnedNotes[id];
static const char *noteNames[] = {
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
};
int oct = note / 12 - 1;
int semi = note % 12;
text = string::f("%s%d", noteNames[semi], oct);
color.a = 1.0;

if (app()->event->selectedWidget == this)
app()->event->selectedWidget = NULL;
}
}

void onSelect(const event::Select &e) override {
e.consume(this);
if (!module)
return;
module->learningId = id;
}

void onDeselect(const event::Deselect &e) override {
if (!module)
return;
module->learningId = -1;
}
};

+ 9
- 94
src/Core/MIDI_CC.cpp View File

@@ -1,5 +1,4 @@
#include "Core.hpp" #include "Core.hpp"
#include "midi.hpp"




struct MIDI_CC : Module { struct MIDI_CC : Module {
@@ -20,7 +19,7 @@ struct MIDI_CC : Module {
midi::InputQueue midiInput; midi::InputQueue midiInput;
int8_t values[128]; int8_t values[128];
int learningId = -1; int learningId = -1;
int ccs[16] = {};
int learnedCcs[16] = {};
dsp::ExponentialFilter valueFilters[16]; dsp::ExponentialFilter valueFilters[16];
int8_t lastValues[16] = {}; int8_t lastValues[16] = {};


@@ -34,7 +33,7 @@ struct MIDI_CC : Module {
values[i] = 0; values[i] = 0;
} }
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
ccs[i] = i;
learnedCcs[i] = i;
} }
learningId = -1; learningId = -1;
midiInput.reset(); midiInput.reset();
@@ -51,7 +50,7 @@ struct MIDI_CC : Module {
if (!outputs[CC_OUTPUT + i].active) if (!outputs[CC_OUTPUT + i].active)
continue; continue;


int cc = ccs[i];
int cc = learnedCcs[i];


float value = rescale(values[cc], 0, 127, 0.f, 10.f); float value = rescale(values[cc], 0, 127, 0.f, 10.f);
valueFilters[i].lambda = lambda; valueFilters[i].lambda = lambda;
@@ -77,7 +76,7 @@ struct MIDI_CC : Module {
uint8_t cc = msg.getNote(); uint8_t cc = msg.getNote();
// Learn // Learn
if (learningId >= 0 && values[cc] != msg.data2) { if (learningId >= 0 && values[cc] != msg.data2) {
ccs[learningId] = cc;
learnedCcs[learningId] = cc;
learningId = -1; learningId = -1;
} }
// Allow CC to be negative if the 8th bit is set. // Allow CC to be negative if the 8th bit is set.
@@ -93,7 +92,7 @@ struct MIDI_CC : Module {


json_t *ccsJ = json_array(); json_t *ccsJ = json_array();
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
json_array_append_new(ccsJ, json_integer(ccs[i]));
json_array_append_new(ccsJ, json_integer(learnedCcs[i]));
} }
json_object_set_new(rootJ, "ccs", ccsJ); json_object_set_new(rootJ, "ccs", ccsJ);


@@ -114,7 +113,7 @@ struct MIDI_CC : Module {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
json_t *ccJ = json_array_get(ccsJ, i); json_t *ccJ = json_array_get(ccsJ, i);
if (ccJ) if (ccJ)
ccs[i] = json_integer_value(ccJ);
learnedCcs[i] = json_integer_value(ccJ);
} }
} }


@@ -135,90 +134,6 @@ struct MIDI_CC : Module {
}; };




struct MidiCcChoice : GridChoice {
MIDI_CC *module;
int id;
int focusCc;

MidiCcChoice() {
box.size.y = mm2px(6.666);
textOffset.y -= 4;
}

void setId(int id) override {
this->id = id;
}

void step() override {
if (!module) {
text = "";
return;
}
if (module->learningId == id) {
if (0 <= focusCc)
text = string::f("%d", focusCc);
else
text = "LRN";
color.a = 0.5;
}
else {
text = string::f("%d", module->ccs[id]);
color.a = 1.0;
if (app()->event->selectedWidget == this)
app()->event->selectedWidget = NULL;
}
}

void onSelect(const event::Select &e) override {
e.consume(this);
if (!module)
return;
module->learningId = id;
focusCc = -1;
}

void onDeselect(const event::Deselect &e) override {
if (!module)
return;
if (0 <= focusCc && focusCc < 128) {
module->ccs[id] = focusCc;
}
module->learningId = -1;
}

void onSelectText(const event::SelectText &e) override {
char c = e.codepoint;
if ('0' <= c && c <= '9') {
if (focusCc < 0)
focusCc = 0;
focusCc = focusCc * 10 + (c - '0');
}
e.consume(this);
}

void onSelectKey(const event::SelectKey &e) override {
if (app()->event->selectedWidget == this) {
if (e.action == GLFW_PRESS && (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER)) {
event::Deselect eDeselect;
onDeselect(eDeselect);
app()->event->selectedWidget = NULL;
e.consume(this);
}
}
}
};


struct MidiCcWidget : Grid16MidiWidget {
MIDI_CC *module;
GridChoice *createGridChoice() override {
MidiCcChoice *gridChoice = new MidiCcChoice;
gridChoice->module = module;
return gridChoice;
}
};


struct MIDI_CCWidget : ModuleWidget { struct MIDI_CCWidget : ModuleWidget {
MIDI_CCWidget(MIDI_CC *module) { MIDI_CCWidget(MIDI_CC *module) {
setModule(module); setModule(module);
@@ -246,12 +161,12 @@ struct MIDI_CCWidget : ModuleWidget {
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), module, MIDI_CC::CC_OUTPUT + 14)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), module, MIDI_CC::CC_OUTPUT + 14));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), module, MIDI_CC::CC_OUTPUT + 15)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), module, MIDI_CC::CC_OUTPUT + 15));


MidiCcWidget *midiWidget = createWidget<MidiCcWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->module = module;
typedef Grid16MidiWidget<CcChoice<MIDI_CC>> TMidiWidget;
TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->box.size = mm2px(Vec(44, 54.667)); midiWidget->box.size = mm2px(Vec(44, 54.667));
if (module) if (module)
midiWidget->midiIO = &module->midiInput; midiWidget->midiIO = &module->midiInput;
midiWidget->createGridChoices();
midiWidget->setModule(module);
addChild(midiWidget); addChild(midiWidget);
} }
}; };


+ 0
- 1
src/Core/MIDI_CV.cpp View File

@@ -1,5 +1,4 @@
#include "Core.hpp" #include "Core.hpp"
#include "midi.hpp"


#include <algorithm> #include <algorithm>




+ 13
- 75
src/Core/MIDI_Gate.cpp View File

@@ -1,6 +1,4 @@
#include "Core.hpp" #include "Core.hpp"
#include "midi.hpp"
#include "event.hpp"




struct MIDI_Gate : Module { struct MIDI_Gate : Module {
@@ -25,7 +23,7 @@ struct MIDI_Gate : Module {
uint8_t velocities[16]; uint8_t velocities[16];
int learningId = -1; int learningId = -1;
uint8_t learnedNotes[16] = {}; uint8_t learnedNotes[16] = {};
bool velocity = false;
bool velocityMode = false;


MIDI_Gate() { MIDI_Gate() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -76,7 +74,7 @@ struct MIDI_Gate : Module {


for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (gateTimes[i] > 0.f) { if (gateTimes[i] > 0.f) {
outputs[TRIG_OUTPUT + i].setVoltage(velocity ? rescale(velocities[i], 0, 127, 0.f, 10.f) : 10.f);
outputs[TRIG_OUTPUT + i].setVoltage(velocityMode ? rescale(velocities[i], 0, 127, 0.f, 10.f) : 10.f);
// If the gate is off, wait 1 ms before turning the pulse off. // If the gate is off, wait 1 ms before turning the pulse off.
// This avoids drum controllers sending a pulse with 0 ms duration. // This avoids drum controllers sending a pulse with 0 ms duration.
if (!gates[i]) { if (!gates[i]) {
@@ -119,8 +117,9 @@ struct MIDI_Gate : Module {
} }
json_object_set_new(rootJ, "notes", notesJ); json_object_set_new(rootJ, "notes", notesJ);


json_object_set_new(rootJ, "velocity", json_boolean(velocityMode));

json_object_set_new(rootJ, "midi", midiInput.toJson()); json_object_set_new(rootJ, "midi", midiInput.toJson());
json_object_set_new(rootJ, "velocity", json_boolean(velocity));
return rootJ; return rootJ;
} }


@@ -134,74 +133,13 @@ struct MIDI_Gate : Module {
} }
} }


json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ)
midiInput.fromJson(midiJ);

json_t *velocityJ = json_object_get(rootJ, "velocity"); json_t *velocityJ = json_object_get(rootJ, "velocity");
if (velocityJ) if (velocityJ)
velocity = json_boolean_value(velocityJ);
}
};


struct MidiTrigChoice : GridChoice {
MIDI_Gate *module;
int id;

MidiTrigChoice() {
box.size.y = mm2px(6.666);
textOffset.y -= 4;
textOffset.x -= 4;
}

void setId(int id) override {
this->id = id;
}

void step() override {
if (!module)
return;
if (module->learningId == id) {
text = "LRN";
color.a = 0.5;
}
else {
uint8_t note = module->learnedNotes[id];
static const char *noteNames[] = {
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
};
int oct = note / 12 - 1;
int semi = note % 12;
text = string::f("%s%d", noteNames[semi], oct);
color.a = 1.0;

if (app()->event->selectedWidget == this)
app()->event->selectedWidget = NULL;
}
}

void onSelect(const event::Select &e) override {
e.consume(this);
if (!module)
return;
module->learningId = id;
}
velocityMode = json_boolean_value(velocityJ);


void onDeselect(const event::Deselect &e) override {
if (!module)
return;
module->learningId = -1;
}
};


struct MidiTrigWidget : Grid16MidiWidget {
MIDI_Gate *module;
GridChoice *createGridChoice() override {
MidiTrigChoice *gridChoice = new MidiTrigChoice;
gridChoice->module = module;
return gridChoice;
json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ)
midiInput.fromJson(midiJ);
} }
}; };


@@ -233,12 +171,12 @@ struct MIDI_GateWidget : ModuleWidget {
addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 14)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 14));
addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 15)); addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 15));


MidiTrigWidget *midiWidget = createWidget<MidiTrigWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->module = module;
typedef Grid16MidiWidget<NoteChoice<MIDI_Gate>> TMidiWidget;
TMidiWidget *midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->box.size = mm2px(Vec(44, 54.667)); midiWidget->box.size = mm2px(Vec(44, 54.667));
if (module) if (module)
midiWidget->midiIO = &module->midiInput; midiWidget->midiIO = &module->midiInput;
midiWidget->createGridChoices();
midiWidget->setModule(module);
addChild(midiWidget); addChild(midiWidget);
} }


@@ -248,12 +186,12 @@ struct MIDI_GateWidget : ModuleWidget {
struct VelocityItem : MenuItem { struct VelocityItem : MenuItem {
MIDI_Gate *module; MIDI_Gate *module;
void onAction(const event::Action &e) override { void onAction(const event::Action &e) override {
module->velocity ^= true;
module->velocityMode ^= true;
} }
}; };


menu->addChild(new MenuEntry); menu->addChild(new MenuEntry);
VelocityItem *velocityItem = createMenuItem<VelocityItem>("Velocity", CHECKMARK(module->velocity));
VelocityItem *velocityItem = createMenuItem<VelocityItem>("Velocity", CHECKMARK(module->velocityMode));
velocityItem->module = module; velocityItem->module = module;
menu->addChild(velocityItem); menu->addChild(velocityItem);
} }


Loading…
Cancel
Save