linux/sound/core/seq/oss/seq_oss_event.c
<<
>>
Prefs
   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 */
  34static int extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
  35static int chn_voice_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  36static int chn_common_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  37static int timing_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  38static int local_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  39static int old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
  40static int note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
  41static int note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
  42static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev);
  43static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev);
  44static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev);
  45
  46
  47/*
  48 * convert an OSS event to ALSA event
  49 * return 0 : enqueued
  50 *        non-zero : invalid - ignored
  51 */
  52
  53int
  54snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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 */
 106static int
 107old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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 */
 132static int
 133extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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 */
 186static int
 187chn_voice_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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 */
 207static int
 208chn_common_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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 */
 234static int
 235timing_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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                        union evrec 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 */
 269static int
 270local_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *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 */
 285static int
 286note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
 287{
 288        struct seq_oss_synthinfo *info;
 289
 290        if (!snd_seq_oss_synth_is_valid(dp, dev))
 291                return -ENXIO;
 292
 293        info = &dp->synths[dev];
 294        switch (info->arg.event_passing) {
 295        case SNDRV_SEQ_OSS_PROCESS_EVENTS:
 296                if (! info->ch || ch < 0 || ch >= info->nr_voices) {
 297                        /* pass directly */
 298                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 299                }
 300
 301                if (note == 255 && info->ch[ch].note >= 0) {
 302                        /* volume control */
 303                        int type;
 304                        //if (! vel)
 305                                /* set volume to zero -- note off */
 306                        //      type = SNDRV_SEQ_EVENT_NOTEOFF;
 307                        //else
 308                                if (info->ch[ch].vel)
 309                                /* sample already started -- volume change */
 310                                type = SNDRV_SEQ_EVENT_KEYPRESS;
 311                        else
 312                                /* sample not started -- start now */
 313                                type = SNDRV_SEQ_EVENT_NOTEON;
 314                        info->ch[ch].vel = vel;
 315                        return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev);
 316                } else if (note >= 128)
 317                        return -EINVAL; /* invalid */
 318
 319                if (note != info->ch[ch].note && info->ch[ch].note >= 0)
 320                        /* note changed - note off at beginning */
 321                        set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev);
 322                /* set current status */
 323                info->ch[ch].note = note;
 324                info->ch[ch].vel = vel;
 325                if (vel) /* non-zero velocity - start the note now */
 326                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 327                return -EINVAL;
 328                
 329        case SNDRV_SEQ_OSS_PASS_EVENTS:
 330                /* pass the event anyway */
 331                return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 332
 333        case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
 334                if (note >= 128) /* key pressure: shifted by 128 */
 335                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev);
 336                else /* normal note-on event */
 337                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 338        }
 339        return -EINVAL;
 340}
 341
 342/*
 343 * process note-off event for OSS synth
 344 */
 345static int
 346note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
 347{
 348        struct seq_oss_synthinfo *info;
 349
 350        if (!snd_seq_oss_synth_is_valid(dp, dev))
 351                return -ENXIO;
 352
 353        info = &dp->synths[dev];
 354        switch (info->arg.event_passing) {
 355        case SNDRV_SEQ_OSS_PROCESS_EVENTS:
 356                if (! info->ch || ch < 0 || ch >= info->nr_voices) {
 357                        /* pass directly */
 358                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 359                }
 360
 361                if (info->ch[ch].note >= 0) {
 362                        note = info->ch[ch].note;
 363                        info->ch[ch].vel = 0;
 364                        info->ch[ch].note = -1;
 365                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
 366                }
 367                return -EINVAL; /* invalid */
 368
 369        case SNDRV_SEQ_OSS_PASS_EVENTS:
 370        case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
 371                /* pass the event anyway */
 372                return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
 373
 374        }
 375        return -EINVAL;
 376}
 377
 378/*
 379 * create a note event
 380 */
 381static int
 382set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev)
 383{
 384        if (! snd_seq_oss_synth_is_valid(dp, dev))
 385                return -ENXIO;
 386        
 387        ev->type = type;
 388        snd_seq_oss_synth_addr(dp, dev, ev);
 389        ev->data.note.channel = ch;
 390        ev->data.note.note = note;
 391        ev->data.note.velocity = vel;
 392
 393        return 0;
 394}
 395
 396/*
 397 * create a control event
 398 */
 399static int
 400set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev)
 401{
 402        if (! snd_seq_oss_synth_is_valid(dp, dev))
 403                return -ENXIO;
 404        
 405        ev->type = type;
 406        snd_seq_oss_synth_addr(dp, dev, ev);
 407        ev->data.control.channel = ch;
 408        ev->data.control.param = param;
 409        ev->data.control.value = val;
 410
 411        return 0;
 412}
 413
 414/*
 415 * create an echo event
 416 */
 417static int
 418set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev)
 419{
 420        ev->type = SNDRV_SEQ_EVENT_ECHO;
 421        /* echo back to itself */
 422        snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port);
 423        memcpy(&ev->data, rec, LONG_EVENT_SIZE);
 424        return 0;
 425}
 426
 427/*
 428 * event input callback from ALSA sequencer:
 429 * the echo event is processed here.
 430 */
 431int
 432snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data,
 433                        int atomic, int hop)
 434{
 435        struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
 436        union evrec *rec;
 437
 438        if (ev->type != SNDRV_SEQ_EVENT_ECHO)
 439                return snd_seq_oss_midi_input(ev, direct, private_data);
 440
 441        if (ev->source.client != dp->cseq)
 442                return 0; /* ignored */
 443
 444        rec = (union evrec*)&ev->data;
 445        if (rec->s.code == SEQ_SYNCTIMER) {
 446                /* sync echo back */
 447                snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time);
 448                
 449        } else {
 450                /* echo back event */
 451                if (dp->readq == NULL)
 452                        return 0;
 453                snd_seq_oss_readq_put_event(dp->readq, rec);
 454        }
 455        return 0;
 456}
 457
 458