source: roaraudio/roard/midi.c @ 3517:1a3218a3fc5b

Last change on this file since 3517:1a3218a3fc5b was 3517:1a3218a3fc5b, checked in by phi, 14 years ago

updated license headers, FSF moved office

File size: 18.3 KB
RevLine 
[169]1//midi.c:
2
[668]3/*
[3358]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2010
[668]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[668]23 *
24 */
25
[169]26#include "roard.h"
27
[2500]28#ifndef ROAR_WITHOUT_DCOMP_MIDI
29
[1751]30#if defined(ROAR_HAVE_IO_POSIX) && !defined(ROAR_TARGET_WIN32)
31#define _HAVE_CONSOLE
32#endif
33
[1924]34int midi_init_config(void) {
35 midi_config.init        = 1;
36 midi_config.inited      = 0;
[2487]37
38#ifndef ROAR_WITHOUT_DCOMP_CB
[2445]39 midi_config.init_cb     = 0;
[1924]40 midi_config.console_dev = NULL;
[2487]41#endif
[1924]42
43 return 0;
44}
45
[185]46int midi_init (void) {
[2943]47 struct roar_stream_server * ss;
[3215]48 int i;
[1843]49
[1924]50 midi_config.inited = 0;
[1843]51
[1924]52 if ( midi_config.init ) {
[2487]53#ifndef ROAR_WITHOUT_DCOMP_CB
[1924]54  if ( midi_config.init_cb ) {
55   if ( midi_cb_init() == -1 ) {
56    ROAR_WARN("Can not initialize MIDI subsystem component CB");
57   }
58  }
[2487]59#endif
[1924]60
61  if ( midi_clock_init() == -1 ) {
62   ROAR_WARN("Can not initialize MIDI subsystem component clock");
63  }
64
[1848]65 }
66
[1863]67 g_midi_mess.buf = NULL;
68
[2943]69 if ( (g_midi_mixer.stream = add_mixer(ROAR_SUBSYS_MIDI, _MIXER_NAME("MIDI"), &ss)) == -1 ) {
[2941]70  ROAR_WARN("Can not create MIDI mixer");
71 }
[2943]72 ss->state = ROAR_STREAMSTATE_OLD;
[2941]73
[3215]74 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
75  if ( g_streams[i] != NULL ) {
76   if ( streams_get_subsys(i) == ROAR_SUBSYS_MIDI ) {
77    streams_set_mixer_stream(i, g_midi_mixer.stream);
78   }
79  }
80 }
81
[1924]82 midi_config.inited |= MIDI_INITED_MAIN;
83
[1843]84 return 0;
85}
[1848]86
[1843]87int midi_free (void) {
[1924]88 if ( midi_reinit() == -1 )
89  return -1;
90
[2487]91#ifndef ROAR_WITHOUT_DCOMP_CB
[1924]92 if ( midi_cb_free() == -1 )
93  return -1;
[2487]94#endif
[1924]95
96 return 0;
[1843]97}
98
99int midi_update(void) {
[1848]100
[1850]101 if ( g_midi_clock.stream != -1 )
102  midi_check_bridge(g_midi_clock.stream);
[1848]103
[2489]104#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2461]105 midi_conv_mes2ssynth();
[2489]106#endif
[2461]107
[2487]108#ifndef ROAR_WITHOUT_DCOMP_CB
[1843]109 return midi_cb_update();
[2487]110#else
111 return 0;
112#endif
[1843]113}
114
[1855]115int midi_reinit(void) {
[1868]116
117 if ( g_midi_mess.buf != NULL )
118  roar_buffer_free(g_midi_mess.buf);
119
120 g_midi_mess.buf = NULL;
121
[1855]122 return 0;
123}
124
[1845]125// STREAMS:
126
127int midi_check_stream  (int id) {
[1846]128 struct roar_stream        *   s;
129 struct roar_stream_server *  ss;
[1858]130 struct roar_buffer        *   b;
131 char                      * buf;
132 ssize_t                     len;
[1846]133
134 if ( g_streams[id] == NULL )
135  return -1;
136
137 ROAR_DBG("midi_check_stream(id=%i) = ?", id);
138
139 s = ROAR_STREAM(ss = g_streams[id]);
140
[1848]141 if ( s->dir == ROAR_DIR_BRIDGE )
142  return midi_check_bridge(id);
143
[1846]144 switch (s->info.codec) {
[1858]145  case ROAR_CODEC_MIDI:
146   break;
147  default:
148    streams_delete(id);
149    return -1;
150 }
151
152 if ( roar_buffer_new(&b, MIDI_READ_SIZE) == -1 ) {
153  ROAR_ERR("midi_check_stream(*): Can not alloc buffer space!");
154  ROAR_DBG("midi_check_stream(*) = -1");
155  return -1;
156 }
157
158 roar_buffer_get_data(b, (void **)&buf);
159
160 if ( (len = stream_vio_s_read(ss, buf, MIDI_READ_SIZE)) < 1 ) {
161  streams_delete(id);
[1862]162  roar_buffer_free(b);
[1858]163  return -1;
164 }
165
166 roar_buffer_set_len(b, len);
167
[1859]168 if ( stream_add_buffer(id, b) == -1 ) {
169  roar_buffer_free(b);
170  streams_delete(id);
171  return -1;
172 }
173
[1858]174 switch (s->info.codec) {
175  case ROAR_CODEC_MIDI:
176    return midi_conv_midi2mes(id);
177   break;
[1846]178  default:
179    streams_delete(id);
180    return -1;
181 }
182
183 return 0;
[1845]184}
[1846]185
[1845]186int midi_send_stream   (int id) {
[1846]187 struct roar_stream        *   s;
188 struct roar_stream_server *  ss;
189
190 if ( g_streams[id] == NULL )
191  return -1;
192
193 ROAR_DBG("midi_send_stream(id=%i) = ?", id);
194
195 s = ROAR_STREAM(ss = g_streams[id]);
196
197 switch (s->info.codec) {
[1877]198  case ROAR_CODEC_MIDI:
199    return midi_conv_mes2midi(id);
200   break;
[1846]201  default:
202    streams_delete(id);
203    return -1;
204 }
205
206 return 0;
[1845]207}
208
[1858]209int midi_conv_midi2mes (int id) {
[1863]210 unsigned char * data;
211 struct roar_stream        *   s;
212 struct roar_stream_server *  ss;
213 struct roar_buffer        * buf = NULL;
214 struct midi_message       * mes = NULL;
[1879]215 size_t need = 0, have = 0, last_have = 0, old_have = 0;
[1863]216 int alive = 1;
217
218 if ( g_streams[id] == NULL )
219  return -1;
220
221 ROAR_DBG("midi_conv_midi2mes(id=%i) = ?", id);
222
223 s = ROAR_STREAM(ss = g_streams[id]);
224
225 while (ss->buffer != NULL && alive) {
226  if ( roar_buffer_get_data(ss->buffer, (void**)&data) == -1 ) {
227   alive = 0;
228   continue;
229  }
230
231  if ( roar_buffer_get_len(ss->buffer, &have) == -1 ) {
232   alive = 0;
233   continue;
234  }
[1879]235  old_have = have;
[1863]236
237  while (have && alive) {
238   if ( *data & 0x80 ) {
[1865]239    if ( buf != NULL ) {
[1866]240     midi_add_buf(id, buf);
[1865]241     buf = NULL;
242    }
243
[1879]244    last_have = have;
245
[1863]246    need = 0;
247    if ( midi_new_bufmes(&buf, &mes) == -1 ) {
248     alive = 0;
249     continue;
250    }
[1865]251
252    if (*data == MIDI_TYPE_CLOCK_TICK || *data == MIDI_TYPE_CLOCK_START || *data == MIDI_TYPE_CLOCK_STOP ) {
253     mes->type = *data;
[1891]254
255     if ( *data == MIDI_TYPE_CLOCK_TICK ) {
256      s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
257     }
[1865]258    } else {
259     mes->type    = *data & 0xF0;
260     mes->channel = *data & 0x0F;
261     switch (*data & 0xF0) {
262      case MIDI_TYPE_NOTE_ON:
263      case MIDI_TYPE_NOTE_OFF:
264        need = 2;
265       break;
266      case MIDI_TYPE_PA:
267        need = 2;
268       break;
269      case MIDI_TYPE_CONTROLER:
270        need = 2;
271       break;
272      case MIDI_TYPE_PROGRAM:
273        need = 1;
274       break;
275      case MIDI_TYPE_MA:
276        need = 1;
277       break;
278      case MIDI_TYPE_PB:
279      case MIDI_TYPE_SYSEX:
280        need = 1;
281       break;
282     }
283    }
284
[1863]285   } else {
[1871]286
287    if ( mes == NULL ) {
288     ROAR_WARN("midi_conv_midi2mes(id=%i): Lost sync.", id);
289     data++;
290     have--;
291     continue;
292    }
293
294    switch (mes->type) {
[1873]295      case MIDI_TYPE_NOTE_ON:
296      case MIDI_TYPE_NOTE_OFF:
[1881]297       if ( need == 2 ) {
298        roar_midi_note_from_midiid(&(mes->d.note), *data);
[2409]299
300        // if velocity is zero we have a NOTE OFF event
301        if ( data[1] == 0 )
302         mes->type = MIDI_TYPE_NOTE_OFF;
[1881]303       }
[1874]304      case MIDI_TYPE_PA:
305      case MIDI_TYPE_CONTROLER:
[1873]306        if ( need == 2 ) {
307         mes->kk = *data;
308        } else {
309         mes->vv = *data;
310        }
311       break;
312      case MIDI_TYPE_PROGRAM:
313      case MIDI_TYPE_MA:
[1874]314        mes->vv = *data;
315       break;
[1873]316      case MIDI_TYPE_PB:
317      case MIDI_TYPE_SYSEX:
[1874]318        ROAR_WARN("midi_conv_midi2mes(id=%i): Message of Type 0x%.2X (PB or SysEx) not yet supported", id, mes->type);
[1873]319       break;
[1871]320    }
321
[1863]322    if ( need )
323     need--;
[1893]324
325    if ( !need ) {
326     switch (mes->type) {
327      case MIDI_TYPE_CONTROLER:
328       switch (mes->kk) {
329        case MIDI_CCE_MAIN_VOL:
330         if ( 516 * mes->vv > 65100 ) { // max volume
331          ss->mixer.mixer[mes->channel] = 65535;
332         } else {
333          ss->mixer.mixer[mes->channel] = 516 * mes->vv;
334         }
335         break;
336       }
337      break;
338     }
339    }
340
[1863]341   }
342   data++;
343   have--;
344  }
345
[1865]346  if ( need ) {
[1879]347   if ( roar_buffer_set_offset(ss->buffer, old_have - last_have) == -1 ) {
348    ROAR_ERR("midi_conv_midi2mes(*): FIXME: BUG!!! Need to restore buffer here with corrected length");
349   }
[1865]350  } else if ( !have ) {
[1863]351   roar_buffer_next(&(ss->buffer));
352  }
353
354  if ( need && buf != NULL ) {
355   roar_buffer_free(buf);
356   buf = NULL;
357  } else if ( buf != NULL ) {
[1866]358   midi_add_buf(id, buf);
[1863]359   buf = NULL;
360  }
361 }
362
363 return 0;
[1858]364}
365
[1877]366#define _nb  len++; *(d++)
[1858]367int midi_conv_mes2midi (int id) {
[1877]368 struct roar_stream        *   s;
369 struct roar_stream_server *  ss;
370 struct roar_buffer        * buf = g_midi_mess.buf;
371 struct midi_message       * mes = NULL;
372 unsigned char               data[3];
373 unsigned char             * d;
374 int                         len;
[1909]375 int                         send_clock;
[1877]376
377 if ( g_streams[id] == NULL )
378  return -1;
379
380 ROAR_DBG("midi_conv_mes2midi(id=%i) = ?", id);
381
382 s = ROAR_STREAM(ss = g_streams[id]);
383
[1909]384 send_clock = streams_get_flag(id, ROAR_FLAG_SYNC);
385
[1877]386 while (buf != NULL) {
387  if ( roar_buffer_get_data(buf, (void**)&mes) == -1 ) {
388   return -1;
389  }
390
391  if (mes->type == MIDI_TYPE_CLOCK_TICK || mes->type == MIDI_TYPE_CLOCK_START || mes->type == MIDI_TYPE_CLOCK_STOP ) {
[1910]392   if ( send_clock ) {
[1909]393    if ( stream_vio_s_write(ss, &(mes->type), 1) != 1 ) {
394     streams_delete(id);
395     return -1;
396    }
[1877]397   }
[1896]398
399   if ( mes->type == MIDI_TYPE_CLOCK_TICK ) {
400    s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
401   }
[1877]402  } else {
403   len = 0;
404   d   = data;
405
406   _nb = (mes->type & 0xF0) | (mes->channel & 0x0F);
407
408   switch (mes->type) {
[1898]409    case MIDI_TYPE_CONTROLER:
410      switch (mes->kk) {
411       case MIDI_CCE_MAIN_VOL:
412         if ( 516 * mes->vv > 65100 ) { // max volume
413          ss->mixer.mixer[mes->channel] = 65535;
414         } else {
415          ss->mixer.mixer[mes->channel] = 516 * mes->vv;
416         }
417        break;
418      }
[1877]419    case MIDI_TYPE_NOTE_ON:
420    case MIDI_TYPE_NOTE_OFF:
421    case MIDI_TYPE_PA:
422      _nb = mes->kk;
423      _nb = mes->vv;
424     break;
425    case MIDI_TYPE_PROGRAM:
426    case MIDI_TYPE_MA:
427      _nb = mes->vv;
428     break;
429    case MIDI_TYPE_PB:
430    case MIDI_TYPE_SYSEX:
431     break;
432   }
433
434   if ( stream_vio_s_write(ss, data, len) != len ) {
435    streams_delete(id);
436    return -1;
437   }
438  }
439
440  if ( roar_buffer_get_next(buf, &buf) == -1 )
441   buf = NULL;
442 }
443
444 return 0;
[1858]445}
[1877]446#undef _nb
[1858]447
[2489]448#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2461]449int midi_conv_mes2ssynth(void) {
[2462]450 struct roar_buffer        * buf = g_midi_mess.buf;
451 struct midi_message       * mes = NULL;
452
453 while (buf != NULL) {
454  if ( roar_buffer_get_data(buf, (void**)&mes) == -1 ) {
455   return -1;
456  }
457
458  if ( ssynth_eval_message(mes) == -1 )
459   return -1;
460
461  if ( roar_buffer_get_next(buf, &buf) == -1 )
462   buf = NULL;
463 }
464
465 return 0;
[2461]466}
[2489]467#endif
[2461]468
[1863]469int midi_new_bufmes    (struct roar_buffer ** buf, struct midi_message ** mes) {
470 if ( buf == NULL || mes == NULL )
471  return -1;
472
[1867]473 *buf = (void*)(*mes = NULL);
[1863]474
475 if ( roar_buffer_new(buf, sizeof(struct midi_message)) == -1 )
476  return -1;
477
478 if ( roar_buffer_get_data(*buf, (void**)mes) == -1 ) {
479  roar_buffer_free(*buf);
[1867]480  *buf = (void*)(*mes = NULL);
[1863]481  return -1;
482 }
483
484 memset((void*)*mes, 0, sizeof(struct midi_message));
485
486 (*mes)->type = MIDI_TYPE_NONE;
487
488 return 0;
489}
490
[1866]491int midi_add_buf       (int id, struct roar_buffer * buf) {
[1869]492 struct midi_message * mes;
493
[1866]494 if ( id == -1 || buf == NULL )
495  return -1;
496
[1872]497 if ( roar_buffer_get_data(buf, (void**)&mes) == -1 )
[1869]498  return -1;
499
[1878]500 ROAR_DBG("midi_add_buf(id=%i, buf=%p) = ?", id, buf);
501 ROAR_DBG("midi_add_buf(*): MIDI Message of Type 0x%.2X", mes->type);
502 ROAR_DBG("midi_add_buf(*): Channel: %i", mes->channel);
503 ROAR_DBG("midi_add_buf(*): flags=0x%.2X", mes->flags);
504 ROAR_DBG("midi_add_buf(*): kk=0x%.2X, vv=0x%.2X", mes->kk, mes->vv);
[1869]505
[1866]506 if ( g_midi_mess.buf == NULL ) {
507  g_midi_mess.buf = buf;
508 } else {
509  roar_buffer_add(g_midi_mess.buf, buf);
510 }
511
512 return 0;
513}
514
[1848]515// bridges:
516int midi_check_bridge  (int id) {
[1851]517
[1860]518 ROAR_DBG("midi_check_bridge(id=%i) = ?", id);
[1851]519
520 if ( id == g_midi_clock.stream ) {
521  midi_clock_tick();
522
523  return 0;
524 }
525
[1848]526 return -1;
527}
528
529// clock:
530
531int midi_clock_init (void) {
532 struct roar_stream * s;
533 struct roar_stream_server * ss;
534
[1850]535 if ( (g_midi_clock.stream = streams_new()) == -1 ) {
[1848]536  ROAR_WARN("Error while initializing MIDI subsystem component clock");
537  return -1;
538 }
539
[2915]540 client_stream_add(g_self_client, g_midi_clock.stream);
541
[1850]542 midi_vio_set_dummy(g_midi_clock.stream);
[1848]543
[1850]544 streams_get(g_midi_clock.stream, &ss);
[1848]545 s = ROAR_STREAM(ss);
546
547 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
548
[1850]549 s->pos_rel_id    =  g_midi_clock.stream;
[1848]550
551 s->info.codec    =  ROAR_CODEC_MIDI;
552 ss->codec_orgi   =  ROAR_CODEC_MIDI;
553
[2401]554 s->info.channels = 1; // we have only one channel, ticking on channel 0
[2400]555 s->info.rate     = ROAR_MIDI_TICKS_PER_BEAT; // one beat per sec
556 s->info.bits     = ROAR_MIDI_BITS;
[1848]557
[1850]558 if ( streams_set_dir(g_midi_clock.stream, ROAR_DIR_BRIDGE, 1) == -1 ) {
[1848]559  ROAR_WARN("Error while initializing MIDI subsystem component clock");
560  return -1;
561 }
562
[1850]563 streams_set_name(g_midi_clock.stream, "MIDI Clock");
[1848]564
[1850]565 streams_set_flag(g_midi_clock.stream, ROAR_FLAG_PRIMARY);
566 streams_set_flag(g_midi_clock.stream, ROAR_FLAG_SYNC);
[1848]567
[2400]568 midi_clock_set_bph(3600); // one beat per sec
[1851]569
[2943]570 ss->state = ROAR_STREAMSTATE_NEW;
571
[1924]572 midi_config.inited |= MIDI_INITED_CLOCK;
573
[1851]574 return 0;
575}
576
577int midi_clock_set_bph (uint_least32_t bph) {
578 uint_least32_t sph = g_sa->rate/2 * 75 * g_sa->channels; // samples per houre
579
580 g_midi_clock.bph  = bph;
581
582 g_midi_clock.spt  = sph/bph;
583
584 g_midi_clock.nt   = ROAR_MATH_OVERFLOW_ADD(g_pos, g_midi_clock.spt);
585
586 return 0;
587}
588
589int midi_clock_tick (void) {
[1875]590 struct roar_buffer  * buf;
591 struct midi_message * mes;
[1888]592 struct roar_stream_server * ss;
[1851]593 unsigned int diff;
594
[1888]595 if ( streams_get(g_midi_clock.stream, &ss) == -1 ) {
596  ROAR_ERR("midi_clock_tick(void): Something very BAD happend: can not get stream object of my own stream!");
597  g_midi_clock.stream = -1;
598  ROAR_WARN("midi_clock_tick(void): Disabled MIDI Clock");
599  return -1;
600 }
601
[1851]602 while ( g_pos >= g_midi_clock.nt ) {
603  diff = g_pos - g_midi_clock.nt;
[1911]604  ROAR_DBG("midi_clock_tick(void): g_pos is %u samples (%5.2f%%) after of nt.", diff, (float)diff/g_midi_clock.spt);
[1851]605
606  g_midi_clock.nt   = ROAR_MATH_OVERFLOW_ADD(g_midi_clock.nt, g_midi_clock.spt);
607
608  if ( streams_get_flag(g_midi_clock.stream, ROAR_FLAG_SYNC) ) {
[1860]609   ROAR_DBG("midi_clock_tick(void): TICK! (nt=%lu)", g_midi_clock.nt);
[1875]610   if ( midi_new_bufmes(&buf, &mes) == -1 ) {
611    ROAR_ERR("midi_clock_tick(void): Can not create Clock-Tick-Message");
612   }
613
614   mes->type = MIDI_TYPE_CLOCK_TICK;
615
616   if ( midi_add_buf(g_midi_clock.stream, buf) == -1 ) {
617    ROAR_ERR("midi_clock_tick(void): Can not add Clock-Tick-Message");
618    roar_buffer_free(buf);
619    return -1;
620   }
[1888]621
622   ROAR_STREAM(ss)->pos = ROAR_MATH_OVERFLOW_ADD(ROAR_STREAM(ss)->pos, 1);
[2943]623   ss->state = ROAR_STREAMSTATE_OLD;
[1851]624  } else {
[1860]625   ROAR_DBG("midi_clock_tick(void): silent tick. (nt=%lu)", g_midi_clock.nt);
[1851]626  }
627 }
628
[1848]629 return 0;
630}
631
[1845]632// CB:
[1843]633
[2487]634#ifndef ROAR_WITHOUT_DCOMP_CB
[1843]635int midi_cb_init (void) {
[1751]636#ifdef _HAVE_CONSOLE
[1843]637 struct roar_stream * s;
638 struct roar_stream_server * ss;
[185]639 int i;
640 char * files[] = {
[1924]641                   "/NX",
642                   "/dev/roarconsole",
[185]643                   "/dev/console",
644#ifdef __linux__
645                   "/dev/tty0",
646                   "/dev/vc/0",
647#endif
648                   NULL
649                  };
650
[1853]651 g_midi_cb.console  = -1;
652 g_midi_cb.stream   = -1;
653 g_midi_cb.stoptime =  0;
654 g_midi_cb.playing  =  0;
[185]655
[1924]656 if ( midi_config.console_dev != NULL ) {
657  files[0] = midi_config.console_dev;
658 }
659
[185]660 for (i = 0; files[i] != NULL; i++) {
[1853]661  if ( (g_midi_cb.console = open(files[i], O_WRONLY|O_NOCTTY, 0)) != -1 )
[185]662   break;
663 }
664
[1853]665 if ( g_midi_cb.console == -1 )
[1843]666  return -1;
667
[1853]668 if ( (g_midi_cb.stream = streams_new()) == -1 ) {
[1843]669  ROAR_WARN("Error while initializing MIDI subsystem component CB");
670  midi_cb_free();
[187]671  return -1;
672 }
[1843]673
[2915]674 client_stream_add(g_self_client, g_midi_clock.stream);
675
[1853]676 midi_vio_set_dummy(g_midi_cb.stream);
[1848]677
[1853]678 streams_get(g_midi_cb.stream, &ss);
[1843]679 s = ROAR_STREAM(ss);
680
681 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
682
683 s->pos_rel_id    = -1;
684
685 s->info.codec    =  0;
686 ss->codec_orgi   =  0;
687
688 s->info.channels =  1;
689 s->info.rate     = 1193180;
690 s->info.bits     =  8;
691
[1853]692 if ( streams_set_dir(g_midi_cb.stream, ROAR_DIR_BRIDGE, 1) == -1 ) {
[1843]693  ROAR_WARN("Error while initializing MIDI subsystem component CB");
694  midi_cb_free();
695  return -1;
696 }
697
[1853]698 streams_set_name(g_midi_cb.stream, "Console speaker bridge");
[1843]699
[1853]700 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_OUTPUT);
701 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_PRIMARY);
702 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_HWMIXER);
[1885]703 streams_set_flag(g_midi_cb.stream, ROAR_FLAG_MUTE);
[1843]704
[1924]705 midi_config.inited |= MIDI_INITED_CB;
706
[1843]707 return 0;
[1485]708#else
[1853]709 g_midi_cb.console  = -1;
710 g_midi_cb.stream   = -1;
[1843]711
[1485]712 return -1;
713#endif
[185]714}
715
[1843]716int midi_cb_free (void) {
[1751]717#ifdef _HAVE_CONSOLE
[1843]718
719 midi_cb_stop();
720
[1853]721 if ( g_midi_cb.stream != -1 )
722  streams_delete(g_midi_cb.stream);
[1843]723
[1853]724 if ( g_midi_cb.console != -1 )
725  close(g_midi_cb.console);
[1843]726
[185]727 return 0;
[1485]728#else
729 return -1;
730#endif
[185]731}
732
733int midi_cb_play(float t, float freq, int override) {
[191]734 float samples_per_sec /* S/s */ = g_sa->rate * g_sa->channels;
735
[189]736/*
737#define MIDI_CB_NOOVERRIDE 0
738#define MIDI_CB_OVERRIDE   1
739*/
[1853]740 if ( g_midi_cb.playing && override != MIDI_CB_OVERRIDE )
[191]741  return -1;
742
[1853]743 g_midi_cb.stoptime = ROAR_MATH_OVERFLOW_ADD(g_pos, samples_per_sec*t);
[191]744 midi_cb_start(freq);
745
746 return 0;
[185]747}
748
[190]749int midi_cb_update (void) {
[1884]750
751 if ( !streams_get_flag(g_midi_cb.stream, ROAR_FLAG_MUTE) ) {
752  if ( midi_cb_readbuf() == -1 )
753   return -1;
754 } else if ( g_midi_cb.playing ) {
755  midi_cb_stop();
756 }
[1882]757
[1853]758 if ( !g_midi_cb.playing )
[192]759  return 0;
760
[1884]761/*
[1853]762 if ( g_midi_cb.stoptime <= g_pos )
[189]763  midi_cb_stop();
[1884]764*/
[189]765
[1882]766 ROAR_DBG("midi_cb_update(void) = ?");
767
[189]768 return 0;
769}
770
[185]771int midi_cb_start(float freq) {
772// On linux this uses ioctl KIOCSOUND
[188]773#ifdef __linux__
[1853]774 if ( g_midi_cb.console == -1 )
[188]775  return -1;
776
[1853]777 if ( ioctl(g_midi_cb.console, KIOCSOUND, freq == 0 ? 0 : (int)(1193180.0/freq)) == -1 )
[188]778  return -1;
779
[1884]780 g_midi_cb.playing = 1;
781
[188]782 return 0;
783#else
[185]784 return -1;
[188]785#endif
[185]786}
787
788int midi_cb_stop (void) {
789#ifdef __linux__
[1884]790 int ret;
791
792 ret = midi_cb_start(0);
[1853]793 g_midi_cb.playing = 0;
[1884]794
795 return ret;
[185]796#else
797 return -1;
798#endif
799}
800
[1882]801int midi_cb_readbuf(void) {
802 struct roar_buffer        * buf = g_midi_mess.buf;
803 struct midi_message       * mes = NULL;
804
805 ROAR_DBG("midi_cb_readbuf(void) = ?");
806
807 while (buf != NULL) {
808  ROAR_DBG("midi_cb_readbuf(void): buf=%p", buf);
809
810  if ( roar_buffer_get_data(buf, (void**)&mes) == -1 ) {
811   return -1;
812  }
813
814  switch (mes->type) {
815   case MIDI_TYPE_NOTE_ON:
816     midi_cb_start(mes->d.note.freq);
817    break;
818   case MIDI_TYPE_NOTE_OFF:
819     midi_cb_stop();
820    break;
[1890]821   case MIDI_TYPE_CONTROLER:
[1894]822     if ( mes->kk == MIDI_CCE_ALL_NOTE_OFF ) /* all note off */
[1890]823      midi_cb_stop();
824    break;
[1882]825  }
826
827  if ( roar_buffer_get_next(buf, &buf) == -1 )
828   buf = NULL;
829 }
830
831 return 0;
832}
[2487]833#endif
[1882]834
[1848]835// VIO:
836
837int     midi_vio_set_dummy(int stream) {
838 struct roar_stream_server * ss;
839
840 if ( streams_get(stream, &ss) == -1 )
841  return -1;
842
843 ss->vio.read     = NULL;
844 ss->vio.write    = NULL;
845 ss->vio.lseek    = NULL;
[1849]846 ss->vio.nonblock = (int (*)(struct roar_vio_calls * vio, int state))midi_vio_ok;
847 ss->vio.sync     = (int (*)(struct roar_vio_calls * vio))midi_vio_ok;
[1848]848 ss->vio.ctl      = NULL;
[1849]849 ss->vio.close    = (int (*)(struct roar_vio_calls * vio))midi_vio_ok;
850
851 return 0;
[1848]852}
853
854int     midi_vio_ok(struct roar_vio_calls * vio, ...) {
855 return 0;
856}
857
[2500]858#endif
859
[169]860//ll
Note: See TracBrowser for help on using the repository browser.