Files
commandergenius/project/jni/sdl_mixer/native_midi_gpl/patchload.c

413 lines
9.7 KiB
C

/************************************************************************
patchload.c -- loads patches for playmidi package
Some of this code was adapted from code written by Hannu Solovainen
Copyright (C) 1994-1996 Nathan I. Laredo
This program is modifiable/redistributable under the terms
of the GNU General Public Licence.
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.
Send your comments and all your spare pocket change to
laredo@gnu.ai.mit.edu (Nathan Laredo) or to PSC 1, BOX 709, 2401
Kelly Drive, Lackland AFB, TX 78236-5128, USA.
*************************************************************************/
/* edited by Peter Kutak */
/* email : kutak@stonline.sk */
#if defined(linux) || defined(__FreeBSD__)
#include "playmidi.h"
#ifdef linux
#include <linux/ultrasound.h>
#else
#include <machine/ultrasound.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "gmvoices.h"
SEQ_USE_EXTBUF();
extern int play_gus, play_sb, play_ext, playing, verbose, force8bit;
extern int reverb, fmloaded[256], patchloaded[256];
extern int gus_dev, sb_dev, ext_dev, seqfd, wantopl3;
extern struct synth_info card_info[MAX_CARDS];
static int use8bit = 0;
struct pat_header {
char magic[12];
char version[10];
char description[60];
unsigned char instruments;
char voices;
char channels;
unsigned short nr_waveforms;
unsigned short master_volume;
unsigned int data_size;
};
struct sample_header {
char name[7];
unsigned char fractions;
int len;
int loop_start;
int loop_end;
unsigned short base_freq;
int low_note;
int high_note;
int base_note;
short detune;
unsigned char panning;
unsigned char envelope_rate[6];
unsigned char envelope_offset[6];
unsigned char tremolo_sweep;
unsigned char tremolo_rate;
unsigned char tremolo_depth;
unsigned char vibrato_sweep;
unsigned char vibrato_rate;
unsigned char vibrato_depth;
char modes;
short scale_frequency;
unsigned short scale_factor;
};
struct patch_info *patch;
int spaceleft, totalspace;
void gus_reload_8_bit();
void gus_load(pgm)
int pgm;
{
int i, j, patfd, offset;
struct pat_header header;
struct sample_header sample;
char buf[256], name[256];
struct stat info;
if (pgm < 0) {
use8bit = force8bit;
GUS_NUMVOICES(gus_dev, (card_info[gus_dev].nr_voices = 32));
SEQ_DUMPBUF();
for (i = 0; i < 256; i++)
patchloaded[i] = 0;
if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
{
/* error: should quit */
}
spaceleft = gus_dev;
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &spaceleft);
totalspace = spaceleft;
}
if (patchloaded[pgm] < 0)
return;
if (patchloaded[pgm] == 1)
return;
if (gmvoice[pgm] == NULL) {
patchloaded[pgm] = -1;
return;
}
sprintf(name, PATCH_PATH1 "/%s.pat", gmvoice[pgm]);
if (stat(name, &info) == -1) {
sprintf(name, PATCH_PATH2 "/%s.pat", gmvoice[pgm]);
if (stat(name, &info) == -1)
return;
}
if ((patfd = open(name, O_RDONLY, 0)) == -1)
return;
if (spaceleft < info.st_size) {
if (!use8bit)
gus_reload_8_bit();
if (use8bit)
if (spaceleft < info.st_size / 2) {
close(patfd);
patchloaded[pgm] = -1; /* no space for patch */
return;
}
}
if (read(patfd, buf, 0xef) != 0xef) {
close(patfd);
return;
}
memcpy((char *) &header, buf, sizeof(header));
if (strncmp(header.magic, "GF1PATCH110", 12)) {
close(patfd);
return;
}
if (strncmp(header.version, "ID#000002", 10)) {
close(patfd);
return;
}
header.nr_waveforms = *(unsigned short *) &buf[85];
header.master_volume = *(unsigned short *) &buf[87];
offset = 0xef;
for (i = 0; i < header.nr_waveforms; i++) {
if (lseek(patfd, offset, 0) == -1) {
close(patfd);
return;
}
if (read(patfd, &buf, sizeof(sample)) != sizeof(sample)) {
close(patfd);
return;
}
memcpy((char *) &sample, buf, sizeof(sample));
/*
* Since some fields of the patch record are not 32bit aligned, we must
* handle them specially.
*/
sample.low_note = *(int *) &buf[22];
sample.high_note = *(int *) &buf[26];
sample.base_note = *(int *) &buf[30];
sample.detune = *(short *) &buf[34];
sample.panning = (unsigned char) buf[36];
memcpy(sample.envelope_rate, &buf[37], 6);
memcpy(sample.envelope_offset, &buf[43], 6);
sample.tremolo_sweep = (unsigned char) buf[49];
sample.tremolo_rate = (unsigned char) buf[50];
sample.tremolo_depth = (unsigned char) buf[51];
sample.vibrato_sweep = (unsigned char) buf[52];
sample.vibrato_rate = (unsigned char) buf[53];
sample.vibrato_depth = (unsigned char) buf[54];
sample.modes = (unsigned char) buf[55];
sample.scale_frequency = *(short *) &buf[56];
sample.scale_factor = *(unsigned short *) &buf[58];
offset = offset + 96;
patch = (struct patch_info *) malloc(sizeof(*patch) + sample.len);
if (patch == NULL) {
close(patfd);
return;
}
patch->key = GUS_PATCH;
patch->device_no = gus_dev;
patch->instr_no = pgm;
patch->mode = sample.modes | WAVE_TREMOLO |
WAVE_VIBRATO | WAVE_SCALE;
patch->len = (use8bit ? sample.len / 2 : sample.len);
patch->loop_start =
(use8bit ? sample.loop_start / 2 : sample.loop_start);
patch->loop_end = (use8bit ? sample.loop_end / 2 : sample.loop_end);
patch->base_note = sample.base_note;
patch->high_note = sample.high_note;
patch->low_note = sample.low_note;
patch->base_freq = sample.base_freq;
patch->detuning = sample.detune;
patch->panning = (sample.panning - 7) * 16;
memcpy(patch->env_rate, sample.envelope_rate, 6);
for (j = 0; j < 6; j++) /* tone things down slightly */
patch->env_offset[j] =
(736 * sample.envelope_offset[j] + 384) / 768;
if (reverb)
if (pgm < 120)
patch->env_rate[3] = (2 << 6) | (12 - (reverb >> 4));
else if (pgm > 127)
patch->env_rate[1] = (3 << 6) | (63 - (reverb >> 1));
patch->tremolo_sweep = sample.tremolo_sweep;
patch->tremolo_rate = sample.tremolo_rate;
patch->tremolo_depth = sample.tremolo_depth;
patch->vibrato_sweep = sample.vibrato_sweep;
patch->vibrato_rate = sample.vibrato_rate;
patch->vibrato_depth = sample.vibrato_depth;
patch->scale_frequency = sample.scale_frequency;
patch->scale_factor = sample.scale_factor;
patch->volume = header.master_volume;
if (lseek(patfd, offset, 0) == -1) {
close(patfd);
return;
}
if (read(patfd, patch->data, sample.len) != sample.len) {
close(patfd);
return;
}
if (patch->mode & WAVE_16_BITS && use8bit) {
patch->mode &= ~WAVE_16_BITS;
/* cut out every other byte to make 8-bit data from 16-bit */
for (j = 0; j < patch->len; j++)
patch->data[j] = patch->data[1 + j * 2];
}
SEQ_WRPATCH(patch, sizeof(*patch) + patch->len);
free(patch);
offset = offset + sample.len;
}
close(patfd);
spaceleft = gus_dev;
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &spaceleft);
patchloaded[pgm] = 1;
return;
}
void gus_reload_8_bit()
{
int i;
if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
{
/* error: should quit */
}
spaceleft = gus_dev;
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &spaceleft);
totalspace = spaceleft;
use8bit = 1;
for (i = 0; i < 256; i++)
if (patchloaded[i] > 0) {
patchloaded[i] = 0;
gus_load(i);
}
}
void adjustfm(buf, key)
char *buf;
int key;
{
unsigned char pan = ((rand() % 3) + 1) << 4;
if (key == FM_PATCH) {
buf[39] &= 0xc0;
if (buf[46] & 1)
buf[38] &= 0xc0;
buf[46] = (buf[46] & 0xcf) | pan;
if (reverb) {
unsigned val;
val = buf[43] & 0x0f;
if (val > 0)
val--;
buf[43] = (buf[43] & 0xf0) | val;
}
} else {
int mode;
if (buf[46] & 1)
mode = 2;
else
mode = 0;
if (buf[57] & 1)
mode++;
buf[50] &= 0xc0;
if (mode == 3)
buf[49] &= 0xc0;
if (mode == 1)
buf[39] &= 0xc0;
if (mode == 2 || mode == 3)
buf[38] &= 0xc0;
buf[46] = (buf[46] & 0xcf) | pan;
buf[57] = (buf[57] & 0xcf) | pan;
if (mode == 1 && reverb) {
unsigned val;
val = buf[43] & 0x0f;
if (val > 0)
val--;
buf[43] = (buf[43] & 0xf0) | val;
val = buf[54] & 0x0f;
if (val > 0)
val--;
buf[54] = (buf[54] & 0xf0) | val;
}
}
}
void loadfm()
{
int sbfd, i, n, voice_size, data_size;
char buf[60];
struct sbi_instrument instr;
for (i = 0; i < 256; i++)
fmloaded[i] = 0;
srand(getpid());
if (wantopl3) {
voice_size = 60;
sbfd = open(O3MELODIC, O_RDONLY, 0);
} else {
voice_size = 52;
sbfd = open(SBMELODIC, O_RDONLY, 0);
}
if (sbfd == -1)
{
/* error: should quit */
}
instr.device = sb_dev;
for (i = 0; i < 128; i++) {
if (read(sbfd, buf, voice_size) != voice_size)
{
/* error: should quit */
}
instr.channel = i;
if (strncmp(buf, "4OP", 3) == 0) {
instr.key = OPL3_PATCH;
data_size = 22;
} else {
instr.key = FM_PATCH;
data_size = 11;
}
fmloaded[i] = instr.key;
adjustfm(buf, instr.key);
for (n = 0; n < 32; n++)
instr.operators[n] = (n < data_size) ? buf[36 + n] : 0;
SEQ_WRPATCH(&instr, sizeof(instr));
}
close(sbfd);
if (wantopl3)
sbfd = open(O3DRUMS, O_RDONLY, 0);
else
sbfd = open(SBDRUMS, O_RDONLY, 0);
for (i = 128; i < 175; i++) {
if (read(sbfd, buf, voice_size) != voice_size)
{
/* error: should quit */
}
instr.channel = i;
if (strncmp(buf, "4OP", 3) == 0) {
instr.key = OPL3_PATCH;
data_size = 22;
} else {
instr.key = FM_PATCH;
data_size = 11;
}
fmloaded[i] = instr.key;
adjustfm(buf, instr.key);
for (n = 0; n < 32; n++)
instr.operators[n] = (n < data_size) ? buf[n + 36] : 0;
SEQ_WRPATCH(&instr, sizeof(instr));
}
close(sbfd);
}
#endif /* linux || FreeBSD */