Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * MIDI byte <-> sequencer event coder | |
3 | * | |
4 | * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>, | |
c1017a4c | 5 | * Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
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 | ||
1da177e4 LT |
22 | #include <linux/slab.h> |
23 | #include <linux/errno.h> | |
24 | #include <linux/string.h> | |
25 | #include <sound/core.h> | |
26 | #include <sound/seq_kernel.h> | |
27 | #include <sound/seq_midi_event.h> | |
28 | #include <sound/asoundef.h> | |
29 | ||
c1017a4c | 30 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>"); |
1da177e4 LT |
31 | MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder"); |
32 | MODULE_LICENSE("GPL"); | |
33 | ||
394d0516 CL |
34 | /* event type, index into status_event[] */ |
35 | /* from 0 to 6 are normal commands (note off, on, etc.) for 0x9?-0xe? */ | |
36 | #define ST_INVALID 7 | |
1da177e4 LT |
37 | #define ST_SPECIAL 8 |
38 | #define ST_SYSEX ST_SPECIAL | |
39 | /* from 8 to 15 are events for 0xf0-0xf7 */ | |
40 | ||
41 | ||
1da177e4 LT |
42 | /* |
43 | * prototypes | |
44 | */ | |
c7e0b5bf TI |
45 | static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev); |
46 | static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
47 | static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
48 | static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
49 | static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
50 | static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev); | |
51 | static void note_decode(struct snd_seq_event *ev, unsigned char *buf); | |
52 | static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf); | |
53 | static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf); | |
54 | static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf); | |
55 | static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf); | |
1da177e4 LT |
56 | |
57 | /* | |
58 | * event list | |
59 | */ | |
c7e0b5bf | 60 | static struct status_event_list { |
1da177e4 LT |
61 | int event; |
62 | int qlen; | |
c7e0b5bf TI |
63 | void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev); |
64 | void (*decode)(struct snd_seq_event *ev, unsigned char *buf); | |
1da177e4 | 65 | } status_event[] = { |
394d0516 | 66 | /* 0x80 - 0xef */ |
bf8c1382 CL |
67 | {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, |
68 | {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, | |
69 | {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, | |
70 | {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, | |
71 | {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, | |
72 | {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, | |
73 | {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, | |
394d0516 | 74 | /* invalid */ |
bf8c1382 | 75 | {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, |
1da177e4 | 76 | /* 0xf0 - 0xff */ |
bf8c1382 CL |
77 | {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ |
78 | {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ | |
79 | {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ | |
80 | {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ | |
81 | {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf4 */ | |
82 | {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf5 */ | |
83 | {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ | |
84 | {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf7 */ | |
85 | {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ | |
86 | {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf9 */ | |
87 | {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ | |
88 | {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ | |
89 | {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ | |
90 | {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xfd */ | |
91 | {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ | |
92 | {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ | |
1da177e4 LT |
93 | }; |
94 | ||
c7e0b5bf TI |
95 | static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len, |
96 | struct snd_seq_event *ev); | |
97 | static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, int count, | |
98 | struct snd_seq_event *ev); | |
1da177e4 | 99 | |
c7e0b5bf | 100 | static struct extra_event_list { |
1da177e4 | 101 | int event; |
c7e0b5bf TI |
102 | int (*decode)(struct snd_midi_event *dev, unsigned char *buf, int len, |
103 | struct snd_seq_event *ev); | |
1da177e4 LT |
104 | } extra_event[] = { |
105 | {SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14}, | |
106 | {SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn}, | |
107 | {SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn}, | |
108 | }; | |
109 | ||
110 | /* | |
111 | * new/delete record | |
112 | */ | |
113 | ||
c7e0b5bf | 114 | int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) |
1da177e4 | 115 | { |
c7e0b5bf | 116 | struct snd_midi_event *dev; |
1da177e4 LT |
117 | |
118 | *rdev = NULL; | |
ecca82b4 | 119 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1da177e4 LT |
120 | if (dev == NULL) |
121 | return -ENOMEM; | |
122 | if (bufsize > 0) { | |
123 | dev->buf = kmalloc(bufsize, GFP_KERNEL); | |
124 | if (dev->buf == NULL) { | |
125 | kfree(dev); | |
126 | return -ENOMEM; | |
127 | } | |
128 | } | |
129 | dev->bufsize = bufsize; | |
130 | dev->lastcmd = 0xff; | |
394d0516 | 131 | dev->type = ST_INVALID; |
1da177e4 LT |
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; | |
394d0516 | 152 | dev->type = ST_INVALID; |
1da177e4 LT |
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; | |
0e75182c | 254 | return ev->type != SNDRV_SEQ_EVENT_NONE; |
1da177e4 LT |
255 | } |
256 | ||
257 | spin_lock_irqsave(&dev->lock, flags); | |
bf8c1382 CL |
258 | if ((c & 0x80) && |
259 | (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) { | |
1da177e4 | 260 | /* new command */ |
bf8c1382 CL |
261 | dev->buf[0] = c; |
262 | if ((c & 0xf0) == 0xf0) /* system messages */ | |
263 | dev->type = (c & 0x0f) + ST_SPECIAL; | |
264 | else | |
265 | dev->type = (c >> 4) & 0x07; | |
1da177e4 | 266 | dev->read = 1; |
bf8c1382 CL |
267 | dev->qlen = status_event[dev->type].qlen; |
268 | } else { | |
269 | if (dev->qlen > 0) { | |
270 | /* rest of command */ | |
1da177e4 | 271 | dev->buf[dev->read++] = c; |
bf8c1382 CL |
272 | if (dev->type != ST_SYSEX) |
273 | dev->qlen--; | |
274 | } else { | |
275 | /* running status */ | |
276 | dev->buf[1] = c; | |
1da177e4 | 277 | dev->qlen = status_event[dev->type].qlen - 1; |
bf8c1382 | 278 | dev->read = 2; |
1da177e4 LT |
279 | } |
280 | } | |
281 | if (dev->qlen == 0) { | |
282 | ev->type = status_event[dev->type].event; | |
283 | ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; | |
284 | ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; | |
285 | if (status_event[dev->type].encode) /* set data values */ | |
286 | status_event[dev->type].encode(dev, ev); | |
0b664f72 CL |
287 | if (dev->type >= ST_SPECIAL) |
288 | dev->type = ST_INVALID; | |
1da177e4 LT |
289 | rc = 1; |
290 | } else if (dev->type == ST_SYSEX) { | |
291 | if (c == MIDI_CMD_COMMON_SYSEX_END || | |
292 | dev->read >= dev->bufsize) { | |
293 | ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; | |
294 | ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE; | |
295 | ev->type = SNDRV_SEQ_EVENT_SYSEX; | |
296 | ev->data.ext.len = dev->read; | |
297 | ev->data.ext.ptr = dev->buf; | |
298 | if (c != MIDI_CMD_COMMON_SYSEX_END) | |
299 | dev->read = 0; /* continue to parse */ | |
300 | else | |
301 | reset_encode(dev); /* all parsed */ | |
302 | rc = 1; | |
303 | } | |
304 | } | |
305 | ||
306 | spin_unlock_irqrestore(&dev->lock, flags); | |
307 | return rc; | |
308 | } | |
309 | ||
310 | /* encode note event */ | |
c7e0b5bf | 311 | static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
312 | { |
313 | ev->data.note.channel = dev->buf[0] & 0x0f; | |
314 | ev->data.note.note = dev->buf[1]; | |
315 | ev->data.note.velocity = dev->buf[2]; | |
316 | } | |
317 | ||
318 | /* encode one parameter controls */ | |
c7e0b5bf | 319 | static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
320 | { |
321 | ev->data.control.channel = dev->buf[0] & 0x0f; | |
322 | ev->data.control.value = dev->buf[1]; | |
323 | } | |
324 | ||
325 | /* encode pitch wheel change */ | |
c7e0b5bf | 326 | static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
327 | { |
328 | ev->data.control.channel = dev->buf[0] & 0x0f; | |
329 | ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192; | |
330 | } | |
331 | ||
332 | /* encode midi control change */ | |
c7e0b5bf | 333 | static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
334 | { |
335 | ev->data.control.channel = dev->buf[0] & 0x0f; | |
336 | ev->data.control.param = dev->buf[1]; | |
337 | ev->data.control.value = dev->buf[2]; | |
338 | } | |
339 | ||
340 | /* encode one parameter value*/ | |
c7e0b5bf | 341 | static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
342 | { |
343 | ev->data.control.value = dev->buf[1]; | |
344 | } | |
345 | ||
346 | /* encode song position */ | |
c7e0b5bf | 347 | static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
1da177e4 LT |
348 | { |
349 | ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1]; | |
350 | } | |
351 | ||
352 | /* | |
353 | * decode from a sequencer event to midi bytes | |
354 | * return the size of decoded midi events | |
355 | */ | |
c7e0b5bf TI |
356 | long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count, |
357 | struct snd_seq_event *ev) | |
1da177e4 LT |
358 | { |
359 | unsigned int cmd, type; | |
360 | ||
361 | if (ev->type == SNDRV_SEQ_EVENT_NONE) | |
362 | return -ENOENT; | |
363 | ||
364 | for (type = 0; type < ARRAY_SIZE(status_event); type++) { | |
365 | if (ev->type == status_event[type].event) | |
366 | goto __found; | |
367 | } | |
368 | for (type = 0; type < ARRAY_SIZE(extra_event); type++) { | |
369 | if (ev->type == extra_event[type].event) | |
370 | return extra_event[type].decode(dev, buf, count, ev); | |
371 | } | |
372 | return -ENOENT; | |
373 | ||
374 | __found: | |
375 | if (type >= ST_SPECIAL) | |
376 | cmd = 0xf0 + (type - ST_SPECIAL); | |
377 | else | |
378 | /* data.note.channel and data.control.channel is identical */ | |
379 | cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f); | |
380 | ||
381 | ||
382 | if (cmd == MIDI_CMD_COMMON_SYSEX) { | |
383 | snd_midi_event_reset_decode(dev); | |
384 | return snd_seq_expand_var_event(ev, count, buf, 1, 0); | |
385 | } else { | |
386 | int qlen; | |
387 | unsigned char xbuf[4]; | |
388 | unsigned long flags; | |
389 | ||
390 | spin_lock_irqsave(&dev->lock, flags); | |
391 | if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) { | |
392 | dev->lastcmd = cmd; | |
393 | spin_unlock_irqrestore(&dev->lock, flags); | |
394 | xbuf[0] = cmd; | |
395 | if (status_event[type].decode) | |
396 | status_event[type].decode(ev, xbuf + 1); | |
397 | qlen = status_event[type].qlen + 1; | |
398 | } else { | |
399 | spin_unlock_irqrestore(&dev->lock, flags); | |
400 | if (status_event[type].decode) | |
401 | status_event[type].decode(ev, xbuf + 0); | |
402 | qlen = status_event[type].qlen; | |
403 | } | |
404 | if (count < qlen) | |
405 | return -ENOMEM; | |
406 | memcpy(buf, xbuf, qlen); | |
407 | return qlen; | |
408 | } | |
409 | } | |
410 | ||
411 | ||
412 | /* decode note event */ | |
c7e0b5bf | 413 | static void note_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
414 | { |
415 | buf[0] = ev->data.note.note & 0x7f; | |
416 | buf[1] = ev->data.note.velocity & 0x7f; | |
417 | } | |
418 | ||
419 | /* decode one parameter controls */ | |
c7e0b5bf | 420 | static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
421 | { |
422 | buf[0] = ev->data.control.value & 0x7f; | |
423 | } | |
424 | ||
425 | /* decode pitch wheel change */ | |
c7e0b5bf | 426 | static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
427 | { |
428 | int value = ev->data.control.value + 8192; | |
429 | buf[0] = value & 0x7f; | |
430 | buf[1] = (value >> 7) & 0x7f; | |
431 | } | |
432 | ||
433 | /* decode midi control change */ | |
c7e0b5bf | 434 | static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
435 | { |
436 | buf[0] = ev->data.control.param & 0x7f; | |
437 | buf[1] = ev->data.control.value & 0x7f; | |
438 | } | |
439 | ||
440 | /* decode song position */ | |
c7e0b5bf | 441 | static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf) |
1da177e4 LT |
442 | { |
443 | buf[0] = ev->data.control.value & 0x7f; | |
444 | buf[1] = (ev->data.control.value >> 7) & 0x7f; | |
445 | } | |
446 | ||
447 | /* decode 14bit control */ | |
c7e0b5bf TI |
448 | static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, |
449 | int count, struct snd_seq_event *ev) | |
1da177e4 LT |
450 | { |
451 | unsigned char cmd; | |
452 | int idx = 0; | |
453 | ||
454 | cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); | |
455 | if (ev->data.control.param < 0x20) { | |
456 | if (count < 4) | |
457 | return -ENOMEM; | |
458 | if (dev->nostat && count < 6) | |
459 | return -ENOMEM; | |
460 | if (cmd != dev->lastcmd || dev->nostat) { | |
461 | if (count < 5) | |
462 | return -ENOMEM; | |
463 | buf[idx++] = dev->lastcmd = cmd; | |
464 | } | |
465 | buf[idx++] = ev->data.control.param; | |
466 | buf[idx++] = (ev->data.control.value >> 7) & 0x7f; | |
467 | if (dev->nostat) | |
468 | buf[idx++] = cmd; | |
469 | buf[idx++] = ev->data.control.param + 0x20; | |
470 | buf[idx++] = ev->data.control.value & 0x7f; | |
471 | } else { | |
472 | if (count < 2) | |
473 | return -ENOMEM; | |
474 | if (cmd != dev->lastcmd || dev->nostat) { | |
475 | if (count < 3) | |
476 | return -ENOMEM; | |
477 | buf[idx++] = dev->lastcmd = cmd; | |
478 | } | |
479 | buf[idx++] = ev->data.control.param & 0x7f; | |
480 | buf[idx++] = ev->data.control.value & 0x7f; | |
481 | } | |
482 | return idx; | |
483 | } | |
484 | ||
485 | /* decode reg/nonreg param */ | |
c7e0b5bf TI |
486 | static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, |
487 | int count, struct snd_seq_event *ev) | |
1da177e4 LT |
488 | { |
489 | unsigned char cmd; | |
490 | char *cbytes; | |
491 | static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB, | |
492 | MIDI_CTL_NONREG_PARM_NUM_LSB, | |
493 | MIDI_CTL_MSB_DATA_ENTRY, | |
494 | MIDI_CTL_LSB_DATA_ENTRY }; | |
495 | static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB, | |
496 | MIDI_CTL_REGIST_PARM_NUM_LSB, | |
497 | MIDI_CTL_MSB_DATA_ENTRY, | |
498 | MIDI_CTL_LSB_DATA_ENTRY }; | |
499 | unsigned char bytes[4]; | |
500 | int idx = 0, i; | |
501 | ||
502 | if (count < 8) | |
503 | return -ENOMEM; | |
504 | if (dev->nostat && count < 12) | |
505 | return -ENOMEM; | |
506 | cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); | |
6423f9ea CL |
507 | bytes[0] = (ev->data.control.param & 0x3f80) >> 7; |
508 | bytes[1] = ev->data.control.param & 0x007f; | |
509 | bytes[2] = (ev->data.control.value & 0x3f80) >> 7; | |
510 | bytes[3] = ev->data.control.value & 0x007f; | |
1da177e4 LT |
511 | if (cmd != dev->lastcmd && !dev->nostat) { |
512 | if (count < 9) | |
513 | return -ENOMEM; | |
514 | buf[idx++] = dev->lastcmd = cmd; | |
515 | } | |
516 | cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn; | |
517 | for (i = 0; i < 4; i++) { | |
518 | if (dev->nostat) | |
519 | buf[idx++] = dev->lastcmd = cmd; | |
520 | buf[idx++] = cbytes[i]; | |
521 | buf[idx++] = bytes[i]; | |
522 | } | |
523 | return idx; | |
524 | } | |
525 | ||
526 | /* | |
527 | * exports | |
528 | */ | |
529 | ||
530 | EXPORT_SYMBOL(snd_midi_event_new); | |
531 | EXPORT_SYMBOL(snd_midi_event_free); | |
1da177e4 LT |
532 | EXPORT_SYMBOL(snd_midi_event_reset_encode); |
533 | EXPORT_SYMBOL(snd_midi_event_reset_decode); | |
534 | EXPORT_SYMBOL(snd_midi_event_no_status); | |
535 | EXPORT_SYMBOL(snd_midi_event_encode); | |
536 | EXPORT_SYMBOL(snd_midi_event_encode_byte); | |
537 | EXPORT_SYMBOL(snd_midi_event_decode); | |
538 | ||
539 | static int __init alsa_seq_midi_event_init(void) | |
540 | { | |
541 | return 0; | |
542 | } | |
543 | ||
544 | static void __exit alsa_seq_midi_event_exit(void) | |
545 | { | |
546 | } | |
547 | ||
548 | module_init(alsa_seq_midi_event_init) | |
549 | module_exit(alsa_seq_midi_event_exit) |