]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * MIDI byte <-> sequencer event coder | |
3 | * | |
4 | * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>, | |
5 | * Jaroslav Kysela <perex@suse.cz> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | */ | |
21 | ||
22 | #include <sound/driver.h> | |
23 | #include <linux/slab.h> | |
24 | #include <linux/errno.h> | |
25 | #include <linux/string.h> | |
26 | #include <sound/core.h> | |
27 | #include <sound/seq_kernel.h> | |
28 | #include <sound/seq_midi_event.h> | |
29 | #include <sound/asoundef.h> | |
30 | ||
31 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>"); | |
32 | MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder"); | |
33 | MODULE_LICENSE("GPL"); | |
34 | ||
35 | /* queue type */ | |
36 | /* from 0 to 7 are normal commands (note off, on, etc.) */ | |
37 | #define ST_NOTEOFF 0 | |
38 | #define ST_NOTEON 1 | |
39 | #define ST_SPECIAL 8 | |
40 | #define ST_SYSEX ST_SPECIAL | |
41 | /* from 8 to 15 are events for 0xf0-0xf7 */ | |
42 | ||
43 | ||
1da177e4 LT |
44 | /* |
45 | * prototypes | |
46 | */ | |
c7e0b5bf TI |
47 | static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev); |
48 | static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
49 | static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
50 | static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
51 | static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
52 | static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
53 | static void note_decode(struct snd_seq_event *ev, unsigned char *buf); | |
54 | static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf); | |
55 | static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf); | |
56 | static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf); | |
57 | static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf); | |
1da177e4 LT |
58 | |
59 | /* | |
60 | * event list | |
61 | */ | |
c7e0b5bf | 62 | static struct status_event_list { |
1da177e4 LT |
63 | int event; |
64 | int qlen; | |
c7e0b5bf TI |
65 | void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev); |
66 | void (*decode)(struct snd_seq_event *ev, unsigned char *buf); | |
1da177e4 LT |
67 | } status_event[] = { |
68 | /* 0x80 - 0xf0 */ | |
69 | {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, | |
70 | {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, | |
71 | {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, | |
72 | {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, | |
73 | {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, | |
74 | {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, | |
75 | {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, | |
76 | {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */ | |
77 | /* 0xf0 - 0xff */ | |
78 | {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ | |
79 | {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ | |
80 | {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ | |
81 | {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ | |
82 | {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */ | |
83 | {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */ | |
84 | {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ | |
85 | {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf7 */ | |
86 | {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ | |
87 | {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf9 */ | |
88 | {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ | |
89 | {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ | |
90 | {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ | |
91 | {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */ | |
92 | {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ | |
93 | {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ | |
94 | }; | |
95 | ||
c7e0b5bf TI |
96 | static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len, |
97 | struct snd_seq_event *ev); | |
98 | static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, int count, | |
99 | struct snd_seq_event *ev); | |
1da177e4 | 100 | |
c7e0b5bf | 101 | static struct extra_event_list { |
1da177e4 | 102 | int event; |
c7e0b5bf TI |
103 | int (*decode)(struct snd_midi_event *dev, unsigned char *buf, int len, |
104 | struct snd_seq_event *ev); | |
1da177e4 LT |
105 | } extra_event[] = { |
106 | {SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14}, | |
107 | {SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn}, | |
108 | {SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn}, | |
109 | }; | |
110 | ||
111 | /* | |
112 | * new/delete record | |
113 | */ | |
114 | ||
c7e0b5bf | 115 | int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) |
1da177e4 | 116 | { |
c7e0b5bf | 117 | struct snd_midi_event *dev; |
1da177e4 LT |
118 | |
119 | *rdev = NULL; | |
ecca82b4 | 120 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1da177e4 LT |
121 | if (dev == NULL) |
122 | return -ENOMEM; | |
123 | if (bufsize > 0) { | |
124 | dev->buf = kmalloc(bufsize, GFP_KERNEL); | |
125 | if (dev->buf == NULL) { | |
126 | kfree(dev); | |
127 | return -ENOMEM; | |
128 | } | |
129 | } | |
130 | dev->bufsize = bufsize; | |
131 | dev->lastcmd = 0xff; | |
132 | spin_lock_init(&dev->lock); | |
133 | *rdev = dev; | |
134 | return 0; | |
135 | } | |
136 | ||
c7e0b5bf | 137 | void snd_midi_event_free(struct snd_midi_event *dev) |
1da177e4 LT |
138 | { |
139 | if (dev != NULL) { | |
140 | kfree(dev->buf); | |
141 | kfree(dev); | |
142 | } | |
143 | } | |
144 | ||
145 | /* | |
146 | * initialize record | |
147 | */ | |
c7e0b5bf | 148 | static inline void reset_encode(struct snd_midi_event *dev) |
1da177e4 LT |
149 | { |
150 | dev->read = 0; | |
151 | dev->qlen = 0; | |
152 | dev->type = 0; | |
153 | } | |
154 | ||
c7e0b5bf | 155 | void snd_midi_event_reset_encode(struct snd_midi_event *dev) |
1da177e4 LT |
156 | { |
157 | unsigned long flags; | |
158 | ||
159 | spin_lock_irqsave(&dev->lock, flags); | |
160 | reset_encode(dev); | |
161 | spin_unlock_irqrestore(&dev->lock, flags); | |
162 | } | |
163 | ||
c7e0b5bf | 164 | void snd_midi_event_reset_decode(struct snd_midi_event *dev) |
1da177e4 LT |
165 | { |
166 | unsigned long flags; | |
167 | ||
168 | spin_lock_irqsave(&dev->lock, flags); | |
169 | dev->lastcmd = 0xff; | |
170 | spin_unlock_irqrestore(&dev->lock, flags); | |
171 | } | |
172 | ||
123992f7 | 173 | #if 0 |
c7e0b5bf | 174 | void snd_midi_event_init(struct snd_midi_event *dev) |
1da177e4 LT |
175 | { |
176 | snd_midi_event_reset_encode(dev); | |
177 | snd_midi_event_reset_decode(dev); | |
178 | } | |
123992f7 | 179 | #endif /* 0 */ |
1da177e4 | 180 | |
c7e0b5bf | 181 | void snd_midi_event_no_status(struct snd_midi_event *dev, int on) |
1da177e4 LT |
182 | { |
183 | dev->nostat = on ? 1 : 0; | |
184 | } | |
185 | ||
186 | /* | |
187 | * resize buffer | |
188 | */ | |
123992f7 | 189 | #if 0 |
c7e0b5bf | 190 | int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize) |
1da177e4 LT |
191 | { |
192 | unsigned char *new_buf, *old_buf; | |
193 | unsigned long flags; | |
194 | ||
195 | if (bufsize == dev->bufsize) | |
196 | return 0; | |
197 | new_buf = kmalloc(bufsize, GFP_KERNEL); | |
198 | if (new_buf == NULL) | |
199 | return -ENOMEM; | |
200 | spin_lock_irqsave(&dev->lock, flags); | |
201 | old_buf = dev->buf; | |
202 | dev->buf = new_buf; | |
203 | dev->bufsize = bufsize; | |
204 | reset_encode(dev); | |
205 | spin_unlock_irqrestore(&dev->lock, flags); | |
206 | kfree(old_buf); | |
207 | return 0; | |
208 | } | |
123992f7 | 209 | #endif /* 0 */ |
1da177e4 LT |
210 | |
211 | /* | |
212 | * read bytes and encode to sequencer event if finished | |
213 | * return the size of encoded bytes | |
214 | */ | |
c7e0b5bf TI |
215 | long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count, |
216 | struct snd_seq_event *ev) | |
1da177e4 LT |
217 | { |
218 | long result = 0; | |
219 | int rc; | |
220 | ||
221 | ev->type = SNDRV_SEQ_EVENT_NONE; | |
222 | ||
223 | while (count-- > 0) { | |
224 | rc = snd_midi_event_encode_byte(dev, *buf++, ev); | |
225 | result++; | |
226 | if (rc < 0) | |
227 | return rc; | |
228 | else if (rc > 0) | |
229 | return result; | |
230 | } | |
231 | ||
232 | return result; | |
233 | } | |
234 | ||
235 | /* | |
236 | * read one byte and encode to sequencer event: | |
237 | * return 1 if MIDI bytes are encoded to an event | |
238 | * 0 data is not finished | |
239 | * negative for error | |
240 | */ | |
c7e0b5bf TI |
241 | int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, |
242 | struct snd_seq_event *ev) | |
1da177e4 LT |
243 | { |
244 | int rc = 0; | |
245 | unsigned long flags; | |
246 | ||
247 | c &= 0xff; | |
248 | ||
249 | if (c >= MIDI_CMD_COMMON_CLOCK) { | |
250 | /* real-time event */ | |
251 | ev->type = status_event[ST_SPECIAL + c - 0xf0].event; | |
252 | ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; | |
253 | ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; | |
254 | return 1; | |
255 | } | |
256 | ||
257 | spin_lock_irqsave(&dev->lock, flags); | |
258 | if (dev->qlen > 0) { | |
259 | /* rest of command */ | |
260 | dev->buf[dev->read++] = c; | |
261 | if (dev->type != ST_SYSEX) | |
262 | dev->qlen--; | |
263 | } else { | |
264 | /* new command */ | |
265 | dev->read = 1; | |
266 | if (c & 0x80) { | |
267 | dev->buf[0] = c; | |
268 | if ((c & 0xf0) == 0xf0) /* special events */ | |
269 | dev->type = (c & 0x0f) + ST_SPECIAL; | |
270 | else | |
271 | dev->type = (c >> 4) & 0x07; | |
272 | dev->qlen = status_event[dev->type].qlen; | |
273 | } else { | |
274 | /* process this byte as argument */ | |
275 | dev->buf[dev->read++] = c; | |
276 | dev->qlen = status_event[dev->type].qlen - 1; | |
277 | } | |
278 | } | |
279 | if (dev->qlen == 0) { | |
280 | ev->type = status_event[dev->type].event; | |
281 | ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; | |
282 | ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; | |
283 | if (status_event[dev->type].encode) /* set data values */ | |
284 | status_event[dev->type].encode(dev, ev); | |
285 | rc = 1; | |
286 | } else if (dev->type == ST_SYSEX) { | |
287 | if (c == MIDI_CMD_COMMON_SYSEX_END || | |
288 | dev->read >= dev->bufsize) { | |
289 | ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; | |
290 | ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE; | |
291 | ev->type = SNDRV_SEQ_EVENT_SYSEX; | |
292 | ev->data.ext.len = dev->read; | |
293 | ev->data.ext.ptr = dev->buf; | |
294 | if (c != MIDI_CMD_COMMON_SYSEX_END) | |
295 | dev->read = 0; /* continue to parse */ | |
296 | else | |
297 | reset_encode(dev); /* all parsed */ | |
298 | rc = 1; | |
299 | } | |
300 | } | |
301 | ||
302 | spin_unlock_irqrestore(&dev->lock, flags); | |
303 | return rc; | |
304 | } | |
305 | ||
306 | /* encode note event */ | |
c7e0b5bf | 307 | static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
308 | { |
309 | ev->data.note.channel = dev->buf[0] & 0x0f; | |
310 | ev->data.note.note = dev->buf[1]; | |
311 | ev->data.note.velocity = dev->buf[2]; | |
312 | } | |
313 | ||
314 | /* encode one parameter controls */ | |
c7e0b5bf | 315 | static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
316 | { |
317 | ev->data.control.channel = dev->buf[0] & 0x0f; | |
318 | ev->data.control.value = dev->buf[1]; | |
319 | } | |
320 | ||
321 | /* encode pitch wheel change */ | |
c7e0b5bf | 322 | static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
323 | { |
324 | ev->data.control.channel = dev->buf[0] & 0x0f; | |
325 | ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192; | |
326 | } | |
327 | ||
328 | /* encode midi control change */ | |
c7e0b5bf | 329 | static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
330 | { |
331 | ev->data.control.channel = dev->buf[0] & 0x0f; | |
332 | ev->data.control.param = dev->buf[1]; | |
333 | ev->data.control.value = dev->buf[2]; | |
334 | } | |
335 | ||
336 | /* encode one parameter value*/ | |
c7e0b5bf | 337 | static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
338 | { |
339 | ev->data.control.value = dev->buf[1]; | |
340 | } | |
341 | ||
342 | /* encode song position */ | |
c7e0b5bf | 343 | static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
344 | { |
345 | ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1]; | |
346 | } | |
347 | ||
348 | /* | |
349 | * decode from a sequencer event to midi bytes | |
350 | * return the size of decoded midi events | |
351 | */ | |
c7e0b5bf TI |
352 | long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count, |
353 | struct snd_seq_event *ev) | |
1da177e4 LT |
354 | { |
355 | unsigned int cmd, type; | |
356 | ||
357 | if (ev->type == SNDRV_SEQ_EVENT_NONE) | |
358 | return -ENOENT; | |
359 | ||
360 | for (type = 0; type < ARRAY_SIZE(status_event); type++) { | |
361 | if (ev->type == status_event[type].event) | |
362 | goto __found; | |
363 | } | |
364 | for (type = 0; type < ARRAY_SIZE(extra_event); type++) { | |
365 | if (ev->type == extra_event[type].event) | |
366 | return extra_event[type].decode(dev, buf, count, ev); | |
367 | } | |
368 | return -ENOENT; | |
369 | ||
370 | __found: | |
371 | if (type >= ST_SPECIAL) | |
372 | cmd = 0xf0 + (type - ST_SPECIAL); | |
373 | else | |
374 | /* data.note.channel and data.control.channel is identical */ | |
375 | cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f); | |
376 | ||
377 | ||
378 | if (cmd == MIDI_CMD_COMMON_SYSEX) { | |
379 | snd_midi_event_reset_decode(dev); | |
380 | return snd_seq_expand_var_event(ev, count, buf, 1, 0); | |
381 | } else { | |
382 | int qlen; | |
383 | unsigned char xbuf[4]; | |
384 | unsigned long flags; | |
385 | ||
386 | spin_lock_irqsave(&dev->lock, flags); | |
387 | if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) { | |
388 | dev->lastcmd = cmd; | |
389 | spin_unlock_irqrestore(&dev->lock, flags); | |
390 | xbuf[0] = cmd; | |
391 | if (status_event[type].decode) | |
392 | status_event[type].decode(ev, xbuf + 1); | |
393 | qlen = status_event[type].qlen + 1; | |
394 | } else { | |
395 | spin_unlock_irqrestore(&dev->lock, flags); | |
396 | if (status_event[type].decode) | |
397 | status_event[type].decode(ev, xbuf + 0); | |
398 | qlen = status_event[type].qlen; | |
399 | } | |
400 | if (count < qlen) | |
401 | return -ENOMEM; | |
402 | memcpy(buf, xbuf, qlen); | |
403 | return qlen; | |
404 | } | |
405 | } | |
406 | ||
407 | ||
408 | /* decode note event */ | |
c7e0b5bf | 409 | static void note_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
410 | { |
411 | buf[0] = ev->data.note.note & 0x7f; | |
412 | buf[1] = ev->data.note.velocity & 0x7f; | |
413 | } | |
414 | ||
415 | /* decode one parameter controls */ | |
c7e0b5bf | 416 | static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
417 | { |
418 | buf[0] = ev->data.control.value & 0x7f; | |
419 | } | |
420 | ||
421 | /* decode pitch wheel change */ | |
c7e0b5bf | 422 | static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
423 | { |
424 | int value = ev->data.control.value + 8192; | |
425 | buf[0] = value & 0x7f; | |
426 | buf[1] = (value >> 7) & 0x7f; | |
427 | } | |
428 | ||
429 | /* decode midi control change */ | |
c7e0b5bf | 430 | static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
431 | { |
432 | buf[0] = ev->data.control.param & 0x7f; | |
433 | buf[1] = ev->data.control.value & 0x7f; | |
434 | } | |
435 | ||
436 | /* decode song position */ | |
c7e0b5bf | 437 | static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
438 | { |
439 | buf[0] = ev->data.control.value & 0x7f; | |
440 | buf[1] = (ev->data.control.value >> 7) & 0x7f; | |
441 | } | |
442 | ||
443 | /* decode 14bit control */ | |
c7e0b5bf TI |
444 | static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, |
445 | int count, struct snd_seq_event *ev) | |
1da177e4 LT |
446 | { |
447 | unsigned char cmd; | |
448 | int idx = 0; | |
449 | ||
450 | cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); | |
451 | if (ev->data.control.param < 0x20) { | |
452 | if (count < 4) | |
453 | return -ENOMEM; | |
454 | if (dev->nostat && count < 6) | |
455 | return -ENOMEM; | |
456 | if (cmd != dev->lastcmd || dev->nostat) { | |
457 | if (count < 5) | |
458 | return -ENOMEM; | |
459 | buf[idx++] = dev->lastcmd = cmd; | |
460 | } | |
461 | buf[idx++] = ev->data.control.param; | |
462 | buf[idx++] = (ev->data.control.value >> 7) & 0x7f; | |
463 | if (dev->nostat) | |
464 | buf[idx++] = cmd; | |
465 | buf[idx++] = ev->data.control.param + 0x20; | |
466 | buf[idx++] = ev->data.control.value & 0x7f; | |
467 | } else { | |
468 | if (count < 2) | |
469 | return -ENOMEM; | |
470 | if (cmd != dev->lastcmd || dev->nostat) { | |
471 | if (count < 3) | |
472 | return -ENOMEM; | |
473 | buf[idx++] = dev->lastcmd = cmd; | |
474 | } | |
475 | buf[idx++] = ev->data.control.param & 0x7f; | |
476 | buf[idx++] = ev->data.control.value & 0x7f; | |
477 | } | |
478 | return idx; | |
479 | } | |
480 | ||
481 | /* decode reg/nonreg param */ | |
c7e0b5bf TI |
482 | static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, |
483 | int count, struct snd_seq_event *ev) | |
1da177e4 LT |
484 | { |
485 | unsigned char cmd; | |
486 | char *cbytes; | |
487 | static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB, | |
488 | MIDI_CTL_NONREG_PARM_NUM_LSB, | |
489 | MIDI_CTL_MSB_DATA_ENTRY, | |
490 | MIDI_CTL_LSB_DATA_ENTRY }; | |
491 | static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB, | |
492 | MIDI_CTL_REGIST_PARM_NUM_LSB, | |
493 | MIDI_CTL_MSB_DATA_ENTRY, | |
494 | MIDI_CTL_LSB_DATA_ENTRY }; | |
495 | unsigned char bytes[4]; | |
496 | int idx = 0, i; | |
497 | ||
498 | if (count < 8) | |
499 | return -ENOMEM; | |
500 | if (dev->nostat && count < 12) | |
501 | return -ENOMEM; | |
502 | cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); | |
503 | bytes[0] = ev->data.control.param & 0x007f; | |
504 | bytes[1] = (ev->data.control.param & 0x3f80) >> 7; | |
505 | bytes[2] = ev->data.control.value & 0x007f; | |
506 | bytes[3] = (ev->data.control.value & 0x3f80) >> 7; | |
507 | if (cmd != dev->lastcmd && !dev->nostat) { | |
508 | if (count < 9) | |
509 | return -ENOMEM; | |
510 | buf[idx++] = dev->lastcmd = cmd; | |
511 | } | |
512 | cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn; | |
513 | for (i = 0; i < 4; i++) { | |
514 | if (dev->nostat) | |
515 | buf[idx++] = dev->lastcmd = cmd; | |
516 | buf[idx++] = cbytes[i]; | |
517 | buf[idx++] = bytes[i]; | |
518 | } | |
519 | return idx; | |
520 | } | |
521 | ||
522 | /* | |
523 | * exports | |
524 | */ | |
525 | ||
526 | EXPORT_SYMBOL(snd_midi_event_new); | |
527 | EXPORT_SYMBOL(snd_midi_event_free); | |
1da177e4 LT |
528 | EXPORT_SYMBOL(snd_midi_event_reset_encode); |
529 | EXPORT_SYMBOL(snd_midi_event_reset_decode); | |
530 | EXPORT_SYMBOL(snd_midi_event_no_status); | |
531 | EXPORT_SYMBOL(snd_midi_event_encode); | |
532 | EXPORT_SYMBOL(snd_midi_event_encode_byte); | |
533 | EXPORT_SYMBOL(snd_midi_event_decode); | |
534 | ||
535 | static int __init alsa_seq_midi_event_init(void) | |
536 | { | |
537 | return 0; | |
538 | } | |
539 | ||
540 | static void __exit alsa_seq_midi_event_exit(void) | |
541 | { | |
542 | } | |
543 | ||
544 | module_init(alsa_seq_midi_event_init) | |
545 | module_exit(alsa_seq_midi_event_exit) |