112 lines
3.5 KiB
C
112 lines
3.5 KiB
C
#include "midi.h"
|
|
#include <stdio.h>
|
|
#include <poll.h>
|
|
#include <stdatomic.h>
|
|
#include <alloca.h>
|
|
|
|
extern atomic_int gRunning;
|
|
|
|
int midiInit(MidiState *m, Synth *synth)
|
|
{
|
|
if (snd_seq_open(&m->seq, "default", SND_SEQ_OPEN_INPUT | SND_SEQ_NONBLOCK, 0) < 0) {
|
|
fprintf(stderr, "Failed to open ALSA sequencer\n");
|
|
return 0;
|
|
}
|
|
snd_seq_nonblock(m->seq, 1);
|
|
snd_seq_set_client_name(m->seq, "soundThing");
|
|
m->client = snd_seq_client_id(m->seq);
|
|
m->port = snd_seq_create_simple_port(m->seq, "MIDI In",
|
|
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
|
|
SND_SEQ_PORT_TYPE_APPLICATION);
|
|
m->synth = synth;
|
|
return 1;
|
|
}
|
|
|
|
void midiListInputs(MidiState *m)
|
|
{
|
|
snd_seq_client_info_t *cinfo;
|
|
snd_seq_port_info_t *pinfo;
|
|
snd_seq_client_info_alloca(&cinfo);
|
|
snd_seq_port_info_alloca(&pinfo);
|
|
|
|
printf("\nAvailable MIDI inputs:\n");
|
|
snd_seq_client_info_set_client(cinfo, -1);
|
|
while (snd_seq_query_next_client(m->seq, cinfo) >= 0) {
|
|
int client = snd_seq_client_info_get_client(cinfo);
|
|
if (client == m->client) continue;
|
|
|
|
snd_seq_port_info_set_client(pinfo, client);
|
|
snd_seq_port_info_set_port(pinfo, -1);
|
|
while (snd_seq_query_next_port(m->seq, pinfo) >= 0) {
|
|
unsigned int caps = snd_seq_port_info_get_capability(pinfo);
|
|
if (caps & SND_SEQ_PORT_CAP_READ && caps & SND_SEQ_PORT_CAP_SUBS_READ) {
|
|
printf(" [%d:%d] %s — %s\n",
|
|
client,
|
|
snd_seq_port_info_get_port(pinfo),
|
|
snd_seq_client_info_get_name(cinfo),
|
|
snd_seq_port_info_get_name(pinfo));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void midiConnect(MidiState *m, int srcClient, int srcPort)
|
|
{
|
|
snd_seq_port_subscribe_t *sub;
|
|
snd_seq_addr_t sender, dest;
|
|
|
|
sender.client = srcClient;
|
|
sender.port = srcPort;
|
|
dest.client = m->client;
|
|
dest.port = m->port;
|
|
|
|
snd_seq_port_subscribe_alloca(&sub);
|
|
snd_seq_port_subscribe_set_sender(sub, &sender);
|
|
snd_seq_port_subscribe_set_dest(sub, &dest);
|
|
snd_seq_subscribe_port(m->seq, sub);
|
|
|
|
printf("Connected [%d:%d] to Cricket\n", srcClient, srcPort);
|
|
}
|
|
|
|
void midiClose(MidiState *m)
|
|
{
|
|
snd_seq_close(m->seq);
|
|
}
|
|
|
|
void *midiThread(void *arg)
|
|
{
|
|
MidiState *m = (MidiState *)arg;
|
|
struct pollfd pfd;
|
|
snd_seq_poll_descriptors(m->seq, &pfd, 1, POLLIN);
|
|
|
|
while (gRunning) {
|
|
int ready = poll(&pfd, 1, 50);
|
|
if (ready <= 0) continue;
|
|
|
|
snd_seq_event_t *ev = NULL;
|
|
while (snd_seq_event_input(m->seq, &ev) >= 0 && ev) {
|
|
switch (ev->type) {
|
|
case SND_SEQ_EVENT_NOTEON:
|
|
if (ev->data.note.velocity == 0)
|
|
synthNoteOff(m->synth, ev->data.note.note);
|
|
else
|
|
synthNoteOn(m->synth, ev->data.note.note);
|
|
break;
|
|
case SND_SEQ_EVENT_NOTEOFF:
|
|
synthNoteOff(m->synth, ev->data.note.note);
|
|
break;
|
|
case SND_SEQ_EVENT_CONTROLLER:
|
|
if (ev->data.control.param == 70)
|
|
m->synth->waveform = ev->data.control.value % WAVE_COUNT;
|
|
break;
|
|
case SND_SEQ_EVENT_PITCHBEND:
|
|
m->synth->pitchBend = ev->data.control.value / 8191.0f;
|
|
break;
|
|
}
|
|
snd_seq_free_event(ev);
|
|
ev = NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|