home *** CD-ROM | disk | FTP | other *** search
- /* phase2.c -- this module plays notes compiled and sorted in phase1 or phasem */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <malloc.h>
- #include "cext.h"
- #include "adagio.h"
- #include "userio.h"
- #include "cmdline.h"
- #include "pitch.h"
- #include "midicode.h"
- #include "midi.h"
- #include "drum.h"
- #include <linux/soundcard.h>
- #include <fcntl.h>
-
- #define MAXTIME 10000000
-
- #ifndef XSELECT
- #define XSELECT 0
- #endif
- #ifndef PSELECT
- #define PSELECT 0x8200
- #endif
-
- extern boolean verbose;
-
- #define n_t_sw 2
- private char *t_switches[n_t_sw] = { "-t", "-trace" };
- #define n_m_sw 2
- private char *m_switches[n_m_sw] = { "-m", "-midi" };
- #define n_e_sw 2
- private char *e_switches[n_e_sw] = { "-e", "-external" };
- #define nmsw 2
- private char *msw[nmsw] = { "-i", "-init" };
- private boolean initflag = false;
- private boolean extflag = false;
- extern int percsel;
- extern boolean drum_mode;
- private boolean v_drum = true;
- private boolean use_damper = false;
-
- private long time = 0; /* time clock */
- private long lasttime = 0; /* time clock */
- private boolean readable = false;
-
- private int user_scale = false; /* true if user-defined scale */
- private int bend[num_voices]; /* current pitch bend on channel */
- private pitch_table pit_tab[128]; /* scale definition */
-
- private char sblast = true;
- /****************************************************************************
- * Routines local to this module
- ****************************************************************************/
- private void off_init();
- private void tuninginit();
- private void read_tuning();
- private boolean note_offs();
- private long next_off();
- private void off_schedule();
- private void f_note();
- private void f_touch();
- private void f_program();
- private void f_ctrl();
- private void f_bend();
- /*private void load_drums();*/
-
-
- static int sb;
- static unsigned char sbbuf[404];
- static int sbptr = 0;
- static int num_cells, perc_mode;
- struct synth_info fm_info;
-
- void midisync(void);
- void fm_program(int,int,int);
- void fm_noteon(int,int,int,int);
- void fm_noteoff(int,int,int);
-
- void sbflush(void)
- {
- if (!sbptr) return;
-
- if (write(sb, sbbuf, sbptr) == -1) {
- perror("write sb");
- exit(-1);
- }
-
- sbptr=0;
- }
-
- void sbwrite(char *msg)
- {
- if (sbptr>400) sbflush();
-
- memcpy(&sbbuf[sbptr], msg, 4);
- sbptr +=4;
- }
-
- void midich(char c)
- {
- char buf[4];
-
- buf[0] = 5;
- buf[1] = c;
- sbwrite(buf);
- }
-
-
- extern struct sub_type{
- char *vname;
- char solo;
- char newv;
- char transpose;
- } sub_voice[];
-
- #define EOX 0xf7
-
- extern int ext_program[];
- extern int ext_chan[];
- extern int ext_pan[];
- private int main_volume[16] = { 90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90 };
- private int expression[16] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
-
- #ifdef K1
- /* form of a multi patch on the Kawai K1 */
- struct patch_multi {
- char name[10];
- char volume;
- char single[8];
- char zonelow[8];
- char zonehigh[8];
- char poly[8];
- char rcvchan[8];
- char transpose[8];
- char tune[8];
- char level[8];
- char checksum;
- } patch = {
- 'M','i','s','c',' ',' ',' ',' ',' ',' ',
- 99,
- 0,1,2,3,4,5,6,7,
- 0,0,0,0,0,0,0,0,
- 127,127,127,127,127,127,127,127,
- 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 24,24,24,24,24,24,24,24,
- 50,50,50,50,50,50,50,50,
- 100,100,100,100,100,100,100,100,
- 0x74
- };
-
- /* send intro to K1 sysex command */
- void
- k1send1(function, voice)
- {
- midich(0xf0);
- midich(0x40); /* Kawai id */
- midich(0x00); /* channel = 0 to 15 */
- midich(function); /* function */
- midich(0x00); /* group */
- midich(0x03); /* machine id number of K1 */
- midich(0x00); /* subcommand 1 = internal */
- midich(voice); /* subcommand 2 = voice/program */
- }
-
- /* byte to K1 and update checksum */
- void
- mchk(c)
- int c;
- {
- midich(c);
- patch.checksum += c & 0x7f;
- }
-
- /* k1msone - send a single voice to the K1 */
- void
- k1msone(iv)
- int iv;
- {
- int n;
-
- k1send1(0x20, iv);
- patch.checksum = 0xa5;
-
- for (n = 0; n < 10; n++) mchk(patch.name[n]);
- mchk(patch.volume);
- for (n = 0; n < 8; n++) mchk(patch.single[n]);
- for (n = 0; n < 8; n++) mchk(patch.zonelow[n]);
- for (n = 0; n < 8; n++) mchk(patch.zonehigh[n]);
- for (n = 0; n < 8; n++) mchk(patch.poly[n]);
- for (n = 0; n < 8; n++) mchk(patch.rcvchan[n]);
- for (n = 0; n < 8; n++) mchk(patch.transpose[n]);
- for (n = 0; n < 8; n++) mchk(patch.tune[n]);
- for (n = 0; n < 8; n++) mchk(patch.level[n]);
- midich(patch.checksum & 0x7f);
- midich(EOX);
-
- }
- #endif
-
- /****************************************************************************
- * phase2
- * Inputs:
- * event_type root: Root of play list
- * Effect:
- * Plays the music
- ****************************************************************************/
-
- void phase2(score)
- event_type score;
- {
- event_type event = score; /* pointer to next note or control event */
- short done = false;
- long offtime = 0; /* time for next note off*/
- int i; /* index counter to initialize channels */
- int n;
-
-
- readable = (cl_nswitch(t_switches, n_t_sw) != NULL);
- sblast = (cl_nswitch(m_switches, n_m_sw) == NULL);
- if (!sblast) extflag = false;
- else extflag = (cl_nswitch(e_switches, n_e_sw) == NULL);
- if (extflag) sblast = true;
- if (readable) sblast = false;
- initflag = (cl_nswitch(msw, nmsw) == NULL);
- if (cl_switch("-s")) use_damper = true;
-
- off_init();
- tuninginit();
-
- if (sblast) {
- char buf[4];
- if ((sb=open("/dev/sequencer", O_WRONLY, 0))==-1) {
- perror("/dev/sequencer");
- exit(-1);
- }
- /*if (drum_mode) load_drums();*/
-
- if (drum_mode)
- if (ioctl(sb, SNDCTL_SEQ_PERCMODE, 1) == -1) {
- perror("/dev/sequencer");
- exit(-1);
- }
-
- if (ioctl(sb, SNDCTL_SYNTH_INFO, &fm_info) == -1) {
- perror("/dev/sequencer");
- exit(-1);
- }
-
- num_cells = fm_info.nr_voices;
- perc_mode = fm_info.perc_mode;
- /* and if card does not support drum mode, make sure not
- * to use any percussion channels
- */
- if (drum_mode && !perc_mode) percsel = 0;
-
- if (verbose) printf("Nr. SB voices %d, %s percussion mode.\n",
- num_cells, perc_mode? "using" : "no");
- }
-
- for (n = 0; n < num_voices; n++) {
- int v;
- if (!extflag) ext_chan[n] = 0;
- /* "ext_program" has the first program requested for each
- * channel, or else -1 or 0 if there was no program request
- * (0 if notes were played on the channel)
- */
- v = program[n] - 1;
- /* if notes were played but there was no program request, use
- * program 0, Ac. Gr. Piano, as default
- */
- if (v == -2 && program[n] == 0) v = 0;
- if (PERCCHAN(n)) {
- if (verbose) {
- printf(" channel %2d: SB percussion", n+1);
- if (program[n] > 0) printf(" (%s[%d] request ignored)",
- sub_voice[program[n]-1].vname, program[n]-1);
- printf(".\n");
- }
- }
- #ifdef K1
- /* which channels shall we send out to the K1? none if the -e flag
- * was given (extflag is 0), no more than the max (etot keeps track),
- * and not for a timbre the K1 doesn't have (marked -1 in the array in
- * vname.h)
- */
- else if (ext_chan[n]) {
- static char *pan[3] = { "right", "center", "left" };
- int etot = ext_chan[n] - 1;
- int leftright = 1;
- int solo = 0;
- if (ext_pan[n] != -1) {
- if (ext_pan[n] < 64) leftright = 2;
- else if (ext_pan[n] > 64) leftright = 0;
-
- }
- v = ext_program[etot] - 1;
- if (sub_voice[v].solo) solo = 2;
- patch.poly[etot] = (0x40&patch.poly[etot])
- | solo
- | (leftright << 4);
- /* use transposition marked in vname.h */
- patch.transpose[etot] = sub_voice[v].transpose + 24;
- /* finally, the voice/timbre for the section */
- patch.single[etot] = sub_voice[v].newv;
- if (verbose) {
- printf(" channel %2d: %s[%d] %s to K1 channel %d at %s.\n", n+1,
- sub_voice[v].vname, v, solo? "solo":"poly",
- etot+1, pan[leftright]);
- if (v != program[n]-1) printf(" (also %s[%d], etc. to SB)\n",
- sub_voice[program[n]-1].vname, program[n]-1);
- }
- }
- #else
- else if (ext_chan[n] && v >= 0) {
- if (verbose) printf(" channel %2d: %s[%d] external.\n", n+1,
- sub_voice[v].vname, v);
- }
- #endif
- else if (program[n] >= 0) {
- if (verbose) {
- printf(" channel %2d: is %s[%d] etc. on SB.\n", n+1,
- sub_voice[program[n]-1].vname, program[n]-1);
- }
- }
- }
- #ifdef K1
- if (extflag) {
- /* I have had a hell of a time getting the K1 to accept and use a patch;
- * the following uses up so much time waiting that the SB sequencer has
- * to be reset -- and it works only 9 times out of 10
- */
- char buf[4];
- k1msone(64);
- sbflush();
- sleep(2);
- midich(PROGRAM + 0);
- midich(64);
- sbflush();
- sleep(4);
- buf[0] = SEQ_SYNCTIMER;
- sbwrite(buf);
- sbflush();
- }
- #endif
-
-
- /* Initialize all midi channels with reasonable start values: */
- for (i = 1; i <= num_voices; i++) {
- int d = ext_chan[i-1];
- program[i-1] = ext_program[i-1];
- if (program[i-1] <= 0) ext_program[i-1] = program[i-1] = 1;
- bend[i-1] = 1 << 13;
- if (!initflag) continue;
- f_program(d, i, program[i-1]);
- f_bend(d, i, 1 << 13);
- f_touch(d, i, 0);
- f_ctrl(d, i, PORTARATE, 99);
- f_ctrl(d, i, PORTASWITCH, 0);
- f_ctrl(d, i, MODWHEEL, 0);
- f_ctrl(d, i, FOOT, 99);
- f_ctrl(d, i, VOLUME, 90);
- if (d) continue;
- f_program(0, i, program[i-1]);
- f_bend(0, i, 1 << 13);
- f_touch(0, i, 0);
- f_ctrl(0, i, PORTARATE, 99);
- f_ctrl(0, i, PORTASWITCH, 0);
- f_ctrl(0, i, MODWHEEL, 0);
- f_ctrl(0, i, FOOT, 99);
- f_ctrl(0, i, VOLUME, 90);
- }
-
- while (event != NULL) { /* play it, Sam */
- int d = event->ndest;
- if (!ext_chan[event->nvoice]) d = 0;
- time = event->ntime;
- note_offs(time);
-
- if (is_note(event)) { /* play a note */
- /* check for correct program (preset) */
- if (event->u.note.nprogram != program[event->nvoice]) {
- f_program(d, event->nvoice+1, event->u.note.nprogram);
- program[event->nvoice] = event->u.note.nprogram;
- }
- /* if it is a note (not a rest) play it */
- if (event->u.note.npitch != NO_PITCH) {
- f_note(d, event->nvoice+1, event->u.note.npitch,
- event->u.note.nloud);
- off_schedule(d, event->ntime + event->u.note.ndur,
- event->nvoice, event->u.note.npitch);
- }
- } else { /* send control info */
- switch (vc_ctrl(event->nvoice)) {
- case 1: f_ctrl(d, vc_voice(event->nvoice) + 1,
- PORTARATE,
- event->u.ctrl.value);
- break;
- case 2: f_ctrl(d, vc_voice(event->nvoice) + 1,
- PORTASWITCH,
- event->u.ctrl.value);
- break;
- case 3: f_ctrl(d, vc_voice(event->nvoice) + 1,
- MODWHEEL,
- event->u.ctrl.value);
- break;
- case 4: f_touch(d, vc_voice(event->nvoice) + 1,
- event->u.ctrl.value);
- break;
- case 5: if (use_damper) f_ctrl(d, vc_voice(event->nvoice) + 1,
- FOOT,
- event->u.ctrl.value);
- break;
- case 6: f_bend(d, vc_voice(event->nvoice) + 1,
- event->u.ctrl.value << 6);
- break;
- /* when d=0 should I also set volume external channel? */
- case 7: f_ctrl(d, vc_voice(event->nvoice) + 1,
- VOLUME,
- event->u.ctrl.value);
- main_volume[vc_voice(event->nvoice)] =
- event->u.ctrl.value;
- break;
- case 8: f_ctrl(d, vc_voice(event->nvoice) + 1,
- PAN,
- event->u.ctrl.value);
- break;
- case 9: f_ctrl(d, vc_voice(event->nvoice) + 1,
- EXPRESSION,
- event->u.ctrl.value);
- expression[vc_voice(event->nvoice)] =
- event->u.ctrl.value;
- break;
- /* pass through any other controls */
- case 15: f_ctrl(d, vc_voice(event->nvoice) + 1,
- event->u.ctrl.control,
- event->u.ctrl.value);
- break;
- default: break;
- }
- }
-
- event = event->next;
- } /* play it, Sam */
-
- note_offs(MAXTIME);
- if (sblast) sbflush();
- }
-
-
- /* noteoff.c -- this module keeps track of pending note offs for adagio */
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 31-Dec-85 | Created changelog
- * 31-Dec-85 | Add c:\ to include directives
- * 1-Jan-86 | Declare malloc char * for lint consistency
- * 21-Jan-86 | note_offs can now turn off more than one note per call
- *****************************************************************************/
-
-
- /* off_type is a structure containing note-off information */
-
- typedef struct off_struct {
- long when;
- int voice;
- int pitch;
- int dest;
- struct off_struct *next;
- } *off_type;
-
- private off_type free_off; /* free list of off_type structures */
- private off_type off_events = NULL; /* active list */
-
- /****************************************************************************
- * Routines declared in this module
- ****************************************************************************/
-
- private off_type off_alloc();
- private void off_free();
-
- /****************************************************************************
- * note_offs
- * Inputs:
- * long time: the current time
- * Outputs:
- * return true if off list has more notes
- * Effect: turn off notes if it is time
- * Assumes:
- * Implementation:
- * Find scheduled note off events in off_events, compare with time
- ****************************************************************************/
-
- private boolean note_offs(mtime)
- long mtime;
- {
- off_type temp;
- while (off_events != NULL && (time=off_events->when) <= mtime) {
- f_note(off_events->dest, (off_events->voice) + 1, off_events->pitch, 0);
- temp = off_events;
- off_events = off_events->next;
- off_free(temp);
- }
- if (mtime < MAXTIME) time = mtime;
- return (off_events != NULL);
- }
-
- /****************************************************************************
- * off_alloc
- * Outputs:
- * returns off_type: an allocated note off structure
- * Effect:
- * allocates a structure using malloc
- ****************************************************************************/
-
- private off_type off_alloc()
- {
- return (off_type) malloc(sizeof(struct off_struct));
- }
-
- /****************************************************************************
- * off_free
- * Inputs:
- * off_type off: a structure to deallocate
- * Effect:
- * returns off to freelist
- ****************************************************************************/
-
- private void off_free(off)
- off_type off;
- {
- off->next = free_off;
- free_off = off;
- }
-
- /****************************************************************************
- * off_init
- * Effect: initialize this module
- * Assumes:
- * only called once, otherwise storage is leaked
- ****************************************************************************/
-
- private void off_init()
- {
- int i;
- for (i = 0; i < 50; i++) off_free(off_alloc());
- }
-
- /****************************************************************************
- * off_schedule
- * Inputs:
- * long offtime: time to turn note off
- * int voice: the midi channel
- * int pitch: the pitch
- * Effect:
- * schedules a note to be turned off
- * Assumes:
- * note_offs will be called frequently to actually turn off notes
- ****************************************************************************/
-
- private void off_schedule(dest, offtime, voice, pitch)
- long offtime;
- int dest, voice, pitch;
- {
- off_type off, ptr, prv;
- /* allocate off */
- if ((off = free_off) == NULL) {
- off = off_alloc();
- } else free_off = off->next;
-
- if (off == NULL) {
- fprintf(stderr, "out of space for note off events");
- exit(1);
- }
-
- off->when = offtime;
- off->voice = voice;
- off->pitch = pitch;
- off->dest = dest;
- /* insert into list of off events */
- ptr = off_events;
- if (ptr == NULL || offtime <= ptr->when) {
- off->next = ptr;
- off_events = off;
- } else {
- while (ptr != NULL && offtime > ptr->when) {
- prv = ptr;
- ptr = ptr->next;
- }
- prv->next = off;
- off->next = ptr;
- }
- /*
- * printf("off_schedule(%ld, %d, %d): \n", offtime, voice, pitch);
- * for (ptr = off_events; ptr != NULL; ptr = ptr->next) {
- * printf(" %ld: %d, %d\n", ptr->when, ptr->voice, ptr->pitch);
- * }
- */
- }
-
- AWriteVarLen (value)
- register long value;
- {
- register long buffer;
-
- buffer = value & 0x7f;
- while ((value >>= 7) > 0)
- {
- buffer <<= 8;
- buffer |= 0x80;
- buffer += (value & 0x7f);
- }
-
- while (true)
- {
- putchar(buffer);
- if (buffer & 0x80)
- buffer >>= 8;
- else
- break;
- }
- }
-
- deltatime()
- {
- float csecs = (float)(time - lasttime);
-
- AWriteVarLen( (long)(((csecs * 10.0) / 4.0 * 96) / 120) );
- lasttime = time;
- }
-
- /****************************************************************************
- * f_note
- * Inputs:
- * int channel: midi channel on which to send data
- * int pitch: midi pitch code
- * int velocity: velocity with which to sound it (0=> release)
- * Effect:
- * Prints a midi note-play request out
- ****************************************************************************/
-
- private void f_note(d, channel, pitch, velocity)
- int d, channel, pitch, velocity;
- {
- if (readable)
- printf("Time=%d Note %s, chan=%d pitch=%d vol=%d\n",
- time, velocity? "on":"off", channel, pitch, velocity);
- else if (sblast) fm_noteon(d, channel-1, pitch+12, velocity);
- else {
- deltatime();
- putchar(NOTEON + channel - 1);
- putchar(pitch+12);
- putchar(velocity);
- }
-
- if (user_scale) {
- /* check for correct pitch bend */
- if ((pit_tab[pitch+12].pbend != bend[MIDI_CHANNEL(channel)]) &&
- (velocity != 0)) {
- f_bend(d, channel, pit_tab[pitch+12].pbend);
- bend[channel] = pit_tab[pitch+12].pbend;
- }
- pitch = pit_tab[pitch+12].ppitch;
- }
- }
-
- /****************************************************************************
- * f_bend
- * Inputs:
- * int channel: midi channel on which to send data
- * int value: pitch bend value
- * Effect:
- * Prints a midi pitch bend message
- ****************************************************************************/
-
- private void f_bend(d, channel, value)
- int d, channel, value;
- {
- if (readable)
- printf("Time=%d Pitchbend, chan=%d value=%d\n",
- time, channel, value);
- else if (sblast) {
- if (d) {
- midisync();
- midich(PITCHBEND + d - 1);
- midich(value & 0x7f);
- midich((value>>7) & 0x7f);
- }
- }
- else {
- deltatime();
- putchar(PITCHBEND + channel - 1);
- /* are these bytes in right order? */
- putchar(value & 0x7f);
- putchar((value>>7) & 0x7f);
- }
-
- bend[MIDI_CHANNEL(channel)] = value;
- }
-
- /****************************************************************************
- * f_ctrl
- * Inputs:
- * int channel: midi channel on which to send data
- * int control: control number
- * int value: control value
- * Effect:
- * Prints a midi control change message
- ****************************************************************************/
-
- private void f_ctrl(d, channel, control, value)
- int d, channel, control, value;
- {
- if (readable)
- printf("Time=%d Parameter, chan=%d ctrl=%d value=%d\n",
- time, channel, control, value);
- else if (sblast) {
- if (d) {
- #ifdef K1
- /* no expression controller for K1, so use volume */
- if (control == EXPRESSION) {
- float vol_factor = main_volume[channel-1]/127.0;
- control = VOLUME;
- value *= vol_factor;
- }
- #endif
- midisync();
- midich(CONTROLLER + d - 1);
- midich(control);
- midich(value);
- }
- }
- else {
- deltatime();
- putchar(CONTROLLER + channel - 1);
- putchar(control);
- putchar(value);
- }
- }
-
- /****************************************************************************
- * f_program
- * Inputs:
- * int channel: Channel on which to send midi program change request
- * int program: Program number to send (decremented by 1 before
- * being sent as midi data)
- * Effect:
- * Prints a program change request out the channel
- ****************************************************************************/
-
- private void f_program(d, channel, program)
- int d; /* destination */
- int channel; /* midi channel */
- int program; /* the program number */
- {
- if (readable)
- printf("Time=%d Program, chan=%d program=%d\n",
- time, channel, program);
- else if (sblast) fm_program(d, channel-1, program-1);
- else {
- deltatime();
- putchar(PROGRAM + channel - 1);
- putchar(program - 1);
- }
- }
-
- /****************************************************************************
- * f_touch
- * Inputs:
- * int channel: midi channel on which to send data
- * int value: control value
- * Effect:
- * Prints a midi after touch message
- ****************************************************************************/
-
- private void f_touch(d, channel, value)
- int d, channel, value;
- {
- if (readable)
- printf("Time=%d Channel pressure, chan=%d value=%d\n",
- time, channel, value);
- else if (sblast) {
- if (d) {
- midisync();
- midich(CHANPRESSURE + d - 1);
- midich(value);
- }
- }
- else {
- deltatime();
- putchar(CHANPRESSURE + channel - 1);
- putchar(value);
- }
- }
-
- /*****************************************************************
- * set_pitch_default
- *****************************************************************/
- private void set_pitch_default()
- {
- int i;
-
- for (i = 0; i < 128; i++) {
- pit_tab[i].pbend = 8192;
- pit_tab[i].ppitch = i;
- }
- }
-
- /*****************************************************************
- * read_tuning
- *****************************************************************/
-
- private void read_tuning(filename)
- char *filename;
- {
- int index, pit, lineno = 0;
- float bend;
- FILE *fpp;
-
- user_scale = true;
- set_pitch_default();
- fpp = fileopen(filename, "tun", "r", "Tuning definition file");
- while ((fscanf(fpp, "%d %d %f\n", &index, &pit, &bend) > 2) &&
- (lineno < 128)) {
- lineno++;
- if (index >= -12 && index <= 115) {
- pit_tab[index+12].pbend = (int)(8192 * bend/100 + 8192);
- pit_tab[index+12].ppitch = pit;
- }
- }
- }
-
-
- /****************************************************************************
- * tunginginit
- * Effect:
- * Read tuning file
- ****************************************************************************/
-
- private void tuninginit()
- {
- int i;
- char *filename;
-
- filename = cl_option("-tune");
- if (filename != NULL) {
- read_tuning(filename);
- }
- /*
- if (user_scale) {
- for (i = 0; i < num_voices; i++) {
- f_bend(0, i+1, 8192);
- bend[i] = 8192;
- }
- }
- */
-
- }
-
- /*
- * following code mostly stolen from:
- *
- * fmplay by Hannu Savolainen (hsavolai@cs.helsinki.fi)
- * Modifications, bugfixes, and ANSIfied by Rob Hooft (hooft@chem.ruu.nl)
- *
- */
- static int chn_pgm[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
- #define N_CELL (20)
- static int cell_next[N_CELL]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,0};
- static int cell_chan[N_CELL]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
- static int cell_pitch[N_CELL]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
- static int cell_restarted[N_CELL]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- static int cell_pointer=0;
- static int cell_circled=0;
-
- void fm_drumon(int drum, int vol)
- {
- char buf[4];
- if (!perc_mode) return;
-
- buf[0] = SEQ_DRUMON;
- buf[1] = 0;
- buf[2] = drum;
- buf[3] = vol;
- sbwrite(buf);
- }
-
- void fm_drumoff(int drum, int vol)
- {
- char buf[4];
-
- if (!perc_mode) return;
- buf[0] = SEQ_DRUMOFF;
- buf[1] = 0;
- buf[2] = drum;
- buf[3] = vol;
- sbwrite(buf);
- }
-
- void fm_noteon(int d, int chan,int pitch,int vol)
- {
- char buf[4];
- int cell, dv;
- midisync();
-
-
- if (d) {
- midich(NOTEON + d - 1);
- midich(pitch);
- midich(vol);
- return;
- }
-
- if (vol && main_volume[chan] >= 0) {
- float vol_factor = (float)main_volume[chan];
- if (expression[chan] >= 0) vol_factor *=
- ((float)expression[chan]/127.0);
- vol = vol * (vol_factor/127.0);
- }
-
- if (PERCCHAN(chan)) {
- if (drum_mode) {
- if (!vol) fm_drumoff(pitch, vol);
- else fm_drumon(pitch, vol);
- return;
- }
- else if (v_drum) {
- if (pitch >= 35 && pitch <= 81) {
- dv = d_voice[pitch - 35].dv;
- pitch = d_voice[pitch - 35].dnote;
- }
- else {
- dv = 130;
- pitch = 50;
- }
- }
- }
-
- if (!cell_circled) {
- cell_next[num_cells-1] = 0;
- cell_circled = 1;
- }
- if (!vol) {
- fm_noteoff(chan,pitch,vol);
- return;
- }
-
- /* first determine: is this note already running ? */
- cell=0;
- while (cell<num_cells && (cell_chan[cell]!=chn_pgm[chan] || cell_pitch[cell]!=pitch)) {
- ++cell;
- }
- if (cell<num_cells) {
- /* terminate identical running note first */
- fm_noteoff(chan,pitch,vol);
- /* And AFTER putting it to silence, mark it as
- restarted, such that it will not be stopped
- immediately. */
- cell_restarted[cell_pointer]=1;
- }
- /* now allocate the cell, and move the pointer */
- cell=cell_pointer;
- cell_pointer=cell_next[cell_pointer];
- cell_pitch[cell]=pitch;
- if (1) /*if (cell_chan[cell] != chn_pgm[chan])*/ {
- buf[0] = SEQ_FMPGMCHANGE;
- buf[1] = cell;
- if (v_drum && PERCCHAN(chan)) buf[2] = dv;
- else buf[2] = chn_pgm[chan];
- sbwrite(buf);
- cell_chan[cell]=chn_pgm[chan];
- }
- buf[0] = SEQ_FMNOTEON;
- buf[1] = cell;
- buf[2] = pitch;
- buf[3] = vol;
- sbwrite(buf);
- }
-
- void fm_noteoff(int chan,int pitch,int vol)
- {
- char buf[4];
- int cell,before,last;
- midisync();
-
-
- if (PERCCHAN(chan)) {
- fm_drumoff(pitch, vol);
- return;
- }
-
- cell=0;
- while (cell_chan[cell]!=chn_pgm[chan] || cell_pitch[cell]!=pitch) {
- if (++cell>=num_cells) {
- return;
- }
- }
- if (cell_restarted[cell]) {
- return;
- }
- buf[0] = SEQ_FMNOTEOFF;
- buf[1] = cell;
- buf[2] = pitch;
- buf[3] = vol;
- sbwrite(buf);
- if (cell!=cell_pointer) {
- before=0;
- while (cell_next[before]!=cell) {
- if (++before>=num_cells) {
- int nn;
- fprintf(stderr,"Can not happen 1\n");
- fprintf(stderr,"(cell %d, before %d, ptr %d) {",
- cell, before, cell_pointer);
- for (nn = 0; nn < num_cells; nn++)
- fprintf(stderr," %d",cell_next[nn]);
- fprintf(stderr," }\n");
- return;
- }
- }
- last=0;
- while (cell_next[last]!=cell_pointer) {
- if (++last>=num_cells) {
- fprintf(stderr,"Can not happen 2\n");
- return;
- }
- }
- if (last != cell) {
- cell_next[before]=cell_next[cell];
- cell_next[last]=cell;
- cell_next[cell]=cell_pointer;
- }
- cell_pointer=cell;
- cell_pitch[cell]=-1;
- }
- }
-
-
- void fm_program(int d, int chan,int program)
- {
- chn_pgm[chan] = program;
- #ifndef K1
- /* K1 can't remember channel programs */
- if (d) {
- midich(PROGRAM + d);
- midich(program);
- return;
- }
- #endif
- }
-
- void midisync(void)
- {
- unsigned jiffies;
-
- static int prevtime = 0;
- int i;
-
- jiffies = time;
- if (jiffies > prevtime)
- {
- prevtime = jiffies;
- jiffies = (jiffies << 8) | SEQ_WAIT;
- sbwrite((char*)&jiffies);
- for (i=0;i<num_cells;i++) cell_restarted[i]=0;
- }
- }
-
- /* if other programs use the SB voices > 127, maybe should use this to
- reload the percussion voices on startup ...
- void load_drums()
- { int f, n, v;
- struct sbi_instrument instr;
- char buf[52];
-
- if ((f = open("drums.sb", O_RDONLY, 0)) == -1) {
- fprintf(stderr,"can't find drums.sb file\n");
- exit(1);
- }
- for (v = 0; v < 16; v++) {
- if (read(f, buf, 52) != 52) {
- fprintf(stderr,"short library file\n");
- exit(1);
- }
- instr.channel = v + 128;
- for (n = 0x24; n < 52; n++) instr.operators[n - 0x24] = buf[n];
- if (ioctl(sb, SNDCTL_FM_LOAD_INSTR, &instr) == -1) {
- fprintf(stderr,"can't load instrument %d\n", v);
- exit(1);
- }
- }
- }
- */
-