source: buchla-emu/emu/mid.c@ 379ffd9

Last change on this file since 379ffd9 was 379ffd9, checked in by Alexander Heinrich <alex.heinrich@…>, 6 years ago

Correct parameters of midi callback.

  • Property mode set to 100644
File size: 4.7 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* midiin;
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 midi_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 midiin = rtmidi_in_create_default();
124 ver2("%p", midiin->ptr);
125 // check if null
126 uint32_t portcount = rtmidi_get_port_count(midiin);
127 ver2("%d", midiin->ok);
128
129 if (portcount == 0) {
130 midiin = NULL;
131 ver2("no midi ports\n");
132 return;
133 }
134
135 for (uint32_t i = 0; i < portcount; i++) {
136 ver2("Port %d: %s", i, rtmidi_get_port_name(midiin, i));
137 }
138
139 rtmidi_open_port(midiin, 0, rtmidi_get_port_name(midiin, 0));
140 if(!midiin->ok) {
141 fail("Failed to open Midi port");
142 }
143
144 rtmidi_in_set_callback(midiin, midi_callback, midiin->data);
145 if(!midiin->ok) {
146 fail("Failed to set Midi Callback");
147 }
148}
149
150void mid_quit(void)
151{
152 if(midiin) {
153 rtmidi_close_port(midiin);
154 rtmidi_in_free(midiin);
155 }
156
157 ver("mid quit");
158}
159
160bool mid_exec(void)
161{
162 ver3("mid exec");
163 return state[0].irq_r || state[0].irq_t || state[1].irq_r || state[1].irq_t;
164}
165
166uint32_t mid_read(uint32_t off, int32_t sz)
167{
168 ver2("mid rd %u:%d", off, sz * 8);
169
170 if (sz != 1 || off > 7) {
171 fail("invalid mid rd %u:%d", off, sz * 8);
172 }
173
174 int32_t rg = (int32_t)(off % 4);
175 int32_t un = (int32_t)(off / 4);
176
177 uint32_t rv;
178
179 switch (rg) {
180 case REG_IER_ISR:
181 rv = (uint32_t)(0xc0 | (state[un].rdr_ok ? 0x01 : 0x00));
182 state[un].irq_r = false;
183 state[un].irq_t = false;
184 ver2("ISR[%d] 0x%02x", un, rv);
185 break;
186
187 case REG_TDR_RDR:
188 rv = state[un].rdr;
189 state[un].rdr_ok = false;
190 ver2("RDR[%d] 0x%02x", un, rv);
191 break;
192
193 default:
194 rv = 0x00;
195 break;
196 }
197
198 if (!state[un].irq_r && !state[un].rdr_ok) {
199 xmit(un);
200 }
201
202 return rv;
203}
204
205void mid_write(uint32_t off, int32_t sz, uint32_t val)
206{
207 ver2("mid wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
208
209 if (sz != 1 || off > 7) {
210 fail("invalid mid wr %u:%d", off, sz * 8);
211 }
212
213 int32_t rg = (int32_t)(off % 4);
214 int32_t un = (int32_t)(off / 4);
215
216 switch (rg) {
217 case REG_CFR_SR:
218 ver2("CFR[%d] 0x%02x", un, val);
219
220 if (un == 1) {
221 fdd_set_side((int32_t)val & 0x01);
222 }
223 else {
224 fdd_set_sel((int32_t)val & 0x01);
225 }
226
227 break;
228
229 default:
230 break;
231 }
232}
Note: See TracBrowser for help on using the repository browser.