source: roaraudio/roard/midi.c @ 1855:60ee58430f49

Last change on this file since 1855:60ee58430f49 was 1855:60ee58430f49, checked in by phi, 15 years ago

there need to be a function for midi called before mixing and one after for cleanup.

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
56int midi_reinit(void) {
57 return 0;
58}
59
60// STREAMS:
61
62int midi_check_stream  (int id) {
63 struct roar_stream        *   s;
64 struct roar_stream_server *  ss;
65
66 if ( g_streams[id] == NULL )
67  return -1;
68
69 ROAR_DBG("midi_check_stream(id=%i) = ?", id);
70
71 s = ROAR_STREAM(ss = g_streams[id]);
72
73 if ( s->dir == ROAR_DIR_BRIDGE )
74  return midi_check_bridge(id);
75
76 switch (s->info.codec) {
77  default:
78    streams_delete(id);
79    return -1;
80 }
81
82 return 0;
83}
84
85int midi_send_stream   (int id) {
86 struct roar_stream        *   s;
87 struct roar_stream_server *  ss;
88
89 if ( g_streams[id] == NULL )
90  return -1;
91
92 ROAR_DBG("midi_send_stream(id=%i) = ?", id);
93
94 s = ROAR_STREAM(ss = g_streams[id]);
95
96 switch (s->info.codec) {
97  default:
98    streams_delete(id);
99    return -1;
100 }
101
102 return 0;
103}
104
105// bridges:
106int midi_check_bridge  (int id) {
107
108 ROAR_WARN("midi_check_bridge(id=%i) = ?", id);
109
110 if ( id == g_midi_clock.stream ) {
111  midi_clock_tick();
112
113  return 0;
114 }
115
116 return -1;
117}
118
119// clock:
120
121int midi_clock_init (void) {
122 struct roar_stream * s;
123 struct roar_stream_server * ss;
124
125 if ( (g_midi_clock.stream = streams_new()) == -1 ) {
126  ROAR_WARN("Error while initializing MIDI subsystem component clock");
127  return -1;
128 }
129
130 midi_vio_set_dummy(g_midi_clock.stream);
131
132 streams_get(g_midi_clock.stream, &ss);
133 s = ROAR_STREAM(ss);
134
135 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
136
137 s->pos_rel_id    =  g_midi_clock.stream;
138
139 s->info.codec    =  ROAR_CODEC_MIDI;
140 ss->codec_orgi   =  ROAR_CODEC_MIDI;
141
142 s->info.channels =  0;
143 s->info.rate     = MIDI_RATE;
144 s->info.bits     =  8;
145
146 if ( streams_set_dir(g_midi_clock.stream, ROAR_DIR_BRIDGE, 1) == -1 ) {
147  ROAR_WARN("Error while initializing MIDI subsystem component clock");
148  return -1;
149 }
150
151 streams_set_name(g_midi_clock.stream, "MIDI Clock");
152
153 streams_set_flag(g_midi_clock.stream, ROAR_FLAG_PRIMARY);
154 streams_set_flag(g_midi_clock.stream, ROAR_FLAG_SYNC);
155
156 midi_clock_set_bph(3600); // one tick per sec
157
158 return 0;
159}
160
161int midi_clock_set_bph (uint_least32_t bph) {
162 uint_least32_t sph = g_sa->rate/2 * 75 * g_sa->channels; // samples per houre
163
164 g_midi_clock.bph  = bph;
165
166 g_midi_clock.spt  = sph/bph;
167
168 g_midi_clock.nt   = ROAR_MATH_OVERFLOW_ADD(g_pos, g_midi_clock.spt);
169
170 return 0;
171}
172
173int midi_clock_tick (void) {
174 unsigned int diff;
175
176 while ( g_pos >= g_midi_clock.nt ) {
177  diff = g_pos - g_midi_clock.nt;
178  ROAR_WARN("midi_clock_tick(void): g_pos is %u samples (%5.2f%%) ahead of nt.", diff, (float)diff/g_midi_clock.spt);
179
180  g_midi_clock.nt   = ROAR_MATH_OVERFLOW_ADD(g_midi_clock.nt, g_midi_clock.spt);
181
182  if ( streams_get_flag(g_midi_clock.stream, ROAR_FLAG_SYNC) ) {
183   ROAR_WARN("midi_clock_tick(void): TICK! (nt=%lu)", g_midi_clock.nt);
184  } else {
185   ROAR_WARN("midi_clock_tick(void): silent tick. (nt=%lu)", g_midi_clock.nt);
186  }
187 }
188
189 return 0;
190}
191
192// CB:
193
194int midi_cb_init (void) {
195#ifdef _HAVE_CONSOLE
196 struct roar_stream * s;
197 struct roar_stream_server * ss;
198 int i;
199 char * files[] = {
200                   "/dev/console",
201#ifdef __linux__
202                   "/dev/tty0",
203                   "/dev/vc/0",
204#endif
205                   NULL
206                  };
207
208 g_midi_cb.console  = -1;
209 g_midi_cb.stream   = -1;
210 g_midi_cb.stoptime =  0;
211 g_midi_cb.playing  =  0;
212
213 for (i = 0; files[i] != NULL; i++) {
214  if ( (g_midi_cb.console = open(files[i], O_WRONLY|O_NOCTTY, 0)) != -1 )
215   break;
216 }
217
218 if ( g_midi_cb.console == -1 )
219  return -1;
220
221 if ( (g_midi_cb.stream = streams_new()) == -1 ) {
222  ROAR_WARN("Error while initializing MIDI subsystem component CB");
223  midi_cb_free();
224  return -1;
225 }
226
227 midi_vio_set_dummy(g_midi_cb.stream);
228
229 streams_get(g_midi_cb.stream, &ss);
230 s = ROAR_STREAM(ss);
231
232 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
233
234 s->pos_rel_id    = -1;
235
236 s->info.codec    =  0;
237 ss->codec_orgi   =  0;
238
239 s->info.channels =  1;
240 s->info.rate     = 1193180;
241 s->info.bits     =  8;
242
243 if ( streams_set_dir(g_midi_cb.stream, ROAR_DIR_BRIDGE, 1) == -1 ) {
244  ROAR_WARN("Error while initializing MIDI subsystem component CB");
245  midi_cb_free();
246  return -1;
247 }
248
249 streams_set_name(g_midi_cb.stream, "Console speaker bridge");
250
251 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_OUTPUT);
252 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_PRIMARY);
253 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_HWMIXER);
254
255 return 0;
256#else
257 g_midi_cb.console  = -1;
258 g_midi_cb.stream   = -1;
259
260 return -1;
261#endif
262}
263
264int midi_cb_free (void) {
265#ifdef _HAVE_CONSOLE
266
267 midi_cb_stop();
268
269 if ( g_midi_cb.stream != -1 )
270  streams_delete(g_midi_cb.stream);
271
272 if ( g_midi_cb.console != -1 )
273  close(g_midi_cb.console);
274
275 return 0;
276#else
277 return -1;
278#endif
279}
280
281int midi_cb_play(float t, float freq, int override) {
282 float samples_per_sec /* S/s */ = g_sa->rate * g_sa->channels;
283
284/*
285#define MIDI_CB_NOOVERRIDE 0
286#define MIDI_CB_OVERRIDE   1
287*/
288 if ( g_midi_cb.playing && override != MIDI_CB_OVERRIDE )
289  return -1;
290
291 g_midi_cb.stoptime = ROAR_MATH_OVERFLOW_ADD(g_pos, samples_per_sec*t);
292 midi_cb_start(freq);
293 g_midi_cb.playing = 1;
294
295 return 0;
296}
297
298int midi_cb_update (void) {
299 if ( !g_midi_cb.playing )
300  return 0;
301
302 if ( g_midi_cb.stoptime <= g_pos )
303  midi_cb_stop();
304
305 return 0;
306}
307
308int midi_cb_start(float freq) {
309// On linux this uses ioctl KIOCSOUND
310#ifdef __linux__
311 if ( g_midi_cb.console == -1 )
312  return -1;
313
314 if ( ioctl(g_midi_cb.console, KIOCSOUND, freq == 0 ? 0 : (int)(1193180.0/freq)) == -1 )
315  return -1;
316
317 return 0;
318#else
319 return -1;
320#endif
321}
322
323int midi_cb_stop (void) {
324#ifdef __linux__
325 g_midi_cb.playing = 0;
326 return midi_cb_start(0);
327#else
328 return -1;
329#endif
330}
331
332// VIO:
333
334int     midi_vio_set_dummy(int stream) {
335 struct roar_stream_server * ss;
336
337 if ( streams_get(stream, &ss) == -1 )
338  return -1;
339
340 ss->vio.read     = NULL;
341 ss->vio.write    = NULL;
342 ss->vio.lseek    = NULL;
343 ss->vio.nonblock = (int (*)(struct roar_vio_calls * vio, int state))midi_vio_ok;
344 ss->vio.sync     = (int (*)(struct roar_vio_calls * vio))midi_vio_ok;
345 ss->vio.ctl      = NULL;
346 ss->vio.close    = (int (*)(struct roar_vio_calls * vio))midi_vio_ok;
347
348 return 0;
349}
350
351int     midi_vio_ok(struct roar_vio_calls * vio, ...) {
352 return 0;
353}
354
355//ll
Note: See TracBrowser for help on using the repository browser.