📄 sequencer.c
字号:
/* * sound/sequencer.c * * The sequencer personality manager. * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#define SEQUENCER_C#include <i386/isa/sound/sound_config.h>#include <i386/isa/sound/midi_ctrl.h>extern void seq_drain_midi_queues __P((void));#ifdef CONFIGURE_SOUNDCARD#ifndef EXCLUDE_SEQUENCERstatic 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 *//* * 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 capabilites) */#define SEQ_1 1#define SEQ_2 2static int seq_mode = SEQ_1;DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);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;static unsigned long seq_time = 0;#include <i386/isa/sound/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 int sequencer_busy = 0;static int output_treshold;static int 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);static int pmgr_present[MAX_SYNTH_DEV] ={0};#if MAX_SYNTH_DEV > 15#error Too many synthesizer devices enabled.#endifintsequencer_read (int dev, struct fileinfo *file, snd_rw_buf * 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; if (dev) /* * Patch manager device */ return pmgr_read (dev - 1, file, buf, count); DISABLE_INTR (flags); if (!iqlen) { if (ISSET_FILE_FLAG (file, O_NONBLOCK)) { RESTORE_INTR (flags); return RET_ERROR (EAGAIN); } DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout); if (!iqlen) { RESTORE_INTR (flags); return 0; } } while (iqlen && c >= ev_len) { COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], ev_len); p += ev_len; c -= ev_len; iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; iqlen--; } RESTORE_INTR (flags); return count - c;}static voidsequencer_midi_output (int dev){ /* * Currently NOP */}voidseq_copy_to_input (unsigned char *event, 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 */ DISABLE_INTR (flags); memcpy (&iqueue[iqtail * IEV_SZ], event, len); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag)) { WAKE_UP (midi_sleeper, midi_sleep_flag); } RESTORE_INTR (flags);#if defined(__FreeBSD__) if (selinfo[0].si_pid) selwakeup(&selinfo[0]);#endif}static voidsequencer_midi_input (int dev, unsigned char data){ unsigned int tstamp; unsigned char event[4]; if (data == 0xfe) /* Ignore active sensing */ return; tstamp = GET_TIME () - 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[0] = SEQ_MIDIPUTC; event[1] = data; event[2] = dev; event[3] = 0; seq_copy_to_input (event, 4);}voidseq_input_event (unsigned char *event, int len){ unsigned long this_time; if (seq_mode == SEQ_2) this_time = tmr->get_time (tmr_no); else this_time = GET_TIME () - 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 long *) &tmp_event[4] = this_time; seq_copy_to_input (tmp_event, 8); prev_input_time = this_time; } seq_copy_to_input (event, len);}intsequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){ unsigned char event[EV_SZ], ev_code; int p = 0, c, ev_size; int err; int mode = file->mode & O_ACCMODE; dev = dev >> 4; DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); if (mode == OPEN_READ) return RET_ERROR (EIO); if (dev) /* * Patch manager device */ return pmgr_write (dev - 1, file, buf, count); c = count; while (c >= 4) { COPY_FROM_USER (event, buf, p, 4); ev_code = event[0]; if (ev_code == SEQ_FULLSIZE) { int err; dev = *(unsigned short *) &event[2]; if (dev < 0 || dev >= max_synthdev) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) return RET_ERROR (ENXIO); err = synth_devs[dev]->load_patch (dev, *(short *) &event[0], 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 ("Sequencer: Invalid level 2 event %x\n", ev_code); return RET_ERROR (EINVAL); } ev_size = 8; if (c < ev_size) { if (!seq_playing) seq_startplay (); return count - c; } COPY_FROM_USER (&event[4], buf, p + 4, 4); } else { if (seq_mode == SEQ_2) { printk ("Sequencer: 4 byte event in level 2 mode\n"); return RET_ERROR (EINVAL); } ev_size = 4; } if (event[0] == SEQ_MIDIPUTC) { if (!midi_opened[event[2]]) { int mode; int dev = event[2]; if (dev >= max_mididev) { printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); return RET_ERROR (ENXIO); } mode = file->mode & O_ACCMODE; if ((err = midi_devs[dev]->open (dev, mode, sequencer_midi_input, sequencer_midi_output)) < 0) { seq_reset (); printk ("Sequencer Error: Unable to open Midi #%d\n", dev); return err; } midi_opened[dev] = 1; } } if (!seq_queue (event, ISSET_FILE_FLAG (file, O_NONBLOCK))) { int processed = count - c; if (!seq_playing) seq_startplay (); if (!processed && ISSET_FILE_FLAG (file, O_NONBLOCK)) return RET_ERROR (EAGAIN); else return processed; } p += ev_size; c -= ev_size; } if (!seq_playing) seq_startplay (); return count; /* This will "eat" chunks shorter than 4 bytes (if written * alone) Should we really do that ? */}static intseq_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 && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { /* * Sleep until there is enough space on the queue */ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } 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 intextended_event (unsigned char *q){ int dev = q[2]; if (dev < 0 || dev >= max_synthdev) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) return RET_ERROR (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; 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]); break; case SEQ_VOLMODE: if (synth_devs[dev]->volume_method != NULL) synth_devs[dev]->volume_method (dev, q[3]); break; default: return RET_ERROR (EINVAL); } return 0;}static intfind_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 intalloc_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 voidseq_chn_voice_event (unsigned char *event){ unsigned char dev = event[1]; unsigned char cmd = event[2]; unsigned char chn = event[3]; unsigned char note = event[4]; unsigned char parm = event[5]; int voice = -1; if ((int) dev > max_synthdev) 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 && 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); note = 60; /* Middle C */ } } if (seq_mode == SEQ_2) { 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:; }}static voidseq_chn_common_event (unsigned char *event){ unsigned char dev = event[1]; unsigned char cmd = event[2]; unsigned char chn = event[3]; unsigned char p1 = event[4]; /* unsigned char p2 = event[5]; */ unsigned short w14 = *(short *) &event[6]; if ((int) dev > max_synthdev) 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 (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 (dev < num_synths) { int val = w14 & 0x7f; int i, key; if (p1 < 64) /* Combine MSB and LSB */ { val = ((synth_devs[dev]-> chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) | (synth_devs[dev]-> chn_info[chn].controllers[p1 | 32] & 0x7f); p1 &= ~32; } /* Handle all playing notes on this channel */ key = (chn << 8); for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) synth_devs[dev]->controller (dev, i, p1, val); } else synth_devs[dev]->controller (dev, chn, p1, w14); } else /* Mode 1 */ synth_devs[dev]->controller (dev, chn, p1, w14); break; case MIDI_PITCH_BEND: if (seq_mode == SEQ_2) { synth_devs[dev]->chn_info[chn].bender_value = w14; if (dev < num_synths) { /* Handle all playing notes on this channel */ int i, key; key = (chn << 8); for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) synth_devs[dev]->bender (dev, i, w14); } else synth_devs[dev]->bender (dev, chn, w14); } else /* MODE 1 */ synth_devs[dev]->bender (dev, chn, w14); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -