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