📄 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 "sound_config.h"#ifdef CONFIGURE_SOUNDCARD#ifndef EXCLUDE_SEQUENCERstatic int sequencer_ok = 0;DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */#define midi_sleeper seq_sleeper#define midi_sleep_flag seq_sleep_flagstatic int midi_opened[MAX_MIDI_DEV] ={0}; /* 1 if the process has opened MIDI */static int midi_written[MAX_MIDI_DEV] ={0};long seq_time = 0; /* Reference point for the timer */#include "tuning.h"#define EV_SZ 8#define IEV_SZ 4static unsigned char *queue = NULL; /* SEQ_MAX_QUEUE * EV_SZ bytes */static unsigned char *iqueue = NULL; /* SEQ_MAX_QUEUE * IEV_SZ bytes */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 unsigned synth_open_mask;static int seq_queue (unsigned char *note);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#endifintsequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){ int c = count, p = 0; dev = dev >> 4; if (dev) /* Patch manager device */ return pmgr_read (dev - 1, file, buf, count); while (c > 3) { if (!iqlen) { DO_SLEEP (midi_sleeper, midi_sleep_flag, 0); if (!iqlen) return count - c; } COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ); p += 4; c -= 4; iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; iqlen--; } return count - c;}static voidsequencer_midi_output (int dev){ /* Currently NOP */}static voidcopy_to_input (unsigned char *event){ unsigned long flags; if (iqlen >= (SEQ_MAX_QUEUE - 1)) return; /* Overflow */ memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; DISABLE_INTR (flags); if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag)) { WAKE_UP (midi_sleeper, midi_sleep_flag); } RESTORE_INTR (flags);}static voidsequencer_midi_input (int dev, unsigned char data){ int tstamp; unsigned char event[4]; if (data == 0xfe) /* Active sensing */ return; /* Ignore */ tstamp = GET_TIME () - seq_time; /* Time since open() */ tstamp = (tstamp << 8) | SEQ_WAIT; copy_to_input ((unsigned char *) &tstamp); event[0] = SEQ_MIDIPUTC; event[1] = data; event[2] = dev; event[3] = 0; copy_to_input (event);}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 >= num_synths) 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 == SEQ_EXTENDED || ev_code == SEQ_PRIVATE) { 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 ev_size = 4; if (event[0] == SEQ_MIDIPUTC) { if (!midi_opened[event[2]]) { int mode; int dev = event[2]; if (dev >= num_midis) { 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)) { if (!seq_playing) seq_startplay (); return count - c; } p += ev_size; c -= ev_size; } if (!seq_playing) seq_startplay (); return count;}static intseq_queue (unsigned char *note){ /* 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 (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 >= num_synths) 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[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; default: return RET_ERROR (EINVAL); } return 0;}static voidseq_startplay (void){ int this_one; unsigned long *delay; unsigned char *q; while (qlen > 0) { qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; qlen--; q = &queue[this_one*EV_SZ]; switch (q[0]) { case SEQ_NOTEOFF: if (synth_open_mask & (1 << 0)) if (synth_devs[0]) synth_devs[0]->kill_note (0, q[1], q[3]); break; case SEQ_NOTEON: if (q[4] < 128 || q[4] == 255) if (synth_open_mask & (1 << 0)) if (synth_devs[0]) synth_devs[0]->start_note (0, q[1], q[2], q[3]); break; case SEQ_WAIT: delay = (unsigned long *) q; /* Bytes 1 to 3 are containing the * delay in GET_TIME() */ *delay = (*delay >> 8) & 0xffffff; if (*delay > 0) { long time; seq_playing = 1; time = *delay; request_sound_timer (time); if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) { unsigned long flags; DISABLE_INTR (flags); if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); } return; /* Stop here. Timer routine will continue * playing after the delay */ } break; case SEQ_PGMCHANGE: if (synth_open_mask & (1 << 0)) if (synth_devs[0]) synth_devs[0]->set_instr (0, q[1], q[2]); break; case SEQ_SYNCTIMER: /* Reset timer */ seq_time = GET_TIME (); break; case SEQ_MIDIPUTC: /* Put a midi character */ if (midi_opened[q[2]]) { int dev; dev = q[2]; if (!midi_devs[dev]->putc (dev, q[1])) { /* * Output FIFO is full. Wait one timer cycle and try again. */ qlen++; qhead = this_one; /* Restore queue */ seq_playing = 1; request_sound_timer (-1); return; } else midi_written[dev] = 1; } break; case SEQ_ECHO: copy_to_input (q); /* Echo back to the process */ break; case SEQ_PRIVATE: if (q[1] < num_synths) synth_devs[q[1]]->hw_control (q[1], q); break; case SEQ_EXTENDED: extended_event (q); break; default:; } } seq_playing = 0; if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) { unsigned long flags; DISABLE_INTR (flags); if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); }}intsequencer_open (int dev, struct fileinfo *file) { int retval, mode, i; dev = dev >> 4; mode = file->mode & O_ACCMODE; DEB (printk ("sequencer_open(dev=%d)\n", dev)); if (!sequencer_ok) { printk ("Soundcard: Sequencer not initialized\n"); return RET_ERROR (ENXIO); } if (dev) /* Patch manager device */ { int err; dev--; if (pmgr_present[dev]) return RET_ERROR (EBUSY); if ((err = pmgr_open (dev)) < 0) return err; /* Failed */ pmgr_present[dev] = 1; return err; } if (sequencer_busy) { printk ("Sequencer busy\n"); return RET_ERROR (EBUSY); } if (!(num_synths + num_midis)) return RET_ERROR (ENXIO); synth_open_mask = 0; if (mode == OPEN_WRITE || mode == OPEN_READWRITE) for (i = 0; i < num_synths; i++) /* Open synth devices */ if (synth_devs[i]->open (i, mode) < 0) printk ("Sequencer: Warning! Cannot open synth device #%d\n", i); else synth_open_mask |= (1 << i); seq_time = GET_TIME (); for (i = 0; i < num_midis; i++) { midi_opened[i] = 0; midi_written[i] = 0; } if (mode == OPEN_READ || mode == OPEN_READWRITE) { /* Initialize midi input devices */ if (!num_midis) { printk ("Sequencer: No Midi devices. Input not possible\n"); return RET_ERROR (ENXIO); } for (i = 0; i < num_midis; i++) { if ((retval = midi_devs[i]->open (i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) midi_opened[i] = 1; } } sequencer_busy = 1; RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); output_treshold = SEQ_MAX_QUEUE / 2; for (i = 0; i < num_synths; i++) if (pmgr_present[i]) pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0); return 0; }voidseq_drain_midi_queues (void){ int i, n; /* * Give the Midi drivers time to drain their output queues */ n = 1; while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n) { n = 0; for (i = 0; i < num_midis; i++) if (midi_opened[i] && midi_written[i]) if (midi_devs[i]->buffer_status != NULL) if (midi_devs[i]->buffer_status (i)) n++; /* * Let's have a delay */ if (n) { DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -