PageRenderTime 72ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/KoboDeluxe-0.5.1/sound/a_midi.c

#
C | 267 lines | 203 code | 30 blank | 34 comment | 18 complexity | 1ee4445e56510c9e5a757d4cef9861a4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. /*(LGPL)
  2. ---------------------------------------------------------------------------
  3. a_midi.c - midi_socket_t MIDI Input Driver for OSS or ALSA
  4. ---------------------------------------------------------------------------
  5. * Copyright (C) 2001, 2003, David Olofson
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation; either version 2.1 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program; if not, write to the Free Software Foundation,
  19. * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. /*
  22. * NOTE: This code will build for ALSA *or* OSS, in that order of preference.
  23. */
  24. #include "config.h"
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "kobolog.h"
  28. #include "a_midi.h"
  29. #ifdef HAVE_ALSA
  30. # include <sys/asoundlib.h>
  31. # define USE_MIDI
  32. #elif defined(HAVE_OSS)
  33. # include <fcntl.h>
  34. # include <unistd.h>
  35. # define USE_MIDI
  36. #else
  37. # undef USE_MIDI
  38. #endif
  39. #define MDBG(x)
  40. #define MDBG2(x)
  41. #ifdef USE_MIDI
  42. /* MIDI open/close */
  43. #ifdef HAVE_ALSA
  44. static snd_rawmidi_t *m_in_fd = NULL;
  45. static snd_rawmidi_t *m_out_fd = NULL;
  46. #elif defined(HAVE_OSS)
  47. static int m_fd = 0;
  48. #endif
  49. /* MIDI I/O */
  50. #ifdef HAVE_ALSA
  51. # define midi_read(b,s) snd_rawmidi_read(m_in_fd, b, s)
  52. # define midi_write(b,s) snd_rawmidi_write(m_out_fd, b, s)
  53. #elif defined(HAVE_OSS)
  54. # define midi_read(b,s) read(m_fd, b, s)
  55. # define midi_write(b,s) write(m_fd, b, s)
  56. #endif
  57. /*
  58. * Basic real time MIDI parsing
  59. */
  60. static midisock_t *ms;
  61. static midisock_t *mon;
  62. /* Global state stuff - *not* per channel! */
  63. static int m_channel = 0; /* current channel */
  64. static int m_datacount = 0; /* current data byte */
  65. static char m_status = 0; /* current (last seen) status */
  66. static char m_buf[3]; /* space for data bytes */
  67. static int m_expect = -1; /* expected message data length */
  68. static inline void decode_midi_message(void)
  69. {
  70. /* Seems like we've got a complete message! */
  71. int val;
  72. switch(m_status & 0xf0)
  73. {
  74. case 0x80: /* Note off */
  75. MDBG2(mon->note_off(m_channel, m_buf[0], m_buf[1]);)
  76. ms->note_off(m_channel, m_buf[0], m_buf[1]);
  77. break;
  78. case 0x90: /* Note on */
  79. MDBG2(mon->note_on(m_channel, m_buf[0], m_buf[1]);)
  80. ms->note_on(m_channel, m_buf[0], m_buf[1]);
  81. break;
  82. case 0xa0: /* Poly pressure */
  83. MDBG2(mon->poly_pressure(m_channel, m_buf[0], m_buf[1]);)
  84. ms->poly_pressure(m_channel, m_buf[0], m_buf[1]);
  85. break;
  86. case 0xb0: /* Control change */
  87. MDBG2(mon->control_change(m_channel, m_buf[0], m_buf[1]);)
  88. ms->control_change(m_channel, m_buf[0], m_buf[1]);
  89. break;
  90. case 0xc0: /* Program change */
  91. MDBG2(mon->program_change(m_channel, m_buf[0]);)
  92. ms->program_change(m_channel, m_buf[0]);
  93. break;
  94. case 0xd0: /* Channel pressure */
  95. MDBG2(mon->channel_pressure(m_channel, m_buf[0]);)
  96. ms->channel_pressure(m_channel, m_buf[0]);
  97. break;
  98. case 0xe0: /* Pitch bend */
  99. val = ((m_buf[1] << 7) | m_buf[0]) - 8192;
  100. MDBG2(mon->pitch_bend(m_channel, val);)
  101. ms->pitch_bend(m_channel, val);
  102. break;
  103. case 0xf0: /* System message */
  104. break;
  105. }
  106. m_datacount = 0;
  107. }
  108. static const int full_xtab[8] = {
  109. 2, /* 0x80/0: Note off, */
  110. 2, /* 0x90/1: Note on */
  111. 2, /* 0xa0/2: Poly pressure */
  112. 2, /* 0xb0/3: Control change */
  113. 1, /* 0xc0/4: Program change */
  114. 1, /* 0xd0/5: Channel pressure */
  115. 2, /* 0xe0/6: Pitch bend */
  116. -1 /* 0xf0/7: System message (unsupported) */
  117. };
  118. static int xtab[8];
  119. static inline void decode_midi_byte(unsigned char b)
  120. {
  121. if(b & 0x80) /* New status! */
  122. {
  123. MDBG(log_printf(D3LOG, "\n%2.2X", b & 0xff));
  124. m_status = b;
  125. m_datacount = 0;
  126. m_channel = b & 0x0f;
  127. m_expect = xtab[(m_status >> 4) & 0x07];
  128. return;
  129. }
  130. MDBG(log_printf(D3LOG, " %2.2X", b));
  131. if(m_expect < 0)
  132. return; /* Ignore --> */
  133. m_buf[m_datacount++] = b;
  134. if(m_datacount >= m_expect)
  135. decode_midi_message();
  136. }
  137. #endif /*USE_MIDI*/
  138. int midi_open(midisock_t *output)
  139. {
  140. #ifdef USE_MIDI
  141. if(!output)
  142. output = &dummy_midisock;
  143. ms = output;
  144. /*
  145. * Set up the message length table to ignore messages
  146. * that aren't supported by the output midisock.
  147. */
  148. memset(xtab, -1, sizeof(xtab));
  149. if(output->note_off)
  150. xtab[0] = full_xtab[0];
  151. if(output->note_on)
  152. xtab[1] = full_xtab[1];
  153. if(output->poly_pressure)
  154. xtab[2] = full_xtab[2];
  155. if(output->control_change)
  156. xtab[3] = full_xtab[3];
  157. if(output->program_change)
  158. xtab[4] = full_xtab[4];
  159. if(output->channel_pressure)
  160. xtab[5] = full_xtab[5];
  161. if(output->pitch_bend)
  162. xtab[6] = full_xtab[6];
  163. mon = &monitor_midisock;
  164. #ifdef HAVE_ALSA
  165. if(snd_rawmidi_open(&m_in_fd, 0, 0, SND_RAWMIDI_OPEN_INPUT |
  166. SND_RAWMIDI_OPEN_NONBLOCK))
  167. {
  168. log_printf(ELOG, "Failed to open MIDI input device!\n");
  169. return -1;
  170. }
  171. # ifdef MIDI_THRU
  172. if(snd_rawmidi_open(&m_out_fd, 0, 0, SND_RAWMIDI_OPEN_OUTPUT))
  173. {
  174. log_printf(ELOG, "Failed to open MIDI output device!\n");
  175. return -2;
  176. }
  177. # endif
  178. return 0;
  179. #elif defined(HAVE_OSS)
  180. {
  181. # ifdef MIDI_THRU
  182. int flags = O_RDWR | O_NONBLOCK;
  183. # else
  184. int flags = O_RDONLY | O_NONBLOCK;
  185. # endif
  186. m_fd = open("/dev/midi00", flags);
  187. if(m_fd < 0)
  188. {
  189. log_printf(ELOG, "Failed to open MIDI device!\n");
  190. return -1;
  191. }
  192. return 0;
  193. }
  194. #endif /*HAVE_OSS*/
  195. #else /*USE_MIDI*/
  196. log_printf(ELOG, "MIDI support not compiled in!\n");
  197. return -3;
  198. #endif /*USE_MIDI*/
  199. }
  200. void midi_close(void)
  201. {
  202. #ifdef USE_MIDI
  203. #ifdef HAVE_ALSA
  204. if(m_in_fd)
  205. {
  206. snd_rawmidi_input_flush(m_in_fd);
  207. snd_rawmidi_close(m_in_fd);
  208. }
  209. if(m_out_fd)
  210. {
  211. snd_rawmidi_output_flush(m_out_fd);
  212. snd_rawmidi_close(m_out_fd);
  213. }
  214. m_in_fd = m_out_fd = NULL;
  215. #elif defined(HAVE_OSS)
  216. if(m_fd)
  217. close(m_fd);
  218. m_fd = 0;
  219. #endif
  220. #endif /*USE_MIDI*/
  221. }
  222. void midi_process(void)
  223. {
  224. #ifdef USE_MIDI
  225. int bytes;
  226. static char buf[MIDIMAXBYTES];
  227. if( (bytes = midi_read(buf, MIDIMAXBYTES)) > 0 )
  228. {
  229. char *bufp = buf;
  230. #ifdef MIDI_THRU
  231. midi_write(buf, bytes); /* MIDI Thru */
  232. #endif
  233. while(bytes--)
  234. decode_midi_byte(*bufp++);
  235. }
  236. #endif /*USE_MIDI*/
  237. }