Browse Source

Merge branch 'dllmusic-patch-1'

tags/v0.6.0
Andrew Belt 7 years ago
parent
commit
bd43dd72d4
1 changed files with 132 additions and 38 deletions
  1. +132
    -38
      src/Core/QuadMIDIToCVInterface.cpp

+ 132
- 38
src/Core/QuadMIDIToCVInterface.cpp View File

@@ -1,5 +1,6 @@
#include "Core.hpp" #include "Core.hpp"
#include "midi.hpp" #include "midi.hpp"
#include "dsp/digital.hpp"


#include <algorithm> #include <algorithm>


@@ -26,6 +27,9 @@ struct QuadMIDIToCVInterface : Module {


enum PolyMode { enum PolyMode {
ROTATE_MODE, ROTATE_MODE,
// Added REUSE option that reuses a channel when receiving the same note.
// Good when using sustain pedal so it doesn't "stack" unisons ... not sure this is the best name but it is descriptive...
REUSE_MODE,
RESET_MODE, RESET_MODE,
REASSIGN_MODE, REASSIGN_MODE,
UNISON_MODE, UNISON_MODE,
@@ -39,13 +43,17 @@ struct QuadMIDIToCVInterface : Module {
}; };


NoteData noteData[128]; NoteData noteData[128];
std::vector<uint8_t> heldNotes;
// cachedNotes : UNISON_MODE and REASSIGN_MODE cache all played notes. The other polyModes cache stolen notes (after the 4th one).
std::vector<uint8_t> cachedNotes;
uint8_t notes[4]; uint8_t notes[4];
bool gates[4]; bool gates[4];
// gates set to TRUE by pedal and current gate. FALSE by pedal.
bool pedalgates[4];
bool pedal; bool pedal;
int rotateIndex; int rotateIndex;
int stealIndex;


QuadMIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS), heldNotes(128) {
QuadMIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS), cachedNotes(128) {
onReset(); onReset();
} }


@@ -70,71 +78,107 @@ struct QuadMIDIToCVInterface : Module {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
notes[i] = 60; notes[i] = 60;
gates[i] = false; gates[i] = false;
pedalgates[i] = false;
} }
pedal = false; pedal = false;
rotateIndex = 0;
rotateIndex = -1;
cachedNotes.clear();
} }


void pressNote(uint8_t note) {
// Remove existing similar note
auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
if (it != heldNotes.end())
heldNotes.erase(it);
// Push note
heldNotes.push_back(note);
int getPolyIndex(int nowIndex) {
for (int i = 0; i < 4; i++) {
nowIndex++;
if (nowIndex > 3)
nowIndex = 0;
if (!(gates[nowIndex] || pedalgates[nowIndex])) {
stealIndex = nowIndex;
return nowIndex;
}
}
// All taken = steal (stealIndex always rotates)
stealIndex++;
if (stealIndex > 3)
stealIndex = 0;
if ((polyMode < REASSIGN_MODE) && (gates[stealIndex]))
cachedNotes.push_back(notes[stealIndex]);
return stealIndex;
}


void pressNote(uint8_t note) {
// Set notes and gates // Set notes and gates
switch (polyMode) { switch (polyMode) {
case ROTATE_MODE: { case ROTATE_MODE: {
rotateIndex = getPolyIndex(rotateIndex);
} break; } break;


case RESET_MODE: {
case REUSE_MODE: {
bool reuse = false;
for (int i = 0; i < 4; i++) {
if (notes[i] == note) {
rotateIndex = i;
reuse = true;
break;
}
}
if (!reuse)
rotateIndex = getPolyIndex(rotateIndex);
} break;


case RESET_MODE: {
rotateIndex = getPolyIndex(-1);
} break; } break;


case REASSIGN_MODE: { case REASSIGN_MODE: {

cachedNotes.push_back(note);
rotateIndex = getPolyIndex(-1);
} break; } break;


case UNISON_MODE: { case UNISON_MODE: {
cachedNotes.push_back(note);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
notes[i] = note; notes[i] = note;
gates[i] = true; gates[i] = true;
pedalgates[i] = pedal;
// reTrigger[i].trigger(1e-3);
} }
return;
} break; } break;


default: break; default: break;
} }
// Set notes and gates
// if (gates[rotateIndex] || pedalgates[rotateIndex])
// reTrigger[rotateIndex].trigger(1e-3);
notes[rotateIndex] = note;
gates[rotateIndex] = true;
pedalgates[rotateIndex] = pedal;
} }


