source: buchla-emu/emu/mid.c @ 77d8df8

Last change on this file since 77d8df8 was 77d8df8, checked in by Alexander Heinrich <alex.heinrich@…>, 21 months ago

Add CLI option for selecting MIDI ports.

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 *  Copyright (C) 2017 The Contributors
3 *
4 *  This program is free software: you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation, either version 3 of the License, or (at
7 *  your option) any later version.
8 *
9 *  This program is distributed in the hope that it will be useful, but
10 *  WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 *  General Public License for more details.
13 *
14 *  A copy of the GNU General Public License can be found in the file
15 *  "gpl.txt" in the top directory of this repository.
16 */
17
18#include <all.h>
19#include <rtmidi/rtmidi_c.h>
20
21#define ver(...) _ver(mid_verbose, 0, __VA_ARGS__)
22#define ver2(...) _ver(mid_verbose, 1, __VA_ARGS__)
23#define ver3(...) _ver(mid_verbose, 2, __VA_ARGS__)
24
25#define REG_IER_ISR 0
26#define REG_CFR_SR  1
27#define REG_CDR_TBR 2
28#define REG_TDR_RDR 3
29
30#define BUF_SZ 256
31
32typedef struct {
33        int32_t buf_hd;
34        int32_t buf_tl;
35        uint8_t buf[BUF_SZ];
36        bool irq_r;
37        bool irq_t;
38        bool rdr_ok;
39        uint8_t rdr;
40} state_t;
41
42static state_t state[] = {
43        { .buf_hd = 0, .buf_tl = 0, .irq_r = false, .irq_t = false, .rdr_ok = false, .rdr = 0x00 },
44        { .buf_hd = 0, .buf_tl = 0, .irq_r = false, .irq_t = false, .rdr_ok = false, .rdr = 0x00 }
45};
46
47int32_t mid_verbose = 0;
48
49struct RtMidiWrapper* mid_in;
50
51static void xmit(int32_t un)
52{
53        int32_t i = state[un].buf_tl;
54        ver2("mid xmit %d %d", i, state[un].buf_hd);
55
56        if (i >= state[un].buf_hd) {
57                return;
58        }
59
60        uint8_t byte = state[un].buf[i % BUF_SZ];
61        ver2("mid xmit 0x%02x", byte);
62
63        state[un].rdr = byte;
64        state[un].rdr_ok = true;
65        state[un].irq_r = true;
66
67        state[un].buf_tl = i + 1;
68
69        if (state[un].buf_tl >= BUF_SZ) {
70                state[un].buf_hd -= BUF_SZ;
71                state[un].buf_tl -= BUF_SZ;
72                ver2("mid adj %d %d", state[un].buf_tl, state[un].buf_hd);
73        }
74}
75
76static void out_lk(int32_t un, uint8_t c)
77{
78        int32_t i = state[un].buf_hd;
79        ver2("mid out %d %d 0x%02x", state[un].buf_tl, i, c);
80
81        if (i >= state[un].buf_tl + BUF_SZ) {
82                err("midi port %d losing data", un);
83                return;
84        }
85
86        state[un].buf[i % BUF_SZ] = c;
87        state[un].buf_hd = i + 1;
88
89        if (!state[un].irq_r && !state[un].rdr_ok) {
90                xmit(un);
91        }
92}
93
94static void out(int32_t un, uint8_t c)
95{
96        if (SDL_LockMutex(cpu_mutex) < 0) {
97                fail("SDL_LockMutex() failed: %s", SDL_GetError());
98        }
99
100        out_lk(un, c);
101
102        if (SDL_UnlockMutex(cpu_mutex) < 0) {
103                fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
104        }
105}
106
107static void mid_callback(double timeStamp, const unsigned char* message, size_t size, void *userData) {
108        (void) size;
109        (void) userData;
110
111        ver2("Timestamp %f\n", timeStamp);
112
113        for (uint8_t i = 0; i < sizeof(message); i++) {
114                ver2("Message %i %u", i, (uint8_t) message[i]);
115                out(0, message[i]);
116        }
117}
118
119void mid_init(void)
120{
121        ver("mid init");
122
123        mid_in = rtmidi_in_create_default();
124        ver2("%p", mid_in->ptr);
125        // check if null
126
127        uint32_t portcount = rtmidi_get_port_count(mid_in);
128        if (portcount == 0) {
129                mid_in = NULL;
130                ver2("No MIDI ports\n");
131                return;
132        }
133
134        if (mid_port > portcount) {
135                mid_in = NULL;
136                ver2("Selected MIDI port larger than number of midi ports");
137                return;
138        }
139
140        rtmidi_open_port(mid_in, mid_port, rtmidi_get_port_name(mid_in, mid_port));
141
142        if(mid_in->ok == 0) {
143                fail("Failed to open MIDI port");
144        }
145
146        ver2("Using MIDI port %u", mid_port);
147
148        rtmidi_in_set_callback(mid_in, mid_callback, mid_in->data);
149
150        if(mid_in->ok == 0) {
151                fail("Failed to set MIDI Callback");
152        }
153}
154
155void mid_quit(void)
156{
157        if(mid_in) {
158                rtmidi_close_port(mid_in);
159                rtmidi_in_free(mid_in);
160        }
161
162        ver("mid quit");
163}
164
165bool mid_exec(void)
166{
167        ver3("mid exec");
168        return state[0].irq_r || state[0].irq_t || state[1].irq_r || state[1].irq_t;
169}
170
171uint32_t mid_read(uint32_t off, int32_t sz)
172{
173        ver2("mid rd %u:%d", off, sz * 8);
174
175        if (sz != 1 || off > 7) {
176                fail("invalid mid rd %u:%d", off, sz * 8);
177        }
178
179        int32_t rg = (int32_t)(off % 4);
180        int32_t un = (int32_t)(off / 4);
181
182        uint32_t rv;
183
184        switch (rg) {
185        case REG_IER_ISR:
186                rv = (uint32_t)(0xc0 | (state[un].rdr_ok ? 0x01 : 0x00));
187                state[un].irq_r = false;
188                state[un].irq_t = false;
189                ver2("ISR[%d] 0x%02x", un, rv);
190                break;
191
192        case REG_TDR_RDR:
193                rv = state[un].rdr;
194                state[un].rdr_ok = false;
195                ver2("RDR[%d] 0x%02x", un, rv);
196                break;
197
198        default:
199                rv = 0x00;
200                break;
201        }
202
203        if (!state[un].irq_r && !state[un].rdr_ok) {
204                xmit(un);
205        }
206
207        return rv;
208}
209
210void mid_write(uint32_t off, int32_t sz, uint32_t val)
211{
212        ver2("mid wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
213
214        if (sz != 1 || off > 7) {
215                fail("invalid mid wr %u:%d", off, sz * 8);
216        }
217
218        int32_t rg = (int32_t)(off % 4);
219        int32_t un = (int32_t)(off / 4);
220
221        switch (rg) {
222        case REG_CFR_SR:
223                ver2("CFR[%d] 0x%02x", un, val);
224
225                if (un == 1) {
226                        fdd_set_side((int32_t)val & 0x01);
227                }
228                else {
229                        fdd_set_sel((int32_t)val & 0x01);
230                }
231
232                break;
233
234        default:
235                break;
236        }
237}
238
239void mid_list(void) {
240        mid_in = rtmidi_in_create_default();
241
242        uint32_t portcount = rtmidi_get_port_count(mid_in);
243
244        if (portcount == 0) {
245                mid_in = NULL;
246                ver2("no MIDI ports\n");
247                return;
248        }
249
250        fprintf(stdout, "the following MIDI ports are available:\n");
251
252        for (uint32_t i = 0; i < portcount; i++) {
253                fprintf(stdout, "port %d: %s\n", i, rtmidi_get_port_name(mid_in, i));
254        }
255
256        rtmidi_in_free(mid_in);
257}
Note: See TracBrowser for help on using the repository browser.