source: roaraudio/roard/midi.c @ 1853:345470a7b87b

Last change on this file since 1853:345470a7b87b was 1853:345470a7b87b, checked in by phi, 15 years ago

added struct g_midi_cb with all CB things

File size: 7.3 KB
Line 
1//midi.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "roard.h"
26
27#if defined(ROAR_HAVE_IO_POSIX) && !defined(ROAR_TARGET_WIN32)
28#define _HAVE_CONSOLE
29#endif
30
31int midi_init (void) {
32
33 if ( midi_cb_init() == -1 ) {
34  ROAR_WARN("Can not initialize MIDI subsystem component CB");
35 }
36
37 if ( midi_clock_init() == -1 ) {
38  ROAR_WARN("Can not initialize MIDI subsystem component clock");
39 }
40
41 return 0;
42}
43
44int midi_free (void) {
45 return midi_cb_free();
46}
47
48int midi_update(void) {
49
50 if ( g_midi_clock.stream != -1 )
51  midi_check_bridge(g_midi_clock.stream);
52
53 return midi_cb_update();
54}
55
56// STREAMS:
57
58int midi_check_stream  (int id) {
59 struct roar_stream        *   s;
60 struct roar_stream_server *  ss;
61
62 if ( g_streams[id] == NULL )
63  return -1;
64
65 ROAR_DBG("midi_check_stream(id=%i) = ?", id);
66
67 s = ROAR_STREAM(ss = g_streams[id]);
68
69 if ( s->dir == ROAR_DIR_BRIDGE )
70  return midi_check_bridge(id);
71
72 switch (s->info.codec) {
73  default:
74    streams_delete(id);
75    return -1;
76 }
77
78 return 0;
79}
80
81int midi_send_stream   (int id) {
82 struct roar_stream        *   s;
83 struct roar_stream_server *  ss;
84
85 if ( g_streams[id] == NULL )
86  return -1;
87
88 ROAR_DBG("midi_send_stream(id=%i) = ?", id);
89
90 s = ROAR_STREAM(ss = g_streams[id]);
91
92 switch (s->info.codec) {
93  default:
94    streams_delete(id);
95    return -1;
96 }
97
98 return 0;
99}
100
101// bridges:
102int midi_check_bridge  (int id) {
103
104 ROAR_WARN("midi_check_bridge(id=%i) = ?", id);
105
106 if ( id == g_midi_clock.stream ) {
107  midi_clock_tick();
108
109  return 0;
110 }
111
112 return -1;
113}
114
115// clock:
116
117int midi_clock_init (void) {
118 struct roar_stream * s;
119 struct roar_stream_server * ss;
120
121 if ( (g_midi_clock.stream = streams_new()) == -1 ) {
122  ROAR_WARN("Error while initializing MIDI subsystem component clock");
123  return -1;
124 }
125
126 midi_vio_set_dummy(g_midi_clock.stream);
127
128 streams_get(g_midi_clock.stream, &ss);
129 s = ROAR_STREAM(ss);
130
131 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
132
133 s->pos_rel_id    =  g_midi_clock.stream;
134
135 s->info.codec    =  ROAR_CODEC_MIDI;
136 ss->codec_orgi   =  ROAR_CODEC_MIDI;
137
138 s->info.channels =  0;
139 s->info.rate     = MIDI_RATE;
140 s->info.bits     =  8;
141
142 if ( streams_set_dir(g_midi_clock.stream, ROAR_DIR_BRIDGE, 1) == -1 ) {
143  ROAR_WARN("Error while initializing MIDI subsystem component clock");
144  return -1;
145 }
146
147 streams_set_name(g_midi_clock.stream, "MIDI Clock");
148
149 streams_set_flag(g_midi_clock.stream, ROAR_FLAG_PRIMARY);
150 streams_set_flag(g_midi_clock.stream, ROAR_FLAG_SYNC);
151
152 midi_clock_set_bph(3600); // one tick per sec
153
154 return 0;
155}
156
157int midi_clock_set_bph (uint_least32_t bph) {
158 uint_least32_t sph = g_sa->rate/2 * 75 * g_sa->channels; // samples per houre
159
160 g_midi_clock.bph  = bph;
161
162 g_midi_clock.spt  = sph/bph;
163
164 g_midi_clock.nt   = ROAR_MATH_OVERFLOW_ADD(g_pos, g_midi_clock.spt);
165
166 return 0;
167}
168
169int midi_clock_tick (void) {
170 unsigned int diff;
171
172 while ( g_pos >= g_midi_clock.nt ) {
173  diff = g_pos - g_midi_clock.nt;
174  ROAR_WARN("midi_clock_tick(void): g_pos is %u samples (%5.2f%%) ahead of nt.", diff, (float)diff/g_midi_clock.spt);
175
176  g_midi_clock.nt   = ROAR_MATH_OVERFLOW_ADD(g_midi_clock.nt, g_midi_clock.spt);
177
178  if ( streams_get_flag(g_midi_clock.stream, ROAR_FLAG_SYNC) ) {
179   ROAR_WARN("midi_clock_tick(void): TICK! (nt=%lu)", g_midi_clock.nt);
180  } else {
181   ROAR_WARN("midi_clock_tick(void): silent tick. (nt=%lu)", g_midi_clock.nt);
182  }
183 }
184
185 return 0;
186}
187
188// CB:
189
190int midi_cb_init (void) {
191#ifdef _HAVE_CONSOLE
192 struct roar_stream * s;
193 struct roar_stream_server * ss;
194 int i;
195 char * files[] = {
196                   "/dev/console",
197#ifdef __linux__
198                   "/dev/tty0",
199                   "/dev/vc/0",
200#endif
201                   NULL
202                  };
203
204 g_midi_cb.console  = -1;
205 g_midi_cb.stream   = -1;
206 g_midi_cb.stoptime =  0;
207 g_midi_cb.playing  =  0;
208
209 for (i = 0; files[i] != NULL; i++) {
210  if ( (g_midi_cb.console = open(files[i], O_WRONLY|O_NOCTTY, 0)) != -1 )
211   break;
212 }
213
214 if ( g_midi_cb.console == -1 )
215  return -1;
216
217 if ( (g_midi_cb.stream = streams_new()) == -1 ) {
218  ROAR_WARN("Error while initializing MIDI subsystem component CB");
219  midi_cb_free();
220  return -1;
221 }
222
223 midi_vio_set_dummy(g_midi_cb.stream);
224
225 streams_get(g_midi_cb.stream, &ss);
226 s = ROAR_STREAM(ss);
227
228 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
229
230 s->pos_rel_id    = -1;
231
232 s->info.codec    =  0;
233 ss->codec_orgi   =  0;
234
235 s->info.channels =  1;
236 s->info.rate     = 1193180;
237 s->info.bits     =  8;
238
239 if ( streams_set_dir(g_midi_cb.stream, ROAR_DIR_BRIDGE, 1) == -1 ) {
240  ROAR_WARN("Error while initializing MIDI subsystem component CB");
241  midi_cb_free();
242  return -1;
243 }
244
245 streams_set_name(g_midi_cb.stream, "Console speaker bridge");
246
247 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_OUTPUT);
248 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_PRIMARY);
249 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_HWMIXER);
250
251 return 0;
252#else
253 g_midi_cb.console  = -1;
254 g_midi_cb.stream   = -1;
255
256 return -1;
257#endif
258}
259
260int midi_cb_free (void) {
261#ifdef _HAVE_CONSOLE
262
263 midi_cb_stop();
264
265 if ( g_midi_cb.stream != -1 )
266  streams_delete(g_midi_cb.stream);
267
268 if ( g_midi_cb.console != -1 )
269  close(g_midi_cb.console);
270
271 return 0;
272#else
273 return -1;
274#endif
275}
276
277int midi_cb_play(float t, float freq, int override) {
278 float samples_per_sec /* S/s */ = g_sa->rate * g_sa->channels;
279
280/*
281#define MIDI_CB_NOOVERRIDE 0
282#define MIDI_CB_OVERRIDE   1
283*/
284 if ( g_midi_cb.playing && override != MIDI_CB_OVERRIDE )
285  return -1;
286
287 g_midi_cb.stoptime = ROAR_MATH_OVERFLOW_ADD(g_pos, samples_per_sec*t);
288 midi_cb_start(freq);
289 g_midi_cb.playing = 1;
290
291 return 0;
292}
293
294int midi_cb_update (void) {
295 if ( !g_midi_cb.playing )
296  return 0;
297
298 if ( g_midi_cb.stoptime <= g_pos )
299  midi_cb_stop();
300
301 return 0;
302}
303
304int midi_cb_start(float freq) {
305// On linux this uses ioctl KIOCSOUND
306#ifdef __linux__
307 if ( g_midi_cb.console == -1 )
308  return -1;
309
310 if ( ioctl(g_midi_cb.console, KIOCSOUND, freq == 0 ? 0 : (int)(1193180.0/freq)) == -1 )
311  return -1;
312
313 return 0;
314#else
315 return -1;
316#endif
317}
318
319int midi_cb_stop (void) {
320#ifdef __linux__
321 g_midi_cb.playing = 0;
322 return midi_cb_start(0);
323#else
324 return -1;
325#endif
326}
327
328// VIO:
329
330int     midi_vio_set_dummy(int stream) {
331 struct roar_stream_server * ss;
332
333 if ( streams_get(stream, &ss) == -1 )
334  return -1;
335
336 ss->vio.read     = NULL;
337 ss->vio.write    = NULL;
338 ss->vio.lseek    = NULL;
339 ss->vio.nonblock = (int (*)(struct roar_vio_calls * vio, int state))midi_vio_ok;
340 ss->vio.sync     = (int (*)(struct roar_vio_calls * vio))midi_vio_ok;
341 ss->vio.ctl      = NULL;
342 ss->vio.close    = (int (*)(struct roar_vio_calls * vio))midi_vio_ok;
343
344 return 0;
345}
346
347int     midi_vio_ok(struct roar_vio_calls * vio, ...) {
348 return 0;
349}
350
351//ll
Note: See TracBrowser for help on using the repository browser.