linux/sound/core/seq/oss/seq_oss_event.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * OSS compatible sequencer driver
   4 *
   5 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
   6 */
   7
   8#include "seq_oss_device.h"
   9#include "seq_oss_synth.h"
  10#include "seq_oss_midi.h"
  11#include "seq_oss_event.h"
  12#include "seq_oss_timer.h"
  13#include <sound/seq_oss_legacy.h>
  14#include "seq_oss_readq.h"
  15#include "seq_oss_writeq.h"
  16#include <linux/nospec.h>
  17
  18
  19/*
  20 * prototypes
  21 */
  22static int extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
  23static int chn_voice_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  24static int chn_common_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  25static int timing_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  26static int local_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
  27static int old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
  28static int note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
  29static int note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
  30static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev);
  31static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev);
  32static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev);
  33
  34
  35/*
  36 * convert an OSS event to ALSA event
  37 * return 0 : enqueued
  38 *        non-zero : invalid - ignored
  39 */
  40
  41int
  42snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
  43{
  44        switch (q->s.code) {
  45        case SEQ_EXTENDED:
  46                return extended_event(dp, q, ev);
  47
  48        case EV_CHN_VOICE:
  49                return chn_voice_event(dp, q, ev);
  50
  51        case EV_CHN_COMMON:
  52                return chn_common_event(dp, q, ev);
  53
  54        case EV_TIMING:
  55                return timing_event(dp, q, ev);
  56
  57        case EV_SEQ_LOCAL:
  58                return local_event(dp, q, ev);
  59
  60        case EV_SYSEX:
  61                return snd_seq_oss_synth_sysex(dp, q->x.dev, q->x.buf, ev);
  62
  63        case SEQ_MIDIPUTC:
  64                if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
  65                        return -EINVAL;
  66                /* put a midi byte */
  67                if (! is_write_mode(dp->file_mode))
  68                        break;
  69                if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
  70                        break;
  71                if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
  72                        return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
  73                break;
  74
  75        case SEQ_ECHO:
  76                if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
  77                        return -EINVAL;
  78                return set_echo_event(dp, q, ev);
  79
  80        case SEQ_PRIVATE:
  81                if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
  82                        return -EINVAL;
  83                return snd_seq_oss_synth_raw_event(dp, q->c[1], q->c, ev);
  84
  85        default:
  86                if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
  87                        return -EINVAL;
  88                return old_event(dp, q, ev);
  89        }
  90        return -EINVAL;
  91}
  92
  93/* old type events: mode1 only */
  94static int
  95old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
  96{
  97        switch (q->s.code) {
  98        case SEQ_NOTEOFF:
  99                return note_off_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
 100
 101        case SEQ_NOTEON:
 102                return note_on_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
 103
 104        case SEQ_WAIT:
 105                /* skip */
 106                break;
 107
 108        case SEQ_PGMCHANGE:
 109                return set_control_event(dp, 0, SNDRV_SEQ_EVENT_PGMCHANGE,
 110                                         q->n.chn, 0, q->n.note, ev);
 111
 112        case SEQ_SYNCTIMER:
 113                return snd_seq_oss_timer_reset(dp->timer);
 114        }
 115
 116        return -EINVAL;
 117}
 118
 119/* 8bytes extended event: mode1 only */
 120static int
 121extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
 122{
 123        int val;
 124
 125        switch (q->e.cmd) {
 126        case SEQ_NOTEOFF:
 127                return note_off_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
 128
 129        case SEQ_NOTEON:
 130                return note_on_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
 131
 132        case SEQ_PGMCHANGE:
 133                return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
 134                                         q->e.chn, 0, q->e.p1, ev);
 135
 136        case SEQ_AFTERTOUCH:
 137                return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CHANPRESS,
 138                                         q->e.chn, 0, q->e.p1, ev);
 139
 140        case SEQ_BALANCE:
 141                /* convert -128:127 to 0:127 */
 142                val = (char)q->e.p1;
 143                val = (val + 128) / 2;
 144                return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CONTROLLER,
 145                                         q->e.chn, CTL_PAN, val, ev);
 146
 147        case SEQ_CONTROLLER:
 148                val = ((short)q->e.p3 << 8) | (short)q->e.p2;
 149                switch (q->e.p1) {
 150                case CTRL_PITCH_BENDER: /* SEQ1 V2 control */
 151                        /* -0x2000:0x1fff */
 152                        return set_control_event(dp, q->e.dev,
 153                                                 SNDRV_SEQ_EVENT_PITCHBEND,
 154                                                 q->e.chn, 0, val, ev);
 155                case CTRL_PITCH_BENDER_RANGE:
 156                        /* conversion: 100/semitone -> 128/semitone */
 157                        return set_control_event(dp, q->e.dev,
 158                                                 SNDRV_SEQ_EVENT_REGPARAM,
 159                                                 q->e.chn, 0, val*128/100, ev);
 160                default:
 161                        return set_control_event(dp, q->e.dev,
 162                                                  SNDRV_SEQ_EVENT_CONTROL14,
 163                                                  q->e.chn, q->e.p1, val, ev);
 164                }
 165
 166        case SEQ_VOLMODE:
 167                return snd_seq_oss_synth_raw_event(dp, q->e.dev, q->c, ev);
 168
 169        }
 170        return -EINVAL;
 171}
 172
 173/* channel voice events: mode1 and 2 */
 174static int
 175chn_voice_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
 176{
 177        if (q->v.chn >= 32)
 178                return -EINVAL;
 179        switch (q->v.cmd) {
 180        case MIDI_NOTEON:
 181                return note_on_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
 182
 183        case MIDI_NOTEOFF:
 184                return note_off_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
 185
 186        case MIDI_KEY_PRESSURE:
 187                return set_note_event(dp, q->v.dev, SNDRV_SEQ_EVENT_KEYPRESS,
 188                                       q->v.chn, q->v.note, q->v.parm, ev);
 189
 190        }
 191        return -EINVAL;
 192}
 193
 194/* channel common events: mode1 and 2 */
 195static int
 196chn_common_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
 197{
 198        if (q->l.chn >= 32)
 199                return -EINVAL;
 200        switch (q->l.cmd) {
 201        case MIDI_PGM_CHANGE:
 202                return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
 203                                          q->l.chn, 0, q->l.p1, ev);
 204
 205        case MIDI_CTL_CHANGE:
 206                return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CONTROLLER,
 207                                          q->l.chn, q->l.p1, q->l.val, ev);
 208
 209        case MIDI_PITCH_BEND:
 210                /* conversion: 0:0x3fff -> -0x2000:0x1fff */
 211                return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PITCHBEND,
 212                                          q->l.chn, 0, q->l.val - 8192, ev);
 213                
 214        case MIDI_CHN_PRESSURE:
 215                return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CHANPRESS,
 216                                          q->l.chn, 0, q->l.val, ev);
 217        }
 218        return -EINVAL;
 219}
 220
 221/* timer events: mode1 and mode2 */
 222static int
 223timing_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
 224{
 225        switch (q->t.cmd) {
 226        case TMR_ECHO:
 227                if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
 228                        return set_echo_event(dp, q, ev);
 229                else {
 230                        union evrec tmp;
 231                        memset(&tmp, 0, sizeof(tmp));
 232                        /* XXX: only for little-endian! */
 233                        tmp.echo = (q->t.time << 8) | SEQ_ECHO;
 234                        return set_echo_event(dp, &tmp, ev);
 235                } 
 236
 237        case TMR_STOP:
 238                if (dp->seq_mode)
 239                        return snd_seq_oss_timer_stop(dp->timer);
 240                return 0;
 241
 242        case TMR_CONTINUE:
 243                if (dp->seq_mode)
 244                        return snd_seq_oss_timer_continue(dp->timer);
 245                return 0;
 246
 247        case TMR_TEMPO:
 248                if (dp->seq_mode)
 249                        return snd_seq_oss_timer_tempo(dp->timer, q->t.time);
 250                return 0;
 251        }
 252
 253        return -EINVAL;
 254}
 255
 256/* local events: mode1 and 2 */
 257static int
 258local_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
 259{
 260        return -EINVAL;
 261}
 262
 263/*
 264 * process note-on event for OSS synth
 265 * three different modes are available:
 266 * - SNDRV_SEQ_OSS_PROCESS_EVENTS  (for one-voice per channel mode)
 267 *      Accept note 255 as volume change.
 268 * - SNDRV_SEQ_OSS_PASS_EVENTS
 269 *      Pass all events to lowlevel driver anyway
 270 * - SNDRV_SEQ_OSS_PROCESS_KEYPRESS  (mostly for Emu8000)
 271 *      Use key-pressure if note >= 128
 272 */
 273static int
 274note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
 275{
 276        struct seq_oss_synthinfo *info;
 277
 278        info = snd_seq_oss_synth_info(dp, dev);
 279        if (!info)
 280                return -ENXIO;
 281
 282        switch (info->arg.event_passing) {
 283        case SNDRV_SEQ_OSS_PROCESS_EVENTS:
 284                if (! info->ch || ch < 0 || ch >= info->nr_voices) {
 285                        /* pass directly */
 286                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 287                }
 288
 289                ch = array_index_nospec(ch, info->nr_voices);
 290                if (note == 255 && info->ch[ch].note >= 0) {
 291                        /* volume control */
 292                        int type;
 293                        //if (! vel)
 294                                /* set volume to zero -- note off */
 295                        //      type = SNDRV_SEQ_EVENT_NOTEOFF;
 296                        //else
 297                                if (info->ch[ch].vel)
 298                                /* sample already started -- volume change */
 299                                type = SNDRV_SEQ_EVENT_KEYPRESS;
 300                        else
 301                                /* sample not started -- start now */
 302                                type = SNDRV_SEQ_EVENT_NOTEON;
 303                        info->ch[ch].vel = vel;
 304                        return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev);
 305                } else if (note >= 128)
 306                        return -EINVAL; /* invalid */
 307
 308                if (note != info->ch[ch].note && info->ch[ch].note >= 0)
 309                        /* note changed - note off at beginning */
 310                        set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev);
 311                /* set current status */
 312                info->ch[ch].note = note;
 313                info->ch[ch].vel = vel;
 314                if (vel) /* non-zero velocity - start the note now */
 315                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 316                return -EINVAL;
 317                
 318        case SNDRV_SEQ_OSS_PASS_EVENTS:
 319                /* pass the event anyway */
 320                return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 321
 322        case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
 323                if (note >= 128) /* key pressure: shifted by 128 */
 324                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev);
 325                else /* normal note-on event */
 326                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 327        }
 328        return -EINVAL;
 329}
 330
 331/*
 332 * process note-off event for OSS synth
 333 */
 334static int
 335note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
 336{
 337        struct seq_oss_synthinfo *info;
 338
 339        info = snd_seq_oss_synth_info(dp, dev);
 340        if (!info)
 341                return -ENXIO;
 342
 343        switch (info->arg.event_passing) {
 344        case SNDRV_SEQ_OSS_PROCESS_EVENTS:
 345                if (! info->ch || ch < 0 || ch >= info->nr_voices) {
 346                        /* pass directly */
 347                        return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
 348                }
 349
 350                ch = array_index_nospec(ch, info->nr_voices);
 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 */
 371static int
 372set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev)
 373{
 374        if (!snd_seq_oss_synth_info(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 */
 389static int
 390set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev)
 391{
 392        if (!snd_seq_oss_synth_info(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 */
 407static int
 408set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *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 */
 421int
 422snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data,
 423                        int atomic, int hop)
 424{
 425        struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
 426        union evrec *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 = (union evrec*)&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
 448