Browse Source

Add CV functionality to MIDI to CV interface

tags/v0.6.0
Andrew Belt 7 years ago
parent
commit
13fe861ddd
4 changed files with 82 additions and 90 deletions
  1. +1
    -1
      include/util/common.hpp
  2. +69
    -86
      src/Core/MIDIToCVInterface.cpp
  3. +1
    -1
      src/audio.cpp
  4. +11
    -2
      src/midi.cpp

+ 1
- 1
include/util/common.hpp View File

@@ -74,7 +74,7 @@ T *construct(F f, V v, Args... args) {
return o;
}

/** Delays code until the scope is destructed
/** Defers code until the scope is destructed
From http://www.gingerbill.org/article/defer-in-cpp.html

Example:


+ 69
- 86
src/Core/MIDIToCVInterface.cpp View File

@@ -2,6 +2,8 @@
#include "midi.hpp"
#include "dsp/filter.hpp"

#include <algorithm>


struct MidiNoteData {
uint8_t velocity;
@@ -41,62 +43,78 @@ struct MIDIToCVInterface : Module {
ExponentialFilter modFilter;
uint16_t pitch = 0;
ExponentialFilter pitchFilter;
bool pedal = false;

MidiNoteData noteData[128];
std::list<uint8_t> heldNotes;
uint8_t lastNote = 60;
bool gate = false;

MIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}

void onReset() override {
heldNotes.clear();
pedal = false;
}

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);
lastNote = note;
gate = true;
}

void releaseNote(uint8_t note) {
// Remove the note
if (note < 128) {
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
if (!heldNotes.empty()) {
auto it2 = heldNotes.end();
it2--;
lastNote = *it2;
gate = true;
}
else {
gate = false;
}
}

void pressPedal() {
pedal = true;
}

void releasePedal() {
pedal = false;
releaseNote(255);
}

void step() override {
MidiMessage msg;
while (midiInput.shift(&msg)) {
processMessage(msg);
}

outputs[CV_OUTPUT].value = (lastNote - 60) / 12.f;
outputs[GATE_OUTPUT].value = gate ? 10.f : 0.f;
outputs[VELOCITY_OUTPUT].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f);
modFilter.lambda = 100.f * engineGetSampleTime();
outputs[MOD_OUTPUT].value = modFilter.process(rescale(mod, 0, 127, 0.f, 10.f));

pitchFilter.lambda = 100.f * engineGetSampleTime();
outputs[PITCH_OUTPUT].value = pitchFilter.process(rescale(pitch, 0, 16384, -5.f, 5.f));

/*
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);
}
}

outputs[PITCH_OUTPUT].value = ((note - 60)) / 12.0;

if (resetTrigger.process(params[RESET_PARAM].value)) {
resetMidi();
return;
}

lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / 0.55 / engineGetSampleRate(); // fade out light

outputs[GATE_OUTPUT].value = gate ? 10.0 : 0.0;
outputs[VELOCITY_OUTPUT].value = vel / 127.0 * 10.0;

int steps = int(engineGetSampleRate() / 32);

if (mod.changed) {
mod.tSmooth.set(outputs[MOD_OUTPUT].value, (mod.val / 127.0 * 10.0), steps);
mod.changed = false;
}
outputs[MOD_OUTPUT].value = mod.tSmooth.next();

if (pitchWheel.changed) {
pitchWheel.tSmooth.set(outputs[PITCHWHEEL_OUTPUT].value, (pitchWheel.val - 64) / 64.0 * 10.0, steps);
pitchWheel.changed = false;
}
outputs[PITCHWHEEL_OUTPUT].value = pitchWheel.tSmooth.next();

outputs[CHANNEL_AFTERTOUCH_OUTPUT].value = afterTouch.val / 127.0 * 10.0;
*/
outputs[AFTERTOUCH_OUTPUT].value = rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f);
}