void releaseNote(uint8_t note) { void releaseNote(uint8_t note) {
// Remove the note // Remove the note
auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
if (it != heldNotes.end())
heldNotes.erase(it);
// Hold note if pedal is pressed
if (pedal)
return;
// Set last note
switch (polyMode) {
case ROTATE_MODE: {

} break;

case RESET_MODE: {

} break;
auto it = std::find(cachedNotes.begin(), cachedNotes.end(), note);
if (it != cachedNotes.end())
cachedNotes.erase(it);


switch (polyMode) {
case REASSIGN_MODE: { case REASSIGN_MODE: {

for (int i = 0; i < 4; i++) {
if (i < (int) cachedNotes.size()) {
if (!pedalgates[i])
notes[i] = cachedNotes[i];
pedalgates[i] = pedal;
}
else {
gates[i] = false;
}
}
} break; } break;


case UNISON_MODE: { case UNISON_MODE: {
if (!heldNotes.empty()) {
auto it2 = heldNotes.end();
it2--;
if (!cachedNotes.empty()) {
uint8_t backnote = cachedNotes.back();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
notes[i] = *it2;
notes[i] = backnote;
gates[i] = true; gates[i] = true;
} }
} }
@@ -145,18 +189,57 @@ struct QuadMIDIToCVInterface : Module {
} }
} break; } break;


default: break;
// default ROTATE_MODE REUSE_MODE RESET_MODE
default: {
for (int i = 0; i < 4; i++) {
if (notes[i] == note) {
if (pedalgates[i]) {
gates[i] = false;
}
else if (!cachedNotes.empty()) {
notes[i] = cachedNotes.back();
cachedNotes.pop_back();
}
else {
gates[i] = false;
}
}
}
} break;
} }

} }


void pressPedal() { void pressPedal() {
pedal = true; pedal = true;
for (int i = 0; i < 4; i++) {
pedalgates[i] = gates[i];
}
} }


void releasePedal() { void releasePedal() {
pedal = false; pedal = false;
releaseNote(255);
// When pedal is off, recover notes for pressed keys (if any) after they were already being "cycled" out by pedal-sustained notes.
for (int i = 0; i < 4; i++) {
pedalgates[i] = false;
if (!cachedNotes.empty()) {
if (polyMode < REASSIGN_MODE) {
notes[i] = cachedNotes.back();
cachedNotes.pop_back();
gates[i] = true;
}
}
}
if (polyMode == REASSIGN_MODE) {
for (int i = 0; i < 4; i++) {
if (i < (int) cachedNotes.size()) {
notes[i] = cachedNotes[i];
gates[i] = true;
}
else {
gates[i] = false;
}
}
}
} }


void step() override { void step() override {
@@ -167,14 +250,19 @@ struct QuadMIDIToCVInterface : Module {


for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
uint8_t lastNote = notes[i]; uint8_t lastNote = notes[i];
uint8_t lastGate = (gates[i] || pedalgates[i]);
outputs[CV_OUTPUT + i].value = (lastNote - 60) / 12.f; outputs[CV_OUTPUT + i].value = (lastNote - 60) / 12.f;
outputs[GATE_OUTPUT + i].value = gates[i] ? 10.f : 0.f;
outputs[GATE_OUTPUT + i].value = lastGate ? 10.f : 0.f;
outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f); outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f);
outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f);
outputs[AFTERTOUCH_OUTPUT + i].value = rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f);
} }
} }


void processMessage(MidiMessage msg) { void processMessage(MidiMessage msg) {
// filter MIDI channel
if ((midiInput.channel > -1) && (midiInput.channel != msg.channel()))
return;

switch (msg.status()) { switch (msg.status()) {
// note off // note off
case 0x8: { case 0x8: {
@@ -262,7 +350,13 @@ struct QuadMIDIToCVInterfaceWidget : ModuleWidget {


menu->addChild(MenuEntry::create()); menu->addChild(MenuEntry::create());
menu->addChild(MenuLabel::create("Polyphony mode")); menu->addChild(MenuLabel::create("Polyphony mode"));
std::vector<std::string> polyModeNames = {"Rotate", "Reset", "Reassign", "Unison"};
std::vector<std::string> polyModeNames = {
"Rotate",
"Reuse",
"Reset",
"Reassign",
"Unison"
};
for (int i = 0; i < QuadMIDIToCVInterface::NUM_MODES; i++) { for (int i = 0; i < QuadMIDIToCVInterface::NUM_MODES; i++) {
PolyphonyItem *item = MenuItem::create<PolyphonyItem>(polyModeNames[i], CHECKMARK(module->polyMode == i)); PolyphonyItem *item = MenuItem::create<PolyphonyItem>(polyModeNames[i], CHECKMARK(module->polyMode == i));
item->module = module; item->module = module;


Loading…
Cancel
Save