aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sfx/seq
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sfx/seq')
-rw-r--r--engines/sci/sfx/seq/Makefile.am5
-rw-r--r--engines/sci/sfx/seq/gm.c185
-rw-r--r--engines/sci/sfx/seq/instrument-map.c539
-rw-r--r--engines/sci/sfx/seq/instrument-map.h132
-rw-r--r--engines/sci/sfx/seq/map-mt32-to-gm.c813
-rw-r--r--engines/sci/sfx/seq/mt32.c480
-rw-r--r--engines/sci/sfx/seq/oss-adlib.c374
-rw-r--r--engines/sci/sfx/seq/sequencers.c68
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];
+ }
+}