📄 sequencer.c
字号:
/* * sound/sequencer.c * * The sequencer personality manager. *//* * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. *//* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Alan Cox : reformatted and fixed a pair of null pointer bugs */#include <linux/kmod.h>#define SEQUENCER_C#include "sound_config.h"#include "midi_ctrl.h"static int sequencer_ok = 0;static struct sound_timer_operations *tmr;static int tmr_no = -1; /* Currently selected timer */static int pending_timer = -1; /* For timer change operation */extern unsigned long seq_time;static int obsolete_api_used = 0;/* * Local counts for number of synth and MIDI devices. These are initialized * by the sequencer_open. */static int max_mididev = 0;static int max_synthdev = 0;/* * The seq_mode gives the operating mode of the sequencer: * 1 = level1 (the default) * 2 = level2 (extended capabilities) */#define SEQ_1 1#define SEQ_2 2static int seq_mode = SEQ_1;static DECLARE_WAIT_QUEUE_HEAD(seq_sleeper);static DECLARE_WAIT_QUEUE_HEAD(midi_sleeper);static int midi_opened[MAX_MIDI_DEV] = { 0};static int midi_written[MAX_MIDI_DEV] = { 0};static unsigned long prev_input_time = 0;static int prev_event_time;#include "tuning.h"#define EV_SZ 8#define IEV_SZ 8static unsigned char *queue = NULL;static unsigned char *iqueue = NULL;static volatile int qhead = 0, qtail = 0, qlen = 0;static volatile int iqhead = 0, iqtail = 0, iqlen = 0;static volatile int seq_playing = 0;static volatile int sequencer_busy = 0;static int output_threshold;static long pre_event_timeout;static unsigned synth_open_mask;static int seq_queue(unsigned char *note, char nonblock);static void seq_startplay(void);static int seq_sync(void);static void seq_reset(void);#if MAX_SYNTH_DEV > 15#error Too many synthesizer devices enabled.#endifint sequencer_read(int dev, struct file *file, char *buf, int count){ int c = count, p = 0; int ev_len; unsigned long flags; dev = dev >> 4; ev_len = seq_mode == SEQ_1 ? 4 : 8; save_flags(flags); cli(); if (!iqlen) { if (file->f_flags & O_NONBLOCK) { restore_flags(flags); return -EAGAIN; } interruptible_sleep_on_timeout(&midi_sleeper, pre_event_timeout); if (!iqlen) { restore_flags(flags); return 0; } } while (iqlen && c >= ev_len) { char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; copy_to_user(&(buf)[p], fixit, ev_len); p += ev_len; c -= ev_len; iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; iqlen--; } restore_flags(flags); return count - c;}static void sequencer_midi_output(int dev){ /* * Currently NOP */}void seq_copy_to_input(unsigned char *event_rec, int len){ unsigned long flags; /* * Verify that the len is valid for the current mode. */ if (len != 4 && len != 8) return; if ((seq_mode == SEQ_1) != (len == 4)) return; if (iqlen >= (SEQ_MAX_QUEUE - 1)) return; /* Overflow */ save_flags(flags); cli(); memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; wake_up(&midi_sleeper); restore_flags(flags);}static void sequencer_midi_input(int dev, unsigned char data){ unsigned int tstamp; unsigned char event_rec[4]; if (data == 0xfe) /* Ignore active sensing */ return; tstamp = jiffies - seq_time; if (tstamp != prev_input_time) { tstamp = (tstamp << 8) | SEQ_WAIT; seq_copy_to_input((unsigned char *) &tstamp, 4); prev_input_time = tstamp; } event_rec[0] = SEQ_MIDIPUTC; event_rec[1] = data; event_rec[2] = dev; event_rec[3] = 0; seq_copy_to_input(event_rec, 4);}void seq_input_event(unsigned char *event_rec, int len){ unsigned long this_time; if (seq_mode == SEQ_2) this_time = tmr->get_time(tmr_no); else this_time = jiffies - seq_time; if (this_time != prev_input_time) { unsigned char tmp_event[8]; tmp_event[0] = EV_TIMING; tmp_event[1] = TMR_WAIT_ABS; tmp_event[2] = 0; tmp_event[3] = 0; *(unsigned int *) &tmp_event[4] = this_time; seq_copy_to_input(tmp_event, 8); prev_input_time = this_time; } seq_copy_to_input(event_rec, len);}int sequencer_write(int dev, struct file *file, const char *buf, int count){ unsigned char event_rec[EV_SZ], ev_code; int p = 0, c, ev_size; int err; int mode = translate_mode(file); dev = dev >> 4; DEB(printk("sequencer_write(dev=%d, count=%d)\n", dev, count)); if (mode == OPEN_READ) return -EIO; c = count; while (c >= 4) { copy_from_user((char *) event_rec, &(buf)[p], 4); ev_code = event_rec[0]; if (ev_code == SEQ_FULLSIZE) { int err, fmt; dev = *(unsigned short *) &event_rec[2]; if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) return -ENXIO; if (!(synth_open_mask & (1 << dev))) return -ENXIO; fmt = (*(short *) &event_rec[0]) & 0xffff; err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); if (err < 0) return err; return err; } if (ev_code >= 128) { if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) { printk(KERN_WARNING "Sequencer: Invalid level 2 event %x\n", ev_code); return -EINVAL; } ev_size = 8; if (c < ev_size) { if (!seq_playing) seq_startplay(); return count - c; } copy_from_user((char *) &event_rec[4], &(buf)[p + 4], 4); } else { if (seq_mode == SEQ_2) { printk(KERN_WARNING "Sequencer: 4 byte event in level 2 mode\n"); return -EINVAL; } ev_size = 4; if (event_rec[0] != SEQ_MIDIPUTC) obsolete_api_used = 1; } if (event_rec[0] == SEQ_MIDIPUTC) { if (!midi_opened[event_rec[2]]) { int mode; int dev = event_rec[2]; if (dev >= max_mididev || midi_devs[dev]==NULL) { /*printk("Sequencer Error: Nonexistent MIDI device %d\n", dev);*/ return -ENXIO; } mode = translate_mode(file); if ((err = midi_devs[dev]->open(dev, mode, sequencer_midi_input, sequencer_midi_output)) < 0) { seq_reset(); printk(KERN_WARNING "Sequencer Error: Unable to open Midi #%d\n", dev); return err; } midi_opened[dev] = 1; } } if (!seq_queue(event_rec, (file->f_flags & (O_NONBLOCK) ? 1 : 0))) { int processed = count - c; if (!seq_playing) seq_startplay(); if (!processed && (file->f_flags & O_NONBLOCK)) return -EAGAIN; else return processed; } p += ev_size; c -= ev_size; } if (!seq_playing) seq_startplay(); return count;}static int seq_queue(unsigned char *note, char nonblock){ /* * Test if there is space in the queue */ if (qlen >= SEQ_MAX_QUEUE) if (!seq_playing) seq_startplay(); /* * Give chance to drain the queue */ if (!nonblock && qlen >= SEQ_MAX_QUEUE && !waitqueue_active(&seq_sleeper)) { /* * Sleep until there is enough space on the queue */ interruptible_sleep_on(&seq_sleeper); } if (qlen >= SEQ_MAX_QUEUE) { return 0; /* * To be sure */ } memcpy(&queue[qtail * EV_SZ], note, EV_SZ); qtail = (qtail + 1) % SEQ_MAX_QUEUE; qlen++; return 1;}static int extended_event(unsigned char *q){ int dev = q[2]; if (dev < 0 || dev >= max_synthdev) return -ENXIO; if (!(synth_open_mask & (1 << dev))) return -ENXIO; switch (q[1]) { case SEQ_NOTEOFF: synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); break; case SEQ_NOTEON: if (q[4] > 127 && q[4] != 255) return 0; if (q[5] == 0) { synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); break; } synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); break; case SEQ_PGMCHANGE: synth_devs[dev]->set_instr(dev, q[3], q[4]); break; case SEQ_AFTERTOUCH: synth_devs[dev]->aftertouch(dev, q[3], q[4]); break; case SEQ_BALANCE: synth_devs[dev]->panning(dev, q[3], (char) q[4]); break; case SEQ_CONTROLLER: synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); break; case SEQ_VOLMODE: if (synth_devs[dev]->volume_method != NULL) synth_devs[dev]->volume_method(dev, q[3]); break; default: return -EINVAL; } return 0;}static int find_voice(int dev, int chn, int note){ unsigned short key; int i; key = (chn << 8) | (note + 1); for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) if (synth_devs[dev]->alloc.map[i] == key) return i; return -1;}static int alloc_voice(int dev, int chn, int note){ unsigned short key; int voice; key = (chn << 8) | (note + 1); voice = synth_devs[dev]->alloc_voice(dev, chn, note, &synth_devs[dev]->alloc); synth_devs[dev]->alloc.map[voice] = key; synth_devs[dev]->alloc.alloc_times[voice] = synth_devs[dev]->alloc.timestamp++; return voice;}static void seq_chn_voice_event(unsigned char *event_rec){#define dev event_rec[1]#define cmd event_rec[2]#define chn event_rec[3]#define note event_rec[4]#define parm event_rec[5] int voice = -1; if ((int) dev > max_synthdev || synth_devs[dev] == NULL) return; if (!(synth_open_mask & (1 << dev))) return; if (!synth_devs[dev]) return; if (seq_mode == SEQ_2) { if (synth_devs[dev]->alloc_voice) voice = find_voice(dev, chn, note); if (cmd == MIDI_NOTEON && parm == 0) { cmd = MIDI_NOTEOFF; parm = 64; } } switch (cmd) { case MIDI_NOTEON: if (note > 127 && note != 255) /* Not a seq2 feature */ return; if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) { /* Internal synthesizer (FM, GUS, etc) */ voice = alloc_voice(dev, chn, note); } if (voice == -1) voice = chn; if (seq_mode == SEQ_2 && (int) dev < num_synths) { /* * The MIDI channel 10 is a percussive channel. Use the note * number to select the proper patch (128 to 255) to play. */ if (chn == 9) { synth_devs[dev]->set_instr(dev, voice, 128 + note); synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; } synth_devs[dev]->setup_voice(dev, voice, chn); } synth_devs[dev]->start_note(dev, voice, note, parm); break; case MIDI_NOTEOFF: if (voice == -1) voice = chn; synth_devs[dev]->kill_note(dev, voice, note, parm); break; case MIDI_KEY_PRESSURE: if (voice == -1) voice = chn; synth_devs[dev]->aftertouch(dev, voice, parm); break; default:; }#undef dev#undef cmd#undef chn#undef note#undef parm}static void seq_chn_common_event(unsigned char *event_rec){ unsigned char dev = event_rec[1]; unsigned char cmd = event_rec[2]; unsigned char chn = event_rec[3]; unsigned char p1 = event_rec[4]; /* unsigned char p2 = event_rec[5]; */ unsigned short w14 = *(short *) &event_rec[6]; if ((int) dev > max_synthdev || synth_devs[dev] == NULL) return; if (!(synth_open_mask & (1 << dev))) return; if (!synth_devs[dev]) return; switch (cmd) { case MIDI_PGM_CHANGE: if (seq_mode == SEQ_2) { synth_devs[dev]->chn_info[chn].pgm_num = p1; if ((int) dev >= num_synths) synth_devs[dev]->set_instr(dev, chn, p1); } else synth_devs[dev]->set_instr(dev, chn, p1); break; case MIDI_CTL_CHANGE: if (seq_mode == SEQ_2) { if (chn > 15 || p1 > 127) break; synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; if (p1 < 32) /* Setting MSB should clear LSB to 0 */ synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; if ((int) dev < num_synths) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -