1 /*
2 * Copyright by Hannu Savolainen 1993
3 *
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
6 * conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
15 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * $FreeBSD: releng/5.2/sys/dev/sound/midi/midisynth.c 88869 2002-01-04 01:13:49Z tanimura $
28 *
29 */
30
31 /*
32 * This is the interface for a sequencer to interact a midi driver.
33 * This interface translates the sequencer operations to the corresponding
34 * midi messages, and vice versa.
35 */
36
37 #include <dev/sound/midi/midi.h>
38
39 #define TYPEDRANGE(type, x, lower, upper) \
40 { \
41 type tl, tu; \
42 tl = (lower); \
43 tu = (upper); \
44 if (x < tl) { \
45 x = tl; \
46 } else if(x > tu) { \
47 x = tu; \
48 } \
49 }
50
51 /*
52 * These functions goes into midisynthdev_op_desc.
53 */
54 static mdsy_killnote_t synth_killnote;
55 static mdsy_setinstr_t synth_setinstr;
56 static mdsy_startnote_t synth_startnote;
57 static mdsy_reset_t synth_reset;
58 static mdsy_hwcontrol_t synth_hwcontrol;
59 static mdsy_loadpatch_t synth_loadpatch;
60 static mdsy_panning_t synth_panning;
61 static mdsy_aftertouch_t synth_aftertouch;
62 static mdsy_controller_t synth_controller;
63 static mdsy_patchmgr_t synth_patchmgr;
64 static mdsy_bender_t synth_bender;
65 static mdsy_allocvoice_t synth_allocvoice;
66 static mdsy_setupvoice_t synth_setupvoice;
67 static mdsy_sendsysex_t synth_sendsysex;
68 static mdsy_prefixcmd_t synth_prefixcmd;
69 static mdsy_volumemethod_t synth_volumemethod;
70 static mdsy_readraw_t synth_readraw;
71 static mdsy_writeraw_t synth_writeraw;
72
73 /*
74 * This is the synthdev_info for a midi interface device.
75 * You may have to replace a few of functions for an internal
76 * synthesizer.
77 */
78 synthdev_info midisynth_op_desc = {
79 synth_killnote,
80 synth_setinstr,
81 synth_startnote,
82 synth_reset,
83 synth_hwcontrol,
84 synth_loadpatch,
85 synth_panning,
86 synth_aftertouch,
87 synth_controller,
88 synth_patchmgr,
89 synth_bender,
90 synth_allocvoice,
91 synth_setupvoice,
92 synth_sendsysex,
93 synth_prefixcmd,
94 synth_volumemethod,
95 synth_readraw,
96 synth_writeraw,
97 };
98
99 /* The following functions are local. */
100 static int synth_leavesysex(mididev_info *md);
101
102 /*
103 * Here are the main functions to interact to the midi sequencer.
104 * These are called from the sequencer functions in sequencer.c.
105 */
106
107 static int
108 synth_killnote(mididev_info *md, int chn, int note, int vel)
109 {
110 int unit, lenw;
111 synthdev_info *sd;
112 u_char c[3];
113
114 unit = md->unit;
115 sd = &md->synth;
116
117 if (note < 0 || note > 127 || chn < 0 || chn > 15)
118 return (EINVAL);
119 TYPEDRANGE(int, vel, 0, 127);
120 if (synth_leavesysex(md) == EAGAIN)
121 return (EAGAIN);
122
123 if (vel == 64) {
124 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
125 c[1] = (u_char)note;
126 c[2] = 0;
127 } else {
128 c[0] = 0x80 | (chn & 0x0f); /* Note off. */
129 c[1] = (u_char)note;
130 c[2] = (u_char)vel;
131 }
132
133 if (synth_prefixcmd(md, c[0]))
134 return (0);
135
136 return (md->synth.writeraw(md, c, 3, &lenw, 1));
137 }
138
139 static int
140 synth_setinstr(mididev_info *md, int chn, int instr)
141 {
142 int unit, lenw;
143 synthdev_info *sd;
144 u_char c[2];
145
146 unit = md->unit;
147 sd = &md->synth;
148
149 if (instr < 0 || instr > 127 || chn < 0 || chn > 15)
150 return (EINVAL);
151
152 if (synth_leavesysex(md) == EAGAIN)
153 return (EAGAIN);
154
155 c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
156 c[1] = (u_char)instr;
157
158 return (md->synth.writeraw(md, c, 3, &lenw, 1));
159 }
160
161 static int
162 synth_startnote(mididev_info *md, int chn, int note, int vel)
163 {
164 int unit, lenw;
165 synthdev_info *sd;
166 u_char c[3];
167
168 unit = md->unit;
169 sd = &md->synth;
170
171 if (note < 0 || note > 127 || chn < 0 || chn > 15)
172 return (EINVAL);
173 TYPEDRANGE(int, vel, 0, 127);
174 if (synth_leavesysex(md) == EAGAIN)
175 return (EAGAIN);
176
177 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
178 c[1] = (u_char)note;
179 c[2] = (u_char)vel;
180 if (synth_prefixcmd(md, c[0]))
181 return (0);
182
183 return (md->synth.writeraw(md, c, 3, &lenw, 1));
184 }
185
186 static int
187 synth_reset(mididev_info *md)
188 {
189 synth_leavesysex(md);
190 return (0);
191 }
192
193 static int
194 synth_hwcontrol(mididev_info *md, u_char *event)
195 {
196 /* NOP. */
197 return (0);
198 }
199
200 static int
201 synth_loadpatch(mididev_info *md, int format, struct uio *buf, int offs, int count, int pmgr_flag)
202 {
203 struct sysex_info sysex;
204 synthdev_info *sd;
205 int unit, i, eox_seen, first_byte, left, src_offs, hdr_size, lenw;
206 u_char c[count];
207
208 unit = md->unit;
209 sd = &md->synth;
210
211 eox_seen = 0;
212 first_byte = 1;
213 hdr_size = offsetof(struct sysex_info, data);
214
215 if (synth_leavesysex(md) == EAGAIN)
216 return (EAGAIN);
217
218 if (synth_prefixcmd(md, 0xf0))
219 return (0);
220 if (format != SYSEX_PATCH) {
221 printf("synth_loadpatch: patch format 0x%x is invalid.\n", format);
222 return (EINVAL);
223 }
224 if (count < hdr_size) {
225 printf("synth_loadpatch: patch header is too short.\n");
226 return (EINVAL);
227 }
228 count -= hdr_size;
229
230 /* Copy the patch data. */
231 if (uiomove((caddr_t)&((char *)&sysex)[offs], hdr_size - offs, buf))
232 printf("synth_loadpatch: memory mangled?\n");
233
234 if (count < sysex.len) {
235 sysex.len = (long)count;
236 printf("synth_loadpatch: sysex record of %d bytes is too long, adjusted to %d bytes.\n", (int)sysex.len, count);
237 }
238 left = sysex.len;
239 src_offs = 0;
240
241 for (i = 0 ; i < left ; i++) {
242 uiomove((caddr_t)&c[i], 1, buf);
243 eox_seen = i > 0 && (c[i] & 0x80) != 0;
244 if (eox_seen && c[i] != 0xf7)
245 c[i] = 0xf7;
246 if (i == 0 && c[i] != 0x80) {
247 printf("synth_loadpatch: sysex does not begin with the status.\n");
248 return (EINVAL);
249 }
250 if (!first_byte && (c[i] & 0x80) != 0) {
251 md->synth.writeraw(md, c, i + 1, &lenw, 0);
252 return (0);
253 }
254 first_byte = 0;
255 }
256
257 if (!eox_seen) {
258 c[0] = 0xf7;
259 md->synth.writeraw(md, c, 1, &lenw, 0);
260 }
261
262 return (0);
263 }
264
265 static int
266 synth_panning(mididev_info *md, int chn, int pan)
267 {
268 /* NOP. */
269 return (0);
270 }
271
272 static int
273 synth_aftertouch(mididev_info *md, int chn, int press)
274 {
275 int unit, lenw;
276 synthdev_info *sd;
277 u_char c[2];
278
279 unit = md->unit;
280 sd = &md->synth;
281
282 if (press < 0 || press > 127 || chn < 0 || chn > 15)
283 return (EINVAL);
284 if (synth_leavesysex(md) == EAGAIN)
285 return (EAGAIN);
286
287 c[0] = 0xd0 | (chn & 0x0f); /* Channel Pressure. */
288 c[1] = (u_char)press;
289 if (synth_prefixcmd(md, c[0]))
290 return (0);
291
292 return (md->synth.writeraw(md, c, 2, &lenw, 1));
293 }
294
295 static int
296 synth_controller(mididev_info *md, int chn, int ctrlnum, int val)
297 {
298 int unit, lenw;
299 synthdev_info *sd;
300 u_char c[3];
301
302 unit = md->unit;
303 sd = &md->synth;
304
305 if (ctrlnum < 1 || ctrlnum > 127 || chn < 0 || chn > 15)
306 return (EINVAL);
307 if (synth_leavesysex(md) == EAGAIN)
308 return (EAGAIN);
309
310 c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
311 c[1] = (u_char)ctrlnum;
312 if (synth_prefixcmd(md, c[0]))
313 return (0);
314
315 return (md->synth.writeraw(md, c, 3, &lenw, 1));
316 }
317
318 static int
319 synth_patchmgr(mididev_info *md, struct patmgr_info *rec)
320 {
321 return (EINVAL);
322 }
323
324 static int
325 synth_bender(mididev_info *md, int chn, int val)
326 {
327 int unit, lenw;
328 synthdev_info *sd;
329 u_char c[3];
330
331 unit = md->unit;
332 sd = &md->synth;
333
334 if (val < 0 || val > 16383 || chn < 0 || chn > 15)
335 return (EINVAL);
336 if (synth_leavesysex(md) == EAGAIN)
337 return (EAGAIN);
338
339 c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
340 c[1] = (u_char)val & 0x7f;
341 c[2] = (u_char)(val >> 7) & 0x7f;
342 if (synth_prefixcmd(md, c[0]))
343 return (0);
344
345 return (md->synth.writeraw(md, c, 3, &lenw, 1));
346 }
347
348 static int
349 synth_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *alloc)
350 {
351 /* NOP. */
352 return (0);
353 }
354
355 static int
356 synth_setupvoice(mididev_info *md, int voice, int chn)
357 {
358 /* NOP. */
359 return (0);
360 }
361
362 static int
363 synth_sendsysex(mididev_info *md, u_char *sysex, int len)
364 {
365 int unit, i, lenw;
366 synthdev_info *sd;
367 u_char c[len];
368
369 unit = md->unit;
370 sd = &md->synth;
371
372 mtx_lock(&sd->status_mtx);
373 for (i = 0 ; i < len ; i++) {
374 switch (sysex[i]) {
375 case 0xf0:
376 /* Sysex begins. */
377 if (synth_prefixcmd(md, 0xf0)) {
378 mtx_unlock(&sd->status_mtx);
379 return (0);
380 }
381 sd->sysex_state = 1;
382 break;
383 case 0xf7:
384 /* Sysex ends. */
385 if (!sd->sysex_state) {
386 mtx_unlock(&sd->status_mtx);
387 return (0);
388 }
389 sd->sysex_state = 0;
390 break;
391 default:
392 if (!sd->sysex_state) {
393 mtx_unlock(&sd->status_mtx);
394 return (0);
395 }
396 if ((sysex[i] & 0x80) != 0) {
397 /* A status in a sysex? */
398 sysex[i] = 0xf7;
399 sd->sysex_state = 0;
400 }
401 break;
402 }
403 c[i] = sysex[i];
404 if (!sd->sysex_state)
405 break;
406 }
407 mtx_unlock(&sd->status_mtx);
408
409 return (md->synth.writeraw(md, c, i, &lenw, 1));
410 }
411
412 static int
413 synth_prefixcmd(mididev_info *md, int status)
414 {
415 /* NOP. */
416 return (0);
417 }
418
419 static int
420 synth_volumemethod(mididev_info *md, int mode)
421 {
422 /* NOP. */
423 return (0);
424 }
425
426 static int
427 synth_readraw(mididev_info *md, u_char *buf, int len, int *lenr, int nonblock)
428 {
429 int unit, ret;
430
431 if (md == NULL)
432 return (ENXIO);
433 if (lenr == NULL)
434 return (EINVAL);
435
436 *lenr = 0;
437 unit = md->unit;
438
439 if ((md->fflags & FREAD) == 0) {
440 MIDI_DEBUG(printf("synth_readraw: unit %d is not for reading.\n", unit));
441 return (EIO);
442 }
443
444 mtx_lock(&md->flagqueue_mtx);
445
446 /* Begin recording. */
447 if ((md->flags & MIDI_F_READING) == 0)
448 md->callback(md, MIDI_CB_START | MIDI_CB_RD);
449
450 if (nonblock) {
451 /* Have we got enough data to read? */
452 if (md->midi_dbuf_in.rl < len) {
453 mtx_unlock(&md->flagqueue_mtx);
454 return (EAGAIN);
455 }
456 }
457
458 ret = midibuf_seqread(&md->midi_dbuf_in, buf, len, lenr,
459 md->callback, md, MIDI_CB_START | MIDI_CB_RD,
460 &md->flagqueue_mtx);
461
462 mtx_unlock(&md->flagqueue_mtx);
463
464 return (ret);
465 }
466
467 static int
468 synth_writeraw(mididev_info *md, u_char *buf, int len, int *lenw, int nonblock)
469 {
470 int unit, ret;
471
472 if (md == NULL)
473 return (ENXIO);
474 if (lenw == NULL)
475 return (EINVAL);
476
477 *lenw = 0;
478 unit = md->unit;
479
480 if ((md->fflags & FWRITE) == 0) {
481 MIDI_DEBUG(printf("synth_writeraw: unit %d is not for writing.\n", unit));
482 return (EIO);
483 }
484
485 /* For nonblocking, have we got enough space to write? */
486 mtx_lock(&md->flagqueue_mtx);
487 if (nonblock && md->midi_dbuf_out.fl < len) {
488 /* Begin playing. */
489 md->callback(md, MIDI_CB_START | MIDI_CB_WR);
490 mtx_unlock(&md->flagqueue_mtx);
491 return (EAGAIN);
492 }
493
494 ret = midibuf_seqwrite(&md->midi_dbuf_out, buf, len, lenw,
495 md->callback, md, MIDI_CB_START | MIDI_CB_WR,
496 &md->flagqueue_mtx);
497
498 if (ret == 0)
499 /* Begin playing. */
500 md->callback(md, MIDI_CB_START | MIDI_CB_WR);
501
502 mtx_unlock(&md->flagqueue_mtx);
503
504 return (ret);
505 }
506
507 /*
508 * The functions below here are the libraries for the above ones.
509 */
510
511 static int
512 synth_leavesysex(mididev_info *md)
513 {
514 int unit, lenw;
515 synthdev_info *sd;
516 u_char c;
517
518 unit = md->unit;
519 sd = &md->synth;
520
521 mtx_lock(&sd->status_mtx);
522 if (!sd->sysex_state) {
523 mtx_unlock(&sd->status_mtx);
524 return (0);
525 }
526
527 sd->sysex_state = 0;
528 mtx_unlock(&sd->status_mtx);
529 c = 0xf7;
530
531 return (md->synth.writeraw(md, &c, sizeof(c), &lenw, 1));
532 }
Cache object: 72258b0686981032ad34d92b6b8e3d54
|