freebsd-dev/sys/i386/isa/sound/gustest/gmod.c
Jordan K. Hubbard 6b8afe4d37 This is the Linux generic soundcard driver, version 1.0c. Supports
SBlaster/Adlib/ProAudio Spectrum/Gravis/etc cards.  This is a BETA test
driver, please test it and get back to me!
1993-10-23 10:55:52 +00:00

1590 lines
33 KiB
C

/*
* gmod.c - Module player for GUS and Linux.
* (C) Hannu Savolainen, 1993
*
* NOTE! This program doesn't try to be a complete module player.
* It's just a too I used while developing the driver. In
* addition it can be used as an example on programming
* the LInux Sound Driver with GUS.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ultrasound.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <math.h>
#include <string.h>
#define CMD_ARPEG 0x00
#define CMD_SLIDEUP 0x01
#define CMD_SLIDEDOWN 0x02
#define CMD_SLIDETO 0x03
#define SLIDE_SIZE 8
#define CMD_VOLSLIDE 0x0a
#define CMD_JUMP 0x0b
#define CMD_VOLUME 0x0c
#define CMD_BREAK 0x0d
#define CMD_SPEED 0x0f
#define CMD_NOP 0xfe
#define CMD_NONOTE 0xff
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX_TRACK 8
#define MAX_PATTERN 128
#define MAX_POSITION 128
struct note_info
{
unsigned char note;
unsigned char vol;
unsigned char sample;
unsigned char command;
short parm1, parm2;
};
struct voice_info
{
int sample;
int note;
int volume;
int pitchbender;
/* Pitch sliding */
int slide_pitch;
int slide_goal;
int slide_rate;
int volslide;
};
typedef struct note_info pattern[MAX_TRACK][64];
int pattern_len[MAX_POSITION];
int pattern_tempo[MAX_POSITION];
pattern *pattern_table[MAX_PATTERN];
struct voice_info voices[MAX_TRACK];
int nr_channels, nr_patterns, songlength;
int tune[MAX_POSITION];
double tick_duration;
int period_table[] =
{
856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113
};
SEQ_DEFINEBUF (2048);
int seqfd;
int sample_ok[128], sample_vol[128];
int tmp, gus_dev;
double this_time, next_time;
int ticks_per_division;
double clock_rate; /* HZ */
/*
* The function seqbuf_dump() must always be provided
*/
void play_module (char *name);
int load_module (char *name);
int play_note (int channel, struct note_info *pat);
void lets_play_voice (int channel, struct voice_info *v);
void
seqbuf_dump ()
{
if (_seqbufptr)
if (write (seqfd, _seqbuf, _seqbufptr) == -1)
{
perror ("write /dev/sequencer");
exit (-1);
}
_seqbufptr = 0;
}
void
init_voices ()
{
int i;
for (i = 0; i < MAX_TRACK; i++)
{
voices[i].sample = 0;
voices[i].note = 0;
voices[i].volume = 64;
voices[i].slide_pitch = 0;
voices[i].slide_goal = 0;
voices[i].slide_rate = 0;
voices[i].pitchbender = 0;
voices[i].volslide = 0;
}
}
int
main (int argc, char *argv[])
{
int i, n, j;
struct synth_info info;
if ((seqfd = open ("/dev/sequencer", O_WRONLY, 0)) == -1)
{
perror ("/dev/sequencer");
exit (-1);
}
if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
{
perror ("/dev/sequencer");
exit (-1);
}
for (i = 0; i < n; i++)
{
info.device = i;
if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
{
perror ("/dev/sequencer");
exit (-1);
}
if (info.synth_type == SYNTH_TYPE_SAMPLE
&& info.synth_subtype == SAMPLE_TYPE_GUS)
gus_dev = i;
}
if (gus_dev == -1)
{
fprintf (stderr, "Gravis Ultrasound not detected\n");
exit (-1);
}
GUS_NUMVOICES (gus_dev, 14);
for (i = 1; i < argc; i++)
{
for (j = 0; j < MAX_PATTERN; j++)
pattern_table[j] = NULL;
if (load_module (argv[i]))
{
tick_duration = 100.0 / clock_rate;
play_module (argv[i]);
}
}
SEQ_DUMPBUF ();
close (seqfd);
exit (0);
}
unsigned short
intelize (unsigned short v)
{
return ((v & 0xff) << 8) | ((v >> 8) & 0xff);
}
unsigned long
intelize4 (unsigned long v)
{
return
(((v >> 16) & 0xff) << 8) | (((v >> 16) >> 8) & 0xff) |
(((v & 0xff) << 8) | ((v >> 8) & 0xff) << 16);
}
int
load_stm_module (int mod_fd, char *name)
{
struct sample_header
{
char name[12];
unsigned char instr_disk;
unsigned short reserved1;
unsigned short length; /* In bytes */
unsigned short loop_start;
unsigned short loop_end;
unsigned char volume;
unsigned char reserved2;
unsigned short C2_speed;
unsigned short reserved3;
};
int i, total_mem;
int sample_ptr;
int position;
unsigned char *tune_ptr; /* array 0-127 */
char header[1105], sname[21];
int nr_samples; /* 16 or 32 samples (or 64 or ???) */
int slen, npat;
fprintf (stderr, "Loading .STM module: %s\n", name);
if (read (mod_fd, header, sizeof (header)) != sizeof (header))
{
fprintf (stderr, "%s: Short file (header)\n", name);
close (mod_fd);
return 0;
}
strncpy (sname, header, 20);
fprintf (stderr, "\nModule: %s - ", sname);
if (header[28] != 0x1a)
{
fprintf (stderr, "Not a STM module\n");
close (mod_fd);
return 0;
}
npat = header[33];
slen = 0;
tune_ptr = &header[48 + (31 * 32)];
for (i = 0; i < 64; i++)
{
tune[i] = tune_ptr[i];
if (tune[i] < npat)
slen = i;
}
fprintf (stderr, "Song lenght %d, %d patterns.\n", slen, npat);
nr_samples = 31;
sample_ptr = 48 + (31 * 32) + 64 + (npat * 1024); /* Location where the
* first sample is
* stored */
total_mem = 0;
for (i = 0; i < 32; i++)
sample_ok[i] = 0;
for (i = 0; i < nr_samples; i++)
{
int len, loop_start, loop_end, base_freq;
unsigned short loop_flags = 0;
struct sample_header *sample;
struct patch_info *patch;
sample = (struct sample_header *) &header[48 + (i * 32)];
len = sample->length;
loop_start = sample->loop_start;
loop_end = sample->loop_end;
base_freq = sample->C2_speed;
if (strlen (sample->name) > 21)
{
fprintf (stderr, "\nInvalid name for sample #%d\n", i);
close (mod_fd);
return 0;
}
if (len > 0)
{
int x;
if (loop_end > len)
loop_end = 1;
else if (loop_end < loop_start)
{
loop_start = 0;
loop_end = 0;
}
else
loop_flags = WAVE_LOOPING;
total_mem += len;
patch = (struct patch_info *) malloc (sizeof (*patch) + len);
patch->key = GUS_PATCH;
patch->device_no = gus_dev;
patch->instr_no = i;
patch->mode = loop_flags;
patch->len = len;
patch->loop_start = loop_start;
patch->loop_end = loop_end;
patch->base_freq = base_freq;
patch->base_note = 261630; /* Mid C */
patch->low_note = 0;
patch->high_note = 0x7fffffff;
patch->volume = 120;
if (lseek (mod_fd, sample_ptr, 0) == -1)
{
perror (name);
close (mod_fd);
free (patch);
return 0;
}
sample_ptr += len;
if ((x = read (mod_fd, patch->data, len)) != len)
{
fprintf (stderr, "Short file (sample at %d (%d!=%d)\n", sample_ptr, x, len);
close (mod_fd);
free (patch);
return 0;
}
fprintf (stderr, "Sample %02d: %05d, %05d, %05d, %07d %s\n",
i,
len,
loop_start,
loop_end,
base_freq,
sample->name);
if (write (seqfd, patch, sizeof (*patch) + len) == -1)
{
perror ("ioctl /dev/sequencer");
exit (-1);
}
else
sample_ok[i] = 1;
free (patch);
}
}
nr_patterns = slen;
songlength = slen;
nr_channels = 4;
for (position = 0; position < npat; position++)
{
unsigned char patterns[64][4][4];
int pat, channel, x;
int pp = 1104 + (position * 1024);
if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
{
fprintf (stderr, "Can't allocate memory for a pattern\n");
return 0;
}
if (lseek (mod_fd, pp, 0) == -1)
{
perror (name);
close (mod_fd);
return 0;
}
if ((x = read (mod_fd, patterns, 1024)) != 1024)
{
fprintf (stderr, "Short file (pattern at %d), %d!=%d\n", pp, x, 1024);
close (mod_fd);
return 0;
}
for (pat = 0; pat < 64; pat++)
{
for (channel = 0; channel < 4; channel++)
{
unsigned char *p;
unsigned vol, note, octave, sample, effect, params;
p = &patterns[pat][channel][0];
if (p[0] < 251)
{
note = p[0] & 15;
octave = p[0] / 16;
note = 48 + octave * 12 + note;
sample = p[1] / 8;
vol = (p[1] & 7) + (p[2] / 2);
effect = p[2] & 0xF;
params = p[3];
}
else
{
note = 0;
octave = 0;
sample = 0;
vol = 0;
effect = CMD_NONOTE;
params = 0;
}
(*pattern_table[position])[channel][pat].note = note;
(*pattern_table[position])[channel][pat].sample = sample;
(*pattern_table[position])[channel][pat].command = effect;
(*pattern_table[position])[channel][pat].parm1 = params;
(*pattern_table[position])[channel][pat].parm2 = 0;
(*pattern_table[position])[channel][pat].vol = vol;
}
}
}
close (mod_fd);
return 1;
}
int
load_669_module (int mod_fd, char *name)
{
struct sample_header
{
char name[13];
unsigned long length; /* In bytes */
unsigned long loop_start;
unsigned long loop_end;
};
int i, total_mem;
int sample_ptr;
int position;
unsigned char *tune_ptr, *len_ptr, *tempo_ptr; /* array 0-127 */
char header[1084];
char msg[110];
int nr_samples; /* 16 or 32 samples */
int slen, npat;
clock_rate = 25.0;
fprintf (stderr, "Loading .669 module: %s\n", name);
if (read (mod_fd, header, sizeof (header)) != sizeof (header))
{
fprintf (stderr, "%s: Short file (header)\n", name);
close (mod_fd);
return 0;
}
if (*(unsigned short *) &header[0] != 0x6669)
{
fprintf (stderr, "Not a 669 file\n");
close (mod_fd);
return 0;
}
strncpy (msg, &header[2], 108);
for (i = 0; i < strlen (msg); i++)
if ((msg[i] >= ' ' && msg[i] <= 'z') || msg[i] == '\n')
printf ("%c", msg[i]);
printf ("\n");
npat = header[0x6f];
tune_ptr = &header[0x71];
for (slen = 0; slen < 128 && tune_ptr[slen] != 0xff; slen++);
slen--;
for (i = 0; i < slen; i++)
tune[i] = tune_ptr[i];
len_ptr = &header[0x171];
for (i = 0; i < slen; i++)
pattern_len[i] = len_ptr[i] - 1;
tempo_ptr = &header[0xf1];
for (i = 0; i < slen; i++)
pattern_tempo[i] = tempo_ptr[i];
nr_samples = header[0x6e];
fprintf (stderr, "Song lenght %d, %d patterns, %d samples.\n", slen, npat, nr_samples);
sample_ptr = 0x1f1 + (nr_samples * 0x19) + (npat * 0x600); /* Location where the
* first sample is
* stored */
total_mem = 0;
for (i = 0; i < 64; i++)
sample_ok[i] = 0;
for (i = 0; i < nr_samples; i++)
{
int len, loop_start, loop_end;
unsigned short loop_flags = 0;
struct sample_header *sample;
char sname[14];
struct patch_info *patch;
sample = (struct sample_header *) &header[0x1f1 + (i * 0x19)];
len = *(unsigned long *) &sample->name[13];
loop_start = *(unsigned long *) &sample->name[17];
loop_end = *(unsigned long *) &sample->name[21];
if (loop_end > len)
loop_end = 1;
else if (loop_end == len)
loop_end--;
if (loop_end < loop_start)
{
loop_start = 0;
loop_end = 0;
}
strncpy (sname, sample->name, 13);
if (len > 0 && len < 200000)
{
total_mem += len;
fprintf (stderr, "Sample %02d: %05d, %05d, %05d %s\n",
i,
len,
loop_start,
loop_end,
sname);
patch = (struct patch_info *) malloc (sizeof (*patch) + len);
if (loop_end == 0)
loop_end = 1;
if (loop_end >= len)
loop_end = 1;
if (loop_end > 1) loop_flags = WAVE_LOOPING;
patch->key = GUS_PATCH;
patch->device_no = gus_dev;
patch->instr_no = i;
patch->mode = WAVE_UNSIGNED | loop_flags;
patch->len = len;
patch->loop_start = loop_start;
patch->loop_end = loop_end;
patch->base_freq = 8448;
patch->base_note = 261630;
patch->low_note = 1000;
patch->high_note = 0x7fffffff;
patch->volume = 120;
if (lseek (mod_fd, sample_ptr, 0) == -1)
{
fprintf (stderr, "Seek failed\n");
perror (name);
close (mod_fd);
free (patch);
return 0;
}
sample_ptr += len;
if (read (mod_fd, patch->data, len) != len)
{
fprintf (stderr, "Short file (sample at %d)\n", sample_ptr);
close (mod_fd);
free (patch);
return 0;
}
if (write (seqfd, patch, sizeof (*patch) + len) == -1)
{
perror ("ioctl /dev/sequencer");
/* exit (-1); */
}
else
sample_ok[i] = 1;
free (patch);
}
}
nr_patterns = slen;
songlength = slen;
nr_channels = 8;
for (position = 0; position < npat; position++)
{
unsigned char patterns[0x600];
int pat, channel, x;
int pp = 0x1f1 + (nr_samples * 0x19) + (position * 0x600);
if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
{
fprintf (stderr, "Can't allocate memory for a pattern\n");
return 0;
}
if (lseek (mod_fd, pp, 0) == -1)
{
perror (name);
close (mod_fd);
return 0;
}
if ((x = read (mod_fd, patterns, 1024)) != 1024)
{
fprintf (stderr, "Short file (pattern at %d) %d!=1024\n", pp, x);
close (mod_fd);
return 0;
}
for (pat = 0; pat < 64; pat++)
{
for (channel = 0; channel < 8; channel++)
{
unsigned char *p;
unsigned vol, period, sample, effect, params;
p = &patterns[pat * 24 + channel * 3];
if (p[0] >= 0xfe ||
(p[0] == 0xff && p[1] == 0xff && p[2] == 0xff) ||
(p[0] == 0 && p[1] == 0 && p[2] == 0) ||
*(int *) p == -1)
{
period = 0;
effect = CMD_NONOTE;
sample = 0;
vol = 0;
params = 0;
if (p[0] == 0)
{
effect = CMD_BREAK;
params = -2;
}
}
else
{
period = (p[0] >> 2) + 48;
effect = (p[2] >> 4);
params = p[2] & 0x0f;
vol = p[1] & 0x0f;
if (p[2] == 0xfe)
{
effect = CMD_VOLUME;
params = vol;
}
else if (p[2] == 0xff)
{
effect = CMD_NOP;
}
else
switch (effect)
{
case 0: /* a - Portamento up */
effect = CMD_SLIDEUP;
break;
case 1: /* b - Portamento down */
effect = CMD_SLIDEDOWN;
break;
case 2: /* c - Port to note */
effect = CMD_SLIDETO;
break;
case 3: /* d - Frequency adjust */
effect = CMD_NOP; /* To be implemented */
break;
case 4: /* e - Frequency vibrato */
effect = CMD_NOP; /* To be implemented */
break;
case 5: /* f - Set tempo */
effect = CMD_SPEED;
break;
default:
effect = CMD_NOP;
}
sample = (((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)) + 1;
}
(*pattern_table[position])[channel][pat].note = period;
(*pattern_table[position])[channel][pat].sample = sample;
(*pattern_table[position])[channel][pat].command = effect;
(*pattern_table[position])[channel][pat].parm1 = params;
(*pattern_table[position])[channel][pat].parm2 = 0;
(*pattern_table[position])[channel][pat].vol = vol;
}
}
}
close (mod_fd);
return 1;
}
int
load_mmd0_module (int mod_fd, char *name)
{
struct sample_header
{
unsigned short loop_start;
unsigned short loop_end;
unsigned char midich;
unsigned char midipreset;
unsigned char volume;
unsigned char strans;
};
int i, total_mem;
int sample_ptr;
int position;
unsigned char *tune_ptr; /* array 0-127 */
char header[1105];
int nr_samples; /* 16 or 32 samples (or 64 or ???) */
int slen, npat;
fprintf (stderr, "Loading .MED module: %s\n", name);
if (read (mod_fd, header, sizeof (header)) != sizeof (header))
{
fprintf (stderr, "%s: Short file (header)\n", name);
close (mod_fd);
return 0;
}
if (strncmp (header, "MMD0", 4))
{
fprintf (stderr, "Not a MED module\n");
close (mod_fd);
return 0;
}
printf ("Module len %d\n", intelize4 (*(long *) &header[4]));
printf ("Song info %d\n", intelize4 (*(long *) &header[8]));
printf ("Song len %d\n", intelize4 (*(long *) &header[12]));
printf ("Blockarr %x\n", intelize4 (*(long *) &header[16]));
printf ("Blockarr len %d\n", intelize4 (*(long *) &header[20]));
printf ("Sample array %x\n", intelize4 (*(long *) &header[24]));
printf ("Sample array len %d\n", intelize4 (*(long *) &header[28]));
printf ("Exp data %x\n", intelize4 (*(long *) &header[32]));
printf ("Exp size %d\n", intelize4 (*(long *) &header[36]));
printf ("Pstate %d\n", intelize (*(long *) &header[40]));
printf ("Pblock %d\n", intelize (*(long *) &header[42]));
return 0;
npat = header[33];
slen = 0;
tune_ptr = &header[48 + (31 * 32)];
for (i = 0; i < 64; i++)
{
tune[i] = tune_ptr[i];
if (tune[i] < npat)
slen = i;
}
fprintf (stderr, "Song lenght %d, %d patterns.\n", slen, npat);
nr_samples = 31;
sample_ptr = 48 + (31 * 32) + 64 + (npat * 1024); /* Location where the
* first sample is
* stored */
total_mem = 0;
for (i = 0; i < 32; i++)
sample_ok[i] = 0;
for (i = 0; i < nr_samples; i++)
{
int len, loop_start, loop_end, base_freq;
unsigned short loop_flags = 0;
struct sample_header *sample;
struct patch_info *patch;
sample = (struct sample_header *) &header[48 + (i * 32)];
/*
* len = sample->length; loop_start = sample->loop_start; loop_end =
* sample->loop_end; base_freq = sample->C2_speed;
*
* if (strlen (sample->name) > 21) { fprintf (stderr, "\nInvalid name for
* sample #%d\n", i); close (mod_fd); return 0; }
*/
if (len > 0)
{
int x;
if (loop_end > len)
loop_end = 1;
if (loop_end < loop_start)
{
loop_start = 0;
loop_end = 0;
}
if (loop_end > 2) loop_flags = WAVE_LOOPING;
total_mem += len;
patch = (struct patch_info *) malloc (sizeof (*patch) + len);
patch->key = GUS_PATCH;
patch->device_no = gus_dev;
patch->instr_no = i;
patch->mode = loop_flags;
patch->len = len;
patch->loop_start = loop_start;
patch->loop_end = loop_end;
patch->base_freq = base_freq;
patch->base_note = 261630; /* Mid C */
patch->low_note = 0;
patch->high_note = 0x7fffffff;
patch->volume = 120;
if (lseek (mod_fd, sample_ptr, 0) == -1)
{
perror (name);
close (mod_fd);
free (patch);
return 0;
}
sample_ptr += len;
if ((x = read (mod_fd, patch->data, len)) != len)
{
fprintf (stderr, "Short file (sample at %d (%d!=%d)\n", sample_ptr, x, len);
close (mod_fd);
free (patch);
return 0;
}
/*
* fprintf (stderr, "Sample %02d: %05d, %05d, %05d, %07d %s\n", i,
* len, loop_start, loop_end, base_freq, sample->name);
*/
if (write (seqfd, patch, sizeof (*patch) + len) == -1)
{
perror ("ioctl /dev/sequencer");
exit (-1);
}
else
sample_ok[i] = 1;
free (patch);
}
}
nr_patterns = slen;
songlength = slen;
nr_channels = 4;
for (position = 0; position < npat; position++)
{
unsigned char patterns[64][4][4];
int pat, channel, x;
int pp = 1104 + (position * 1024);
if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
{
fprintf (stderr, "Can't allocate memory for a pattern\n");
return 0;
}
if (lseek (mod_fd, pp, 0) == -1)
{
perror (name);
close (mod_fd);
return 0;
}
if ((x = read (mod_fd, patterns, 1024)) != 1024)
{
fprintf (stderr, "Short file (pattern at %d), %d!=%d\n", pp, x, 1024);
close (mod_fd);
return 0;
}
for (pat = 0; pat < 64; pat++)
{
for (channel = 0; channel < 4; channel++)
{
unsigned char *p;
unsigned vol, note, octave, sample, effect, params;
p = &patterns[pat][channel][0];
if (p[0] < 251)
{
note = p[0] & 15;
octave = p[0] / 16;
note = 48 + octave * 12 + note;
sample = p[1] / 8;
vol = (p[1] & 7) + (p[2] / 2);
effect = p[2] & 0xF;
params = p[3];
}
else
{
note = 0;
octave = 0;
sample = 0;
vol = 0;
effect = CMD_NONOTE;
params = 0;
}
(*pattern_table[position])[channel][pat].note = note;
(*pattern_table[position])[channel][pat].sample = sample;
(*pattern_table[position])[channel][pat].command = effect;
(*pattern_table[position])[channel][pat].parm1 = params;
(*pattern_table[position])[channel][pat].parm2 = 0;
(*pattern_table[position])[channel][pat].vol = vol;
}
}
}
close (mod_fd);
return 1;
}
int
load_module (char *name)
{
struct sample_header
{
char name[22];
unsigned short length; /* In words */
unsigned char finetune;
unsigned char volume;
unsigned short repeat_point; /* In words */
unsigned short repeat_length; /* In words */
};
int i, mod_fd, total_mem;
int sample_ptr, pattern_loc;
int position;
unsigned char *tune_ptr; /* array 0-127 */
char header[1084];
int nr_samples; /* 16 or 32 samples */
int slen, npat;
char mname[23];
ioctl (seqfd, SNDCTL_SEQ_SYNC, 0);
ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev);
clock_rate = 50.0;
for (i = 0; i < MAX_POSITION; i++)
pattern_len[i] = 64;
for (i = 0; i < MAX_POSITION; i++)
pattern_tempo[i] = 0;
if ((mod_fd = open (name, O_RDONLY, 0)) == -1)
{
perror (name);
return 0;
}
if (read (mod_fd, header, sizeof (header)) != sizeof (header))
{
fprintf (stderr, "%s: Short file (header)\n", name);
close (mod_fd);
return 0;
}
if (lseek (mod_fd, 0, 0) == -1)
{
perror (name);
close (mod_fd);
return 0;
}
if (header[28] == 0x1a)
return load_stm_module (mod_fd, name);
if (*(unsigned short *) &header[0] == 0x6669)
return load_669_module (mod_fd, name);
if (!strncmp (header, "MMD0", 4))
return load_mmd0_module (mod_fd, name);
fprintf (stderr, "Loading .MOD module: %s\n", name);
strncpy (mname, header, 22);
fprintf (stderr, "\nModule: %s - ", mname);
if (!strncmp (&header[1080], "M.K.", 4) || !strncmp (&header[1080], "FLT8", 4))
{
fprintf (stderr, "31 samples\n");
nr_samples = 31;
}
else
{
fprintf (stderr, "15 samples\n");
nr_samples = 15;
}
if (nr_samples == 31)
{
sample_ptr = pattern_loc = 1084;
slen = header[950];
tune_ptr = (unsigned char *) &header[952];
}
else
{
sample_ptr = pattern_loc = 600;
slen = header[470];
tune_ptr = (unsigned char *) &header[472];
}
npat = 0;
for (i = 0; i < 128; i++)
{
tune[i] = tune_ptr[i];
if (tune_ptr[i] > npat)
npat = tune_ptr[i];
}
npat++;
fprintf (stderr, "Song lenght %d, %d patterns.\n", slen, npat);
sample_ptr += (npat * 1024); /* Location where the first sample is stored */
total_mem = 0;
for (i = 0; i < 32; i++)
sample_ok[i] = 0;
for (i = 0; i < nr_samples; i++)
{
int len, loop_start, loop_end;
unsigned short loop_flags = 0;
char pname[22];
struct sample_header *sample;
struct patch_info *patch;
sample = (struct sample_header *) &header[20 + (i * 30)];
len = intelize (sample->length) * 2;
loop_start = intelize (sample->repeat_point) * 2;
loop_end = loop_start + (intelize (sample->repeat_length) * 2);
if (loop_start > len)
loop_start = 0;
if (loop_end > len)
loop_end = len;
if (loop_end <= loop_start)
loop_end = loop_start + 1;
if (loop_end > 2 && loop_end > loop_start)
loop_flags = WAVE_LOOPING;
strncpy (pname, sample->name, 20);
if (len > 0)
{
fprintf (stderr, "Sample %02d: L%05d, S%05d, E%05d V%02d %s\n",
i,
len,
loop_start,
loop_end,
sample->volume,
pname);
total_mem += len;
patch = (struct patch_info *) malloc (sizeof (*patch) + len);
patch->key = GUS_PATCH;
patch->device_no = gus_dev;
patch->instr_no = i;
patch->mode = loop_flags;
patch->len = len;
patch->loop_start = loop_start;
patch->loop_end = loop_end;
patch->base_note = 261630; /* Middle C */
patch->base_freq = 8448;
patch->low_note = 0;
patch->high_note = 20000000;
patch->volume = 120;
patch->panning = 0;
if (lseek (mod_fd, sample_ptr, 0) == -1)
{
perror (name);
close (mod_fd);
free (patch);
return 0;
}
sample_ptr += len;
if (read (mod_fd, patch->data, len) != len)
{
fprintf (stderr, "Short file (sample) %d\n", sample_ptr);
close (mod_fd);
free (patch);
return 0;
}
SEQ_WRPATCH (patch, sizeof (*patch) + len);
sample_ok[i] = 1;
if (sample->volume == 0) sample->volume = 64;
sample_vol[i] = sample->volume;
free (patch);
}
}
nr_patterns = npat;
songlength = slen;
nr_channels = 4;
for (position = 0; position < npat; position++)
{
unsigned char patterns[64][4][4];
int pat, channel;
int pp = pattern_loc + (position * 1024);
if (lseek (mod_fd, pp, 0) == -1)
{
perror (name);
close (mod_fd);
return 0;
}
if (read (mod_fd, patterns, 1024) != 1024)
{
fprintf (stderr, "Short file (pattern %d) %d\n", tune[position], pp);
close (mod_fd);
return 0;
}
if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
{
fprintf (stderr, "Can't allocate memory for a pattern\n");
return 0;
}
for (pat = 0; pat < 64; pat++)
{
for (channel = 0; channel < 4; channel++)
{
unsigned short tmp;
unsigned char *p;
unsigned period, sample, effect, params, note, vol;
p = &patterns[pat][channel][0];
tmp = (p[0] << 8) | p[1];
sample = (tmp >> 8) & 0x10;
period =
MIN (tmp & 0xFFF, 1023);
tmp = (p[2] << 8) | p[3];
sample |= tmp >> 12;
effect = (tmp >> 8) & 0xF;
params = tmp & 0xFF;
note = 0;
if (period)
{
/*
* Convert period to a Midi note number
*/
for (note = 0; note < 37 && period != period_table[note]; note++);
if (note >= 37)
note = 0;
note += 48;
}
vol = 64;
if (sample)
if (effect == 0xc)
{
vol = params;
}
else
vol = sample_vol[sample - 1];
vol *= 2;
if (vol>64)vol--;
(*pattern_table[position])[channel][pat].note = note;
(*pattern_table[position])[channel][pat].sample = sample;
(*pattern_table[position])[channel][pat].command = effect;
(*pattern_table[position])[channel][pat].parm1 = params;
(*pattern_table[position])[channel][pat].parm2 = 0;
(*pattern_table[position])[channel][pat].vol = vol;
}
}
}
close (mod_fd);
return 1;
}
int
panning (int ch)
{
static int panning_tab[] =
{-110, 110, 110, -110};
return panning_tab[ch % 4];
}
void
set_speed (int parm)
{
if (!parm)
parm = 1;
if (parm < 32)
{
ticks_per_division = parm;
}
else
{
tick_duration = (60.0 / parm) * 10.0;
}
}
void
play_module (char *name)
{
int i, position, jump_to_pos;
init_voices ();
SEQ_START_TIMER ();
#if 1
for (i=0;i<32;i++)
{
SEQ_EXPRESSION(gus_dev, i, 127);
SEQ_MAIN_VOLUME(gus_dev, i, 100);
}
#endif
next_time = 0.0;
set_speed (6);
for (position = 0; position < songlength; position++)
{
int tick, pattern, channel, pos, go_to;
pos = tune[position];
if (pattern_tempo[position])
set_speed (pattern_tempo[position]);
jump_to_pos = -1;
for (pattern = 0; pattern < pattern_len[position] && jump_to_pos == -1; pattern++)
{
this_time = 0.0;
for (channel = 0; channel < nr_channels; channel++)
{
if ((go_to = play_note (channel, &(*pattern_table[pos])[channel][pattern])) != -1)
jump_to_pos = go_to;
}
next_time += tick_duration;
for (tick = 1; tick < ticks_per_division; tick++)
{
for (channel = 0; channel < nr_channels; channel++)
lets_play_voice (channel, &voices[channel]);
next_time += tick_duration;
}
}
if (jump_to_pos >= 0)
position = jump_to_pos;
}
SEQ_WAIT_TIME ((int) next_time + 200); /* Wait extra 2 secs */
for (i = 0; i < nr_channels; i++)
SEQ_STOP_NOTE (gus_dev, i, 0, 127);
SEQ_DUMPBUF ();
for (i = 0; i < nr_patterns; i++)
free (pattern_table[i]);
}
void
sync_time ()
{
if (next_time > this_time)
{
SEQ_WAIT_TIME ((long) next_time);
this_time = next_time;
}
}
void
set_volslide (int channel, struct note_info *pat)
{
int n;
voices[channel].volslide = 0;
if ((n = (pat->parm1 & 0xf0) >> 4))
voices[channel].volslide = n;
else
voices[channel].volslide = pat->parm1 & 0xf;
}
void
set_slideto (int channel, struct note_info *pat)
{
int size, rate, dir, range = 200;
rate = pat->parm1;
size = voices[channel].note - pat->note;
if (!size)
return;
if (size < 0)
{
size *= -1;
dir = -1;
}
else
dir = 1;
if (size > 2)
{
range = size * 100;
rate = rate * size / 200;
}
rate = pat->parm1 * dir / 30;
if (!rate)
rate = 1;
voices[channel].slide_pitch = 1;
voices[channel].slide_goal = (dir * 8192 * 200 * 2 / size) / range;
voices[channel].pitchbender = 0;
voices[channel].slide_rate = rate;
SEQ_BENDER_RANGE (gus_dev, channel, range);
}
int
play_note (int channel, struct note_info *pat)
{
int jump = -1;
int sample;
if (pat->sample == 0x3f)
pat->sample = 0;
if (pat->command == CMD_NONOTE)
return -1; /* Undefined */
sample = pat->sample;
if (sample && !pat->note)
{
pat->note = voices[channel].note;
}
if (sample)
voices[channel].sample = sample;
else
sample = voices[channel].sample;
sample--;
if (pat->note && pat->command != 3) /* Have a note -> play */
{
if (sample < 0)
sample = voices[channel].sample - 1;
if (!sample_ok[sample])
sample = voices[channel].sample - 1;
if (sample < 0)
sample = 0;
if (sample_ok[sample])
{
sync_time ();
if (pat->vol > 127) pat->vol=127;
SEQ_SET_PATCH (gus_dev, channel, sample);
SEQ_PANNING (gus_dev, channel, panning (channel));
SEQ_PITCHBEND (gus_dev, channel, 0);
SEQ_START_NOTE (gus_dev, channel, pat->note, pat->vol);
voices[channel].volume = pat->vol;
voices[channel].note = pat->note;
voices[channel].slide_pitch = 0;
}
else
SEQ_STOP_NOTE (gus_dev, channel, pat->note, pat->vol);
}
switch (pat->command)
{
case CMD_NOP:;
break;
case CMD_JUMP:
jump = pat->parm1;
break;
case CMD_BREAK:
jump = -2;
break;
case CMD_SPEED:
set_speed (pat->parm1);
break;
case CMD_SLIDEUP:
voices[channel].slide_pitch = 1;
voices[channel].slide_goal = 8191;
voices[channel].pitchbender = 0;
voices[channel].slide_rate = pat->parm1 * SLIDE_SIZE;
SEQ_BENDER_RANGE (gus_dev, channel, 200);
break;
case CMD_SLIDEDOWN:
voices[channel].slide_pitch = 1;
voices[channel].slide_goal = -8192;
voices[channel].pitchbender = 0;
voices[channel].slide_rate = -pat->parm1 * SLIDE_SIZE;
SEQ_BENDER_RANGE (gus_dev, channel, 200);
break;
case CMD_SLIDETO:
set_slideto (channel, pat);
break;
case CMD_VOLUME:
{
int vol = pat->parm1*2;
if (vol>127) vol=127;
if (pat->note && pat->command != 3)
break;
SEQ_START_NOTE (gus_dev, channel, 255, vol);
}
break;
case CMD_ARPEG:
break;
case 0x0e:
/* printf ("Cmd 0xE%02x\n", pat->parm1); */
break;
case CMD_VOLSLIDE:
set_slideto (channel, pat);
break;
default:
/* printf ("Command %x %02x\n", pat->command, pat->parm1); */
}
return jump;
}
void
lets_play_voice (int channel, struct voice_info *v)
{
if (v->slide_pitch)
{
v->pitchbender += v->slide_rate;
if (v->slide_goal < 0)
{
if (v->pitchbender <= v->slide_goal)
{
v->pitchbender = v->slide_goal;
v->slide_pitch = 0; /* Stop */
}
}
else
{
if (v->pitchbender >= v->slide_goal)
{
v->pitchbender = v->slide_goal;
v->slide_pitch = 0; /* Stop */
}
}
sync_time ();
SEQ_PITCHBEND (gus_dev, channel, v->pitchbender);
}
if (v->volslide)
{
v->volume += v->volslide;
sync_time ();
if (v->volume > 127) v->volume = 127;
SEQ_START_NOTE (gus_dev, channel, 255, v->volume);
}
}