diff options
Diffstat (limited to 'engines/sci/sfx/old/midi_mt32.c')
-rw-r--r-- | engines/sci/sfx/old/midi_mt32.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/engines/sci/sfx/old/midi_mt32.c b/engines/sci/sfx/old/midi_mt32.c new file mode 100644 index 0000000000..be5550bd93 --- /dev/null +++ b/engines/sci/sfx/old/midi_mt32.c @@ -0,0 +1,341 @@ +/*************************************************************************** + midi_mt32.c Copyright (C) 2000 Rickard Lind + + + 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 "glib.h" +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "midi_mt32.h" +#include "midiout.h" + +#define RHYTHM_CHANNEL 9 + +int midi_mt32_poke(guint32 address, guint8 *data, unsigned int n); +int midi_mt32_poke_gather(guint32 address, guint8 *data1, unsigned int count1, + guint8 *data2, unsigned int count2); +int midi_mt32_write_block(guint8 *data, unsigned int count); +int midi_mt32_patch001_type(guint8 *data, unsigned int length); +int midi_mt32_patch001_type0_length(guint8 *data, unsigned int length); +int midi_mt32_patch001_type1_length(guint8 *data, unsigned int length); +int midi_mt32_sysex_delay(); + +static guint8 *data; +static unsigned int length; +static int type; +static guint8 sysex_buffer[266] = {0xF0, 0x41, 0x10, 0x16, 0x12}; + +static gint8 patch_map[128] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}; +static gint8 keyshift[128] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static gint8 volume_adjust[128] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static guint8 velocity_map_index[128] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static guint8 velocity_map[4][128] = { + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}, + {0,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39, + 39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47, + 47,48,48,49,49,50,50,51,51,52,52,53,53,54,54,55, + 55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}, + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,66,67,67,68,68,69,69,70,70,71,71,72,72, + 73,73,74,74,75,75,76,76,77,77,78,78,79,79,80,80, + 81,81,82,82,83,83,84,84,85,85,86,86,87,87,88,88, + 89,89,90,90,91,91,92,92,93,93,94,94,95,95,96,96}, + {0,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39, + 39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47, + 47,48,48,49,49,50,50,51,51,52,52,53,53,54,54,55, + 55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63, + 64,65,66,66,67,67,68,68,69,69,70,70,71,71,72,72, + 73,73,74,74,75,75,76,76,77,77,78,78,79,79,80,80, + 81,81,82,82,83,83,84,84,85,85,86,86,87,87,88,88, + 89,89,90,90,91,91,92,92,93,93,94,94,95,95,96,96}}; +static gint8 rhythmkey_map[128] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,-1,-1,54,-1,56,-1,-1,-1,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,-1,75,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; +/* static struct { + gint8 sci_patch; + gint8 sci_volume; + gint8 sci_pitchwheel; + gint8 patch; + gint8 keyshift; + gint8 volume_adjust; + guint8 velocity_map_index; + guint8 +} channel[16]; */ +static guint8 master_volume; + +int midi_mt32_open(guint8 *data_ptr, unsigned int data_length) +{ + guint8 unknown_sysex[6] = {0x16, 0x16, 0x16, 0x16, 0x16, 0x16}; + guint8 i, memtimbres; + unsigned int block2, block3; + + if (midiout_open() < 0) + return -1; + + data = data_ptr; + length = data_length; + + type = midi_mt32_patch001_type(data, length); + printf("MT-32: Programming Roland MT-32 with patch.001 (v%i)\n", type); + + if (type == 0) { + /* Display MT-32 initialization message */ + printf("MT-32: Displaying Text: \"%.20s\"\n", data + 20); + midi_mt32_poke(0x200000, data + 20, 20); + midi_mt32_sysex_delay(); + + /* 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); + midi_mt32_sysex_delay(); + 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); + midi_mt32_sysex_delay(); + printf("MT-32: Writing Patches #65 - #96\n"); + midi_mt32_poke(0x050400, data + block2 + 130, 256); + midi_mt32_sysex_delay(); + block3 = block2 + 386; + } else { + printf("MT-32: Writing Patches #33 - #48\n"); + midi_mt32_poke(0x050200, data + 363, 128); + midi_mt32_sysex_delay(); + 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); + midi_mt32_sysex_delay(); + } + /* 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); + midi_mt32_sysex_delay(); + printf("MT-32: Writing Partial Reserve\n"); + midi_mt32_poke(0x100004, data + block3 + 258, 9); + midi_mt32_sysex_delay(); + } + /* Display MT-32 initialization done message */ + printf("MT-32: Displaying Text: \"%.20s\"\n", data); + midi_mt32_poke(0x200000, data, 20); + midi_mt32_sysex_delay(); + /* 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); + midi_mt32_sysex_delay(); + return 0; + } else if (type == 1) { + midi_mt32_write_block(data + 1155, (data[1154] << 8) + data[1153]); + memcpy(patch_map, data, 128); + memcpy(keyshift, data + 128, 128); + memcpy(volume_adjust, data + 256, 128); + memcpy(velocity_map_index, data + 513, 128); + for (i = 0; i < 4; i++) + memcpy(velocity_map[i], data + 641 + i * 128, 128); + memcpy(rhythmkey_map, data + 384, 128); + return 0; + } + return -1; +} + +int midi_mt32_close() +{ +if (type == 0) { + printf("MT-32: Displaying Text: \"%.20s\"\n", data + 40); + midi_mt32_poke(0x200000, data + 40, 20); + midi_mt32_sysex_delay(); +} +return midiout_close(); +} + +int midi_mt32_noteoff(guint8 channel, guint8 note) +{ + return 0; +} + +int midi_mt32_noteon(guint8 channel, guint8 note, guint8 velocity) +{ +/* guint8 buffer[3] = {0x90}; + if (channel == RHYTHM_CHANNEL) + if (rhythmkey_map[note] == -1) + return 0; + else { + buffer[0] |= channel + buffer[1] = rhythmkey_map[note]; + buffer[2] = velo + midi_write_event(buffer, 3); + }; */ + return 0; +} + +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; + + return midiout_write_block(sysex_buffer, count + 10); +} + +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; + + return midiout_write_block(sysex_buffer, count1 + count2 + 10); +} + +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_block(data + block_start, i - block_start); + block_start = i; + } + if (data[i] == 0xF7) { + midiout_write_block(data + block_start, i - block_start + 1); + midi_mt32_sysex_delay(); + block_start = i + 1; + } + i++; + } + if (count >= block_start) + midiout_write_block(data + block_start, count - block_start); + return 0; +} + +int midi_mt32_patch001_type(guint8 *data, unsigned int length) +{ + /* length test */ + if (length < 1155) + return 0; + if (length > 16889) + return 1; + if (midi_mt32_patch001_type0_length(data, length) && + !midi_mt32_patch001_type1_length(data, length)) + return 0; + if (midi_mt32_patch001_type1_length(data, length) && + !midi_mt32_patch001_type0_length(data, length)) + return 1; + return -1; +} + +int midi_mt32_patch001_type0_length(guint8 *data, unsigned int length) +{ + unsigned int pos = 492 + 246 * data[491]; + + if ((length >= (pos + 386)) && (data[pos] == 0xAB) && (data[pos + 1] == 0xCD)) + pos += 386; + if ((length >= (pos + 267)) && (data[pos] == 0xDC) && (data[pos + 1] == 0xBA)) + pos += 267; + if (pos == length) + return 1; + return 0; +} + +int midi_mt32_patch001_type1_length(guint8 *data, unsigned int length) +{ + if ((length >= 1155) && (((data[1154] << 8) + data[1153] + 1155) == length)) + return 1; + return 0; +} + +int midi_mt32_sysex_delay() +{ + usleep(320 * 63); /* One MIDI byte is 320us, 320us * 63 > 20ms */ + return 0; +} |