diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/midi_synth.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/midi_synth.c')
-rw-r--r-- | sound/oss/midi_synth.c | 697 |
1 files changed, 697 insertions, 0 deletions
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c new file mode 100644 index 000000000000..972edc62afd1 --- /dev/null +++ b/sound/oss/midi_synth.c | |||
@@ -0,0 +1,697 @@ | |||
1 | /* | ||
2 | * sound/midi_synth.c | ||
3 | * | ||
4 | * High level midi sequencer manager for dumb MIDI interfaces. | ||
5 | */ | ||
6 | /* | ||
7 | * Copyright (C) by Hannu Savolainen 1993-1997 | ||
8 | * | ||
9 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
10 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
11 | * for more info. | ||
12 | */ | ||
13 | /* | ||
14 | * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) | ||
15 | * Andrew Veliath : fixed running status in MIDI input state machine | ||
16 | */ | ||
17 | #define USE_SEQ_MACROS | ||
18 | #define USE_SIMPLE_MACROS | ||
19 | |||
20 | #include "sound_config.h" | ||
21 | |||
22 | #define _MIDI_SYNTH_C_ | ||
23 | |||
24 | #include "midi_synth.h" | ||
25 | |||
26 | static int midi2synth[MAX_MIDI_DEV]; | ||
27 | static int sysex_state[MAX_MIDI_DEV] = | ||
28 | {0}; | ||
29 | static unsigned char prev_out_status[MAX_MIDI_DEV]; | ||
30 | |||
31 | #define STORE(cmd) \ | ||
32 | { \ | ||
33 | int len; \ | ||
34 | unsigned char obuf[8]; \ | ||
35 | cmd; \ | ||
36 | seq_input_event(obuf, len); \ | ||
37 | } | ||
38 | |||
39 | #define _seqbuf obuf | ||
40 | #define _seqbufptr 0 | ||
41 | #define _SEQ_ADVBUF(x) len=x | ||
42 | |||
43 | void | ||
44 | do_midi_msg(int synthno, unsigned char *msg, int mlen) | ||
45 | { | ||
46 | switch (msg[0] & 0xf0) | ||
47 | { | ||
48 | case 0x90: | ||
49 | if (msg[2] != 0) | ||
50 | { | ||
51 | STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); | ||
52 | break; | ||
53 | } | ||
54 | msg[2] = 64; | ||
55 | |||
56 | case 0x80: | ||
57 | STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); | ||
58 | break; | ||
59 | |||
60 | case 0xA0: | ||
61 | STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2])); | ||
62 | break; | ||
63 | |||
64 | case 0xB0: | ||
65 | STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, | ||
66 | msg[1], msg[2])); | ||
67 | break; | ||
68 | |||
69 | case 0xC0: | ||
70 | STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1])); | ||
71 | break; | ||
72 | |||
73 | case 0xD0: | ||
74 | STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1])); | ||
75 | break; | ||
76 | |||
77 | case 0xE0: | ||
78 | STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, | ||
79 | (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7))); | ||
80 | break; | ||
81 | |||
82 | default: | ||
83 | /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ | ||
84 | ; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void | ||
89 | midi_outc(int midi_dev, int data) | ||
90 | { | ||
91 | int timeout; | ||
92 | |||
93 | for (timeout = 0; timeout < 3200; timeout++) | ||
94 | if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff))) | ||
95 | { | ||
96 | if (data & 0x80) /* | ||
97 | * Status byte | ||
98 | */ | ||
99 | prev_out_status[midi_dev] = | ||
100 | (unsigned char) (data & 0xff); /* | ||
101 | * Store for running status | ||
102 | */ | ||
103 | return; /* | ||
104 | * Mission complete | ||
105 | */ | ||
106 | } | ||
107 | /* | ||
108 | * Sorry! No space on buffers. | ||
109 | */ | ||
110 | printk("Midi send timed out\n"); | ||
111 | } | ||
112 | |||
113 | static int | ||
114 | prefix_cmd(int midi_dev, unsigned char status) | ||
115 | { | ||
116 | if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) | ||
117 | return 1; | ||
118 | |||
119 | return midi_devs[midi_dev]->prefix_cmd(midi_dev, status); | ||
120 | } | ||
121 | |||
122 | static void | ||
123 | midi_synth_input(int orig_dev, unsigned char data) | ||
124 | { | ||
125 | int dev; | ||
126 | struct midi_input_info *inc; | ||
127 | |||
128 | static unsigned char len_tab[] = /* # of data bytes following a status | ||
129 | */ | ||
130 | { | ||
131 | 2, /* 8x */ | ||
132 | 2, /* 9x */ | ||
133 | 2, /* Ax */ | ||
134 | 2, /* Bx */ | ||
135 | 1, /* Cx */ | ||
136 | 1, /* Dx */ | ||
137 | 2, /* Ex */ | ||
138 | 0 /* Fx */ | ||
139 | }; | ||
140 | |||
141 | if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) | ||
142 | return; | ||
143 | |||
144 | if (data == 0xfe) /* Ignore active sensing */ | ||
145 | return; | ||
146 | |||
147 | dev = midi2synth[orig_dev]; | ||
148 | inc = &midi_devs[orig_dev]->in_info; | ||
149 | |||
150 | switch (inc->m_state) | ||
151 | { | ||
152 | case MST_INIT: | ||
153 | if (data & 0x80) /* MIDI status byte */ | ||
154 | { | ||
155 | if ((data & 0xf0) == 0xf0) /* Common message */ | ||
156 | { | ||
157 | switch (data) | ||
158 | { | ||
159 | case 0xf0: /* Sysex */ | ||
160 | inc->m_state = MST_SYSEX; | ||
161 | break; /* Sysex */ | ||
162 | |||
163 | case 0xf1: /* MTC quarter frame */ | ||
164 | case 0xf3: /* Song select */ | ||
165 | inc->m_state = MST_DATA; | ||
166 | inc->m_ptr = 1; | ||
167 | inc->m_left = 1; | ||
168 | inc->m_buf[0] = data; | ||
169 | break; | ||
170 | |||
171 | case 0xf2: /* Song position pointer */ | ||
172 | inc->m_state = MST_DATA; | ||
173 | inc->m_ptr = 1; | ||
174 | inc->m_left = 2; | ||
175 | inc->m_buf[0] = data; | ||
176 | break; | ||
177 | |||
178 | default: | ||
179 | inc->m_buf[0] = data; | ||
180 | inc->m_ptr = 1; | ||
181 | do_midi_msg(dev, inc->m_buf, inc->m_ptr); | ||
182 | inc->m_ptr = 0; | ||
183 | inc->m_left = 0; | ||
184 | } | ||
185 | } else | ||
186 | { | ||
187 | inc->m_state = MST_DATA; | ||
188 | inc->m_ptr = 1; | ||
189 | inc->m_left = len_tab[(data >> 4) - 8]; | ||
190 | inc->m_buf[0] = inc->m_prev_status = data; | ||
191 | } | ||
192 | } else if (inc->m_prev_status & 0x80) { | ||
193 | /* Data byte (use running status) */ | ||
194 | inc->m_ptr = 2; | ||
195 | inc->m_buf[1] = data; | ||
196 | inc->m_buf[0] = inc->m_prev_status; | ||
197 | inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; | ||
198 | if (inc->m_left > 0) | ||
199 | inc->m_state = MST_DATA; /* Not done yet */ | ||
200 | else { | ||
201 | inc->m_state = MST_INIT; | ||
202 | do_midi_msg(dev, inc->m_buf, inc->m_ptr); | ||
203 | inc->m_ptr = 0; | ||
204 | } | ||
205 | } | ||
206 | break; /* MST_INIT */ | ||
207 | |||
208 | case MST_DATA: | ||
209 | inc->m_buf[inc->m_ptr++] = data; | ||
210 | if (--inc->m_left <= 0) | ||
211 | { | ||
212 | inc->m_state = MST_INIT; | ||
213 | do_midi_msg(dev, inc->m_buf, inc->m_ptr); | ||
214 | inc->m_ptr = 0; | ||
215 | } | ||
216 | break; /* MST_DATA */ | ||
217 | |||
218 | case MST_SYSEX: | ||
219 | if (data == 0xf7) /* Sysex end */ | ||
220 | { | ||
221 | inc->m_state = MST_INIT; | ||
222 | inc->m_left = 0; | ||
223 | inc->m_ptr = 0; | ||
224 | } | ||
225 | break; /* MST_SYSEX */ | ||
226 | |||
227 | default: | ||
228 | printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); | ||
229 | inc->m_state = MST_INIT; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static void | ||
234 | leave_sysex(int dev) | ||
235 | { | ||
236 | int orig_dev = synth_devs[dev]->midi_dev; | ||
237 | int timeout = 0; | ||
238 | |||
239 | if (!sysex_state[dev]) | ||
240 | return; | ||
241 | |||
242 | sysex_state[dev] = 0; | ||
243 | |||
244 | while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && | ||
245 | timeout < 1000) | ||
246 | timeout++; | ||
247 | |||
248 | sysex_state[dev] = 0; | ||
249 | } | ||
250 | |||
251 | static void | ||
252 | midi_synth_output(int dev) | ||
253 | { | ||
254 | /* | ||
255 | * Currently NOP | ||
256 | */ | ||
257 | } | ||
258 | |||
259 | int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg) | ||
260 | { | ||
261 | /* | ||
262 | * int orig_dev = synth_devs[dev]->midi_dev; | ||
263 | */ | ||
264 | |||
265 | switch (cmd) { | ||
266 | |||
267 | case SNDCTL_SYNTH_INFO: | ||
268 | if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info))) | ||
269 | return -EFAULT; | ||
270 | return 0; | ||
271 | |||
272 | case SNDCTL_SYNTH_MEMAVL: | ||
273 | return 0x7fffffff; | ||
274 | |||
275 | default: | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | int | ||
281 | midi_synth_kill_note(int dev, int channel, int note, int velocity) | ||
282 | { | ||
283 | int orig_dev = synth_devs[dev]->midi_dev; | ||
284 | int msg, chn; | ||
285 | |||
286 | if (note < 0 || note > 127) | ||
287 | return 0; | ||
288 | if (channel < 0 || channel > 15) | ||
289 | return 0; | ||
290 | if (velocity < 0) | ||
291 | velocity = 0; | ||
292 | if (velocity > 127) | ||
293 | velocity = 127; | ||
294 | |||
295 | leave_sysex(dev); | ||
296 | |||
297 | msg = prev_out_status[orig_dev] & 0xf0; | ||
298 | chn = prev_out_status[orig_dev] & 0x0f; | ||
299 | |||
300 | if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) | ||
301 | { /* | ||
302 | * Use running status | ||
303 | */ | ||
304 | if (!prefix_cmd(orig_dev, note)) | ||
305 | return 0; | ||
306 | |||
307 | midi_outc(orig_dev, note); | ||
308 | |||
309 | if (msg == 0x90) /* | ||
310 | * Running status = Note on | ||
311 | */ | ||
312 | midi_outc(orig_dev, 0); /* | ||
313 | * Note on with velocity 0 == note | ||
314 | * off | ||
315 | */ | ||
316 | else | ||
317 | midi_outc(orig_dev, velocity); | ||
318 | } else | ||
319 | { | ||
320 | if (velocity == 64) | ||
321 | { | ||
322 | if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) | ||
323 | return 0; | ||
324 | midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* | ||
325 | * Note on | ||
326 | */ | ||
327 | midi_outc(orig_dev, note); | ||
328 | midi_outc(orig_dev, 0); /* | ||
329 | * Zero G | ||
330 | */ | ||
331 | } else | ||
332 | { | ||
333 | if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f))) | ||
334 | return 0; | ||
335 | midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* | ||
336 | * Note off | ||
337 | */ | ||
338 | midi_outc(orig_dev, note); | ||
339 | midi_outc(orig_dev, velocity); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | int | ||
347 | midi_synth_set_instr(int dev, int channel, int instr_no) | ||
348 | { | ||
349 | int orig_dev = synth_devs[dev]->midi_dev; | ||
350 | |||
351 | if (instr_no < 0 || instr_no > 127) | ||
352 | instr_no = 0; | ||
353 | if (channel < 0 || channel > 15) | ||
354 | return 0; | ||
355 | |||
356 | leave_sysex(dev); | ||
357 | |||
358 | if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f))) | ||
359 | return 0; | ||
360 | midi_outc(orig_dev, 0xc0 | (channel & 0x0f)); /* | ||
361 | * Program change | ||
362 | */ | ||
363 | midi_outc(orig_dev, instr_no); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | int | ||
369 | midi_synth_start_note(int dev, int channel, int note, int velocity) | ||
370 | { | ||
371 | int orig_dev = synth_devs[dev]->midi_dev; | ||
372 | int msg, chn; | ||
373 | |||
374 | if (note < 0 || note > 127) | ||
375 | return 0; | ||
376 | if (channel < 0 || channel > 15) | ||
377 | return 0; | ||
378 | if (velocity < 0) | ||
379 | velocity = 0; | ||
380 | if (velocity > 127) | ||
381 | velocity = 127; | ||
382 | |||
383 | leave_sysex(dev); | ||
384 | |||
385 | msg = prev_out_status[orig_dev] & 0xf0; | ||
386 | chn = prev_out_status[orig_dev] & 0x0f; | ||
387 | |||
388 | if (chn == channel && msg == 0x90) | ||
389 | { /* | ||
390 | * Use running status | ||
391 | */ | ||
392 | if (!prefix_cmd(orig_dev, note)) | ||
393 | return 0; | ||
394 | midi_outc(orig_dev, note); | ||
395 | midi_outc(orig_dev, velocity); | ||
396 | } else | ||
397 | { | ||
398 | if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) | ||
399 | return 0; | ||
400 | midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* | ||
401 | * Note on | ||
402 | */ | ||
403 | midi_outc(orig_dev, note); | ||
404 | midi_outc(orig_dev, velocity); | ||
405 | } | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | void | ||
410 | midi_synth_reset(int dev) | ||
411 | { | ||
412 | |||
413 | leave_sysex(dev); | ||
414 | } | ||
415 | |||
416 | int | ||
417 | midi_synth_open(int dev, int mode) | ||
418 | { | ||
419 | int orig_dev = synth_devs[dev]->midi_dev; | ||
420 | int err; | ||
421 | struct midi_input_info *inc; | ||
422 | |||
423 | if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) | ||
424 | return -ENXIO; | ||
425 | |||
426 | midi2synth[orig_dev] = dev; | ||
427 | sysex_state[dev] = 0; | ||
428 | prev_out_status[orig_dev] = 0; | ||
429 | |||
430 | if ((err = midi_devs[orig_dev]->open(orig_dev, mode, | ||
431 | midi_synth_input, midi_synth_output)) < 0) | ||
432 | return err; | ||
433 | inc = &midi_devs[orig_dev]->in_info; | ||
434 | |||
435 | /* save_flags(flags); | ||
436 | cli(); | ||
437 | don't know against what irqhandler to protect*/ | ||
438 | inc->m_busy = 0; | ||
439 | inc->m_state = MST_INIT; | ||
440 | inc->m_ptr = 0; | ||
441 | inc->m_left = 0; | ||
442 | inc->m_prev_status = 0x00; | ||
443 | /* restore_flags(flags); */ | ||
444 | |||
445 | return 1; | ||
446 | } | ||
447 | |||
448 | void | ||
449 | midi_synth_close(int dev) | ||
450 | { | ||
451 | int orig_dev = synth_devs[dev]->midi_dev; | ||
452 | |||
453 | leave_sysex(dev); | ||
454 | |||
455 | /* | ||
456 | * Shut up the synths by sending just single active sensing message. | ||
457 | */ | ||
458 | midi_devs[orig_dev]->outputc(orig_dev, 0xfe); | ||
459 | |||
460 | midi_devs[orig_dev]->close(orig_dev); | ||
461 | } | ||
462 | |||
463 | void | ||
464 | midi_synth_hw_control(int dev, unsigned char *event) | ||
465 | { | ||
466 | } | ||
467 | |||
468 | int | ||
469 | midi_synth_load_patch(int dev, int format, const char __user *addr, | ||
470 | int offs, int count, int pmgr_flag) | ||
471 | { | ||
472 | int orig_dev = synth_devs[dev]->midi_dev; | ||
473 | |||
474 | struct sysex_info sysex; | ||
475 | int i; | ||
476 | unsigned long left, src_offs, eox_seen = 0; | ||
477 | int first_byte = 1; | ||
478 | int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; | ||
479 | |||
480 | leave_sysex(dev); | ||
481 | |||
482 | if (!prefix_cmd(orig_dev, 0xf0)) | ||
483 | return 0; | ||
484 | |||
485 | if (format != SYSEX_PATCH) | ||
486 | { | ||
487 | /* printk("MIDI Error: Invalid patch format (key) 0x%x\n", format);*/ | ||
488 | return -EINVAL; | ||
489 | } | ||
490 | if (count < hdr_size) | ||
491 | { | ||
492 | /* printk("MIDI Error: Patch header too short\n");*/ | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | count -= hdr_size; | ||
496 | |||
497 | /* | ||
498 | * Copy the header from user space but ignore the first bytes which have | ||
499 | * been transferred already. | ||
500 | */ | ||
501 | |||
502 | if(copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs)) | ||
503 | return -EFAULT; | ||
504 | |||
505 | if (count < sysex.len) | ||
506 | { | ||
507 | /* printk(KERN_WARNING "MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len);*/ | ||
508 | sysex.len = count; | ||
509 | } | ||
510 | left = sysex.len; | ||
511 | src_offs = 0; | ||
512 | |||
513 | for (i = 0; i < left && !signal_pending(current); i++) | ||
514 | { | ||
515 | unsigned char data; | ||
516 | |||
517 | get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])); | ||
518 | |||
519 | eox_seen = (i > 0 && data & 0x80); /* End of sysex */ | ||
520 | |||
521 | if (eox_seen && data != 0xf7) | ||
522 | data = 0xf7; | ||
523 | |||
524 | if (i == 0) | ||
525 | { | ||
526 | if (data != 0xf0) | ||
527 | { | ||
528 | printk(KERN_WARNING "midi_synth: Sysex start missing\n"); | ||
529 | return -EINVAL; | ||
530 | } | ||
531 | } | ||
532 | while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && | ||
533 | !signal_pending(current)) | ||
534 | schedule(); | ||
535 | |||
536 | if (!first_byte && data & 0x80) | ||
537 | return 0; | ||
538 | first_byte = 0; | ||
539 | } | ||
540 | |||
541 | if (!eox_seen) | ||
542 | midi_outc(orig_dev, 0xf7); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | void midi_synth_panning(int dev, int channel, int pressure) | ||
547 | { | ||
548 | } | ||
549 | |||
550 | void midi_synth_aftertouch(int dev, int channel, int pressure) | ||
551 | { | ||
552 | int orig_dev = synth_devs[dev]->midi_dev; | ||
553 | int msg, chn; | ||
554 | |||
555 | if (pressure < 0 || pressure > 127) | ||
556 | return; | ||
557 | if (channel < 0 || channel > 15) | ||
558 | return; | ||
559 | |||
560 | leave_sysex(dev); | ||
561 | |||
562 | msg = prev_out_status[orig_dev] & 0xf0; | ||
563 | chn = prev_out_status[orig_dev] & 0x0f; | ||
564 | |||
565 | if (msg != 0xd0 || chn != channel) /* | ||
566 | * Test for running status | ||
567 | */ | ||
568 | { | ||
569 | if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f))) | ||
570 | return; | ||
571 | midi_outc(orig_dev, 0xd0 | (channel & 0x0f)); /* | ||
572 | * Channel pressure | ||
573 | */ | ||
574 | } else if (!prefix_cmd(orig_dev, pressure)) | ||
575 | return; | ||
576 | |||
577 | midi_outc(orig_dev, pressure); | ||
578 | } | ||
579 | |||
580 | void | ||
581 | midi_synth_controller(int dev, int channel, int ctrl_num, int value) | ||
582 | { | ||
583 | int orig_dev = synth_devs[dev]->midi_dev; | ||
584 | int chn, msg; | ||
585 | |||
586 | if (ctrl_num < 0 || ctrl_num > 127) | ||
587 | return; | ||
588 | if (channel < 0 || channel > 15) | ||
589 | return; | ||
590 | |||
591 | leave_sysex(dev); | ||
592 | |||
593 | msg = prev_out_status[orig_dev] & 0xf0; | ||
594 | chn = prev_out_status[orig_dev] & 0x0f; | ||
595 | |||
596 | if (msg != 0xb0 || chn != channel) | ||
597 | { | ||
598 | if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f))) | ||
599 | return; | ||
600 | midi_outc(orig_dev, 0xb0 | (channel & 0x0f)); | ||
601 | } else if (!prefix_cmd(orig_dev, ctrl_num)) | ||
602 | return; | ||
603 | |||
604 | midi_outc(orig_dev, ctrl_num); | ||
605 | midi_outc(orig_dev, value & 0x7f); | ||
606 | } | ||
607 | |||
608 | void | ||
609 | midi_synth_bender(int dev, int channel, int value) | ||
610 | { | ||
611 | int orig_dev = synth_devs[dev]->midi_dev; | ||
612 | int msg, prev_chn; | ||
613 | |||
614 | if (channel < 0 || channel > 15) | ||
615 | return; | ||
616 | |||
617 | if (value < 0 || value > 16383) | ||
618 | return; | ||
619 | |||
620 | leave_sysex(dev); | ||
621 | |||
622 | msg = prev_out_status[orig_dev] & 0xf0; | ||
623 | prev_chn = prev_out_status[orig_dev] & 0x0f; | ||
624 | |||
625 | if (msg != 0xd0 || prev_chn != channel) /* | ||
626 | * Test for running status | ||
627 | */ | ||
628 | { | ||
629 | if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f))) | ||
630 | return; | ||
631 | midi_outc(orig_dev, 0xe0 | (channel & 0x0f)); | ||
632 | } else if (!prefix_cmd(orig_dev, value & 0x7f)) | ||
633 | return; | ||
634 | |||
635 | midi_outc(orig_dev, value & 0x7f); | ||
636 | midi_outc(orig_dev, (value >> 7) & 0x7f); | ||
637 | } | ||
638 | |||
639 | void | ||
640 | midi_synth_setup_voice(int dev, int voice, int channel) | ||
641 | { | ||
642 | } | ||
643 | |||
644 | int | ||
645 | midi_synth_send_sysex(int dev, unsigned char *bytes, int len) | ||
646 | { | ||
647 | int orig_dev = synth_devs[dev]->midi_dev; | ||
648 | int i; | ||
649 | |||
650 | for (i = 0; i < len; i++) | ||
651 | { | ||
652 | switch (bytes[i]) | ||
653 | { | ||
654 | case 0xf0: /* Start sysex */ | ||
655 | if (!prefix_cmd(orig_dev, 0xf0)) | ||
656 | return 0; | ||
657 | sysex_state[dev] = 1; | ||
658 | break; | ||
659 | |||
660 | case 0xf7: /* End sysex */ | ||
661 | if (!sysex_state[dev]) /* Orphan sysex end */ | ||
662 | return 0; | ||
663 | sysex_state[dev] = 0; | ||
664 | break; | ||
665 | |||
666 | default: | ||
667 | if (!sysex_state[dev]) | ||
668 | return 0; | ||
669 | |||
670 | if (bytes[i] & 0x80) /* Error. Another message before sysex end */ | ||
671 | { | ||
672 | bytes[i] = 0xf7; /* Sysex end */ | ||
673 | sysex_state[dev] = 0; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i])) | ||
678 | { | ||
679 | /* | ||
680 | * Hardware level buffer is full. Abort the sysex message. | ||
681 | */ | ||
682 | |||
683 | int timeout = 0; | ||
684 | |||
685 | bytes[i] = 0xf7; | ||
686 | sysex_state[dev] = 0; | ||
687 | |||
688 | while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) && | ||
689 | timeout < 1000) | ||
690 | timeout++; | ||
691 | } | ||
692 | if (!sysex_state[dev]) | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | return 0; | ||
697 | } | ||