#include <sys/soundcard.h>
/* LRU list for free operators */
unsigned char free_list
[256];
int fhead
=0, ftail
=0, flen
=0;
/* LRU list for still playing notes */
unsigned char note_list
[256];
int nhead
=0, ntail
=0, nlen
=0;
unsigned char oper_note
[32];
int bender
= 0; /* Initially off */
if (write (seqfd
, _seqbuf
, _seqbufptr
) == -1)
perror ("write /dev/sequencer");
stop_note(int note
, int velocity
)
for (i
=0;i
<num_voices
&& op
==255;i
++)
if (oper_note
[i
]== note
) op
=i
;
fprintf(stderr
, "Note %d off, note not started\n", note
);
fprintf(stderr
, "%d, %d\n", flen
, nlen
);
return; /* Has already been killed ??? */
SEQ_STOP_NOTE(dev
, op
, note
, velocity
);
ftail
= (ftail
+1) % num_voices
;
if (note_list
[i
] == op
) note_list
[i
] = 255;
while (nlen
&& note_list
[nhead
] == 255)
/* printf("Remove from note queue %d, len %d\n", nhead, nlen); */
if (!nlen
) {fprintf(stderr
, "Free list empty but no notes playing\n");return;} /* No notes playing */
oldest
= note_list
[nhead
];
fprintf(stderr
, "Killing oper %d, note %d\n", oldest
, oper_note
[oldest
]);
if (oldest
== 255) return; /* Was already stopped. Why? */
stop_note(oper_note
[oldest
], 127);
start_note(int note
, int velocity
)
if (!flen
) kill_one_note();
if (!flen
) {printf("** no free voices\n");return;} /* Panic??? */
fhead
= (fhead
+1) % num_voices
;
fprintf(stderr
, "Note list overflow %d, %d, %d\n",
nlen
=0; /* Overflow -> hard reset */
SEQ_SET_PATCH(dev
, free
, pgm
);
SEQ_PITCHBEND(dev
, free
, bender
);
SEQ_START_NOTE(dev
, free
, note
, velocity
);
channel_pressure(int ch
, int pressure
)
for (i
=0;i
<num_voices
;i
++)
SEQ_CHN_PRESSURE(dev
, i
, pressure
);
SEQ_EXPRESSION(dev
, i
, pressure
);
pitch_bender(int ch
, int value
)
for (i
=0;i
<num_voices
;i
++)
SEQ_PITCHBEND(dev
, i
, value
);
/* printf("Note on %d %d %d\n", ch, buf[1], buf[2]); */
start_note(buf
[1], buf
[2]);
stop_note(buf
[1], buf
[2]);
case 0xb0: /* Control change */
/* printf("Control change %d %d %d\n", ch, buf[1], buf[2]); */
case 0x80: /* Note off */
/* printf("Note off %d %d %d\n", ch, buf[1], buf[2]); */
stop_note(buf
[1], buf
[2]);
case 0xe0: /* Pitch bender */
value
= ((buf
[2] & 0x7f) << 7) | (buf
[1] & 0x7f);
/* printf("Pitch bender %d %d\n", ch, value >> 7); */
case 0xc0: /* Pgm change */
/* printf("Pgm change %d %d\n", ch, buf[1]); */
if (PM_LOAD_PATCH(dev
, 0, pgm
) < 0)
if (errno
!= ESRCH
) /* No such process */
case 0xd0: /* Channel pressure */
/* printf("Channel pressure %d %d\n", ch, buf[1]); */
channel_pressure(ch
, buf
[1]);
main (int argc
, char *argv
[])
int i
, n
, max_voice
= 999;
if (argc
>= 2) dev
= atoi(argv
[1]);
for (i
=0;i
<16;i
++) oper_note
[i
] = 255;
if ((seqfd
= open ("/dev/sequencer", O_RDWR
, 0)) == -1)
perror ("open /dev/sequencer");
ioctl(seqfd
, SNDCTL_FM_4OP_ENABLE
, &d
);
if (ioctl(seqfd
, SNDCTL_SYNTH_INFO
, &info
)==-1)
perror ("info /dev/sequencer");
num_voices
= info
.nr_voices
;
if (num_voices
>max_voice
)num_voices
= max_voice
;
fprintf(stderr
, "Output to synth device %d (%s)\n", dev
, info
.name
);
fprintf(stderr
, "%d voices available\n", num_voices
);
for (i
=0;i
<num_voices
;i
++)
fhead
= (fhead
+1) % num_voices
;
if (PM_LOAD_PATCH(dev
, 0, 0) < 0) /* Load the default instrument */
if (errno
!= ESRCH
) /* No such process */
if ((n
= read (seqfd
, ev
, sizeof (ev
))) == -1)
perror ("read /dev/sequencer");
for (i
= 0; i
<= (n
/ 4); i
++)
if (p
[0] == SEQ_MIDIPUTC
&& p
[2] == 0 /* Midi if# == 0 */)
/* printf("%02x ", p[1]);fflush(stdout); */
if (p
[1] & 0x80) /* Status */
if ((buf
[0] & 0xf0) == 0x90 || (buf
[0] & 0xf0) == 0x80 || (buf
[0] & 0xf0) == 0xb0 ||
if ((buf
[0] & 0xf0) == 0xc0 || (buf
[0] & 0xf0) == 0xd0)