]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * OSS compatible sequencer driver | |
3 | * | |
4 | * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | #include "seq_oss_device.h" | |
22 | #include "seq_oss_synth.h" | |
23 | #include "seq_oss_midi.h" | |
24 | #include "seq_oss_event.h" | |
25 | #include "seq_oss_timer.h" | |
26 | #include <sound/seq_oss_legacy.h> | |
27 | #include "seq_oss_readq.h" | |
28 | #include "seq_oss_writeq.h" | |
29 | ||
30 | ||
31 | /* | |
32 | * prototypes | |
33 | */ | |
34 | static int extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev); | |
35 | static int chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev); | |
36 | static int chn_common_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev); | |
37 | static int timing_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev); | |
38 | static int local_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev); | |
39 | static int old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev); | |
40 | static int note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev); | |
41 | static int note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev); | |
42 | static int set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev); | |
43 | static int set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev); | |
44 | static int set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev); | |
45 | ||
46 | ||
47 | /* | |
48 | * convert an OSS event to ALSA event | |
49 | * return 0 : enqueued | |
50 | * non-zero : invalid - ignored | |
51 | */ | |
52 | ||
53 | int | |
54 | snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
55 | { | |
56 | switch (q->s.code) { | |
57 | case SEQ_EXTENDED: | |
58 | return extended_event(dp, q, ev); | |
59 | ||
60 | case EV_CHN_VOICE: | |
61 | return chn_voice_event(dp, q, ev); | |
62 | ||
63 | case EV_CHN_COMMON: | |
64 | return chn_common_event(dp, q, ev); | |
65 | ||
66 | case EV_TIMING: | |
67 | return timing_event(dp, q, ev); | |
68 | ||
69 | case EV_SEQ_LOCAL: | |
70 | return local_event(dp, q, ev); | |
71 | ||
72 | case EV_SYSEX: | |
73 | return snd_seq_oss_synth_sysex(dp, q->x.dev, q->x.buf, ev); | |
74 | ||
75 | case SEQ_MIDIPUTC: | |
76 | if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) | |
77 | return -EINVAL; | |
78 | /* put a midi byte */ | |
79 | if (! is_write_mode(dp->file_mode)) | |
80 | break; | |
81 | if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE)) | |
82 | break; | |
83 | if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE) | |
84 | return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev); | |
85 | break; | |
86 | ||
87 | case SEQ_ECHO: | |
88 | if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) | |
89 | return -EINVAL; | |
90 | return set_echo_event(dp, q, ev); | |
91 | ||
92 | case SEQ_PRIVATE: | |
93 | if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) | |
94 | return -EINVAL; | |
95 | return snd_seq_oss_synth_raw_event(dp, q->c[1], q->c, ev); | |
96 | ||
97 | default: | |
98 | if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) | |
99 | return -EINVAL; | |
100 | return old_event(dp, q, ev); | |
101 | } | |
102 | return -EINVAL; | |
103 | } | |
104 | ||
105 | /* old type events: mode1 only */ | |
106 | static int | |
107 | old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
108 | { | |
109 | switch (q->s.code) { | |
110 | case SEQ_NOTEOFF: | |
111 | return note_off_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev); | |
112 | ||
113 | case SEQ_NOTEON: | |
114 | return note_on_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev); | |
115 | ||
116 | case SEQ_WAIT: | |
117 | /* skip */ | |
118 | break; | |
119 | ||
120 | case SEQ_PGMCHANGE: | |
121 | return set_control_event(dp, 0, SNDRV_SEQ_EVENT_PGMCHANGE, | |
122 | q->n.chn, 0, q->n.note, ev); | |
123 | ||
124 | case SEQ_SYNCTIMER: | |
125 | return snd_seq_oss_timer_reset(dp->timer); | |
126 | } | |
127 | ||
128 | return -EINVAL; | |
129 | } | |
130 | ||
131 | /* 8bytes extended event: mode1 only */ | |
132 | static int | |
133 | extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
134 | { | |
135 | int val; | |
136 | ||
137 | switch (q->e.cmd) { | |
138 | case SEQ_NOTEOFF: | |
139 | return note_off_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev); | |
140 | ||
141 | case SEQ_NOTEON: | |
142 | return note_on_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev); | |
143 | ||
144 | case SEQ_PGMCHANGE: | |
145 | return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_PGMCHANGE, | |
146 | q->e.chn, 0, q->e.p1, ev); | |
147 | ||
148 | case SEQ_AFTERTOUCH: | |
149 | return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CHANPRESS, | |
150 | q->e.chn, 0, q->e.p1, ev); | |
151 | ||
152 | case SEQ_BALANCE: | |
153 | /* convert -128:127 to 0:127 */ | |
154 | val = (char)q->e.p1; | |
155 | val = (val + 128) / 2; | |
156 | return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CONTROLLER, | |
157 | q->e.chn, CTL_PAN, val, ev); | |
158 | ||
159 | case SEQ_CONTROLLER: | |
160 | val = ((short)q->e.p3 << 8) | (short)q->e.p2; | |
161 | switch (q->e.p1) { | |
162 | case CTRL_PITCH_BENDER: /* SEQ1 V2 control */ | |
163 | /* -0x2000:0x1fff */ | |
164 | return set_control_event(dp, q->e.dev, | |
165 | SNDRV_SEQ_EVENT_PITCHBEND, | |
166 | q->e.chn, 0, val, ev); | |
167 | case CTRL_PITCH_BENDER_RANGE: | |
168 | /* conversion: 100/semitone -> 128/semitone */ | |
169 | return set_control_event(dp, q->e.dev, | |
170 | SNDRV_SEQ_EVENT_REGPARAM, | |
171 | q->e.chn, 0, val*128/100, ev); | |
172 | default: | |
173 | return set_control_event(dp, q->e.dev, | |
174 | SNDRV_SEQ_EVENT_CONTROL14, | |
175 | q->e.chn, q->e.p1, val, ev); | |
176 | } | |
177 | ||
178 | case SEQ_VOLMODE: | |
179 | return snd_seq_oss_synth_raw_event(dp, q->e.dev, q->c, ev); | |
180 | ||
181 | } | |
182 | return -EINVAL; | |
183 | } | |
184 | ||
185 | /* channel voice events: mode1 and 2 */ | |
186 | static int | |
187 | chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
188 | { | |
189 | if (q->v.chn >= 32) | |
190 | return -EINVAL; | |
191 | switch (q->v.cmd) { | |
192 | case MIDI_NOTEON: | |
193 | return note_on_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev); | |
194 | ||
195 | case MIDI_NOTEOFF: | |
196 | return note_off_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev); | |
197 | ||
198 | case MIDI_KEY_PRESSURE: | |
199 | return set_note_event(dp, q->v.dev, SNDRV_SEQ_EVENT_KEYPRESS, | |
200 | q->v.chn, q->v.note, q->v.parm, ev); | |
201 | ||
202 | } | |
203 | return -EINVAL; | |
204 | } | |
205 | ||
206 | /* channel common events: mode1 and 2 */ | |
207 | static int | |
208 | chn_common_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
209 | { | |
210 | if (q->l.chn >= 32) | |
211 | return -EINVAL; | |
212 | switch (q->l.cmd) { | |
213 | case MIDI_PGM_CHANGE: | |
214 | return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PGMCHANGE, | |
215 | q->l.chn, 0, q->l.p1, ev); | |
216 | ||
217 | case MIDI_CTL_CHANGE: | |
218 | return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CONTROLLER, | |
219 | q->l.chn, q->l.p1, q->l.val, ev); | |
220 | ||
221 | case MIDI_PITCH_BEND: | |
222 | /* conversion: 0:0x3fff -> -0x2000:0x1fff */ | |
223 | return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PITCHBEND, | |
224 | q->l.chn, 0, q->l.val - 8192, ev); | |
225 | ||
226 | case MIDI_CHN_PRESSURE: | |
227 | return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CHANPRESS, | |
228 | q->l.chn, 0, q->l.val, ev); | |
229 | } | |
230 | return -EINVAL; | |
231 | } | |
232 | ||
233 | /* timer events: mode1 and mode2 */ | |
234 | static int | |
235 | timing_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
236 | { | |
237 | switch (q->t.cmd) { | |
238 | case TMR_ECHO: | |
239 | if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) | |
240 | return set_echo_event(dp, q, ev); | |
241 | else { | |
242 | evrec_t tmp; | |
243 | memset(&tmp, 0, sizeof(tmp)); | |
244 | /* XXX: only for little-endian! */ | |
245 | tmp.echo = (q->t.time << 8) | SEQ_ECHO; | |
246 | return set_echo_event(dp, &tmp, ev); | |
247 | } | |
248 | ||
249 | case TMR_STOP: | |
250 | if (dp->seq_mode) | |
251 | return snd_seq_oss_timer_stop(dp->timer); | |
252 | return 0; | |
253 | ||
254 | case TMR_CONTINUE: | |
255 | if (dp->seq_mode) | |
256 | return snd_seq_oss_timer_continue(dp->timer); | |
257 | return 0; | |
258 | ||
259 | case TMR_TEMPO: | |
260 | if (dp->seq_mode) | |
261 | return snd_seq_oss_timer_tempo(dp->timer, q->t.time); | |
262 | return 0; | |
263 | } | |
264 | ||
265 | return -EINVAL; | |
266 | } | |
267 | ||
268 | /* local events: mode1 and 2 */ | |
269 | static int | |
270 | local_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev) | |
271 | { | |
272 | return -EINVAL; | |
273 | } | |
274 | ||
275 | /* | |
276 | * process note-on event for OSS synth | |
277 | * three different modes are available: | |
278 | * - SNDRV_SEQ_OSS_PROCESS_EVENTS (for one-voice per channel mode) | |
279 | * Accept note 255 as volume change. | |
280 | * - SNDRV_SEQ_OSS_PASS_EVENTS | |
281 | * Pass all events to lowlevel driver anyway | |
282 | * - SNDRV_SEQ_OSS_PROCESS_KEYPRESS (mostly for Emu8000) | |
283 | * Use key-pressure if note >= 128 | |
284 | */ | |
285 | static int | |
286 | note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev) | |
287 | { | |
288 | seq_oss_synthinfo_t *info = &dp->synths[dev]; | |
289 | switch (info->arg.event_passing) { | |
290 | case SNDRV_SEQ_OSS_PROCESS_EVENTS: | |
291 | if (! info->ch || ch < 0 || ch >= info->nr_voices) { | |
292 | /* pass directly */ | |
293 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); | |
294 | } | |
295 | ||
296 | if (note == 255 && info->ch[ch].note >= 0) { | |
297 | /* volume control */ | |
298 | int type; | |
299 | //if (! vel) | |
300 | /* set volume to zero -- note off */ | |
301 | // type = SNDRV_SEQ_EVENT_NOTEOFF; | |
302 | //else | |
303 | if (info->ch[ch].vel) | |
304 | /* sample already started -- volume change */ | |
305 | type = SNDRV_SEQ_EVENT_KEYPRESS; | |
306 | else | |
307 | /* sample not started -- start now */ | |
308 | type = SNDRV_SEQ_EVENT_NOTEON; | |
309 | info->ch[ch].vel = vel; | |
310 | return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev); | |
311 | } else if (note >= 128) | |
312 | return -EINVAL; /* invalid */ | |
313 | ||
314 | if (note != info->ch[ch].note && info->ch[ch].note >= 0) | |
315 | /* note changed - note off at beginning */ | |
316 | set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev); | |
317 | /* set current status */ | |
318 | info->ch[ch].note = note; | |
319 | info->ch[ch].vel = vel; | |
320 | if (vel) /* non-zero velocity - start the note now */ | |
321 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); | |
322 | return -EINVAL; | |
323 | ||
324 | case SNDRV_SEQ_OSS_PASS_EVENTS: | |
325 | /* pass the event anyway */ | |
326 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); | |
327 | ||
328 | case SNDRV_SEQ_OSS_PROCESS_KEYPRESS: | |
329 | if (note >= 128) /* key pressure: shifted by 128 */ | |
330 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev); | |
331 | else /* normal note-on event */ | |
332 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); | |
333 | } | |
334 | return -EINVAL; | |
335 | } | |
336 | ||
337 | /* | |
338 | * process note-off event for OSS synth | |
339 | */ | |
340 | static int | |
341 | note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev) | |
342 | { | |
343 | seq_oss_synthinfo_t *info = &dp->synths[dev]; | |
344 | switch (info->arg.event_passing) { | |
345 | case SNDRV_SEQ_OSS_PROCESS_EVENTS: | |
346 | if (! info->ch || ch < 0 || ch >= info->nr_voices) { | |
347 | /* pass directly */ | |
348 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); | |
349 | } | |
350 | ||
351 | if (info->ch[ch].note >= 0) { | |
352 | note = info->ch[ch].note; | |
353 | info->ch[ch].vel = 0; | |
354 | info->ch[ch].note = -1; | |
355 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev); | |
356 | } | |
357 | return -EINVAL; /* invalid */ | |
358 | ||
359 | case SNDRV_SEQ_OSS_PASS_EVENTS: | |
360 | case SNDRV_SEQ_OSS_PROCESS_KEYPRESS: | |
361 | /* pass the event anyway */ | |
362 | return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev); | |
363 | ||
364 | } | |
365 | return -EINVAL; | |
366 | } | |
367 | ||
368 | /* | |
369 | * create a note event | |
370 | */ | |
371 | static int | |
372 | set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev) | |
373 | { | |
374 | if (! snd_seq_oss_synth_is_valid(dp, dev)) | |
375 | return -ENXIO; | |
376 | ||
377 | ev->type = type; | |
378 | snd_seq_oss_synth_addr(dp, dev, ev); | |
379 | ev->data.note.channel = ch; | |
380 | ev->data.note.note = note; | |
381 | ev->data.note.velocity = vel; | |
382 | ||
383 | return 0; | |
384 | } | |
385 | ||
386 | /* | |
387 | * create a control event | |
388 | */ | |
389 | static int | |
390 | set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev) | |
391 | { | |
392 | if (! snd_seq_oss_synth_is_valid(dp, dev)) | |
393 | return -ENXIO; | |
394 | ||
395 | ev->type = type; | |
396 | snd_seq_oss_synth_addr(dp, dev, ev); | |
397 | ev->data.control.channel = ch; | |
398 | ev->data.control.param = param; | |
399 | ev->data.control.value = val; | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
404 | /* | |
405 | * create an echo event | |
406 | */ | |
407 | static int | |
408 | set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev) | |
409 | { | |
410 | ev->type = SNDRV_SEQ_EVENT_ECHO; | |
411 | /* echo back to itself */ | |
412 | snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port); | |
413 | memcpy(&ev->data, rec, LONG_EVENT_SIZE); | |
414 | return 0; | |
415 | } | |
416 | ||
417 | /* | |
418 | * event input callback from ALSA sequencer: | |
419 | * the echo event is processed here. | |
420 | */ | |
421 | int | |
422 | snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data, | |
423 | int atomic, int hop) | |
424 | { | |
425 | seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private_data; | |
426 | evrec_t *rec; | |
427 | ||
428 | if (ev->type != SNDRV_SEQ_EVENT_ECHO) | |
429 | return snd_seq_oss_midi_input(ev, direct, private_data); | |
430 | ||
431 | if (ev->source.client != dp->cseq) | |
432 | return 0; /* ignored */ | |
433 | ||
434 | rec = (evrec_t*)&ev->data; | |
435 | if (rec->s.code == SEQ_SYNCTIMER) { | |
436 | /* sync echo back */ | |
437 | snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time); | |
438 | ||
439 | } else { | |
440 | /* echo back event */ | |
441 | if (dp->readq == NULL) | |
442 | return 0; | |
443 | snd_seq_oss_readq_put_event(dp->readq, rec); | |
444 | } | |
445 | return 0; | |
446 | } | |
447 |