You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.2 KiB
141 lines
3.2 KiB
|
|
#include <cassert> |
|
#include <cmath> |
|
#include <string> |
|
|
|
#include "midi.h" |
|
|
|
|
|
// forward declarations |
|
|
|
bool parseDeviceStr(snd_seq_addr_t& src, const char* midi_device); |
|
|
|
|
|
// interface |
|
|
|
bool |
|
midiOpen(alsa_sequencer* seq) |
|
{ |
|
if (snd_seq_open(&seq->seq_handle, "default", SND_SEQ_OPEN_INPUT, 0)) { |
|
printf("Could not open sequencer\n"); |
|
return false; |
|
} |
|
|
|
if (snd_seq_set_client_name(seq->seq_handle, "midi_to_cv")) { |
|
printf("Could not set client name\n"); |
|
return false; |
|
} |
|
|
|
seq->dest.client = snd_seq_client_id(seq->seq_handle); |
|
seq->dest.port = snd_seq_create_simple_port(seq->seq_handle, |
|
"listen:in", |
|
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, |
|
SND_SEQ_PORT_TYPE_APPLICATION); |
|
|
|
if (seq->dest.port < 0) { |
|
printf("Could not open port\n"); |
|
return false; |
|
} |
|
|
|
printf("host client id: %d, host port: %d\n", seq->dest.client, seq->dest.port); |
|
|
|
return true; |
|
} |
|
|
|
bool |
|
midiConnect(alsa_sequencer* seq, const char* midi_device) |
|
{ |
|
if (!parseDeviceStr(seq->src, midi_device)) { |
|
printf("invalid device string\n"); |
|
return false; |
|
} |
|
|
|
snd_seq_port_subscribe_malloc(&seq->subscription); |
|
snd_seq_port_subscribe_set_sender(seq->subscription, &seq->src); |
|
snd_seq_port_subscribe_set_dest(seq->subscription, &seq->dest); |
|
snd_seq_port_subscribe_set_queue(seq->subscription, 1); |
|
snd_seq_port_subscribe_set_time_update(seq->subscription, 1); |
|
snd_seq_port_subscribe_set_time_real(seq->subscription, 1); |
|
|
|
if (snd_seq_subscribe_port(seq->seq_handle, seq->subscription) == 0) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
alsa_note_event |
|
midiProcess(const snd_seq_event_t* ev) |
|
{ |
|
assert(ev != nullptr); |
|
alsa_note_event nev = {0}; |
|
|
|
if((ev->type == SND_SEQ_EVENT_NOTEON) || |
|
(ev->type == SND_SEQ_EVENT_NOTEOFF)) |
|
{ |
|
const char *type = (ev->type==SND_SEQ_EVENT_NOTEON) ? "on " : "off"; |
|
printf("[%d] Note %s: %d, 0x%2x vel(%2x), channel: %d\n", |
|
ev->time.tick, |
|
type, |
|
ev->data.note.note, |
|
ev->data.note.note, |
|
ev->data.note.velocity, |
|
ev->data.note.channel); |
|
|
|
nev.note = ev->data.note.note; |
|
nev.channel = ev->data.note.channel; |
|
nev.note_on = (ev->type == SND_SEQ_EVENT_NOTEON) ? true : false; |
|
} |
|
else if(ev->type == SND_SEQ_EVENT_CONTROLLER) |
|
{ |
|
printf("[%d] Control: 0x%2x val(%2x)\n", |
|
ev->time.tick, |
|
ev->data.control.param, |
|
ev->data.control.value); |
|
} |
|
else |
|
{ |
|
printf("[%d] Unknown: Unhandled Event Received\n", ev->time.tick); |
|
} |
|
|
|
return nev; |
|
} |
|
|
|
i32 |
|
midiClose(alsa_sequencer* seq) |
|
{ |
|
snd_seq_port_subscribe_free(seq->subscription); |
|
return snd_seq_close(seq->seq_handle); |
|
} |
|
|
|
|
|
// internal |
|
|
|
bool |
|
parseDeviceStr(snd_seq_addr_t& src, const char* midi_device) |
|
{ |
|
// NOTE: midi_device should be in the form 'client:port', where each number |
|
// is an unsigned char. So max string length is 'xxx:xxx" = 7 |
|
std::string s(midi_device); |
|
|
|
if (s.size() > 0 && s.size() < 8) { |
|
u32 split = s.find(':'); |
|
|
|
if (split > 0 && split != std::string::npos) { |
|
std::string sub1 = s.substr(0, split); |
|
std::string sub2 = s.substr(split + 1, s.size()); |
|
|
|
u32 client= strtoul(sub1.c_str(), nullptr, 10); |
|
u32 port = strtoul(sub2.c_str(), nullptr, 10); |
|
|
|
if (errno == 0 && client > 0 && client < 256 && port >= 0 && port < 256) |
|
{ |
|
src.client = client; |
|
src.port = port; |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|