📄 sequencer.c
字号:
/************************************************************************* * sequencer.c * * Copyright (C) 1995-1997 Michael Heasley (mheasley@hmc.edu) * * Portions Copyright (c) 1997 Takashi Iwai (iwai@dragon.mm.t.u-tokyo.ac.jp) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *************************************************************************/#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/soundcard.h>#include "musserver.h"struct synth_info sinfo[5];struct midi_info minfo[5];int seqfd;int mixfd;int use_dev = -1;int seq_dev = -1;int synth_patches[16];int chanvol[16];int volscale = 100;unsigned int voxdate;struct synth_voice *voices;struct opl_instr fm_instruments[175];struct sbi_instrument fm_sbi[175];extern int verbose;extern void cleanup(int status);extern void reset_midi();extern void read_genmidi(FILE *wadfile);struct opl_instr fm_instruments[175];struct sbi_instrument fm_sbi[175];SEQ_USE_EXTBUF();SEQ_DEFINEBUF(2048);void seqbuf_dump(void){ if (_seqbufptr) if (write(seqfd, _seqbuf, _seqbufptr) == -1) { perror("write /dev/sequencer"); cleanup(-1); } _seqbufptr = 0;}int find_midi(int m_type, int dev_num){int num_midi;int use_midi = -1;int m = 0; if (ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &num_midi) == -1) return 0; for (m = 0; m < num_midi; m++) { minfo[m].device = m; ioctl(seqfd, SNDCTL_MIDI_INFO, &minfo[m]); use_midi = m; if (minfo[m].dev_type == dev_num) break; } if (m_type == NO_SYNTH) return num_midi; else return use_midi;}int find_synth(int s_type, int dev_num){int num = 0;int fm = -1;#ifdef AWE32_SYNTH_SUPPORTint awe = -1;#endifint s = 0; if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &num) == -1) return 0; else for (s = 0; s < num; s++) { sinfo[s].device = s; ioctl(seqfd, SNDCTL_SYNTH_INFO, &sinfo[s]); if (sinfo[s].synth_type == SYNTH_TYPE_SAMPLE) {#ifdef AWE32_SYNTH_SUPPORT if (sinfo[s].synth_subtype == SAMPLE_TYPE_AWE32) { awe = s; if ((dev_num == SYNTH_TYPE_SAMPLE) && (s_type == AWE32_SYNTH)) break; }#endif } else { fm = s; if ((sinfo[s].synth_type == dev_num) && (s_type == FM_SYNTH)) break; } } switch(s_type) { case FM_SYNTH: return fm; break;#ifdef AWE32_SYNTH_SUPPORT case AWE32_SYNTH: return awe; break;#endif case NO_SYNTH: return num; break; default: return -1; break; }}#ifdef AWE32_SYNTH_SUPPORTvoid setup_awe(int num_awe){ use_dev = AWE32_SYNTH; seq_dev = num_awe; if (verbose) printf("Using synth device number %d (%s)\n", seq_dev+1, sinfo[seq_dev].name);}#endifvoid setup_midi(int num_midi){ use_dev = EXT_MIDI; seq_dev = num_midi; if (verbose) printf("Using midi device number %d (%s)\n", seq_dev+1, minfo[seq_dev].name);}void setup_fm(int num_fm){int x;int y;FILE *sndstat;char sndver[100];char snddate[100]; use_dev = FM_SYNTH; seq_dev = num_fm; sndstat = fopen("/dev/sndstat", "r"); if (sndstat == NULL) { printf("musserver: could not open /dev/sndstat, exiting.\n"); exit(1); } fgets(sndver, 100, sndstat); for (x = 0; x < strlen(sndver); x++) if (sndver[x] == '-') { x++; for (y = x; y < strlen(sndver); y++) if (sndver[y] != ' ') snddate[y-x] = sndver[y]; else { snddate[y-x] = 0; break; } break; } voxdate = atoi(snddate); fclose(sndstat); voices = malloc(sinfo[seq_dev].nr_voices * sizeof(struct synth_voice)); for (x = 0; x < sinfo[seq_dev].nr_voices; x++) { voices[x].note = -1; voices[x].channel = -1; } for (x = 0; x < 16; x++) synth_patches[x] = -1; mixfd = open("/dev/mixer", O_WRONLY, 0); if (verbose) printf("Using synth device number %d (%s)\n", seq_dev+1, sinfo[seq_dev].name);}void list_devs(){int dummy;int x; if ((seqfd = open("/dev/sequencer", O_WRONLY, 0)) < 0) { perror("open /dev/sequencer"); exit(1); } dummy = find_midi(NO_SYNTH, NO_SYNTH); for (x = 0; x < dummy; x++) printf("Found a midi device of type %d (%s)\n", minfo[x].dev_type, minfo[x].name); dummy = find_synth(NO_SYNTH, NO_SYNTH); for (x = 0; x < dummy; x++) printf("Found a synth device of type %d (%s)\n", sinfo[x].synth_type, sinfo[x].name); exit(0);}void seq_setup(int pref_dev, int dev_type){int num_midi;int num_awe;int num_fm; if ((seqfd = open("/dev/sequencer", O_WRONLY, 0)) < 0) { perror("open /dev/sequencer"); exit(1); } num_midi = find_midi(EXT_MIDI, dev_type); num_fm = find_synth(FM_SYNTH, dev_type); num_awe = find_synth(AWE32_SYNTH, dev_type); if ((num_midi == -1) && (num_fm == -1) && (num_awe == -1)) { printf("musserver: no music devices found, exiting.\n"); exit(1); } switch(pref_dev) { case EXT_MIDI: if (num_midi != -1) setup_midi(num_midi);#ifdef AWE32_SYNTH_SUPPORT else if (num_awe != -1) setup_awe(num_awe);#endif else if (num_fm != -1) setup_fm(num_fm); break; case FM_SYNTH: if (num_fm != -1) setup_fm(num_fm); else if (num_midi != -1) setup_midi(num_midi);#ifdef AWE32_SYNTH_SUPPORT else if (num_awe != -1) setup_awe(num_awe);#endif break;#ifdef AWE32_SYNTH_SUPPORT case AWE32_SYNTH: if (num_awe != -1) setup_awe(num_awe); else if (num_midi != -1) setup_midi(num_midi); else if (num_fm != -1) setup_fm(num_fm); break;#endif default: break; } reset_midi();}void cleanup_midi(void){ reset_midi(); close(seqfd); if (use_dev == FM_SYNTH) close(mixfd);}void reset_midi(void){unsigned int channel;#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { AWE_SET_CHANNEL_MODE(seq_dev, 1); AWE_NOTEOFF_ALL(seq_dev); for (channel = 0; channel < 16; channel++) { SEQ_BENDER_RANGE(seq_dev, channel, 200); SEQ_BENDER(seq_dev, channel, 0); } } else#endif if (use_dev == EXT_MIDI) for (channel = 0; channel < 16; channel++) { /* all notes off */ SEQ_MIDIOUT(seq_dev, MIDI_CTL_CHANGE + channel); SEQ_MIDIOUT(seq_dev, 0x7b); SEQ_MIDIOUT(seq_dev, 0); /* reset pitch bender */ SEQ_MIDIOUT(seq_dev, MIDI_PITCH_BEND + channel); SEQ_MIDIOUT(seq_dev, 64 >> 7); SEQ_MIDIOUT(seq_dev, 64 & 127); /* reset volume to 100 */ SEQ_MIDIOUT(seq_dev, MIDI_CTL_CHANGE + channel); SEQ_MIDIOUT(seq_dev, CTL_MAIN_VOLUME); SEQ_MIDIOUT(seq_dev, volscale); chanvol[channel] = 100; /* reset pan */ SEQ_MIDIOUT(seq_dev, MIDI_CTL_CHANGE + channel); SEQ_MIDIOUT(seq_dev, CTL_PAN); SEQ_MIDIOUT(seq_dev, 64); } else for (channel = 0; channel < sinfo[seq_dev].nr_voices; channel++) { SEQ_STOP_NOTE(seq_dev, channel, voices[channel].note, 64); SEQ_BENDER_RANGE(seq_dev, channel, 200); voices[channel].note = -1; voices[channel].channel = -1; } SEQ_DUMPBUF();}void note_off(int note, int channel, int volume){int x = 0;#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { SEQ_STOP_NOTE(seq_dev, channel, note, volume); } else#endif if (use_dev == EXT_MIDI) { SEQ_MIDIOUT(seq_dev, MIDI_NOTEOFF + channel); SEQ_MIDIOUT(seq_dev, note); SEQ_MIDIOUT(seq_dev, volume); } else { for (x = 0; x < sinfo[seq_dev].nr_voices; x++) if ((voices[x].note == note) && (voices[x].channel == channel)) break; if (x != sinfo[seq_dev].nr_voices) { voices[x].note = -1; voices[x].channel = -1; SEQ_STOP_NOTE(seq_dev, x, note, volume); } } SEQ_DUMPBUF();}void note_on(int note, int channel, int volume){int x = 0;#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { SEQ_START_NOTE(seq_dev, channel, note, volume); } else#endif if (use_dev == EXT_MIDI) { SEQ_MIDIOUT(seq_dev, MIDI_NOTEON + channel); SEQ_MIDIOUT(seq_dev, note); SEQ_MIDIOUT(seq_dev, volume); } else { for (x = 0; x < sinfo[seq_dev].nr_voices; x++) if ((voices[x].note == -1) && (voices[x].channel == -1)) break; if (x != sinfo[seq_dev].nr_voices) { voices[x].note = note; voices[x].channel = channel; if (channel == 9) /* drum note */ { if (use_dev == FM_SYNTH) { SEQ_SET_PATCH(seq_dev, x, note + 93); note = fm_instruments[note + 93].note; } else SEQ_SET_PATCH(seq_dev, x, note + 128); } else { SEQ_SET_PATCH(seq_dev, x, synth_patches[channel]); if ((voxdate != 950728) && (use_dev == FM_SYNTH)) note = note + 12; } SEQ_START_NOTE(seq_dev, x, note, volume); } } SEQ_DUMPBUF();}void pitch_bend(int channel, signed int value){int x;#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { SEQ_BENDER(seq_dev, channel, 128 * value); } else#endif if (use_dev == EXT_MIDI) { SEQ_MIDIOUT(seq_dev, MIDI_PITCH_BEND + channel); SEQ_MIDIOUT(seq_dev, value >> 7); SEQ_MIDIOUT(seq_dev, value & 127); } else { for (x = 0; x < sinfo[seq_dev].nr_voices; x++) if (voices[x].channel == channel) { SEQ_BENDER_RANGE(seq_dev, x, 200); SEQ_BENDER(seq_dev, x, 128*value); } } SEQ_DUMPBUF();}void control_change(int controller, int channel, int value){int x; if (controller == CTL_MAIN_VOLUME) { chanvol[channel] = value; value = value * volscale / 100; }#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { SEQ_CONTROL(seq_dev, channel, controller, value); } else#endif if (use_dev == EXT_MIDI) { SEQ_MIDIOUT(seq_dev, MIDI_CTL_CHANGE + channel); SEQ_MIDIOUT(seq_dev, controller); SEQ_MIDIOUT(seq_dev, value); } else { for (x = 0; x < sinfo[seq_dev].nr_voices; x++) if ((voices[x].channel == channel) && (controller == CTL_MAIN_VOLUME)) SEQ_MAIN_VOLUME(seq_dev, x, value); } SEQ_DUMPBUF();}void patch_change(int patch, int channel){int x;#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { SEQ_SET_PATCH(seq_dev, channel, patch); } else#endif if (use_dev == EXT_MIDI) { SEQ_MIDIOUT(seq_dev, MIDI_PGM_CHANGE + channel); SEQ_MIDIOUT(seq_dev, patch); } else { for (x = 0; x < sinfo[seq_dev].nr_voices; x++) if (((voices[x].channel == -1) && (voices[x].note == -1)) || (voices[x].channel == channel)) { synth_patches[channel] = patch; break; } } SEQ_DUMPBUF();}void midi_wait(float time){ ioctl(seqfd, SNDCTL_SEQ_SYNC); SEQ_WAIT_TIME((int) time); SEQ_DUMPBUF();}void midi_timer(int action){ switch (action) { case 0: SEQ_START_TIMER(); break; case 1: SEQ_STOP_TIMER(); break; case 2: SEQ_CONTINUE_TIMER(); break; }}void vol_change(int volume){int x; int logscale[32] = {0,15, 25,33, 40,45, 50,55, 59,62, 65,68, 70,73, 75,77, 79,81, 83,85, 87,89, 90,92, 93,94, 95,97, 98,99, 100,100}; volume = (volume < 0 ? 0 : (volume > 31 ? 31 : volume)); volscale = logscale[volume];#ifdef AWE32_SYNTH_SUPPORT if (use_dev == AWE32_SYNTH) { for (x = 0; x < 16; x++) SEQ_CONTROL(seq_dev, x, CTL_MAIN_VOLUME, chanvol[x] * volscale / 100); } else#endif if (use_dev == EXT_MIDI) { for (x = 0; x < 16; x++) { SEQ_MIDIOUT(seq_dev, MIDI_CTL_CHANGE + x); SEQ_MIDIOUT(seq_dev, CTL_MAIN_VOLUME); SEQ_MIDIOUT(seq_dev, chanvol[x] * volscale / 100); } } else { volume = volscale; volume |= (volume << 8); //if (-1 == ioctl(mixfd, SOUND_MIXER_WRITE_SYNTH, &volume)) // perror("volume change"); ioctl(mixfd, SOUND_MIXER_WRITE_SYNTH, &volume); ioctl(mixfd, SOUND_MIXER_WRITE_LINE2, &volume); } SEQ_DUMPBUF();}void fmload(void){int x; for (x = 0; x < 175; x++) { fm_sbi[x].key = FM_PATCH; fm_sbi[x].device = seq_dev; fm_sbi[x].channel = x; fm_sbi[x].operators[0] = fm_instruments[x].patchdata[0]; fm_sbi[x].operators[1] = fm_instruments[x].patchdata[7]; fm_sbi[x].operators[2] = fm_instruments[x].patchdata[4] + fm_instruments[x].patchdata[5]; fm_sbi[x].operators[3] = fm_instruments[x].patchdata[11] + fm_instruments[x].patchdata[12]; fm_sbi[x].operators[4] = fm_instruments[x].patchdata[1]; fm_sbi[x].operators[5] = fm_instruments[x].patchdata[8]; fm_sbi[x].operators[6] = fm_instruments[x].patchdata[2]; fm_sbi[x].operators[7] = fm_instruments[x].patchdata[9]; fm_sbi[x].operators[8] = fm_instruments[x].patchdata[3]; fm_sbi[x].operators[9] = fm_instruments[x].patchdata[10]; fm_sbi[x].operators[10] = fm_instruments[x].patchdata[6]; fm_sbi[x].operators[11] = fm_instruments[x].patchdata[16]; fm_sbi[x].operators[12] = fm_instruments[x].patchdata[23]; fm_sbi[x].operators[13] = fm_instruments[x].patchdata[20] + fm_instruments[x].patchdata[21]; fm_sbi[x].operators[14] = fm_instruments[x].patchdata[27] + fm_instruments[x].patchdata[28]; fm_sbi[x].operators[15] = fm_instruments[x].patchdata[17]; fm_sbi[x].operators[16] = fm_instruments[x].patchdata[24]; fm_sbi[x].operators[17] = fm_instruments[x].patchdata[18]; fm_sbi[x].operators[18] = fm_instruments[x].patchdata[25]; fm_sbi[x].operators[19] = fm_instruments[x].patchdata[19]; fm_sbi[x].operators[20] = fm_instruments[x].patchdata[26]; fm_sbi[x].operators[21] = fm_instruments[x].patchdata[22]; SEQ_WRPATCH(&fm_sbi[x], sizeof(fm_sbi[x])); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -