diff options
Diffstat (limited to 'engines/sci/sfx/seq')
-rw-r--r-- | engines/sci/sfx/seq/Makefile.am | 5 | ||||
-rw-r--r-- | engines/sci/sfx/seq/gm.c | 185 | ||||
-rw-r--r-- | engines/sci/sfx/seq/instrument-map.c | 539 | ||||
-rw-r--r-- | engines/sci/sfx/seq/instrument-map.h | 132 | ||||
-rw-r--r-- | engines/sci/sfx/seq/map-mt32-to-gm.c | 813 | ||||
-rw-r--r-- | engines/sci/sfx/seq/mt32.c | 480 | ||||
-rw-r--r-- | engines/sci/sfx/seq/oss-adlib.c | 374 | ||||
-rw-r--r-- | engines/sci/sfx/seq/sequencers.c | 68 |
8 files changed, 2596 insertions, 0 deletions
diff --git a/engines/sci/sfx/seq/Makefile.am b/engines/sci/sfx/seq/Makefile.am new file mode 100644 index 0000000000..74fb4fda3f --- /dev/null +++ b/engines/sci/sfx/seq/Makefile.am @@ -0,0 +1,5 @@ +noinst_LIBRARIES = libsciseq.a +INCLUDES = -I$(top_srcdir)/src/include @EXTRA_INCLUDES@ +EXTRA_DIST = instrument-map.h +libsciseq_a_SOURCES = sequencers.c oss-adlib.c mt32.c gm.c instrument-map.c \ + map-mt32-to-gm.c diff --git a/engines/sci/sfx/seq/gm.c b/engines/sci/sfx/seq/gm.c new file mode 100644 index 0000000000..4889e76ea8 --- /dev/null +++ b/engines/sci/sfx/seq/gm.c @@ -0,0 +1,185 @@ +/*************************************************************************** + Copyright (C) 2008 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantability, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <creichen@gmail.com> + +***************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include "../sequencer.h" +#include "../device.h" +#include "instrument-map.h" +#include <resource.h> + +static midi_writer_t *writer = NULL; + +static int +midi_gm_open(int patch_len, byte *data, int patch2_len, byte *data2, void *device) +{ + sfx_instrument_map_t *instrument_map = sfx_instrument_map_load_sci(data, patch_len); + + if (!instrument_map) { + fprintf(stderr, "[GM] No GM instrument map found, trying MT-32 instrument map..\n"); + instrument_map = sfx_instrument_map_mt32_to_gm(data2, patch2_len); + } + + writer = sfx_mapped_writer((midi_writer_t *) device, instrument_map); + + if (!writer) + return SFX_ERROR; + + if (writer->reset_timer) + writer->reset_timer(writer); + + return SFX_OK; +} + +static int +midi_gm_close(void) +{ + return SFX_OK; +} + +static int +midi_gm_event(byte command, int argc, byte *argv) +{ + byte data[4]; + + assert (argc < 4); + data[0] = command; + memcpy(data + 1, argv, argc); + + writer->write(writer, data, argc + 1); + + return SFX_OK; +} + +static int +midi_gm_delay(int ticks) +{ + writer->delay(writer, ticks); + + return SFX_OK; +} + +static int +midi_gm_reset_timer(GTimeVal ts) +{ + writer->reset_timer(writer); + + return SFX_OK; +} + +#define MIDI_MASTER_VOLUME_LEN 8 + +static int +midi_gm_volume(guint8 volume) +{ + byte data[MIDI_MASTER_VOLUME_LEN] = { + 0xf0, + 0x7f, + 0x7f, + 0x04, + 0x01, + volume, + volume, + 0xf7}; + + writer->write(writer, data, MIDI_MASTER_VOLUME_LEN); + if (writer->flush) + writer->flush(writer); + + return SFX_OK; +} + +static int +midi_gm_allstop(void) +{ + byte data[3] = { 0xb0, + 0x78, /* all sound off */ + 0 }; + int i; + + /* All sound off on all channels */ + for (i = 0; i < 16; i++) { + data[0] = 0xb0 | i; + writer->write(writer, data, 3); + } + if (writer->flush) + writer->flush(writer); + + return SFX_OK; +} + +static int +midi_gm_reverb(int reverb) +{ + byte data[3] = { 0xb0, + 91, /* set reverb */ + reverb }; + int i; + + /* Set reverb on all channels */ + for (i = 0; i < 16; i++) + if (i != 9) { + data[0] = 0xb0 | i; + writer->write(writer, data, 3); + } + if (writer->flush) + writer->flush(writer); + + return SFX_OK; +} + +static int +midi_gm_set_option(char *x, char *y) +{ + return SFX_ERROR; +} + +sfx_sequencer_t sfx_sequencer_gm = { + "General MIDI", + "0.1", + SFX_DEVICE_MIDI, + &midi_gm_set_option, + &midi_gm_open, + &midi_gm_close, + &midi_gm_event, + &midi_gm_delay, + &midi_gm_reset_timer, + &midi_gm_allstop, + &midi_gm_volume, + &midi_gm_reverb, + 004, /* patch.004 */ + 001, /* patch.001 */ + 0x01, /* playflag */ + 1, /* do play rhythm */ + 64, /* max polyphony */ + 0 /* no write-ahead needed inherently */ +}; diff --git a/engines/sci/sfx/seq/instrument-map.c b/engines/sci/sfx/seq/instrument-map.c new file mode 100644 index 0000000000..0d829a0582 --- /dev/null +++ b/engines/sci/sfx/seq/instrument-map.c @@ -0,0 +1,539 @@ +/*************************************************************************** + Copyright (C) 2008 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantability, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <creichen@gmail.com> + +***************************************************************************/ + +#include <assert.h> +#include "sci_midi.h" +#include "sci_memory.h" +#include "instrument-map.h" +#include "sfx_engine.h" + +sfx_instrument_map_t * +sfx_instrument_map_new(int velocity_maps_nr) +{ + sfx_instrument_map_t *map = (sfx_instrument_map_t *)sci_malloc(sizeof (sfx_instrument_map_t)); + int i; + + map->initialisation_block_size = 0; + map->initialisation_block = NULL; + + map->velocity_maps_nr = velocity_maps_nr; + map->percussion_velocity_map_index = SFX_NO_VELOCITY_MAP; + + if (velocity_maps_nr == 0) + map->velocity_map = NULL; /* Yes, this complicates control flow needlessly, but it avoids some of the pointless + ** warnings that certain memory tools seem to find appropriate. */ + else { + map->velocity_map = (byte **)sci_malloc(sizeof (byte *) * velocity_maps_nr); + for (i = 0; i < velocity_maps_nr; ++i) + map->velocity_map[i] = (byte *)sci_malloc(SFX_VELOCITIES_NR); + } + for (i = 0; i < SFX_INSTRUMENTS_NR; ++i) + map->velocity_map_index[i] = SFX_NO_VELOCITY_MAP; + + map->percussion_volume_adjust = 0; + for (i = 0; i < SFX_RHYTHM_NR; ++i) + map->percussion_map[i] = i; + + + for (i = 0; i < SFX_INSTRUMENTS_NR; ++i) { + map->patch_map[i].patch = i; + map->patch_key_shift[i] = 0; + map->patch_volume_adjust[i] = 0; + } + + return map; +} + +void +sfx_instrument_map_free(sfx_instrument_map_t *map) +{ + if (!map) + return; + + if (map->velocity_map) { + int i; + for (i = 0; i < map->velocity_maps_nr; i++) + sci_free(map->velocity_map[i]); + sci_free(map->velocity_map); + map->velocity_map = NULL; + } + + if (map->initialisation_block) { + sci_free(map->initialisation_block); + map->initialisation_block = NULL; + } + + sci_free(map); +} + +#define PATCH_MAP_OFFSET 0x0000 +#define PATCH_KEY_SHIFT_OFFSET 0x0080 +#define PATCH_VOLUME_ADJUST_OFFSET 0x0100 +#define PATCH_PERCUSSION_MAP_OFFSET 0x0180 +#define PATCH_PERCUSSION_VOLUME_ADJUST 0x0200 +#define PATCH_VELOCITY_MAP_INDEX 0x0201 +#define PATCH_VELOCITY_MAP(i) (0x0281 + (0x80 * i)) +#define PATCH_INIT_DATA_SIZE_LE 0x0481 +#define PATCH_INIT_DATA 0x0483 + +#define PATCH_INSTRUMENT_MAPS_NR 4 + +#define PATCH_MIN_SIZE PATCH_INIT_DATA + + +static int +patch001_type0_length(byte *data, size_t length) +{ + unsigned int pos = 492 + 246 * data[491]; + +/* printf("timbres %d (post = %04x)\n",data[491], pos);*/ + + if ((length >= (pos + 386)) && (data[pos] == 0xAB) && (data[pos + 1] == 0xCD)) + pos += 386; + +/* printf("pos = %04x (%02x %02x)\n", pos, data[pos], data[pos + 1]); */ + + if ((length >= (pos + 267)) && (data[pos] == 0xDC) && (data[pos + 1] == 0xBA)) + pos += 267; + +/* printf("pos = %04x %04x (%d)\n", pos, length, pos-length); */ + + + if (pos == length) + return 1; + return 0; +} + +static int +patch001_type1_length(byte *data, size_t length) +{ + if ((length >= 1155) && (((data[1154] << 8) + data[1153] + 1155) == length)) + return 1; + return 0; +} + +int +sfx_instrument_map_detect(byte *data, size_t length) +{ + /* length test */ + if (length < 1155) + return SFX_MAP_MT32; + if (length > 16889) + return SFX_MAP_MT32_GM; + if (patch001_type0_length(data, length) && + !patch001_type1_length(data, length)) + return SFX_MAP_MT32; + if (patch001_type1_length(data, length) && + !patch001_type0_length(data, length)) + return SFX_MAP_MT32_GM; + return SFX_MAP_UNKNOWN; +} + + +sfx_instrument_map_t * +sfx_instrument_map_load_sci(byte *data, size_t size) +{ + sfx_instrument_map_t * map; + int i, m; + + if (data == NULL) + return NULL; + + if (size < PATCH_MIN_SIZE) { + fprintf(stderr, "[instrument-map] Instrument map too small: %d of %d\n", (int) size, PATCH_MIN_SIZE); + return NULL; + } + + map = sfx_instrument_map_new(PATCH_INSTRUMENT_MAPS_NR); + + /* Set up MIDI intialisation data */ + map->initialisation_block_size = getInt16(data + PATCH_INIT_DATA_SIZE_LE); + if (map->initialisation_block_size) { + if (size < PATCH_MIN_SIZE + map->initialisation_block_size) { + fprintf(stderr, "[instrument-map] Instrument map too small for initialisation block: %d of %d\n", (int) size, PATCH_MIN_SIZE); + return NULL; + } + + if (size > PATCH_MIN_SIZE + map->initialisation_block_size) + fprintf(stderr, "[instrument-map] Instrument larger than required by initialisation block: %d of %d\n", (int) size, PATCH_MIN_SIZE); + + if (map->initialisation_block_size != 0) { + map->initialisation_block = (byte *)sci_malloc(map->initialisation_block_size); + memcpy(map->initialisation_block, data + PATCH_INIT_DATA, map->initialisation_block_size); + } + } + + /* Set up basic instrument info */ + for (i = 0; i < SFX_INSTRUMENTS_NR; i++) { + map->patch_map[i].patch = (char)data[PATCH_MAP_OFFSET + i]; + map->patch_key_shift[i] = (char)data[PATCH_KEY_SHIFT_OFFSET + i]; + map->patch_volume_adjust[i] = (char)data[PATCH_VOLUME_ADJUST_OFFSET + i]; + map->patch_bend_range[i] = SFX_UNMAPPED; + map->velocity_map_index[i] = data[PATCH_VELOCITY_MAP_INDEX + i]; + } + + /* Set up percussion maps */ + map->percussion_volume_adjust = data[PATCH_PERCUSSION_VOLUME_ADJUST]; + for (i = 0; i < SFX_RHYTHM_NR; i++) { + map->percussion_map[i] = data[PATCH_PERCUSSION_MAP_OFFSET + i]; + map->percussion_velocity_scale[i] = SFX_MAX_VELOCITY; + } + + /* Set up velocity maps */ + for (m = 0; m < PATCH_INSTRUMENT_MAPS_NR; m++) { + byte *velocity_map = map->velocity_map[m]; + for (i = 0; i < SFX_VELOCITIES_NR; i++) + velocity_map[i] = data[PATCH_VELOCITY_MAP(m) + i]; + } + + map->percussion_velocity_map_index = 0; + + return map; +} + + +/* Output with the instrument map */ +#define MIDI_CHANNELS_NR 0x10 + +typedef struct decorated_midi_writer { + MIDI_WRITER_BODY + + midi_writer_t *writer; + sfx_patch_map_t patches[MIDI_CHANNELS_NR]; + sfx_instrument_map_t *map; +} decorated_midi_writer_t; + + +static void +init_decorated(struct _midi_writer *self_) +{ + decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; + self->writer->init(self->writer); +} + +static void +set_option_decorated(struct _midi_writer *self_, char *name, char *value) +{ + decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; + self->writer->set_option(self->writer, name, value); +} + +static void +delay_decorated(struct _midi_writer *self_, int ticks) +{ + decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; + self->writer->delay(self->writer, ticks); +} + +static void +flush_decorated(struct _midi_writer *self_) +{ + decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; + if (self->writer->flush) + self->writer->flush(self->writer); +} + +static void +reset_timer_decorated(struct _midi_writer *self_) +{ + decorated_midi_writer_t *self = (decorated_midi_writer_t *) self_; + self->writer->reset_timer(self->writer); +} + + +static void +close_decorated(decorated_midi_writer_t *self) +{ + sfx_instrument_map_free(self->map); + self->map = NULL; + self->writer->close(self->writer); + sci_free(self->name); + self->name = NULL; + sci_free(self); +} + +#define BOUND_127(x) (((x) < 0)? 0 : (((x) > 0x7f)? 0x7f : (x))) + +static int +bound_hard_127(int i, char *descr) +{ + int r = BOUND_127(i); + if (r != i) + fprintf(stderr, "[instrument-map] Hard-clipping %02x to %02x in %s\n", i, r, descr); + return r; +} + +static int +set_bend_range(midi_writer_t *writer, int channel, int range) +{ + byte buf[3] = {0xb0, 0x65, 0x00}; + + buf[0] |= channel & 0xf; + if (writer->write(writer, buf, 3) != SFX_OK) + return SFX_ERROR; + + buf[1] = 0x64; + if (writer->write(writer, buf, 3) != SFX_OK) + return SFX_ERROR; + + buf[1] = 0x06; + buf[2] = BOUND_127(range); + if (writer->write(writer, buf, 3) != SFX_OK) + return SFX_ERROR; + + buf[1] = 0x26; + buf[2] = 0; + if (writer->write(writer, buf, 3) != SFX_OK) + return SFX_ERROR; + + return SFX_OK; +} + +static int +write_decorated(decorated_midi_writer_t *self, byte *buf, int len) +{ + sfx_instrument_map_t *map = self->map; + int op = *buf & 0xf0; + int chan = *buf & 0x0f; + int patch = self->patches[chan].patch; + int rhythm = self->patches[chan].rhythm; + + assert (len >= 1); + + if (op == 0xC0 && chan != MIDI_RHYTHM_CHANNEL) { /* Program change */ + int patch = bound_hard_127(buf[1], "program change"); + int instrument = map->patch_map[patch].patch; + int bend_range = map->patch_bend_range[patch]; + + self->patches[chan] = map->patch_map[patch]; + + if (instrument == SFX_UNMAPPED || instrument == SFX_MAPPED_TO_RHYTHM) + return SFX_OK; + + assert (len >= 2); + buf[1] = bound_hard_127(instrument, "patch lookup"); + + if (self->writer->write(self->writer, buf, len) != SFX_OK) + return SFX_ERROR; + + if (bend_range != SFX_UNMAPPED) + return set_bend_range(self->writer, chan, bend_range); + + return SFX_OK; + } + + if (chan == MIDI_RHYTHM_CHANNEL || patch == SFX_MAPPED_TO_RHYTHM) { + /* Rhythm channel handling */ + switch (op) { + case 0x80: + case 0x90: { /* Note off / note on */ + int velocity, instrument, velocity_map_index, velocity_scale; + + if (patch == SFX_MAPPED_TO_RHYTHM) { + buf[0] = (buf[0] & ~0x0f) | MIDI_RHYTHM_CHANNEL; + instrument = rhythm; + velocity_scale = SFX_MAX_VELOCITY; + } else { + int instrument_index = bound_hard_127(buf[1], "rhythm instrument index"); + instrument = map->percussion_map[instrument_index]; + velocity_scale = map->percussion_velocity_scale[instrument_index]; + } + + if (instrument == SFX_UNMAPPED) + return SFX_OK; + + assert (len >= 3); + + velocity = bound_hard_127(buf[2], "rhythm velocity"); + velocity_map_index = map->percussion_velocity_map_index; + + if (velocity_map_index != SFX_NO_VELOCITY_MAP) + velocity = BOUND_127(velocity + map->velocity_map[velocity_map_index][velocity]); + + velocity = BOUND_127(velocity * velocity_scale / SFX_MAX_VELOCITY); + + buf[1] = bound_hard_127(instrument, "rhythm instrument"); + buf[2] = velocity; + + break; + } + + case 0xB0: { /* Controller change */ + assert (len >= 3); + if (buf[1] == 0x7) /* Volume change */ + buf[2] = BOUND_127(buf[2] + map->percussion_volume_adjust); + break; + } + + default: break; + } + + } else { + /* Instrument channel handling */ + + if (patch == SFX_UNMAPPED) + return SFX_OK; + + switch (op) { + case 0x80: + case 0x90: { /* Note off / note on */ + int note = bound_hard_127(buf[1], "note"); + int velocity = bound_hard_127(buf[2], "velocity"); + int velocity_map_index = map->velocity_map_index[patch]; + assert (len >= 3); + + note += map->patch_key_shift[patch]; + /* Not the most efficient solutions, but the least error-prone */ + while (note < 0) + note += 12; + while (note > 0x7f) + note -= 12; + + if (velocity_map_index != SFX_NO_VELOCITY_MAP) + velocity = BOUND_127(velocity + map->velocity_map[velocity_map_index][velocity]); + + buf[1] = note; + buf[2] = velocity; + break; + } + + case 0xB0: /* Controller change */ + assert (len >= 3); + if (buf[1] == 0x7) /* Volume change */ + buf[2] = BOUND_127(buf[2] + map->patch_volume_adjust[patch]); + break; + + default: break; + } + } + + return self->writer->write(self->writer, buf, len); +} + +#define MIDI_BYTES_PER_SECOND 3250 /* This seems to be the minimum guarantee by the standard */ +#define MAX_PER_TICK (MIDI_BYTES_PER_SECOND / 60) /* After this, we ought to issue one tick of pause */ + +static void +init(midi_writer_t *writer, byte *data, size_t len) +{ + int offset = 0; + byte status = 0; + + /* Send init data as separate MIDI commands */ + while (offset < len) { + int args; + byte op = data[offset]; + byte msg[3]; + int i; + + if (op == 0xf0) { + int msg_len; + byte *find = (byte *) memchr(data + offset, 0xf7, len - offset); + + if (!find) { + fprintf(stderr, "[instrument-map] Failed to find end of sysex message\n"); + return; + } + + msg_len = find - data - offset + 1; + writer->write(writer, data + offset, msg_len); + + /* Wait at least 40ms after sysex */ + writer->delay(writer, 3); + offset += msg_len; + continue; + } + + if (op < 0x80) + op = status; + else { + status = op; + offset++; + } + + msg[0] = op; + + switch (op & 0xf0) { + case 0xc0: + case 0xd0: + args = 1; + break; + default: + args = 2; + } + + if (args > len - offset) { + fprintf(stderr, "[instrument-map] Insufficient bytes remaining for MIDI command %02x\n", op); + return; + } + + for (i = 0; i < args; i++) + msg[i + 1] = data[offset + i]; + + writer->write(writer, msg, args + 1); + offset += args; + + if (writer->flush) + writer->flush(writer); + } +} + +#define NAME_SUFFIX "+instruments" + +midi_writer_t * +sfx_mapped_writer(midi_writer_t *writer, sfx_instrument_map_t *map) +{ + int i; + decorated_midi_writer_t *retval; + + if (map == NULL) + return writer; + + retval = (decorated_midi_writer_t *)sci_malloc(sizeof(decorated_midi_writer_t)); + retval->writer = writer; + retval->name = (char *)sci_malloc(strlen(writer->name) + strlen(NAME_SUFFIX) + 1); + strcpy(retval->name, writer->name); + strcat(retval->name, NAME_SUFFIX); + + retval->init = (int (*)(midi_writer_t *)) init_decorated; + retval->set_option = (int (*)(midi_writer_t *, char *, char *)) set_option_decorated; + retval->write = (int (*)(midi_writer_t *, byte *, int)) write_decorated; + retval->delay = (void (*)(midi_writer_t *, int)) delay_decorated; + retval->flush = (void (*)(midi_writer_t *)) flush_decorated; + retval->reset_timer = (void (*)(midi_writer_t *)) reset_timer_decorated; + retval->close = (void (*)(midi_writer_t *)) close_decorated; + + retval->map = map; + + init(writer, map->initialisation_block, map->initialisation_block_size); + + for (i = 0; i < MIDI_CHANNELS_NR; i++) + retval->patches[i].patch = SFX_UNMAPPED; + + return (midi_writer_t *) retval; +} + diff --git a/engines/sci/sfx/seq/instrument-map.h b/engines/sci/sfx/seq/instrument-map.h new file mode 100644 index 0000000000..85f654d60b --- /dev/null +++ b/engines/sci/sfx/seq/instrument-map.h @@ -0,0 +1,132 @@ +/*************************************************************************** + Copyright (C) 2008 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantability, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <creichen@gmail.com> + +***************************************************************************/ + +/* Implementation of SCI instrument maps for GM and MT-32. */ + +#ifndef SCI_INSTRUMENT_MAP_ +#define SCI_INSTRUMENT_MAP_ + +#include <stdlib.h> +#include "resource.h" +#include "../device.h" + +#define SFX_INSTRUMENTS_NR 0x80 +#define SFX_RHYTHM_NR 0x80 +#define SFX_VELOCITIES_NR 0x80 +#define SFX_NO_VELOCITY_MAP -1 /* use in velocity_map_index to indicate that no map should be used */ + +/* Instrument map types */ +#define SFX_MAP_UNKNOWN 0 +#define SFX_MAP_MT32 1 /* Original MT-32 map format */ +#define SFX_MAP_MT32_GM 2 /* More recent map format used for both MT-32 and GM */ + +/* Patch not mapped */ +#define SFX_UNMAPPED -1 +/* Patch mapped to rhythm key */ +#define SFX_MAPPED_TO_RHYTHM -2 + +/* Maximum velocity (used for scaling) */ +#define SFX_MAX_VELOCITY 128 + +typedef struct { + int patch; /* Native instrument, SFX_UNMAPPED or SFX_MAPPED_TO_RHYTHM */ + int rhythm; /* Rhythm key when patch == SFX_MAPPED_TO_RHYTHM */ +} sfx_patch_map_t; + +typedef struct { + sfx_patch_map_t patch_map[SFX_INSTRUMENTS_NR]; /* Map patch nr to which native instrument or rhythm key */ + int patch_key_shift[SFX_INSTRUMENTS_NR]; /* Shift patch key by how much? */ + int patch_volume_adjust[SFX_INSTRUMENTS_NR]; /* Adjust controller 7 by how much? */ + int patch_bend_range[SFX_INSTRUMENTS_NR]; /* Bend range in semitones or SFX_UNMAPPED for default */ + + int percussion_map[SFX_RHYTHM_NR]; /* Map percussion instrument (RHYTH_CHANNEL) to what native 'key'? */ + int percussion_volume_adjust; /* unused in SCI patches */ + + int velocity_map_index[SFX_INSTRUMENTS_NR]; /* Velocity translation map to use for that instrument */ + int velocity_maps_nr; /* How many velocity translation maps do we have? */ + byte **velocity_map; /* velocity_maps_nr entries, each of size SFX_VELOCITIES_NR */ + int percussion_velocity_map_index; /* Special index for the percussion map */ + int percussion_velocity_scale[SFX_INSTRUMENTS_NR]; /* Velocity scale (0 - SFX_PERC_MAX_VOL) */ + + size_t initialisation_block_size; + byte *initialisation_block; /* Initial MIDI commands to set up the device */ +} sfx_instrument_map_t; + +sfx_instrument_map_t * +sfx_instrument_map_new(int velocity_maps_nr); +/* Constructs a new default-initialised velocity map +** Parameters: (int) velocity_maps_nr: Number of velocity maps to allocate +** Returns : (sfx_instrument_map *) an initialised instrument map +*/ + +void +sfx_instrument_map_free(sfx_instrument_map_t *map); +/* Deallocates an instrument map +** Parameters: (sfx_instrument_map *) map: The map to deallocate, or NULL for a no-op +*/ + +sfx_instrument_map_t * +sfx_instrument_map_load_sci(byte *data, size_t length); +/* Allocate and initialise an instrument map from SCI data +** Parameters: (byte *) Pointer to the data to initialise from +** (size_t) Number of bytes to expect within +** Returns : (sfx_instrument_map_t *) An initialised instrument map for these settings, or NULL +** if `data' is NULL or `data' and `length' do not permit a valid instrument map +** If `data' is null, the function will return NULL quietly. +*/ + +sfx_instrument_map_t * +sfx_instrument_map_mt32_to_gm(byte *data, size_t size); +/* Allocate and initialise an instrument map from MT-32 patch data +** Parameters: (byte *) Pointer to the MT-32 patch data to initialise from +** (size_t) Number of bytes to expect within +** Returns : (sfx_instrument_map_t *) An initialised instrument map for these settings +** If `data' is null or invalid, the function will return a default MT-32 to GM map. +*/ + +int +sfx_instrument_map_detect(byte *data, size_t size); +/* Detects the type of patch data +** Parameters: (byte *) Pointer to the patch data +** (size_t) Number of bytes to expect within +** Returns : (int) SFX_MAP_SCI1 for an SCI1 instrument map, SFX_MAP_SCI0_MT32 for SCI0 MT-32 patch data, +** or SFX_MAP_UNKNOWN for unknown. +*/ + +midi_writer_t * +sfx_mapped_writer(midi_writer_t *writer, sfx_instrument_map_t *map); +/* Wrap a midi_writer_t into an instrument map +** Parameters: (midi_writer_t *) writer: The writer to wrap +** (sfx_instrument_map_t *) map: The map to apply to all commands going into the writer, or NULL +** Returns : (midi_writer_t *) A MIDI writer that preprocesses all data by `map' and otherwise relies on `writer' +** Effects : If successful and neccessary, this operation will send initialisation messages to the writer, as needed. +** If `map' is NULL, this returns `writer'. Otherwise it sets up a Decorator that handles translation and automatically +** deallocates the instrument map when the writer is closed. +*/ + + +#endif /* !defined(SCI_INSTRUMENT_MAP_) */ diff --git a/engines/sci/sfx/seq/map-mt32-to-gm.c b/engines/sci/sfx/seq/map-mt32-to-gm.c new file mode 100644 index 0000000000..bcaf3556f1 --- /dev/null +++ b/engines/sci/sfx/seq/map-mt32-to-gm.c @@ -0,0 +1,813 @@ +/*************************************************************************** + map-mt32-to-gm.c (C) 1999,2001 Christoph Reichenbach, TU Darmstadt + (C) 1999-2000 Rickard Lind + (C) 2008 Walter van Niftrik + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CJR) [creichen@rbg.informatik.tu-darmstadt.de] + + Roland MT-32 to General MIDI conversion: + + Rickard Lind [rpl@dd.chalmers.se] + +***************************************************************************/ + +#include <sciresource.h> +#include <engine.h> +#include <stdarg.h> +#include "instrument-map.h" + +#define DEBUG_MT32_TO_GM + +static char +*GM_Instrument_Names[] = { + /*000*/ "Acoustic Grand Piano", + /*001*/ "Bright Acoustic Piano", + /*002*/ "Electric Grand Piano", + /*003*/ "Honky-tonk Piano", + /*004*/ "Electric Piano 1", + /*005*/ "Electric Piano 2", + /*006*/ "Harpsichord", + /*007*/ "Clavinet", + /*008*/ "Celesta", + /*009*/ "Glockenspiel", + /*010*/ "Music Box", + /*011*/ "Vibraphone", + /*012*/ "Marimba", + /*013*/ "Xylophone", + /*014*/ "Tubular Bells", + /*015*/ "Dulcimer", + /*016*/ "Drawbar Organ", + /*017*/ "Percussive Organ", + /*018*/ "Rock Organ", + /*019*/ "Church Organ", + /*020*/ "Reed Organ", + /*021*/ "Accordion", + /*022*/ "Harmonica", + /*023*/ "Tango Accordion", + /*024*/ "Acoustic Guitar (nylon)", + /*025*/ "Acoustic Guitar (steel)", + /*026*/ "Electric Guitar (jazz)", + /*027*/ "Electric Guitar (clean)", + /*028*/ "Electric Guitar (muted)", + /*029*/ "Overdriven Guitar", + /*030*/ "Distortion Guitar", + /*031*/ "Guitar Harmonics", + /*032*/ "Acoustic Bass", + /*033*/ "Electric Bass (finger)", + /*034*/ "Electric Bass (pick)", + /*035*/ "Fretless Bass", + /*036*/ "Slap Bass 1", + /*037*/ "Slap Bass 2", + /*038*/ "Synth Bass 1", + /*039*/ "Synth Bass 2", + /*040*/ "Violin", + /*041*/ "Viola", + /*042*/ "Cello", + /*043*/ "Contrabass", + /*044*/ "Tremolo Strings", + /*045*/ "Pizzicato Strings", + /*046*/ "Orchestral Harp", + /*047*/ "Timpani", + /*048*/ "String Ensemble 1", + /*049*/ "String Ensemble 2", + /*050*/ "SynthStrings 1", + /*051*/ "SynthStrings 2", + /*052*/ "Choir Aahs", + /*053*/ "Voice Oohs", + /*054*/ "Synth Voice", + /*055*/ "Orchestra Hit", + /*056*/ "Trumpet", + /*057*/ "Trombone", + /*058*/ "Tuba", + /*059*/ "Muted Trumpet", + /*060*/ "French Horn", + /*061*/ "Brass Section", + /*062*/ "SynthBrass 1", + /*063*/ "SynthBrass 2", + /*064*/ "Soprano Sax", + /*065*/ "Alto Sax", + /*066*/ "Tenor Sax", + /*067*/ "Baritone Sax", + /*068*/ "Oboe", + /*069*/ "English Horn", + /*070*/ "Bassoon", + /*071*/ "Clarinet", + /*072*/ "Piccolo", + /*073*/ "Flute", + /*074*/ "Recorder", + /*075*/ "Pan Flute", + /*076*/ "Blown Bottle", + /*077*/ "Shakuhachi", + /*078*/ "Whistle", + /*079*/ "Ocarina", + /*080*/ "Lead 1 (square)", + /*081*/ "Lead 2 (sawtooth)", + /*082*/ "Lead 3 (calliope)", + /*083*/ "Lead 4 (chiff)", + /*084*/ "Lead 5 (charang)", + /*085*/ "Lead 6 (voice)", + /*086*/ "Lead 7 (fifths)", + /*087*/ "Lead 8 (bass+lead)", + /*088*/ "Pad 1 (new age)", + /*089*/ "Pad 2 (warm)", + /*090*/ "Pad 3 (polysynth)", + /*091*/ "Pad 4 (choir)", + /*092*/ "Pad 5 (bowed)", + /*093*/ "Pad 6 (metallic)", + /*094*/ "Pad 7 (halo)", + /*095*/ "Pad 8 (sweep)", + /*096*/ "FX 1 (rain)", + /*097*/ "FX 2 (soundtrack)", + /*098*/ "FX 3 (crystal)", + /*099*/ "FX 4 (atmosphere)", + /*100*/ "FX 5 (brightness)", + /*101*/ "FX 6 (goblins)", + /*102*/ "FX 7 (echoes)", + /*103*/ "FX 8 (sci-fi)", + /*104*/ "Sitar", + /*105*/ "Banjo", + /*106*/ "Shamisen", + /*107*/ "Koto", + /*108*/ "Kalimba", + /*109*/ "Bag pipe", + /*110*/ "Fiddle", + /*111*/ "Shannai", + /*112*/ "Tinkle Bell", + /*113*/ "Agogo", + /*114*/ "Steel Drums", + /*115*/ "Woodblock", + /*116*/ "Taiko Drum", + /*117*/ "Melodic Tom", + /*118*/ "Synth Drum", + /*119*/ "Reverse Cymbal", + /*120*/ "Guitar Fret Noise", + /*121*/ "Breath Noise", + /*122*/ "Seashore", + /*123*/ "Bird Tweet", + /*124*/ "Telephone Ring", + /*125*/ "Helicopter", + /*126*/ "Applause", + /*127*/ "Gunshot" +}; + +/* The GM Percussion map is downwards compatible to the MT32 map, which is used in SCI */ +static char +*GM_Percussion_Names[] = { + /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*30*/ 0, 0, 0, 0, +/* The preceeding percussions are not covered by the GM standard */ + /*34*/ "Acoustic Bass Drum", + /*35*/ "Bass Drum 1", + /*36*/ "Side Stick", + /*37*/ "Acoustic Snare", + /*38*/ "Hand Clap", + /*39*/ "Electric Snare", + /*40*/ "Low Floor Tom", + /*41*/ "Closed Hi-Hat", + /*42*/ "High Floor Tom", + /*43*/ "Pedal Hi-Hat", + /*44*/ "Low Tom", + /*45*/ "Open Hi-Hat", + /*46*/ "Low-Mid Tom", + /*47*/ "Hi-Mid Tom", + /*48*/ "Crash Cymbal 1", + /*49*/ "High Tom", + /*50*/ "Ride Cymbal 1", + /*51*/ "Chinese Cymbal", + /*52*/ "Ride Bell", + /*53*/ "Tambourine", + /*54*/ "Splash Cymbal", + /*55*/ "Cowbell", + /*56*/ "Crash Cymbal 2", + /*57*/ "Vibraslap", + /*58*/ "Ride Cymbal 2", + /*59*/ "Hi Bongo", + /*60*/ "Low Bongo", + /*61*/ "Mute Hi Conga", + /*62*/ "Open Hi Conga", + /*63*/ "Low Conga", + /*64*/ "High Timbale", + /*65*/ "Low Timbale", + /*66*/ "High Agogo", + /*67*/ "Low Agogo", + /*68*/ "Cabasa", + /*69*/ "Maracas", + /*70*/ "Short Whistle", + /*71*/ "Long Whistle", + /*72*/ "Short Guiro", + /*73*/ "Long Guiro", + /*74*/ "Claves", + /*75*/ "Hi Wood Block", + /*76*/ "Low Wood Block", + /*77*/ "Mute Cuica", + /*78*/ "Open Cuica", + /*79*/ "Mute Triangle", + /*80*/ "Open Triangle" +}; + +/******************************************* + * Fancy instrument mappings begin here... * + *******************************************/ + + +static struct { + char *name; + gint8 gm_instr; + gint8 gm_rhythm_key; +} MT32_PresetTimbreMaps[] = { + /*000*/ {"AcouPiano1", 0, SFX_UNMAPPED}, + /*001*/ {"AcouPiano2", 1, SFX_UNMAPPED}, + /*002*/ {"AcouPiano3", 0, SFX_UNMAPPED}, + /*003*/ {"ElecPiano1", 4, SFX_UNMAPPED}, + /*004*/ {"ElecPiano2", 5, SFX_UNMAPPED}, + /*005*/ {"ElecPiano3", 4, SFX_UNMAPPED}, + /*006*/ {"ElecPiano4", 5, SFX_UNMAPPED}, + /*007*/ {"Honkytonk ", 3, SFX_UNMAPPED}, + /*008*/ {"Elec Org 1", 16, SFX_UNMAPPED}, + /*009*/ {"Elec Org 2", 17, SFX_UNMAPPED}, + /*010*/ {"Elec Org 3", 18, SFX_UNMAPPED}, + /*011*/ {"Elec Org 4", 18, SFX_UNMAPPED}, + /*012*/ {"Pipe Org 1", 19, SFX_UNMAPPED}, + /*013*/ {"Pipe Org 2", 19, SFX_UNMAPPED}, + /*014*/ {"Pipe Org 3", 20, SFX_UNMAPPED}, + /*015*/ {"Accordion ", 21, SFX_UNMAPPED}, + /*016*/ {"Harpsi 1 ", 6, SFX_UNMAPPED}, + /*017*/ {"Harpsi 2 ", 6, SFX_UNMAPPED}, + /*018*/ {"Harpsi 3 ", 6, SFX_UNMAPPED}, + /*019*/ {"Clavi 1 ", 7, SFX_UNMAPPED}, + /*020*/ {"Clavi 2 ", 7, SFX_UNMAPPED}, + /*021*/ {"Clavi 3 ", 7, SFX_UNMAPPED}, + /*022*/ {"Celesta 1 ", 8, SFX_UNMAPPED}, + /*023*/ {"Celesta 2 ", 8, SFX_UNMAPPED}, + /*024*/ {"Syn Brass1", 62, SFX_UNMAPPED}, + /*025*/ {"Syn Brass2", 63, SFX_UNMAPPED}, + /*026*/ {"Syn Brass3", 62, SFX_UNMAPPED}, + /*027*/ {"Syn Brass4", 63, SFX_UNMAPPED}, + /*028*/ {"Syn Bass 1", 38, SFX_UNMAPPED}, + /*029*/ {"Syn Bass 2", 39, SFX_UNMAPPED}, + /*030*/ {"Syn Bass 3", 38, SFX_UNMAPPED}, + /*031*/ {"Syn Bass 4", 39, SFX_UNMAPPED}, + /*032*/ {"Fantasy ", 88, SFX_UNMAPPED}, + /*033*/ {"Harmo Pan ", 89, SFX_UNMAPPED}, + /*034*/ {"Chorale ", 52, SFX_UNMAPPED}, + /*035*/ {"Glasses ", 98, SFX_UNMAPPED}, + /*036*/ {"Soundtrack", 97, SFX_UNMAPPED}, + /*037*/ {"Atmosphere", 99, SFX_UNMAPPED}, + /*038*/ {"Warm Bell ", 89, SFX_UNMAPPED}, + /*039*/ {"Funny Vox ", 85, SFX_UNMAPPED}, + /*040*/ {"Echo Bell ", 39, SFX_UNMAPPED}, + /*041*/ {"Ice Rain ", 101, SFX_UNMAPPED}, + /*042*/ {"Oboe 2001 ", 68, SFX_UNMAPPED}, + /*043*/ {"Echo Pan ", 87, SFX_UNMAPPED}, + /*044*/ {"DoctorSolo", 86, SFX_UNMAPPED}, + /*045*/ {"Schooldaze", 103, SFX_UNMAPPED}, + /*046*/ {"BellSinger", 88, SFX_UNMAPPED}, + /*047*/ {"SquareWave", 80, SFX_UNMAPPED}, + /*048*/ {"Str Sect 1", 48, SFX_UNMAPPED}, + /*049*/ {"Str Sect 2", 48, SFX_UNMAPPED}, + /*050*/ {"Str Sect 3", 49, SFX_UNMAPPED}, + /*051*/ {"Pizzicato ", 45, SFX_UNMAPPED}, + /*052*/ {"Violin 1 ", 40, SFX_UNMAPPED}, + /*053*/ {"Violin 2 ", 40, SFX_UNMAPPED}, + /*054*/ {"Cello 1 ", 42, SFX_UNMAPPED}, + /*055*/ {"Cello 2 ", 42, SFX_UNMAPPED}, + /*056*/ {"Contrabass", 43, SFX_UNMAPPED}, + /*057*/ {"Harp 1 ", 46, SFX_UNMAPPED}, + /*058*/ {"Harp 2 ", 46, SFX_UNMAPPED}, + /*059*/ {"Guitar 1 ", 24, SFX_UNMAPPED}, + /*060*/ {"Guitar 2 ", 25, SFX_UNMAPPED}, + /*061*/ {"Elec Gtr 1", 26, SFX_UNMAPPED}, + /*062*/ {"Elec Gtr 2", 27, SFX_UNMAPPED}, + /*063*/ {"Sitar ", 104, SFX_UNMAPPED}, + /*064*/ {"Acou Bass1", 32, SFX_UNMAPPED}, + /*065*/ {"Acou Bass2", 33, SFX_UNMAPPED}, + /*066*/ {"Elec Bass1", 34, SFX_UNMAPPED}, + /*067*/ {"Elec Bass2", 39, SFX_UNMAPPED}, + /*068*/ {"Slap Bass1", 36, SFX_UNMAPPED}, + /*069*/ {"Slap Bass2", 37, SFX_UNMAPPED}, + /*070*/ {"Fretless 1", 35, SFX_UNMAPPED}, + /*071*/ {"Fretless 2", 35, SFX_UNMAPPED}, + /*072*/ {"Flute 1 ", 73, SFX_UNMAPPED}, + /*073*/ {"Flute 2 ", 73, SFX_UNMAPPED}, + /*074*/ {"Piccolo 1 ", 72, SFX_UNMAPPED}, + /*075*/ {"Piccolo 2 ", 72, SFX_UNMAPPED}, + /*076*/ {"Recorder ", 74, SFX_UNMAPPED}, + /*077*/ {"Panpipes ", 75, SFX_UNMAPPED}, + /*078*/ {"Sax 1 ", 64, SFX_UNMAPPED}, + /*079*/ {"Sax 2 ", 65, SFX_UNMAPPED}, + /*080*/ {"Sax 3 ", 66, SFX_UNMAPPED}, + /*081*/ {"Sax 4 ", 67, SFX_UNMAPPED}, + /*082*/ {"Clarinet 1", 71, SFX_UNMAPPED}, + /*083*/ {"Clarinet 2", 71, SFX_UNMAPPED}, + /*084*/ {"Oboe ", 68, SFX_UNMAPPED}, + /*085*/ {"Engl Horn ", 69, SFX_UNMAPPED}, + /*086*/ {"Bassoon ", 70, SFX_UNMAPPED}, + /*087*/ {"Harmonica ", 22, SFX_UNMAPPED}, + /*088*/ {"Trumpet 1 ", 56, SFX_UNMAPPED}, + /*089*/ {"Trumpet 2 ", 56, SFX_UNMAPPED}, + /*090*/ {"Trombone 1", 57, SFX_UNMAPPED}, + /*091*/ {"Trombone 2", 57, SFX_UNMAPPED}, + /*092*/ {"Fr Horn 1 ", 60, SFX_UNMAPPED}, + /*093*/ {"Fr Horn 2 ", 60, SFX_UNMAPPED}, + /*094*/ {"Tuba ", 58, SFX_UNMAPPED}, + /*095*/ {"Brs Sect 1", 61, SFX_UNMAPPED}, + /*096*/ {"Brs Sect 2", 61, SFX_UNMAPPED}, + /*097*/ {"Vibe 1 ", 11, SFX_UNMAPPED}, + /*098*/ {"Vibe 2 ", 11, SFX_UNMAPPED}, + /*099*/ {"Syn Mallet", 15, SFX_UNMAPPED}, + /*100*/ {"Wind Bell ", 88, SFX_UNMAPPED}, + /*101*/ {"Glock ", 9, SFX_UNMAPPED}, + /*102*/ {"Tube Bell ", 14, SFX_UNMAPPED}, + /*103*/ {"Xylophone ", 13, SFX_UNMAPPED}, + /*104*/ {"Marimba ", 12, SFX_UNMAPPED}, + /*105*/ {"Koto ", 107, SFX_UNMAPPED}, + /*106*/ {"Sho ", 111, SFX_UNMAPPED}, + /*107*/ {"Shakuhachi", 77, SFX_UNMAPPED}, + /*108*/ {"Whistle 1 ", 78, SFX_UNMAPPED}, + /*109*/ {"Whistle 2 ", 78, SFX_UNMAPPED}, + /*110*/ {"BottleBlow", 76, SFX_UNMAPPED}, + /*111*/ {"BreathPipe", 121, SFX_UNMAPPED}, + /*112*/ {"Timpani ", 47, SFX_UNMAPPED}, + /*113*/ {"MelodicTom", 117, SFX_UNMAPPED}, + /*114*/ {"Deep Snare", SFX_MAPPED_TO_RHYTHM, 37}, + /*115*/ {"Elec Perc1", 115, SFX_UNMAPPED}, /* ? */ + /*116*/ {"Elec Perc2", 118, SFX_UNMAPPED}, /* ? */ + /*117*/ {"Taiko ", 116, SFX_UNMAPPED}, + /*118*/ {"Taiko Rim ", 118, SFX_UNMAPPED}, + /*119*/ {"Cymbal ", SFX_MAPPED_TO_RHYTHM, 50}, + /*120*/ {"Castanets ", SFX_MAPPED_TO_RHYTHM, SFX_UNMAPPED}, + /*121*/ {"Triangle ", 112, SFX_UNMAPPED}, + /*122*/ {"Orche Hit ", 55, SFX_UNMAPPED}, + /*123*/ {"Telephone ", 124, SFX_UNMAPPED}, + /*124*/ {"Bird Tweet", 123, SFX_UNMAPPED}, + /*125*/ {"OneNoteJam", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? */ + /*126*/ {"WaterBells", 98, SFX_UNMAPPED}, + /*127*/ {"JungleTune", SFX_UNMAPPED, SFX_UNMAPPED} /* ? */ +}; + +static struct { + char *name; + gint8 gm_instr; + gint8 gm_rhythmkey; +} MT32_RhythmTimbreMaps[] = { + /*00*/ {"Acou BD ", SFX_MAPPED_TO_RHYTHM, 34}, + /*01*/ {"Acou SD ", SFX_MAPPED_TO_RHYTHM, 37}, + /*02*/ {"Acou HiTom", 117, 49}, + /*03*/ {"AcouMidTom", 117, 46}, + /*04*/ {"AcouLowTom", 117, 40}, + /*05*/ {"Elec SD ", SFX_MAPPED_TO_RHYTHM, 39}, + /*06*/ {"Clsd HiHat", SFX_MAPPED_TO_RHYTHM, 41}, + /*07*/ {"OpenHiHat1", SFX_MAPPED_TO_RHYTHM, 45}, + /*08*/ {"Crash Cym ", SFX_MAPPED_TO_RHYTHM, 48}, + /*09*/ {"Ride Cym ", SFX_MAPPED_TO_RHYTHM, 50}, + /*10*/ {"Rim Shot ", SFX_MAPPED_TO_RHYTHM, 36}, + /*11*/ {"Hand Clap ", SFX_MAPPED_TO_RHYTHM, 38}, + /*12*/ {"Cowbell ", SFX_MAPPED_TO_RHYTHM, 55}, + /*13*/ {"Mt HiConga", SFX_MAPPED_TO_RHYTHM, 61}, + /*14*/ {"High Conga", SFX_MAPPED_TO_RHYTHM, 62}, + /*15*/ {"Low Conga ", SFX_MAPPED_TO_RHYTHM, 63}, + /*16*/ {"Hi Timbale", SFX_MAPPED_TO_RHYTHM, 64}, + /*17*/ {"LowTimbale", SFX_MAPPED_TO_RHYTHM, 65}, + /*18*/ {"High Bongo", SFX_MAPPED_TO_RHYTHM, 59}, + /*19*/ {"Low Bongo ", SFX_MAPPED_TO_RHYTHM, 60}, + /*20*/ {"High Agogo", 113, 66}, + /*21*/ {"Low Agogo ", 113, 67}, + /*22*/ {"Tambourine", SFX_MAPPED_TO_RHYTHM, 53}, + /*23*/ {"Claves ", SFX_MAPPED_TO_RHYTHM, 74}, + /*24*/ {"Maracas ", SFX_MAPPED_TO_RHYTHM, 69}, + /*25*/ {"SmbaWhis L", 78, 71}, + /*26*/ {"SmbaWhis S", 78, 70}, + /*27*/ {"Cabasa ", SFX_MAPPED_TO_RHYTHM, 68}, + /*28*/ {"Quijada ", SFX_MAPPED_TO_RHYTHM, 72}, + /*29*/ {"OpenHiHat2", SFX_MAPPED_TO_RHYTHM, 43} +}; + +static gint8 +MT32_PresetRhythmKeymap[] = { + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, 34, 34, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, SFX_UNMAPPED, SFX_UNMAPPED, 53, SFX_UNMAPPED, 55, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, SFX_UNMAPPED, 74, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, + SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED, SFX_UNMAPPED +}; + +/* +++ - Don't change unless you've got a good reason + ++ - Looks good, sounds ok + + - Not too bad, but is it right? + ? - Where do I map this one? + ?? - Any good ideas? + ??? - I'm clueless? + R - Rhythm... */ +static struct { + char *name; + gint8 gm_instr; + gint8 gm_rhythm_key; +} MT32_MemoryTimbreMaps[] = { + {"AccPnoKA2 ", 1, SFX_UNMAPPED}, /* ++ (KQ1) */ + {"Acou BD ", SFX_MAPPED_TO_RHYTHM, 34}, /* R (PQ2) */ + {"Acou SD ", SFX_MAPPED_TO_RHYTHM, 37}, /* R (PQ2) */ + {"AcouPnoKA ", 0, SFX_UNMAPPED}, /* ++ (KQ1) */ + {"BASS ", 32, SFX_UNMAPPED}, /* + (LSL3) */ + {"BASSOONPCM", 70, SFX_UNMAPPED}, /* + (CB) */ + {"BEACH WAVE", 122, SFX_UNMAPPED}, /* + (LSL3) */ + {"BagPipes ", 109, SFX_UNMAPPED}, + {"BassPizzMS", 45, SFX_UNMAPPED}, /* ++ (HQ) */ + {"BassoonKA ", 70, SFX_UNMAPPED}, /* ++ (KQ1) */ + {"Bell MS", 112, SFX_UNMAPPED}, /* ++ (iceMan) */ + {"Bells MS", 112, SFX_UNMAPPED}, /* + (HQ) */ + {"Big Bell ", 14, SFX_UNMAPPED}, /* + (CB) */ + {"Bird Tweet", 123, SFX_UNMAPPED}, + {"BrsSect MS", 61, SFX_UNMAPPED}, /* +++ (iceMan) */ + {"CLAPPING ", 126, SFX_UNMAPPED}, /* ++ (LSL3) */ + {"Cabasa ", SFX_MAPPED_TO_RHYTHM, 68}, /* R (HBoG) */ + {"Calliope ", 82, SFX_UNMAPPED}, /* +++ (HQ) */ + {"CelticHarp", 46, SFX_UNMAPPED}, /* ++ (CoC) */ + {"Chicago MS", 1, SFX_UNMAPPED}, /* ++ (iceMan) */ + {"Chop ", 117, SFX_UNMAPPED}, + {"Chorale MS", 52, SFX_UNMAPPED}, /* + (CoC) */ + {"ClarinetMS", 71, SFX_UNMAPPED}, + {"Claves ", SFX_MAPPED_TO_RHYTHM, 74}, /* R (PQ2) */ + {"Claw MS", 118, SFX_UNMAPPED}, /* + (HQ) */ + {"ClockBell ", 14, SFX_UNMAPPED}, /* + (CB) */ + {"ConcertCym", SFX_MAPPED_TO_RHYTHM, 54}, /* R ? (KQ1) */ + {"Conga MS", SFX_MAPPED_TO_RHYTHM, 63}, /* R (HQ) */ + {"CoolPhone ", 124, SFX_UNMAPPED}, /* ++ (LSL3) */ + {"CracklesMS", 115, SFX_UNMAPPED}, /* ? (CoC, HQ) */ + {"CreakyD MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ??? (KQ1) */ + {"Cricket ", 120, SFX_UNMAPPED}, /* ? (CB) */ + {"CrshCymbMS", SFX_MAPPED_TO_RHYTHM, 56}, /* R +++ (iceMan) */ + {"CstlGateMS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HQ) */ + {"CymSwellMS", SFX_MAPPED_TO_RHYTHM, 54}, /* R ? (CoC, HQ) */ + {"CymbRollKA", SFX_MAPPED_TO_RHYTHM, 56}, /* R ? (KQ1) */ + {"Cymbal Lo ", SFX_UNMAPPED, SFX_UNMAPPED}, /* R ? (LSL3) */ + {"card ", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HBoG) */ + {"DirtGtr MS", 30, SFX_UNMAPPED}, /* + (iceMan) */ + {"DirtGtr2MS", 29, SFX_UNMAPPED}, /* + (iceMan) */ + {"E Bass MS", 33, SFX_UNMAPPED}, /* + (SQ3) */ + {"ElecBassMS", 33, SFX_UNMAPPED}, + {"ElecGtr MS", 27, SFX_UNMAPPED}, /* ++ (iceMan) */ + {"EnglHornMS", 69, SFX_UNMAPPED}, + {"FantasiaKA", 88, SFX_UNMAPPED}, + {"Fantasy ", 99, SFX_UNMAPPED}, /* + (PQ2) */ + {"Fantasy2MS", 99, SFX_UNMAPPED}, /* ++ (CoC, HQ) */ + {"Filter MS", 95, SFX_UNMAPPED}, /* +++ (iceMan) */ + {"Filter2 MS", 95, SFX_UNMAPPED}, /* ++ (iceMan) */ + {"Flame2 MS", 121, SFX_UNMAPPED}, /* ? (HQ) */ + {"Flames MS", 121, SFX_UNMAPPED}, /* ? (HQ) */ + {"Flute MS", 73, SFX_UNMAPPED}, /* +++ (HQ) */ + {"FogHorn MS", 58, SFX_UNMAPPED}, + {"FrHorn1 MS", 60, SFX_UNMAPPED}, /* +++ (HQ) */ + {"FunnyTrmp ", 56, SFX_UNMAPPED}, /* ++ (CB) */ + {"GameSnd MS", 80, SFX_UNMAPPED}, + {"Glock MS", 9, SFX_UNMAPPED}, /* +++ (HQ) */ + {"Gunshot ", 127, SFX_UNMAPPED}, /* +++ (CB) */ + {"Hammer MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HQ) */ + {"Harmonica2", 22, SFX_UNMAPPED}, /* +++ (CB) */ + {"Harpsi 1 ", 6, SFX_UNMAPPED}, /* + (HBoG) */ + {"Harpsi 2 ", 6, SFX_UNMAPPED}, /* +++ (CB) */ + {"Heart MS", 116, SFX_UNMAPPED}, /* ? (iceMan) */ + {"Horse1 MS", 115, SFX_UNMAPPED}, /* ? (CoC, HQ) */ + {"Horse2 MS", 115, SFX_UNMAPPED}, /* ? (CoC, HQ) */ + {"InHale MS", 121, SFX_UNMAPPED}, /* ++ (iceMan) */ + {"KNIFE ", 120, SFX_UNMAPPED}, /* ? (LSL3) */ + {"KenBanjo ", 105, SFX_UNMAPPED}, /* +++ (CB) */ + {"Kiss MS", 25, SFX_UNMAPPED}, /* ++ (HQ) */ + {"KongHit ", SFX_UNMAPPED, SFX_UNMAPPED}, /* ??? (KQ1) */ + {"Koto ", 107, SFX_UNMAPPED}, /* +++ (PQ2) */ + {"Laser MS", 81, SFX_UNMAPPED}, /* ?? (HQ) */ + {"Meeps MS", 62, SFX_UNMAPPED}, /* ? (HQ) */ + {"MTrak MS", 62, SFX_UNMAPPED}, /* ?? (iceMan) */ + {"MachGun MS", 127, SFX_UNMAPPED}, /* ? (iceMan) */ + {"OCEANSOUND", 122, SFX_UNMAPPED}, /* + (LSL3) */ + {"Oboe 2001 ", 68, SFX_UNMAPPED}, /* + (PQ2) */ + {"Ocean MS", 122, SFX_UNMAPPED}, /* + (iceMan) */ + {"PPG 2.3 MS", 75, SFX_UNMAPPED}, /* ? (iceMan) */ + {"PianoCrank", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CB) */ + {"PicSnareMS", SFX_MAPPED_TO_RHYTHM, 39}, /* R ? (iceMan) */ + {"PiccoloKA ", 72, SFX_UNMAPPED}, /* +++ (KQ1) */ + {"PinkBassMS", 39, SFX_UNMAPPED}, + {"Pizz2 ", 45, SFX_UNMAPPED}, /* ++ (CB) */ + {"Portcullis", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (KQ1) */ + {"Raspbry MS", 81, SFX_UNMAPPED}, /* ? (HQ) */ + {"RatSqueek ", 72, SFX_UNMAPPED}, /* ? (CB, CoC) */ + {"Record78 ", SFX_UNMAPPED, SFX_UNMAPPED}, /* +++ (CB) */ + {"RecorderMS", 74, SFX_UNMAPPED}, /* +++ (CoC) */ + {"Red Baron ", 125, SFX_UNMAPPED}, /* ? (CB) */ + {"ReedPipMS ", 20, SFX_UNMAPPED}, /* +++ (Coc) */ + {"RevCymb MS", 119, SFX_UNMAPPED}, + {"RifleShot ", 127, SFX_UNMAPPED}, /* + (CB) */ + {"RimShot MS", SFX_MAPPED_TO_RHYTHM, 36}, /* R */ + {"SHOWER ", 52, SFX_UNMAPPED}, /* ? (LSL3) */ + {"SQ Bass MS", 32, SFX_UNMAPPED}, /* + (SQ3) */ + {"ShakuVibMS", 79, SFX_UNMAPPED}, /* + (iceMan) */ + {"SlapBassMS", 36, SFX_UNMAPPED}, /* +++ (iceMan) */ + {"Snare MS", SFX_MAPPED_TO_RHYTHM, 37}, /* R (HQ) */ + {"Some Birds", 123, SFX_UNMAPPED}, /* + (CB) */ + {"Sonar MS", 78, SFX_UNMAPPED}, /* ? (iceMan) */ + {"Soundtrk2 ", 97, SFX_UNMAPPED}, /* +++ (CB) */ + {"Soundtrack", 97, SFX_UNMAPPED}, /* ++ (CoC) */ + {"SqurWaveMS", 80, SFX_UNMAPPED}, + {"StabBassMS", 34, SFX_UNMAPPED}, /* + (iceMan) */ + {"SteelDrmMS", 114, SFX_UNMAPPED}, /* +++ (iceMan) */ + {"StrSect1MS", 48, SFX_UNMAPPED}, /* ++ (HQ) */ + {"String MS", 45, SFX_UNMAPPED}, /* + (CoC) */ + {"Syn-Choir ", 91, SFX_UNMAPPED}, + {"Syn Brass4", 63, SFX_UNMAPPED}, /* ++ (PQ2) */ + {"SynBass MS", 38, SFX_UNMAPPED}, + {"SwmpBackgr", 120, SFX_UNMAPPED}, /* ?? (CB,HQ) */ + {"T-Bone2 MS", 57, SFX_UNMAPPED}, /* +++ (HQ) */ + {"Taiko ", 116, 34}, /* +++ (Coc) */ + {"Taiko Rim ", 118, 36}, /* +++ (LSL3) */ + {"Timpani1 ", 47, SFX_UNMAPPED}, /* +++ (CB) */ + {"Tom MS", 117, 47}, /* +++ (iceMan) */ + {"Toms MS", 117, 47}, /* +++ (CoC, HQ) */ + {"Tpt1prtl ", 56, SFX_UNMAPPED}, /* +++ (KQ1) */ + {"TriangleMS", 112, 80}, /* R (CoC) */ + {"Trumpet 1 ", 56, SFX_UNMAPPED}, /* +++ (CoC) */ + {"Type MS", 114, SFX_UNMAPPED}, /* ? (iceMan) */ + {"WaterBells", 98, SFX_UNMAPPED}, /* + (PQ2) */ + {"WaterFallK", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (KQ1) */ + {"Whiporill ", 123, SFX_UNMAPPED}, /* + (CB) */ + {"Wind ", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CB) */ + {"Wind MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (HQ, iceMan) */ + {"Wind2 MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CoC) */ + {"Woodpecker", 115, SFX_UNMAPPED}, /* ? (CB) */ + {"WtrFall MS", SFX_UNMAPPED, SFX_UNMAPPED}, /* ? (CoC, HQ, iceMan) */ + {0, 0} +}; + +static gint8 +lookup_instrument(char *iname) +{ + int i = 0; + + while (MT32_MemoryTimbreMaps[i].name) { + if (strncasecmp(iname, MT32_MemoryTimbreMaps[i].name, 10) == 0) + return MT32_MemoryTimbreMaps[i].gm_instr; + i++; + } + return SFX_UNMAPPED; +} + +static gint8 +lookup_rhythm_key(char *iname) +{ + int i = 0; + + while (MT32_MemoryTimbreMaps[i].name) { + if (strncasecmp(iname, MT32_MemoryTimbreMaps[i].name, 10) == 0) + return MT32_MemoryTimbreMaps[i].gm_rhythm_key; + i++; + } + return SFX_UNMAPPED; +} + +static void +print_map(int sci, int ins, int rhythm, int mt32) +{ +#ifdef DEBUG_MT32_TO_GM + if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { + sciprintf("[MT32-to-GM] No mapping available for [%i] `%s' (%i)\n", + sci, MT32_PresetTimbreMaps[mt32].name, mt32); + return; + } + + if (ins == SFX_MAPPED_TO_RHYTHM) { + sciprintf("[MT32-to-GM] Mapping [%i] `%s' (%i) to `%s' [R] (%i)\n", + sci, MT32_PresetTimbreMaps[mt32].name, mt32, + GM_Percussion_Names[rhythm], rhythm); + return; + } + + sciprintf("[MT32-to-GM] Mapping [%i] `%s' (%i) to `%s' (%i)\n", + sci, MT32_PresetTimbreMaps[mt32].name, mt32, + GM_Instrument_Names[ins], ins); +#endif +} + +static void +print_map_mem(int sci, int ins, int rhythm, char *mt32) +{ +#ifdef DEBUG_MT32_TO_GM + char name[11]; + + strncpy(name, mt32, 10); + name[10] = 0; + + if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { + sciprintf("[MT32-to-GM] No mapping available for [%i] `%s'\n", + sci, name); + return; + } + + if (ins == SFX_MAPPED_TO_RHYTHM) { + sciprintf("[MT32-to-GM] Mapping [%i] `%s' to `%s' [R] (%i)\n", + sci, name, GM_Percussion_Names[rhythm], rhythm); + return; + } + + sciprintf("[MT32-to-GM] Mapping [%i] `%s' to `%s' (%i)\n", + sci, name, GM_Instrument_Names[ins], ins); +#endif +} + +static void +print_map_rhythm(int sci, int ins, int rhythm, int mt32) +{ +#ifdef DEBUG_MT32_TO_GM + if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { + sciprintf("[MT32-to-GM] No mapping available for [%i] `%s' [R] (%i)\n", + sci, MT32_RhythmTimbreMaps[mt32].name, mt32); + return; + } + + if (ins == SFX_MAPPED_TO_RHYTHM) { + sciprintf("[MT32-to-GM] Mapping [%i] `%s' [R] (%i) to `%s' [R] (%i)\n", + sci, MT32_RhythmTimbreMaps[mt32].name, mt32, + GM_Percussion_Names[rhythm], rhythm); + return; + } + + sciprintf("[MT32-to-GM] Mapping [%i] `%s' [R] (%i) to `%s' (%i)\n", + sci, MT32_RhythmTimbreMaps[mt32].name, mt32, + GM_Instrument_Names[ins], ins); +#endif +} + +static void +print_map_rhythm_mem(int sci, int rhythm, char *mt32) +{ +#ifdef DEBUG_MT32_TO_GM + char name[11]; + + strncpy(name, mt32, 10); + name[10] = 0; + + if (rhythm == SFX_UNMAPPED) { + sciprintf("[MT32-to-GM] No mapping available for [%i] `%s'\n", + sci, name); + return; + } + + sciprintf("[MT32-to-GM] Mapping [%i] `%s' to `%s' (%i)\n", + sci, name, GM_Percussion_Names[rhythm], rhythm); +#endif +} + +sfx_instrument_map_t * +sfx_instrument_map_mt32_to_gm(byte *data, size_t size) +{ + int memtimbres, patches; + guint8 group, number, keyshift, finetune, bender_range; + guint8 *patchpointer; + guint32 pos; + sfx_instrument_map_t * map; + int i; + int type; + + map = sfx_instrument_map_new(0); + + for (i = 0; i < SFX_INSTRUMENTS_NR; i++) { + map->patch_map[i].patch = MT32_PresetTimbreMaps[i].gm_instr; + map->patch_key_shift[i] = 0; + map->patch_volume_adjust[i] = 0; + map->patch_bend_range[i] = 12; + map->velocity_map_index[i] = SFX_NO_VELOCITY_MAP; + } + + map->percussion_volume_adjust = 0; + map->percussion_velocity_map_index = SFX_NO_VELOCITY_MAP; + + for (i = 0; i < SFX_RHYTHM_NR; i++) { + map->percussion_map[i] = MT32_PresetRhythmKeymap[i]; + map->percussion_velocity_scale[i] = SFX_MAX_VELOCITY; + } + + if (!data) { + sciprintf("[MT32-to-GM] No MT-32 patch data supplied, using default mapping\n"); + return map; + } + + type = sfx_instrument_map_detect(data, size); + + if (type == SFX_MAP_UNKNOWN) { + sciprintf("[MT32-to-GM] Patch data format unknown, using default mapping\n"); + return map; + } + if (type == SFX_MAP_MT32_GM) { + sciprintf("[MT32-to-GM] Patch data format not supported, using default mapping\n"); + return map; + } + + memtimbres = *(data + 0x1EB); + pos = 0x1EC + memtimbres * 0xF6; + + if (size > pos && ((0x100 * *(data + pos) + *(data +pos + 1)) == 0xABCD)) { + patches = 96; + pos += 2 + 8 * 48; + } else + patches = 48; + + sciprintf("[MT32-to-GM] %d MT-32 Patches detected\n", patches); + sciprintf("[MT32-to-GM] %d MT-32 Memory Timbres\n", memtimbres); + + sciprintf("[MT32-to-GM] Mapping patches..\n"); + + for (i = 0; i < patches; i++) { + char *name; + + if (i < 48) + patchpointer = data + 0x6B + 8 * i; + else + patchpointer = data + 0x1EC + 8 * (i - 48) + memtimbres * 0xF6 + 2; + + group = *patchpointer; + number = *(patchpointer + 1); + keyshift = *(patchpointer + 2); + finetune = *(patchpointer + 3); + bender_range = *(patchpointer + 4); + + switch (group) { + case 0: + map->patch_map[i].patch = MT32_PresetTimbreMaps[number].gm_instr; + map->patch_map[i].rhythm = MT32_PresetTimbreMaps[number].gm_rhythm_key; + print_map(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number); + break; + case 1: + map->patch_map[i].patch = MT32_PresetTimbreMaps[number + 64].gm_instr; + map->patch_map[i].rhythm = MT32_PresetTimbreMaps[number + 64].gm_rhythm_key; + print_map(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number + 64); + break; + case 2: + name = (char *) data + 0x1EC + number * 0xF6; + map->patch_map[i].patch = lookup_instrument(name); + map->patch_map[i].rhythm = SFX_UNMAPPED; + print_map_mem(i, map->patch_map[i].patch, map->patch_map[i].rhythm, name); + break; + case 3: + map->patch_map[i].patch = MT32_RhythmTimbreMaps[number].gm_instr; + map->patch_map[i].rhythm = SFX_UNMAPPED; + print_map_rhythm(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number); + break; + default: + break; + } + + /* map->patch_key_shift[i] = (int) (keyshift & 0x3F) - 24; */ + map->patch_bend_range[i] = bender_range & 0x1F; + } + + if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xDCBA)) { + sciprintf("[MT32-to-GM] Mapping percussion..\n"); + + for (i = 0; i < 64 ; i++) { + number = *(data + pos + 4 * i + 2); + + if (number < 64) { + char *name = (char *) data + 0x1EC + number * 0xF6; + map->percussion_map[i + 23] = lookup_rhythm_key(name); + print_map_rhythm_mem(i, map->percussion_map[i + 23], name); + } else { + if (number < 94) { + map->percussion_map[i + 23] = MT32_RhythmTimbreMaps[number - 64].gm_rhythmkey; + print_map_rhythm(i, SFX_MAPPED_TO_RHYTHM, map->percussion_map[i + 23], number - 64); + } else + map->percussion_map[i + 23] = SFX_UNMAPPED; + } + + map->percussion_velocity_scale[i + 23] = *(data + pos + 4 * i + 3) * SFX_MAX_VELOCITY / 100; + } + } + + return map; +} + diff --git a/engines/sci/sfx/seq/mt32.c b/engines/sci/sfx/seq/mt32.c new file mode 100644 index 0000000000..b71d474927 --- /dev/null +++ b/engines/sci/sfx/seq/mt32.c @@ -0,0 +1,480 @@ +/*************************************************************************** + midi_mt32.c Copyright (C) 2000,2001 Rickard Lind, Solomon Peachy + mt32.c Copyright (C) 2002..04 Christoph Reichenbach + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + +***************************************************************************/ + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include "../sequencer.h" +#include "instrument-map.h" +#include <resource.h> + +#ifdef _WIN32 +# include <win32/sci_win32.h> +# include <windows.h> +#endif + +#ifdef __BEOS__ +# include <be/kernel/OS.h> +#endif + +static int delta = 0; /* Accumulated delta time */ +static midi_writer_t *midi_writer = NULL; + +static int midi_mt32_poke(guint32 address, guint8 *data, unsigned int n); +static int midi_mt32_poke_gather(guint32 address, guint8 *data1, unsigned int count1, + guint8 *data2, unsigned int count2); +static int midi_mt32_write_block(guint8 *data, unsigned int count); +static int midi_mt32_sysex_delay(void); +static int midi_mt32_volume(guint8 volume); +static int midi_mt32_reverb(int param); +static int midi_mt32_event(byte command, int argc, byte *argv); +static int midi_mt32_allstop(void); + +static int type; +static guint8 sysex_buffer[266] = {0xF0, 0x41, 0x10, 0x16, 0x12}; +static guint8 default_reverb; +static char shutdown_msg[20]; + +static long mt32_init_sec, mt32_init_usec; /* Time at initialisation */ +static int mt32_init_delay = 0; /* Used to count the number of ticks (1/60s of a second) we should + ** wait before initialisation has been completed */ + +/* timbre, volume, panpot, reverb. keys 24-87 (64 keys)*/ +static guint8 default_rhythm_keymap[256] = { /* MT-32 default */ + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, /* 24-27 */ + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x40,0x64,7,1, + 0x40,0x64,7,1, 0x4a,0x64,6,1, 0x41,0x64,7,1, 0x4b,0x64,8,1, + 0x45,0x64,6,1, 0x44,0x64,11,1, 0x46,0x64,6,1, 0x44,0x64,11,1, + 0x5d,0x64,6,1, 0x43,0x64,8,1, 0x47,0x64,6,1, 0x43,0x64,8,1, + 0x42,0x64,3,1, 0x48,0x64,6,1, 0x42,0x64,3,1, 0x49,0x64,8,1, + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x56,0x64,9,1, 0x7f,0x64,7,1, + 0x4c,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, + 0x52,0x64,2,1, 0x53,0x64,4,1, 0x4d,0x64,8,1, 0x4e,0x64,9,1, + 0x4f,0x64,10,1, 0x50,0x64,7,1, 0x51,0x64,5,1, 0x54,0x64,2,1, + 0x55,0x64,2,1, 0x5b,0x64,9,1, 0x58,0x64,4,1, 0x5a,0x64,9,1, + 0x59,0x64,9,1, 0x5c,0x64,10,1, 0x7f,0x64,7,1, 0x57,0x64,12,1, + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, + 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1, 0x7f,0x64,7,1 /* 84-87 */ +}; + +static guint8 default_partial_reserve[9] = { /* MT-32 DEFAULT */ + 3, 10, 6, 4, 3, 0, 0, 0, 6 }; + +static struct { + guint8 mode; + guint8 time; + guint8 level; +} mt32_reverb[11]; + + +static int +midiout_write_block(byte *buf, int len, int delta) +{ + if (delta) + midi_writer->delay(midi_writer, delta); + + return midi_writer->write(midi_writer, buf, len); +} + +/* The following is the result of some experimenting, trying to approach the MT32's processing speed */ +#define MAGIC_MIDIOUT_DELAY 40 + +static int +midiout_write_delayed_block(byte *buf, int len) + /* Only used for initial programming */ +{ + int rv = midiout_write_block(buf, len, 0); + int delay = 1 + (len / MAGIC_MIDIOUT_DELAY); + + midi_writer->delay(midi_writer, delay); + + mt32_init_delay += delay; /* Keep track of delay times */ + + return rv; +} + +/* send default rhythm map and reserve */ +int midi_mt32_defaults(guint8 volume, guint8 reverb) { + printf("MT-32: Writing Default Rhythm key map\n"); + midi_mt32_poke(0x030110, default_rhythm_keymap, 256); + + printf("MT-32: Writing Default Partial Reserve\n"); + midi_mt32_poke(0x100004, default_partial_reserve, 9); + + if (reverb) { + mt32_reverb[0].mode = 0; + mt32_reverb[0].time = 5; + mt32_reverb[0].level = 3; + default_reverb = 0; + + printf("MT-32: Setting up default reverb levels\n"); + midi_mt32_reverb(default_reverb); + } + + if (volume) { + printf("MT-32: Setting default volume (%d)\n", volume); + midi_mt32_volume(volume); + } + + return SFX_OK; +} + +int midi_mt32_open(int length, byte *data, int length2, byte *data2, void *dev) +{ + guint8 unknown_sysex[6] = {0x16, 0x16, 0x16, 0x16, 0x16, 0x16}; + guint8 i, memtimbres; + unsigned int block2, block3; + + if (!dev) { + fprintf(stderr, "Attempt to use MT-32 sequencer without device\n"); + return SFX_ERROR; + } + + sci_gettime(&mt32_init_sec, &mt32_init_usec); + + midi_writer = (midi_writer_t *) dev; + + midi_mt32_allstop(); + + if (!data) { + type = SFX_MAP_UNKNOWN; + sciprintf("MT-32: No patch.001 found, using defaults\n"); + } else { + type = sfx_instrument_map_detect(data, length); + if (type == SFX_MAP_UNKNOWN) + sciprintf("MT-32: Unknown patch.001 format, using defaults\n"); + else + sciprintf("MT-32: Programming Roland MT-32 with patch.001 (v%i) %d bytes\n", type, length); + } + + if (type == SFX_MAP_MT32) { + /* Display MT-32 initialization message */ + printf("MT-32: Displaying Text: \"%.20s\"\n", data + 20); + midi_mt32_poke(0x200000, data + 20, 20); + + /* Cache a copy of the shutdown message */ + memcpy(shutdown_msg, data + 40, 20); + + /* Write Patches (48 or 96) */ + memtimbres = data[491]; + block2 = (memtimbres * 246) + 492; + printf("MT-32: Writing Patches #01 - #32\n"); + midi_mt32_poke(0x050000, data + 107, 256); + if ((length > block2) && + data[block2] == 0xAB && + data[block2 + 1] == 0xCD) { + printf("MT-32: Writing Patches #33 - #64\n"); + midi_mt32_poke_gather(0x050200, data + 363, 128, data + block2 + 2, 128); + printf("MT-32: Writing Patches #65 - #96\n"); + midi_mt32_poke(0x050400, data + block2 + 130, 256); + block3 = block2 + 386; + } else { + printf("MT-32: Writing Patches #33 - #48\n"); + midi_mt32_poke(0x050200, data + 363, 128); + block3 = block2; + } + /* Write Memory Timbres */ + for (i = 0; i < memtimbres; i++) { + printf("MT-32: Writing Memory Timbre #%02d: \"%.10s\"\n", + i + 1, data + 492 + i * 246); + midi_mt32_poke(0x080000 + (i << 9), data + 492 + i * 246, 246); + } + /* Write Rhythm key map and Partial Reserve */ + if ((length > block3) && + data[block3] == 0xDC && + data[block3 + 1] == 0xBA) { + printf("MT-32: Writing Rhythm key map\n"); + midi_mt32_poke(0x030110, data + block3 + 2, 256); + printf("MT-32: Writing Partial Reserve\n"); + midi_mt32_poke(0x100004, data + block3 + 258, 9); + } else { + midi_mt32_defaults(0,0); /* send default keymap/reserve */ + } + /* Display MT-32 initialization done message */ + printf("MT-32: Displaying Text: \"%.20s\"\n", data); + midi_mt32_poke(0x200000, data, 20); + /* Write undocumented MT-32(?) SysEx */ + printf("MT-32: Writing {F0 41 10 16 12 52 00 0A 16 16 16 16 16 16 20 F7}\n"); + midi_mt32_poke(0x52000A, unknown_sysex, 6); + printf("MT-32: Setting up reverb levels\n"); + default_reverb = data[0x3e]; + memcpy(mt32_reverb,data+ 0x4a, 3 * 11); + midi_mt32_reverb(default_reverb); + printf("MT-32: Setting default volume (%d)\n", data[0x3c]); + midi_mt32_volume(data[0x3c]); + return 0; + } else if (type == SFX_MAP_MT32_GM) { + printf("MT-32: Loading SysEx bank\n"); + midi_mt32_write_block(data + 1155, (data[1154] << 8) + data[1153]); + return 0; + } else { + midi_mt32_poke(0x200000, (guint8 *)" FreeSCI Rocks! ", 20); + return midi_mt32_defaults(0x0c,1); /* send defaults in absence of patch data */ + } + return -1; +} + +int midi_mt32_close(void) +{ + midi_mt32_allstop(); + if (type == 0) { + printf("MT-32: Displaying Text: \"%.20s\"\n", shutdown_msg); + midi_mt32_poke(0x200000, (unsigned char *) shutdown_msg, 20); + } + midi_writer->close(midi_writer); + return SFX_OK; +} + +int midi_mt32_volume(guint8 volume) +{ + volume &= 0x7f; /* (make sure it's not over 127) */ + if (midi_mt32_poke(0x100016, &volume, 1) < 0) + return -1; + + return 0; +} + +int midi_mt32_allstop(void) +{ + byte buf[4]; + int i; + + buf[0] = 0x7b; + buf[1] = 0; + buf[2] = 0; + + for (i = 0; i < 16; i++) { + midi_mt32_event((guint8)(0xb0 | i), 2, buf); + } + + return 0; +} + +int midi_mt32_reverb(int param) +{ + guint8 buffer[3]; + + if (param == -1) + param = default_reverb; + + printf("MT-32: Sending reverb # %d (%d, %d, %d)\n",param, mt32_reverb[param].mode, + mt32_reverb[param].time, + mt32_reverb[param].level); + + buffer[0] = mt32_reverb[param].mode; + buffer[1] = mt32_reverb[param].time; + buffer[2] = mt32_reverb[param].level; + midi_mt32_poke(0x100001, buffer, 3); + + return 0; +} + + +static int +midi_mt32_poke(guint32 address, guint8 *data, unsigned int count) +{ + guint8 checksum = 0; + unsigned int i; + + if (count > 256) return -1; + + checksum -= (sysex_buffer[5] = (char)((address >> 16) & 0x7F)); + checksum -= (sysex_buffer[6] = (char)((address >> 8) & 0x7F)); + checksum -= (sysex_buffer[7] = (char)(address & 0x7F)); + + for (i = 0; i < count; i++) + checksum -= (sysex_buffer[i + 8] = data[i]); + + sysex_buffer[count + 8] = checksum & 0x7F; + sysex_buffer[count + 9] = 0xF7; + + midiout_write_delayed_block(sysex_buffer, count + 10); + if (midi_writer->flush) + midi_writer->flush(midi_writer); + midi_mt32_sysex_delay(); + + return count + 10; + +} + +static int +midi_mt32_poke_gather(guint32 address, guint8 *data1, unsigned int count1, + guint8 *data2, unsigned int count2) +{ + guint8 checksum = 0; + unsigned int i; + + if ((count1 + count2) > 256) return -1; + + checksum -= (sysex_buffer[5] = (char)((address >> 16) & 0x7F)); + checksum -= (sysex_buffer[6] = (char)((address >> 8) & 0x7F)); + checksum -= (sysex_buffer[7] = (char)(address & 0x7F)); + + for (i = 0; i < count1; i++) + checksum -= (sysex_buffer[i + 8] = data1[i]); + for (i = 0; i < count2; i++) + checksum -= (sysex_buffer[i + 8 + count1] = data2[i]); + + sysex_buffer[count1 + count2 + 8] = checksum & 0x7F; + sysex_buffer[count1 + count2 + 9] = 0xF7; + + midiout_write_delayed_block(sysex_buffer, count1 + count2 + 10); + if (midi_writer->flush) + midi_writer->flush(midi_writer); + midi_mt32_sysex_delay(); + return count1 + count2 + 10; +} + + +static int +midi_mt32_write_block(guint8 *data, unsigned int count) +{ + unsigned int block_start = 0; + unsigned int i = 0; + + while (i < count) { + if ((data[i] == 0xF0) && (i != block_start)) { + midiout_write_delayed_block(data + block_start, i - block_start); + block_start = i; + } + if (data[i] == 0xF7) { + midiout_write_delayed_block(data + block_start, i - block_start + 1); + midi_mt32_sysex_delay(); + block_start = i + 1; + } + i++; + } + if (count >= block_start) { + if (midiout_write_delayed_block(data + block_start, count - block_start + ) != (count - block_start)) { + fprintf(stderr, "midi_mt32_write_block(): midiout_write_block failed!\n"); + return 1; + } + } + + return 0; +} + +static int +midi_mt32_sysex_delay(void) +{ + /* Under Win32, we won't get any sound, in any case... */ +#ifdef HAVE_USLEEP + usleep(320 * 63); /* One MIDI byte is 320us, 320us * 63 > 20ms */ +#elif defined (_WIN32) + Sleep(((320 * 63) / 1000) + 1); +#elif defined (__BEOS__) + snooze(320 * 63); +#else + sleep(1); +#endif + return 0; +} + +static int +midi_mt32_event(byte command, int argc, byte *argv) +{ + byte buf[8]; + + buf[0] = command; + memcpy(buf + 1, argv, argc); + + midiout_write_block(buf, argc + 1, delta); + delta = 0; + + return SFX_OK; +} + + +static void +delay_init(void) +{/* Wait for MT-32 initialisation to complete */ + long endsec = mt32_init_sec, uendsec = mt32_init_usec; + long sec, usec; + int loopcount = 0; + + uendsec += (mt32_init_delay * 100000) / 6; /* mt32_init_delay is in ticks (1/60th seconds), uendsecs in microseconds */ + endsec += uendsec / 1000000; + uendsec %= 1000000; + + + do { + if (loopcount == 1) + sciprintf("Waiting for MT-32 programming to complete...\n"); + + sci_gettime(&sec, &usec); + sleep(1); /* Idle a bit */ + ++loopcount; + } while ((sec < endsec) || ((sec == endsec) && (usec < uendsec))); + +} + +static int +midi_mt32_reset_timer(GTimeVal ts) +{ + if (mt32_init_delay) { /* We might still have to wait for initialisation to complete */ + delay_init(); + mt32_init_delay = 0; + } + + + midi_writer->reset_timer(midi_writer); + return SFX_OK; +} + + +static int +midi_mt32_delay(int ticks) +{ + delta += ticks; /* Accumulate, write before next command */ + return SFX_OK; +} + +static int +midi_mt32_set_option(char *name, char *value) +{ + return SFX_ERROR; /* No options are supported at this time */ +} + +/* the driver struct */ + +sfx_sequencer_t sfx_sequencer_mt32 = { + "MT32", + "0.1", + SFX_DEVICE_MIDI, /* No device dependancy-- fixme, this might becomde ossseq */ + &midi_mt32_set_option, + &midi_mt32_open, + &midi_mt32_close, + &midi_mt32_event, + &midi_mt32_delay, + &midi_mt32_reset_timer, + &midi_mt32_allstop, + &midi_mt32_volume, + &midi_mt32_reverb, + 001, /* patch.001 */ + SFX_SEQ_PATCHFILE_NONE, + 0x01, /* playflag */ + 1, /* do play channel 9 */ + 32, /* Max polyphony */ + 0 /* Does not require any write-ahead by its own */ +}; diff --git a/engines/sci/sfx/seq/oss-adlib.c b/engines/sci/sfx/seq/oss-adlib.c new file mode 100644 index 0000000000..0406556f56 --- /dev/null +++ b/engines/sci/sfx/seq/oss-adlib.c @@ -0,0 +1,374 @@ +/*************************************************************************** + oss-adlib.c Copyright (C) 2001 Solomon Peachy, 03,04 Christoph Reichenbach + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + +***************************************************************************/ + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include "../sequencer.h" + +#ifdef HAVE_SYS_SOUNDCARD_H + +#include "../adlib.h" + +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/soundcard.h> +#include <sfx_iterator.h> /* for some MIDI information */ + +#if 1 +SEQ_DEFINEBUF(2048); +static int seqfd; +#else +extern unsigned char _seqbuf[2048]; +extern int _seqbuflen; +extern int _seqbufptr; +extern int seqfd; +#endif + +static guint8 instr[MIDI_CHANNELS]; +static int dev; +static int free_voices = ADLIB_VOICES; +static long note_time[ADLIB_VOICES]; +static unsigned char oper_note[ADLIB_VOICES]; +static unsigned char oper_chn[ADLIB_VOICES]; + +#if 1 +void seqbuf_dump(void) /* OSS upcall */ +{ + if (_seqbufptr) + if (write(seqfd, _seqbuf, _seqbufptr) == -1) { + perror("ADLIB write "); + exit(-1); + } + _seqbufptr = 0; +} +#endif + +/* initialise note/operator lists, etc. */ +void adlib_init_lists(void) +{ + int i; + for(i = 0 ; i < ADLIB_VOICES ; i++) { + oper_note[i] = 255; + oper_chn[i] = 255; + note_time[i] = 0; + } + free_voices = ADLIB_VOICES; +} + +int adlib_stop_note(int chn, int note, int velocity) +{ + int i, op=255; + + for (i=0;i<ADLIB_VOICES && op==255;i++) { + if (oper_chn[i] == chn) + if (oper_note[i] == note) + op=i; + } + + if (op==255) { + printf ("can't stop.. chn %d %d %d\n", chn, note, velocity); + return 255; /* not playing */ + } + + SEQ_STOP_NOTE(dev, op, note, velocity); + SEQ_DUMPBUF(); + + oper_chn[op] = 255; + oper_note[op] = 255; + note_time[op] = 0; + + free_voices++; + + return op; +} + +int adlib_kill_one_note(int chn) +{ + int oldest = 255, i = 255; + long time = 0; + + if (free_voices >= ADLIB_VOICES) { + printf("Free list empty but no notes playing\n"); + return 255; + } /* No notes playing */ + + for (i = 0; i < ADLIB_VOICES ; i++) { + if (oper_chn[i] != chn) + continue; + if (note_time[i] == 0) + continue; + if (time == 0) { + time = note_time[i]; + oldest = i; + continue; + } + if (note_time[i] < time) { + time = note_time[i]; + oldest = i; + } + } + + /* printf("Killing chn %d, oper %d\n", chn, oldest); */ + + if (oldest == 255) + return 255; /* Was already stopped. Why? */ + + SEQ_STOP_NOTE(dev, oldest, oper_note[oldest], 0); + SEQ_DUMPBUF(); + + oper_chn[oldest] = 255; + oper_note[oldest] = 255; + note_time[oldest] = 0; + free_voices++; + + return oldest; +} + +static void +adlib_start_note(int chn, int note, int velocity) +{ + int free; + struct timeval now; + + if (velocity == 0) { + adlib_stop_note(chn, note, velocity); + return; + } + + gettimeofday(&now, NULL); + + if (free_voices <= 0) + free = adlib_kill_one_note(chn); + else + for (free = 0; free < ADLIB_VOICES ; free++) + if (oper_chn[free] == 255) + break; + + /* printf("play operator %d/%d: %d %d %d\n", free, free_voices, chn, note, velocity); */ + + oper_chn[free] = chn; + oper_note[free] = note; + note_time[free] = now.tv_sec * 1000000 + now.tv_usec; + free_voices--; + + SEQ_SET_PATCH(dev, free, instr[chn]); + SEQ_START_NOTE(dev, free, note, velocity); + SEQ_DUMPBUF(); +} + +static int +midi_adlib_open(int data_length, byte *data_ptr, int data2_length, + byte *data2_ptr, void *seq) +{ + int nrdevs, i, n; + struct synth_info info; + struct sbi_instrument sbi; + + if (data_length < 1344) { + printf ("invalid patch.003"); + return -1; + } + + for (i = 0; i < 48; i++) + make_sbi((adlib_def *)(data_ptr+(28 * i)), adlib_sbi[i]); + + if (data_length > 1344) + for (i = 48; i < 96; i++) + make_sbi((adlib_def *)(data_ptr+2+(28 * i)), adlib_sbi[i]); + + memset(instr, 0, sizeof(instr)); + + if (!IS_VALID_FD(seqfd=open("/dev/sequencer", O_WRONLY, 0))) { + perror("/dev/sequencer"); + return(-1); + } + if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &nrdevs) == -1) { + perror("/dev/sequencer"); + return(-1); + } + for (i=0;i<nrdevs && dev==-1;i++) { + info.device = i; + if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &info)==-1) { + perror("info: /dev/sequencer"); + return(-1); + } + if (info.synth_type == SYNTH_TYPE_FM) + dev = i; + } + if (dev == -1) { + fprintf(stderr, "ADLIB: FM synthesizer not detected\n"); + return(-1); + } + + /* free_voices = info.nr_voices; */ + adlib_init_lists(); + + printf("ADLIB: Loading patches into synthesizer\n"); + sbi.device = dev; + sbi.key = FM_PATCH; + for (i = 0; i < 96; i++) { + for (n = 0; n < 32; n++) + memcpy(sbi.operators, &adlib_sbi[i], sizeof(sbi_instr_data)); + sbi.channel=i; + SEQ_WRPATCH(&sbi, sizeof(sbi)); + SEQ_DUMPBUF(); + } + SEQ_START_TIMER(); + SEQ_SET_TEMPO(60); + SEQ_DUMPBUF(); + return 0; +} + + +static int +midi_adlib_close(void) +{ + SEQ_DUMPBUF(); + return close(seqfd); +} + + +static int +midi_adlib_allstop(void) +{ + int i; + for (i = 0; i < ADLIB_VOICES ; i++) { + if (oper_chn[i] == 255) + continue; + adlib_stop_note(oper_chn[i], oper_note[i], 0); + } + adlib_init_lists(); + + return 0; +} + +static int +midi_adlib_reverb(int param) +{ + printf("reverb NYI %04x \n", param); + return 0; +} + +static inline int +midi_adlib_event1(guint8 command, guint8 note, guint8 velocity) +{ + guint8 channel, oper; + + channel = command & 0x0f; + oper = command & 0xf0; + + switch (oper) { + case 0x80: + adlib_stop_note(channel, note, velocity); + return 0; + case 0x90: + adlib_start_note(channel,note,velocity); + return 0; + case 0xe0: /* Pitch bend needs scaling? */ + SEQ_BENDER(dev, channel, ((note << 8) & velocity)); + SEQ_DUMPBUF(); + break; + case 0xb0: /* CC changes. we ignore. */ + /* XXXX we need to parse out 0x07 volume, at least. */ + return 0; + case 0xd0: /* aftertouch */ + SEQ_CHN_PRESSURE(dev, channel, note); + SEQ_DUMPBUF(); + return 0; + default: + printf("ADLIB: Unknown event %02x\n", command); + return 0; + } + + SEQ_DUMPBUF(); + return 0; +} + +static inline int +midi_adlib_event2(guint8 command, guint8 param) +{ + guint8 channel; + guint8 oper; + + channel = command & 0x0f; + oper = command & 0xf0; + switch (oper) { + case 0xc0: { /* change instrument */ + int inst = param; + instr[channel] = inst; /* XXXX offset? */ + // SEQ_SET_PATCH(dev, channel, inst); + // SEQ_DUMPBUF(); + return 0; + } + default: + printf("ADLIB: Unknown event %02x\n", command); + } + + SEQ_DUMPBUF(); + return 0; +} + +static int +midi_adlib_event(byte command, int argc, byte *argv) +{ + if (argc > 1) + return midi_adlib_event1(command, argv[0], argv[1]); + else + return midi_adlib_event2(command, argv[0]); +} + +static int +midi_adlib_delay(int ticks) +{ + SEQ_DELTA_TIME(ticks); + return SFX_OK; +} + +static int +midi_adlib_set_option(char *name, char *value) +{ + return SFX_ERROR; /* No options are supported at this time */ +} + +/* the driver struct */ + +sfx_sequencer_t sfx_sequencer_oss_adlib = { + "adlib", + "0.1", + SFX_DEVICE_NONE, /* No device dependancy-- fixme, this might become ossseq */ + &midi_adlib_set_option, + &midi_adlib_open, + &midi_adlib_close, + &midi_adlib_event, + &midi_adlib_delay, + NULL, + &midi_adlib_allstop, + NULL, + &midi_adlib_reverb, + 003, /* patch.003 */ + SFX_SEQ_PATCHFILE_NONE, + 0x04, /* playflag */ + 0, /* do not play channel 9 */ + ADLIB_VOICES, /* Max polyphony */ + 0 /* Does not require any write-ahead by its own */ +}; + +#endif /* HAVE_SYS_SOUNDCARD_H */ diff --git a/engines/sci/sfx/seq/sequencers.c b/engines/sci/sfx/seq/sequencers.c new file mode 100644 index 0000000000..cb43381fa9 --- /dev/null +++ b/engines/sci/sfx/seq/sequencers.c @@ -0,0 +1,68 @@ +/*************************************************************************** + sequencers.c Copyright (C) 2004 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include "../sequencer.h" +#include <resource.h> + +#ifndef SCUMMVM +extern sfx_sequencer_t sfx_sequencer_gm; +extern sfx_sequencer_t sfx_sequencer_mt32; +#ifdef HAVE_SYS_SOUNDCARD_H +extern sfx_sequencer_t sfx_sequencer_oss_adlib; +#endif +#endif // SCUMMVM + +sfx_sequencer_t *sfx_sequencers[] = { +#ifndef SCUMMVM + &sfx_sequencer_gm, + &sfx_sequencer_mt32, +#ifdef HAVE_SYS_SOUNDCARD_H + &sfx_sequencer_oss_adlib, +#endif +#endif // SCUMMVM + NULL +}; + + +sfx_sequencer_t * +sfx_find_sequencer(char *name) +{ + if (!name) { + /* Implement default policy for your platform (if any) here, or in a function + ** called from here (if it's non-trivial). Try to use midi_devices[0], if + ** feasible. */ + + return sfx_sequencers[0]; /* default */ + } else { + int n = 0; + while (sfx_sequencers[n] + && strcasecmp(sfx_sequencers[n]->name, name)) + ++n; + + return sfx_sequencers[n]; + } +} |