annotate plugin/api/dssi_alsa_compat.c @ 299:576be0d0d218

* Merge transform directory from sv-match-alignment branch (the previous comment included notes for this stuff, but I missed it in the actual merge) * Fix crash when a transform fails to create an output model and the thread that created the transform then deletes its input model thinking it's no longer needed, even though the transform run thread is still using it -- fix is to wait() on the transform before returning the null output model
author Chris Cannam
date Fri, 28 Sep 2007 16:15:06 +0000
parents da6937383da8
children d7f3dfe6f9a4
rev   line source
Chris@0 1 /* DSSI ALSA compatibility library
Chris@0 2 *
Chris@0 3 * This library provides for non-ALSA systems the ALSA snd_seq_event_t handling
Chris@0 4 * necessary to compile and run DSSI. It was extracted from alsa-lib 1.0.8.
Chris@0 5 *
Chris@0 6 * See ./alsa/README for more information.
Chris@0 7 */
Chris@0 8
Chris@0 9 #include <stdlib.h>
Chris@0 10 #include <errno.h>
Chris@0 11
Chris@0 12 #include "alsa/asoundef.h"
Chris@0 13 #include "alsa/sound/asequencer.h"
Chris@0 14 #include "alsa/seq.h"
Chris@0 15 #include "alsa/seq_event.h"
Chris@0 16 #include "alsa/seq_midi_event.h"
Chris@0 17
Chris@0 18 /**
Chris@0 19 * \file seq/seq_event.c
Chris@0 20 * \brief Sequencer Event Types
Chris@0 21 * \author Takashi Iwai <tiwai@suse.de>
Chris@0 22 * \date 2001
Chris@0 23 */
Chris@0 24
Chris@0 25 #define FIXED_EV(x) (_SND_SEQ_TYPE(SND_SEQ_EVFLG_FIXED) | _SND_SEQ_TYPE(x))
Chris@0 26
Chris@0 27 /** Event types conversion array */
Chris@0 28 const unsigned int snd_seq_event_types[256] = {
Chris@0 29 [SND_SEQ_EVENT_SYSTEM ... SND_SEQ_EVENT_RESULT]
Chris@0 30 = FIXED_EV(SND_SEQ_EVFLG_RESULT),
Chris@0 31 [SND_SEQ_EVENT_NOTE]
Chris@0 32 = FIXED_EV(SND_SEQ_EVFLG_NOTE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_NOTE_TWOARG),
Chris@0 33 [SND_SEQ_EVENT_NOTEON ... SND_SEQ_EVENT_KEYPRESS]
Chris@0 34 = FIXED_EV(SND_SEQ_EVFLG_NOTE),
Chris@0 35 [SND_SEQ_EVENT_CONTROLLER ... SND_SEQ_EVENT_REGPARAM]
Chris@0 36 = FIXED_EV(SND_SEQ_EVFLG_CONTROL),
Chris@0 37 [SND_SEQ_EVENT_START ... SND_SEQ_EVENT_STOP]
Chris@0 38 = FIXED_EV(SND_SEQ_EVFLG_QUEUE),
Chris@0 39 [SND_SEQ_EVENT_SETPOS_TICK]
Chris@0 40 = FIXED_EV(SND_SEQ_EVFLG_QUEUE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_QUEUE_TICK),
Chris@0 41 [SND_SEQ_EVENT_SETPOS_TIME]
Chris@0 42 = FIXED_EV(SND_SEQ_EVFLG_QUEUE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_QUEUE_TIME),
Chris@0 43 [SND_SEQ_EVENT_TEMPO ... SND_SEQ_EVENT_SYNC_POS]
Chris@0 44 = FIXED_EV(SND_SEQ_EVFLG_QUEUE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_QUEUE_VALUE),
Chris@0 45 [SND_SEQ_EVENT_TUNE_REQUEST ... SND_SEQ_EVENT_SENSING]
Chris@0 46 = FIXED_EV(SND_SEQ_EVFLG_NONE),
Chris@0 47 [SND_SEQ_EVENT_ECHO ... SND_SEQ_EVENT_OSS]
Chris@0 48 = FIXED_EV(SND_SEQ_EVFLG_RAW) | FIXED_EV(SND_SEQ_EVFLG_SYSTEM),
Chris@0 49 [SND_SEQ_EVENT_CLIENT_START ... SND_SEQ_EVENT_PORT_CHANGE]
Chris@0 50 = FIXED_EV(SND_SEQ_EVFLG_MESSAGE),
Chris@0 51 [SND_SEQ_EVENT_PORT_SUBSCRIBED ... SND_SEQ_EVENT_PORT_UNSUBSCRIBED]
Chris@0 52 = FIXED_EV(SND_SEQ_EVFLG_CONNECTION),
Chris@0 53 [SND_SEQ_EVENT_SAMPLE ... SND_SEQ_EVENT_SAMPLE_PRIVATE1]
Chris@0 54 = FIXED_EV(SND_SEQ_EVFLG_SAMPLE),
Chris@0 55 [SND_SEQ_EVENT_USR0 ... SND_SEQ_EVENT_USR9]
Chris@0 56 = FIXED_EV(SND_SEQ_EVFLG_RAW) | FIXED_EV(SND_SEQ_EVFLG_USERS),
Chris@0 57 [SND_SEQ_EVENT_INSTR_BEGIN ... SND_SEQ_EVENT_INSTR_CHANGE]
Chris@0 58 = _SND_SEQ_TYPE(SND_SEQ_EVFLG_INSTR) | _SND_SEQ_TYPE(SND_SEQ_EVFLG_VARUSR),
Chris@0 59 [SND_SEQ_EVENT_SYSEX ... SND_SEQ_EVENT_BOUNCE]
Chris@0 60 = _SND_SEQ_TYPE(SND_SEQ_EVFLG_VARIABLE),
Chris@0 61 [SND_SEQ_EVENT_USR_VAR0 ... SND_SEQ_EVENT_USR_VAR4]
Chris@0 62 = _SND_SEQ_TYPE(SND_SEQ_EVFLG_VARIABLE) | _SND_SEQ_TYPE(SND_SEQ_EVFLG_USERS),
Chris@0 63 [SND_SEQ_EVENT_NONE]
Chris@0 64 = FIXED_EV(SND_SEQ_EVFLG_NONE),
Chris@0 65 };
Chris@0 66
Chris@0 67 /**
Chris@0 68 * \file seq/seq_midi_event.c
Chris@0 69 * \brief MIDI byte <-> sequencer event coder
Chris@0 70 * \author Takashi Iwai <tiwai@suse.de>
Chris@0 71 * \author Jaroslav Kysela <perex@suse.cz>
Chris@0 72 * \date 2000-2001
Chris@0 73 */
Chris@0 74
Chris@0 75 /*
Chris@0 76 * MIDI byte <-> sequencer event coder
Chris@0 77 *
Chris@0 78 * Copyright (C) 1998,99,2000 Takashi Iwai <tiwai@suse.de>,
Chris@0 79 * Jaroslav Kysela <perex@suse.cz>
Chris@0 80 *
Chris@0 81 *
Chris@0 82 * This library is free software; you can redistribute it and/or modify
Chris@0 83 * it under the terms of the GNU Lesser General Public License as
Chris@0 84 * published by the Free Software Foundation; either version 2.1 of
Chris@0 85 * the License, or (at your option) any later version.
Chris@0 86 *
Chris@0 87 * This program is distributed in the hope that it will be useful,
Chris@0 88 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 89 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 90 * GNU Lesser General Public License for more details.
Chris@0 91 *
Chris@0 92 * You should have received a copy of the GNU Lesser General Public
Chris@0 93 * License along with this library; if not, write to the Free Software
Chris@0 94 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Chris@0 95 */
Chris@0 96
Chris@0 97 /* midi status */
Chris@0 98 struct snd_midi_event {
Chris@0 99 size_t qlen; /* queue length */
Chris@0 100 size_t read; /* chars read */
Chris@0 101 int type; /* current event type */
Chris@0 102 unsigned char lastcmd;
Chris@0 103 unsigned char nostat;
Chris@0 104 size_t bufsize;
Chris@0 105 unsigned char *buf; /* input buffer */
Chris@0 106 };
Chris@0 107
Chris@0 108
Chris@0 109 /* queue type */
Chris@0 110 /* from 0 to 7 are normal commands (note off, on, etc.) */
Chris@0 111 #define ST_NOTEOFF 0
Chris@0 112 #define ST_NOTEON 1
Chris@0 113 #define ST_SPECIAL 8
Chris@0 114 #define ST_SYSEX ST_SPECIAL
Chris@0 115 /* from 8 to 15 are events for 0xf0-0xf7 */
Chris@0 116
Chris@0 117
Chris@0 118 /* status event types */
Chris@0 119 typedef void (*event_encode_t)(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 120 typedef void (*event_decode_t)(const snd_seq_event_t *ev, unsigned char *buf);
Chris@0 121
Chris@0 122 /*
Chris@0 123 * prototypes
Chris@0 124 */
Chris@0 125 static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 126 static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 127 static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 128 static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 129 static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 130 static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
Chris@0 131 static void note_decode(const snd_seq_event_t *ev, unsigned char *buf);
Chris@0 132 static void one_param_decode(const snd_seq_event_t *ev, unsigned char *buf);
Chris@0 133 static void pitchbend_decode(const snd_seq_event_t *ev, unsigned char *buf);
Chris@0 134 static void two_param_decode(const snd_seq_event_t *ev, unsigned char *buf);
Chris@0 135 static void songpos_decode(const snd_seq_event_t *ev, unsigned char *buf);
Chris@0 136
Chris@0 137 /*
Chris@0 138 * event list
Chris@0 139 */
Chris@0 140 static struct status_event_list_t {
Chris@0 141 int event;
Chris@0 142 int qlen;
Chris@0 143 event_encode_t encode;
Chris@0 144 event_decode_t decode;
Chris@0 145 } status_event[] = {
Chris@0 146 /* 0x80 - 0xf0 */
Chris@0 147 {SND_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
Chris@0 148 {SND_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
Chris@0 149 {SND_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode},
Chris@0 150 {SND_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode},
Chris@0 151 {SND_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode},
Chris@0 152 {SND_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode},
Chris@0 153 {SND_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode},
Chris@0 154 {SND_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */
Chris@0 155 /* 0xf0 - 0xff */
Chris@0 156 {SND_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */
Chris@0 157 {SND_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
Chris@0 158 {SND_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
Chris@0 159 {SND_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
Chris@0 160 {SND_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */
Chris@0 161 {SND_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */
Chris@0 162 {SND_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */
Chris@0 163 {SND_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf7 */
Chris@0 164 {SND_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */
Chris@0 165 {SND_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf9 */
Chris@0 166 {SND_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */
Chris@0 167 {SND_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */
Chris@0 168 {SND_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */
Chris@0 169 {SND_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */
Chris@0 170 {SND_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */
Chris@0 171 {SND_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
Chris@0 172 };
Chris@0 173
Chris@0 174 #ifdef UNNEEDED_BY_DSSI
Chris@0 175 static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, const snd_seq_event_t *ev);
Chris@0 176 static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, const snd_seq_event_t *ev);
Chris@0 177
Chris@0 178 static struct extra_event_list_t {
Chris@0 179 int event;
Chris@0 180 int (*decode)(snd_midi_event_t *dev, unsigned char *buf, int len, const snd_seq_event_t *ev);
Chris@0 181 } extra_event[] = {
Chris@0 182 {SND_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
Chris@0 183 {SND_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
Chris@0 184 {SND_SEQ_EVENT_REGPARAM, extra_decode_xrpn},
Chris@0 185 };
Chris@0 186
Chris@0 187 #define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
Chris@0 188 #endif /* UNNEEDED_BY_DSSI */
Chris@0 189
Chris@0 190 /**
Chris@0 191 * \brief Initialize MIDI event parser
Chris@0 192 * \param bufsize buffer size for MIDI message
Chris@0 193 * \param rdev allocated MIDI event parser
Chris@0 194 * \return 0 on success otherwise a negative error code
Chris@0 195 *
Chris@0 196 * Allocates and initializes MIDI event parser.
Chris@0 197 */
Chris@0 198 int snd_midi_event_new(size_t bufsize, snd_midi_event_t **rdev)
Chris@0 199 {
Chris@0 200 snd_midi_event_t *dev;
Chris@0 201
Chris@0 202 *rdev = NULL;
Chris@0 203 dev = (snd_midi_event_t *)calloc(1, sizeof(snd_midi_event_t));
Chris@0 204 if (dev == NULL)
Chris@0 205 return -ENOMEM;
Chris@0 206 if (bufsize > 0) {
Chris@0 207 dev->buf = malloc(bufsize);
Chris@0 208 if (dev->buf == NULL) {
Chris@0 209 free(dev);
Chris@0 210 return -ENOMEM;
Chris@0 211 }
Chris@0 212 }
Chris@0 213 dev->bufsize = bufsize;
Chris@0 214 dev->lastcmd = 0xff;
Chris@0 215 *rdev = dev;
Chris@0 216 return 0;
Chris@0 217 }
Chris@0 218
Chris@0 219 /**
Chris@0 220 * \brief Free MIDI event parser
Chris@0 221 * \param rdev MIDI event parser
Chris@0 222 * \return 0 on success otherwise a negative error code
Chris@0 223 *
Chris@0 224 * Frees MIDI event parser.
Chris@0 225 */
Chris@0 226 void snd_midi_event_free(snd_midi_event_t *dev)
Chris@0 227 {
Chris@0 228 if (dev != NULL) {
Chris@0 229 if (dev->buf)
Chris@0 230 free(dev->buf);
Chris@0 231 free(dev);
Chris@0 232 }
Chris@0 233 }
Chris@0 234
Chris@0 235 #ifdef UNNEEDED_BY_DSSI
Chris@0 236 /**
Chris@0 237 * \brief Enable/disable MIDI command merging
Chris@0 238 * \param dev MIDI event parser
Chris@0 239 * \param on 0 - enable MIDI command merging, 1 - always pass the command
Chris@0 240 *
Chris@0 241 * Enable/disable MIDI command merging
Chris@0 242 */
Chris@0 243 void snd_midi_event_no_status(snd_midi_event_t *dev, int on)
Chris@0 244 {
Chris@0 245 dev->nostat = on ? 1 : 0;
Chris@0 246 }
Chris@0 247 #endif /* UNNEEDED_BY_DSSI */
Chris@0 248
Chris@0 249 /*
Chris@0 250 * initialize record
Chris@0 251 */
Chris@0 252 inline static void reset_encode(snd_midi_event_t *dev)
Chris@0 253 {
Chris@0 254 dev->read = 0;
Chris@0 255 dev->qlen = 0;
Chris@0 256 dev->type = 0;
Chris@0 257 }
Chris@0 258
Chris@0 259 /**
Chris@0 260 * \brief Reset MIDI encode parser
Chris@0 261 * \param dev MIDI event parser
Chris@0 262 * \return 0 on success otherwise a negative error code
Chris@0 263 *
Chris@0 264 * Resets MIDI encode parser
Chris@0 265 */
Chris@0 266 void snd_midi_event_reset_encode(snd_midi_event_t *dev)
Chris@0 267 {
Chris@0 268 reset_encode(dev);
Chris@0 269 }
Chris@0 270
Chris@0 271 #ifdef UNNEEDED_BY_DSSI
Chris@0 272 /**
Chris@0 273 * \brief Reset MIDI decode parser
Chris@0 274 * \param dev MIDI event parser
Chris@0 275 * \return 0 on success otherwise a negative error code
Chris@0 276 *
Chris@0 277 * Resets MIDI decode parser
Chris@0 278 */
Chris@0 279 void snd_midi_event_reset_decode(snd_midi_event_t *dev)
Chris@0 280 {
Chris@0 281 dev->lastcmd = 0xff;
Chris@0 282 }
Chris@0 283
Chris@0 284 /**
Chris@0 285 * \brief Initializes MIDI parsers
Chris@0 286 * \param dev MIDI event parser
Chris@0 287 * \return 0 on success otherwise a negative error code
Chris@0 288 *
Chris@0 289 * Initializes MIDI parsers (both encode and decode)
Chris@0 290 */
Chris@0 291 void snd_midi_event_init(snd_midi_event_t *dev)
Chris@0 292 {
Chris@0 293 snd_midi_event_reset_encode(dev);
Chris@0 294 snd_midi_event_reset_decode(dev);
Chris@0 295 }
Chris@0 296
Chris@0 297 /**
Chris@0 298 * \brief Resize MIDI message (event) buffer
Chris@0 299 * \param dev MIDI event parser
Chris@0 300 * \param bufsize new requested buffer size
Chris@0 301 * \return 0 on success otherwise a negative error code
Chris@0 302 *
Chris@0 303 * Resizes MIDI message (event) buffer.
Chris@0 304 */
Chris@0 305 int snd_midi_event_resize_buffer(snd_midi_event_t *dev, size_t bufsize)
Chris@0 306 {
Chris@0 307 unsigned char *new_buf, *old_buf;
Chris@0 308
Chris@0 309 if (bufsize == dev->bufsize)
Chris@0 310 return 0;
Chris@0 311 new_buf = malloc(bufsize);
Chris@0 312 if (new_buf == NULL)
Chris@0 313 return -ENOMEM;
Chris@0 314 old_buf = dev->buf;
Chris@0 315 dev->buf = new_buf;
Chris@0 316 dev->bufsize = bufsize;
Chris@0 317 reset_encode(dev);
Chris@0 318 if (old_buf)
Chris@0 319 free(old_buf);
Chris@0 320 return 0;
Chris@0 321 }
Chris@0 322 #endif /* UNNEEDED_BY_DSSI */
Chris@0 323
Chris@0 324 /**
Chris@0 325 * \brief Read bytes and encode to sequencer event if finished
Chris@0 326 * \param dev MIDI event parser
Chris@0 327 * \param buf MIDI byte stream
Chris@0 328 * \param count count of bytes of MIDI byte stream to encode
Chris@0 329 * \param ev Result - sequencer event
Chris@0 330 * \return count of encoded bytes otherwise a negative error code
Chris@0 331 *
Chris@0 332 * Read bytes and encode to sequencer event if finished.
Chris@0 333 * If complete sequencer event is available, ev->type is not
Chris@0 334 * equal to #SND_SEQ_EVENT_NONE.
Chris@0 335 */
Chris@0 336 long snd_midi_event_encode(snd_midi_event_t *dev, const unsigned char *buf, long count, snd_seq_event_t *ev)
Chris@0 337 {
Chris@0 338 long result = 0;
Chris@0 339 int rc;
Chris@0 340
Chris@0 341 ev->type = SND_SEQ_EVENT_NONE;
Chris@0 342
Chris@0 343 while (count-- > 0) {
Chris@0 344 rc = snd_midi_event_encode_byte(dev, *buf++, ev);
Chris@0 345 result++;
Chris@0 346 if (rc < 0)
Chris@0 347 return rc;
Chris@0 348 else if (rc > 0)
Chris@0 349 return result;
Chris@0 350 }
Chris@0 351
Chris@0 352 return result;
Chris@0 353 }
Chris@0 354
Chris@0 355 /**
Chris@0 356 * \brief Read one byte and encode to sequencer event if finished
Chris@0 357 * \param dev MIDI event parser
Chris@0 358 * \param c a byte of MIDI stream
Chris@0 359 * \param ev Result - sequencer event
Chris@0 360 * \return 1 - sequencer event is completed, 0 - next byte is required for completion, otherwise a negative error code
Chris@0 361 *
Chris@0 362 * Read byte and encode to sequencer event if finished.
Chris@0 363 */
Chris@0 364 int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev)
Chris@0 365 {
Chris@0 366 int rc = 0;
Chris@0 367
Chris@0 368 c &= 0xff;
Chris@0 369
Chris@0 370 if (c >= MIDI_CMD_COMMON_CLOCK) {
Chris@0 371 /* real-time event */
Chris@0 372 ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
Chris@0 373 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
Chris@0 374 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
Chris@0 375 return 1;
Chris@0 376 }
Chris@0 377
Chris@0 378 if (dev->qlen > 0) {
Chris@0 379 /* rest of command */
Chris@0 380 dev->buf[dev->read++] = c;
Chris@0 381 if (dev->type != ST_SYSEX)
Chris@0 382 dev->qlen--;
Chris@0 383 } else {
Chris@0 384 /* new command */
Chris@0 385 dev->read = 1;
Chris@0 386 if (c & 0x80) {
Chris@0 387 dev->buf[0] = c;
Chris@0 388 if ((c & 0xf0) == 0xf0) /* special events */
Chris@0 389 dev->type = (c & 0x0f) + ST_SPECIAL;
Chris@0 390 else
Chris@0 391 dev->type = (c >> 4) & 0x07;
Chris@0 392 dev->qlen = status_event[dev->type].qlen;
Chris@0 393 } else {
Chris@0 394 /* process this byte as argument */
Chris@0 395 dev->buf[dev->read++] = c;
Chris@0 396 dev->qlen = status_event[dev->type].qlen - 1;
Chris@0 397 }
Chris@0 398 }
Chris@0 399 if (dev->qlen == 0) {
Chris@0 400 ev->type = status_event[dev->type].event;
Chris@0 401 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
Chris@0 402 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
Chris@0 403 if (status_event[dev->type].encode) /* set data values */
Chris@0 404 status_event[dev->type].encode(dev, ev);
Chris@0 405 rc = 1;
Chris@0 406 } else if (dev->type == ST_SYSEX) {
Chris@0 407 if (c == MIDI_CMD_COMMON_SYSEX_END ||
Chris@0 408 dev->read >= dev->bufsize) {
Chris@0 409 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
Chris@0 410 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
Chris@0 411 ev->type = SNDRV_SEQ_EVENT_SYSEX;
Chris@0 412 ev->data.ext.len = dev->read;
Chris@0 413 ev->data.ext.ptr = dev->buf;
Chris@0 414 if (c != MIDI_CMD_COMMON_SYSEX_END)
Chris@0 415 dev->read = 0; /* continue to parse */
Chris@0 416 else
Chris@0 417 reset_encode(dev); /* all parsed */
Chris@0 418 rc = 1;
Chris@0 419 }
Chris@0 420 }
Chris@0 421
Chris@0 422 return rc;
Chris@0 423 }
Chris@0 424
Chris@0 425 /* encode note event */
Chris@0 426 static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
Chris@0 427 {
Chris@0 428 ev->data.note.channel = dev->buf[0] & 0x0f;
Chris@0 429 ev->data.note.note = dev->buf[1];
Chris@0 430 ev->data.note.velocity = dev->buf[2];
Chris@0 431 }
Chris@0 432
Chris@0 433 /* encode one parameter controls */
Chris@0 434 static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
Chris@0 435 {
Chris@0 436 ev->data.control.channel = dev->buf[0] & 0x0f;
Chris@0 437 ev->data.control.value = dev->buf[1];
Chris@0 438 }
Chris@0 439
Chris@0 440 /* encode pitch wheel change */
Chris@0 441 static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
Chris@0 442 {
Chris@0 443 ev->data.control.channel = dev->buf[0] & 0x0f;
Chris@0 444 ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192;
Chris@0 445 }
Chris@0 446
Chris@0 447 /* encode midi control change */
Chris@0 448 static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
Chris@0 449 {
Chris@0 450 ev->data.control.channel = dev->buf[0] & 0x0f;
Chris@0 451 ev->data.control.param = dev->buf[1];
Chris@0 452 ev->data.control.value = dev->buf[2];
Chris@0 453 }
Chris@0 454
Chris@0 455 /* encode one parameter value*/
Chris@0 456 static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
Chris@0 457 {
Chris@0 458 ev->data.control.value = dev->buf[1];
Chris@0 459 }
Chris@0 460
Chris@0 461 /* encode song position */
Chris@0 462 static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
Chris@0 463 {
Chris@0 464 ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1];
Chris@0 465 }
Chris@0 466
Chris@0 467 #ifdef UNNEEDED_BY_DSSI
Chris@0 468 /**
Chris@0 469 * \brief Decode sequencer event to MIDI byte stream
Chris@0 470 * \param dev MIDI event parser
Chris@0 471 * \param buf Result - MIDI byte stream
Chris@0 472 * \param count Available bytes in MIDI byte stream
Chris@0 473 * \param ev Event to decode
Chris@0 474 * \return count of decoded bytes otherwise a negative error code
Chris@0 475 *
Chris@0 476 * Decode sequencer event to MIDI byte stream.
Chris@0 477 */
Chris@0 478 long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count, const snd_seq_event_t *ev)
Chris@0 479 {
Chris@0 480 int cmd;
Chris@0 481 long qlen;
Chris@0 482 unsigned int type;
Chris@0 483
Chris@0 484 if (ev->type == SNDRV_SEQ_EVENT_NONE)
Chris@0 485 return -ENOENT;
Chris@0 486
Chris@0 487 for (type = 0; type < numberof(status_event); type++) {
Chris@0 488 if (ev->type == status_event[type].event)
Chris@0 489 goto __found;
Chris@0 490 }
Chris@0 491 for (type = 0; type < numberof(extra_event); type++) {
Chris@0 492 if (ev->type == extra_event[type].event)
Chris@0 493 return extra_event[type].decode(dev, buf, count, ev);
Chris@0 494 }
Chris@0 495 return -ENOENT;
Chris@0 496
Chris@0 497 __found:
Chris@0 498 if (type >= ST_SPECIAL)
Chris@0 499 cmd = 0xf0 + (type - ST_SPECIAL);
Chris@0 500 else
Chris@0 501 /* data.note.channel and data.control.channel is identical */
Chris@0 502 cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f);
Chris@0 503
Chris@0 504
Chris@0 505 if (cmd == MIDI_CMD_COMMON_SYSEX) {
Chris@0 506 qlen = ev->data.ext.len;
Chris@0 507 if (count < qlen)
Chris@0 508 return -ENOMEM;
Chris@0 509 switch (ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) {
Chris@0 510 case SNDRV_SEQ_EVENT_LENGTH_FIXED:
Chris@0 511 return -EINVAL; /* invalid event */
Chris@0 512 }
Chris@0 513 memcpy(buf, ev->data.ext.ptr, qlen);
Chris@0 514 return qlen;
Chris@0 515 } else {
Chris@0 516 unsigned char xbuf[4];
Chris@0 517
Chris@0 518 if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) {
Chris@0 519 dev->lastcmd = cmd;
Chris@0 520 xbuf[0] = cmd;
Chris@0 521 if (status_event[type].decode)
Chris@0 522 status_event[type].decode(ev, xbuf + 1);
Chris@0 523 qlen = status_event[type].qlen + 1;
Chris@0 524 } else {
Chris@0 525 if (status_event[type].decode)
Chris@0 526 status_event[type].decode(ev, xbuf + 0);
Chris@0 527 qlen = status_event[type].qlen;
Chris@0 528 }
Chris@0 529 if (count < qlen)
Chris@0 530 return -ENOMEM;
Chris@0 531 memcpy(buf, xbuf, qlen);
Chris@0 532 return qlen;
Chris@0 533 }
Chris@0 534 }
Chris@0 535 #endif /* UNNEEDED_BY_DSSI */
Chris@0 536
Chris@0 537 /* decode note event */
Chris@0 538 static void note_decode(const snd_seq_event_t *ev, unsigned char *buf)
Chris@0 539 {
Chris@0 540 buf[0] = ev->data.note.note & 0x7f;
Chris@0 541 buf[1] = ev->data.note.velocity & 0x7f;
Chris@0 542 }
Chris@0 543
Chris@0 544 /* decode one parameter controls */
Chris@0 545 static void one_param_decode(const snd_seq_event_t *ev, unsigned char *buf)
Chris@0 546 {
Chris@0 547 buf[0] = ev->data.control.value & 0x7f;
Chris@0 548 }
Chris@0 549
Chris@0 550 /* decode pitch wheel change */
Chris@0 551 static void pitchbend_decode(const snd_seq_event_t *ev, unsigned char *buf)
Chris@0 552 {
Chris@0 553 int value = ev->data.control.value + 8192;
Chris@0 554 buf[0] = value & 0x7f;
Chris@0 555 buf[1] = (value >> 7) & 0x7f;
Chris@0 556 }
Chris@0 557
Chris@0 558 /* decode midi control change */
Chris@0 559 static void two_param_decode(const snd_seq_event_t *ev, unsigned char *buf)
Chris@0 560 {
Chris@0 561 buf[0] = ev->data.control.param & 0x7f;
Chris@0 562 buf[1] = ev->data.control.value & 0x7f;
Chris@0 563 }
Chris@0 564
Chris@0 565 /* decode song position */
Chris@0 566 static void songpos_decode(const snd_seq_event_t *ev, unsigned char *buf)
Chris@0 567 {
Chris@0 568 buf[0] = ev->data.control.value & 0x7f;
Chris@0 569 buf[1] = (ev->data.control.value >> 7) & 0x7f;
Chris@0 570 }
Chris@0 571
Chris@0 572 #ifdef UNNEEDED_BY_DSSI
Chris@0 573 /* decode 14bit control */
Chris@0 574 static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int count, const snd_seq_event_t *ev)
Chris@0 575 {
Chris@0 576 unsigned char cmd;
Chris@0 577 int idx = 0;
Chris@0 578
Chris@0 579 cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
Chris@0 580 if (ev->data.control.param < 32) {
Chris@0 581 if (count < 4)
Chris@0 582 return -ENOMEM;
Chris@0 583 if (dev->nostat && count < 6)
Chris@0 584 return -ENOMEM;
Chris@0 585 if (cmd != dev->lastcmd || dev->nostat) {
Chris@0 586 if (count < 5)
Chris@0 587 return -ENOMEM;
Chris@0 588 buf[idx++] = dev->lastcmd = cmd;
Chris@0 589 }
Chris@0 590 buf[idx++] = ev->data.control.param;
Chris@0 591 buf[idx++] = (ev->data.control.value >> 7) & 0x7f;
Chris@0 592 if (dev->nostat)
Chris@0 593 buf[idx++] = cmd;
Chris@0 594 buf[idx++] = ev->data.control.param + 32;
Chris@0 595 buf[idx++] = ev->data.control.value & 0x7f;
Chris@0 596 } else {
Chris@0 597 if (count < 2)
Chris@0 598 return -ENOMEM;
Chris@0 599 if (cmd != dev->lastcmd || dev->nostat) {
Chris@0 600 if (count < 3)
Chris@0 601 return -ENOMEM;
Chris@0 602 buf[idx++] = dev->lastcmd = cmd;
Chris@0 603 }
Chris@0 604 buf[idx++] = ev->data.control.param & 0x7f;
Chris@0 605 buf[idx++] = ev->data.control.value & 0x7f;
Chris@0 606 }
Chris@0 607 return idx;
Chris@0 608 }
Chris@0 609
Chris@0 610 /* decode reg/nonreg param */
Chris@0 611 static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, const snd_seq_event_t *ev)
Chris@0 612 {
Chris@0 613 unsigned char cmd;
Chris@0 614 char *cbytes;
Chris@0 615 static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
Chris@0 616 MIDI_CTL_NONREG_PARM_NUM_LSB,
Chris@0 617 MIDI_CTL_MSB_DATA_ENTRY,
Chris@0 618 MIDI_CTL_LSB_DATA_ENTRY };
Chris@0 619 static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB,
Chris@0 620 MIDI_CTL_REGIST_PARM_NUM_LSB,
Chris@0 621 MIDI_CTL_MSB_DATA_ENTRY,
Chris@0 622 MIDI_CTL_LSB_DATA_ENTRY };
Chris@0 623 unsigned char bytes[4];
Chris@0 624 int idx = 0, i;
Chris@0 625
Chris@0 626 if (count < 8)
Chris@0 627 return -ENOMEM;
Chris@0 628 if (dev->nostat && count < 12)
Chris@0 629 return -ENOMEM;
Chris@0 630 cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
Chris@0 631 bytes[0] = ev->data.control.param & 0x007f;
Chris@0 632 bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
Chris@0 633 bytes[2] = ev->data.control.value & 0x007f;
Chris@0 634 bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
Chris@0 635 if (cmd != dev->lastcmd && !dev->nostat) {
Chris@0 636 if (count < 9)
Chris@0 637 return -ENOMEM;
Chris@0 638 buf[idx++] = dev->lastcmd = cmd;
Chris@0 639 }
Chris@0 640 cbytes = ev->type == SND_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn;
Chris@0 641 for (i = 0; i < 4; i++) {
Chris@0 642 if (dev->nostat)
Chris@0 643 buf[idx++] = dev->lastcmd = cmd;
Chris@0 644 buf[idx++] = cbytes[i];
Chris@0 645 buf[idx++] = bytes[i];
Chris@0 646 }
Chris@0 647 return idx;
Chris@0 648 }
Chris@0 649 #endif /* UNNEEDED_BY_DSSI */