|
|
@@ -1,28 +1,14 @@ |
|
|
|
#include <assert.h> |
|
|
|
#include <list> |
|
|
|
#include <algorithm> |
|
|
|
#include <portmidi.h> |
|
|
|
#include <rtmidi/RtMidi.h> |
|
|
|
#include "core.hpp" |
|
|
|
#include "gui.hpp" |
|
|
|
#include "../../include/engine.hpp" |
|
|
|
|
|
|
|
|
|
|
|
using namespace rack; |
|
|
|
|
|
|
|
static bool initialized = false; |
|
|
|
|
|
|
|
void midiInit() { |
|
|
|
if (initialized) |
|
|
|
return; |
|
|
|
|
|
|
|
PmError err = Pm_Initialize(); |
|
|
|
if (err) { |
|
|
|
printf("Failed to initialize PortMidi: %s\n", Pm_GetErrorText(err)); |
|
|
|
return; |
|
|
|
} |
|
|
|
initialized = true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct MidiInterface : Module { |
|
|
|
enum ParamIds { |
|
|
|
NUM_PARAMS |
|
|
@@ -39,7 +25,7 @@ struct MidiInterface : Module { |
|
|
|
}; |
|
|
|
|
|
|
|
int portId = -1; |
|
|
|
PortMidiStream *stream = NULL; |
|
|
|
RtMidiIn *midiIn = NULL; |
|
|
|
std::list<int> notes; |
|
|
|
/** Filter MIDI channel |
|
|
|
-1 means all MIDI channels |
|
|
@@ -53,8 +39,13 @@ struct MidiInterface : Module { |
|
|
|
bool retriggered = false; |
|
|
|
|
|
|
|
MidiInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { |
|
|
|
midiInit(); |
|
|
|
} |
|
|
|
try { |
|
|
|
midiIn = new RtMidiIn(); |
|
|
|
} |
|
|
|
catch ( RtMidiError &error ) { |
|
|
|
fprintf(stderr,"Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); |
|
|
|
} |
|
|
|
} |
|
|
|
~MidiInterface() { |
|
|
|
setPortId(-1); |
|
|
|
} |
|
|
@@ -70,7 +61,7 @@ struct MidiInterface : Module { |
|
|
|
} |
|
|
|
void pressNote(int note); |
|
|
|
void releaseNote(int note); |
|
|
|
void processMidi(long msg); |
|
|
|
void processMidi(std::vector<unsigned char> msg); |
|
|
|
|
|
|
|
json_t *toJson() { |
|
|
|
json_t *rootJ = json_object(); |
|
|
@@ -107,12 +98,15 @@ struct MidiInterface : Module { |
|
|
|
|
|
|
|
|
|
|
|
void MidiInterface::step() { |
|
|
|
if (stream) { |
|
|
|
// Read MIDI events |
|
|
|
PmEvent event; |
|
|
|
while (Pm_Read(stream, &event, 1) > 0) { |
|
|
|
processMidi(event.message); |
|
|
|
} |
|
|
|
if (midiIn->isPortOpen()) { |
|
|
|
std::vector<unsigned char> message; |
|
|
|
|
|
|
|
// midiIn->getMessage returns empty vector if there are no messages in the queue |
|
|
|
double stamp = midiIn->getMessage( &message ); |
|
|
|
while(message.size() > 0){ |
|
|
|
processMidi(message); |
|
|
|
stamp = midiIn->getMessage( &message ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
outputs[PITCH_OUTPUT].value = ((note - 60)) / 12.0; |
|
|
@@ -128,36 +122,30 @@ void MidiInterface::step() { |
|
|
|
} |
|
|
|
|
|
|
|
int MidiInterface::getPortCount() { |
|
|
|
return Pm_CountDevices(); |
|
|
|
return midiIn->getPortCount(); |
|
|
|
} |
|
|
|
|
|
|
|
std::string MidiInterface::getPortName(int portId) { |
|
|
|
const PmDeviceInfo *info = Pm_GetDeviceInfo(portId); |
|
|
|
if (!info) |
|
|
|
return ""; |
|
|
|
return stringf("%s: %s (%s)", info->interf, info->name, info->input ? "input" : "output"); |
|
|
|
std::string portName; |
|
|
|
try { |
|
|
|
portName = midiIn->getPortName(portId); |
|
|
|
} |
|
|
|
catch ( RtMidiError &error ) { |
|
|
|
fprintf(stderr, "Failed to get Port Name: %d, %s\n", portId, error.getMessage().c_str()); |
|
|
|
} |
|
|
|
return portName; |
|
|
|
} |
|
|
|
|
|
|
|
void MidiInterface::setPortId(int portId) { |
|
|
|
PmError err; |
|
|
|
|
|
|
|
// Close existing port |
|
|
|
if (stream) { |
|
|
|
err = Pm_Close(stream); |
|
|
|
if (err) { |
|
|
|
printf("Failed to close MIDI port: %s\n", Pm_GetErrorText(err)); |
|
|
|
} |
|
|
|
stream = NULL; |
|
|
|
// Close port if it was previously opened |
|
|
|
if (midiIn->isPortOpen()) { |
|
|
|
midiIn->closePort(); |
|
|
|
} |
|
|
|
this->portId = -1; |
|
|
|
|
|
|
|
// Open new port |
|
|
|
if (portId >= 0) { |
|
|
|
err = Pm_OpenInput(&stream, portId, NULL, 128, NULL, NULL); |
|
|
|
if (err) { |
|
|
|
printf("Failed to open MIDI port: %s\n", Pm_GetErrorText(err)); |
|
|
|
return; |
|
|
|
} |
|
|
|
midiIn->openPort(portId); |
|
|
|
} |
|
|
|
this->portId = portId; |
|
|
|
} |
|
|
@@ -191,12 +179,13 @@ void MidiInterface::releaseNote(int note) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void MidiInterface::processMidi(long msg) { |
|
|
|
int channel = msg & 0xf; |
|
|
|
int status = (msg >> 4) & 0xf; |
|
|
|
int data1 = (msg >> 8) & 0xff; |
|
|
|
int data2 = (msg >> 16) & 0xff; |
|
|
|
// printf("channel %d status %d data1 %d data2 %d\n", channel, status, data1, data2); |
|
|
|
void MidiInterface::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) |
|
|
@@ -238,7 +227,7 @@ struct MidiItem : MenuItem { |
|
|
|
MidiInterface *midiInterface; |
|
|
|
int portId; |
|
|
|
void onAction() { |
|
|
|
midiInterface->setPortId(portId); |
|
|
|
midiInterface->setPortId(portId); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|