1#include <stdio.h>
  2#include <stdlib.h>
  3#include <alloca.h>
  4#include <unistd.h>
  5#include <alsa/asoundlib.h>
  6
  7#include "midi.h"
  8#include "mutex.h"
  9#include "termbox2.h"
 10
 11static snd_seq_t *seq_handle;
 12static snd_seq_addr_t *ports;
 13
 14void *midi(void *arg) {
 15	MidiArgs* args = (MidiArgs*)arg;
 16
 17	if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
 18		fprintf(stderr, "Error opening ALSA sequencer.\n");
 19		exit(1);
 20	}
 21
 22	if (snd_seq_set_client_name(seq_handle, CLIENT_NAME) < 0) {
 23		fprintf(stderr, "Could not set up client name.\n");
 24		exit(1);
 25	}
 26
 27	if (snd_seq_create_simple_port(seq_handle, CLIENT_NAME,
 28				SND_SEQ_PORT_CAP_WRITE |
 29				SND_SEQ_PORT_CAP_SUBS_WRITE,
 30				SND_SEQ_PORT_TYPE_MIDI_GENERIC |
 31				SND_SEQ_PORT_TYPE_APPLICATION) < 0) {
 32		fprintf(stderr, "Error creating sequencer port.\n");
 33		exit(1);
 34	}
 35
 36	// Connecting ports.
 37	ports = realloc(ports, MAX_MIDI_PORTS * sizeof(snd_seq_addr_t));
 38	if (snd_seq_parse_address(seq_handle, &ports[0], args->port_name) < 0) {
 39		fprintf(stderr, "Invalid port %s.\n", args->port_name);
 40		exit(1);
 41	}
 42
 43	// Listing assigned ports.
 44	/* fprintf(stdout, "Ports:\n"); */
 45	/* for (int j = 0; j < MAX_MIDI_PORTS; j++) { */
 46	/* 	fprintf(stdout, " client: %d, port: %d\n", ports[j].client, ports[j].port); */
 47	/* } */
 48
 49	// Connecting ports.
 50	for (int i = 0; i < MAX_MIDI_PORTS; ++i) {
 51		int err = snd_seq_connect_from(seq_handle, 0, ports[i].client, ports[i].port);
 52		if (err < 0) {
 53			fprintf(stderr, "Cannot connect from port %d:%d - %s", ports[i].client, ports[i].port, snd_strerror(err));
 54			exit(1);
 55		}
 56	}
 57
 58	if (snd_seq_nonblock(seq_handle, 1) < 0) {
 59		fprintf(stderr, "Set nonblock mode failed.");
 60		exit(1);
 61	}
 62
 63	// Reading MIDI device.
 64	struct pollfd *pfds;
 65	size_t npfds;
 66
 67	npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
 68	pfds = alloca(sizeof(*pfds) * npfds);
 69
 70	for (;;) {
 71		snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN);
 72		if (poll(pfds, npfds, -1) < 0) {
 73			break;
 74		}
 75
 76		for (;;) {
 77			snd_seq_event_t *ev;
 78
 79			if (snd_seq_event_input(seq_handle, &ev) < 0) {
 80				break;
 81			}
 82
 83			if (ev) {
 84				pthread_mutex_lock(&mutex);
 85				switch (ev->type) {
 86					case SND_SEQ_EVENT_NOTEON:
 87						shared_data.note = ev->data.note.note;
 88						shared_data.state = 1;
 89						shared_data.velocity = ev->data.note.velocity;
 90						tb_printf(0, 3, TB_CYAN, 0, "Note: %-3d", ev->data.note.note);
 91						tb_printf(0, 4, TB_CYAN, 0, "Velocity: %-3d", ev->data.note.velocity);
 92						tb_present();
 93						/* printf("%3d:%-3dNote on  %2d, note %d, velocity: %3d\n", */
 94						/* 		ev->source.client, ev->source.port, */
 95						/* 		ev->data.note.channel, */
 96						/* 		ev->data.note.note, */
 97						/* 		ev->data.note.velocity); */
 98						break;
 99
100					case SND_SEQ_EVENT_NOTEOFF:
101						shared_data.note = ev->data.note.note;
102						shared_data.state = 0;
103						shared_data.velocity = 0;
104						/* printf("%3d:%-3dNote off\t%2d, note %d\n", */
105						/* 		ev->source.client, ev->source.port, */
106						/* 		ev->data.note.channel, */
107						/* 		ev->data.note.note); */
108						break;
109
110
111				}
112
113				shared_data.action = 1;
114
115				pthread_cond_signal(&cond_synth);
116				pthread_mutex_unlock(&mutex);
117			}
118		}
119
120		fflush(stdout);
121	}
122}
123