void processMessage(MidiMessage msg) {
@@ -105,21 +123,25 @@ struct MIDIToCVInterface : Module {
switch (msg.status()) {
// note off
case 0x8: {
// releaseNote(msg.data1);
releaseNote(msg.data1);
} break;
// note on
case 0x9: {
if (msg.data2 > 0) {
uint8_t note = msg.data1 & 0x7f;
noteData[note].velocity = msg.data2;
noteData[note].aftertouch = 0;
// pressNote(msg.data1);
pressNote(msg.data1);
}
else {
// For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released.
// releaseNote(msg.data1);
releaseNote(msg.data1);
}
} break;
// channel aftertouch
case 0xa: {
uint8_t note = msg.data1 & 0x7f;
noteData[note].aftertouch = msg.data2;
} break;
// cc
case 0xb: {
processCC(msg);
@@ -128,11 +150,6 @@ struct MIDIToCVInterface : Module {
case 0xe: {
pitch = msg.data2 * 128 + msg.data1;
} break;
// channel aftertouch
case 0xd: {
// TODO This is pressure, not aftertouch.
// aftertouch = rescale(msg.data1, 0.f, 128.f, 0.f, 10.f);
} break;
case 0xf: {
processSystem(msg);
} break;
@@ -148,10 +165,10 @@ struct MIDIToCVInterface : Module {
} break;
// sustain
case 0x40: {
// pedal = (msg.data2 >= 64);
// if (!pedal) {
// releaseNote(-1);
// }
if (msg.data2 >= 64)
pressPedal();
else
releasePedal();
} break;
default: break;
}
@@ -188,40 +205,6 @@ struct MIDIToCVInterface : Module {
};


/*
void MIDIToCVInterface::pressNote(int note) {
// Remove existing similar note
auto it = std::find(notes.begin(), notes.end(), note);
if (it != notes.end())
notes.erase(it);
// Push note
notes.push_back(note);
this->note = note;
gate = true;
}

void MIDIToCVInterface::releaseNote(int note) {
// Remove the note
auto it = std::find(notes.begin(), notes.end(), note);
if (it != notes.end())
notes.erase(it);

if (pedal) {
// Don't release if pedal is held
gate = true;
} else if (!notes.empty()) {
// Play previous note
auto it2 = notes.end();
it2--;
this->note = *it2;
gate = true;
} else {
gate = false;
}
}
*/


struct MIDIToCVInterfaceWidget : ModuleWidget {
MIDIToCVInterfaceWidget(MIDIToCVInterface *module) : ModuleWidget(module) {
setPanel(SVG::load(assetGlobal("res/Core/MIDIToCVInterface.svg")));


+ 1
- 1
src/audio.cpp View File

@@ -23,7 +23,7 @@ std::vector<int> AudioIO::getDrivers() {
std::vector<int> drivers;
for (RtAudio::Api api : apis)
drivers.push_back((int) api);
// Add Bridge fake driver
// Add fake Bridge driver
drivers.push_back(BRIDGE_DRIVER);
return drivers;
}


+ 11
- 2
src/midi.cpp View File

@@ -1,4 +1,8 @@
#include "midi.hpp"
#include "bridge.hpp"


#define BRIDGE_DRIVER -5000


namespace rack {
@@ -20,7 +24,8 @@ std::vector<int> MidiIO::getDrivers() {
for (RtMidi::Api api : rtApis) {
drivers.push_back((int) api);
}
// drivers.push_back(BRIDGE_DRIVER)
// Add fake Bridge driver
drivers.push_back(BRIDGE_DRIVER);
return drivers;
}

@@ -32,7 +37,7 @@ std::string MidiIO::getDriverName(int driver) {
case RtMidi::UNIX_JACK: return "JACK";
case RtMidi::WINDOWS_MM: return "Windows MIDI";
case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI";
// case BRIDGE_DRIVER: return "Bridge";
case BRIDGE_DRIVER: return "Bridge";
default: return "Unknown";
}
}
@@ -131,6 +136,10 @@ static void midiInputCallback(double timeStamp, std::vector<unsigned char> *mess
midiMessage.data1 = (*message)[1];
if (message->size() >= 3)
midiMessage.data2 = (*message)[2];

// Filter channel
if (midiInput->channel >= 0 && (midiMessage.channel() != midiInput->channel))
return;
midiInput->onMessage(midiMessage);
}



Loading…
Cancel
Save