aboutsummaryrefslogtreecommitdiff
path: root/backends/midi
diff options
context:
space:
mode:
Diffstat (limited to 'backends/midi')
-rw-r--r--backends/midi/adlib.cpp1509
-rw-r--r--backends/midi/emumidi.h107
-rw-r--r--backends/midi/mt32.cpp486
-rw-r--r--backends/midi/mt32/.cvsignore1
-rw-r--r--backends/midi/mt32/freeverb.cpp312
-rw-r--r--backends/midi/mt32/freeverb.h240
-rw-r--r--backends/midi/mt32/i386.cpp817
-rw-r--r--backends/midi/mt32/i386.h49
-rw-r--r--backends/midi/mt32/module.mk17
-rw-r--r--backends/midi/mt32/mt32_file.cpp112
-rw-r--r--backends/midi/mt32/mt32_file.h67
-rw-r--r--backends/midi/mt32/mt32emu.h70
-rw-r--r--backends/midi/mt32/part.cpp603
-rw-r--r--backends/midi/mt32/part.h104
-rw-r--r--backends/midi/mt32/partial.cpp912
-rw-r--r--backends/midi/mt32/partial.h142
-rw-r--r--backends/midi/mt32/partialManager.cpp266
-rw-r--r--backends/midi/mt32/partialManager.h54
-rw-r--r--backends/midi/mt32/structures.h282
-rw-r--r--backends/midi/mt32/synth.cpp1048
-rw-r--r--backends/midi/mt32/synth.h200
-rw-r--r--backends/midi/mt32/tables.cpp729
-rw-r--r--backends/midi/mt32/tables.h101
-rw-r--r--backends/midi/ym2612.cpp907
24 files changed, 0 insertions, 9135 deletions
diff --git a/backends/midi/adlib.cpp b/backends/midi/adlib.cpp
deleted file mode 100644
index 1c4e4cf35f..0000000000
--- a/backends/midi/adlib.cpp
+++ /dev/null
@@ -1,1509 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2001-2004 The ScummVM project
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * $Header$
- */
-
-#include "emumidi.h"
-#include "common/util.h"
-#include "sound/fmopl.h"
-
-#ifdef DEBUG_ADLIB
-static int tick;
-#endif
-
-class MidiDriver_ADLIB;
-struct AdlibVoice;
-
-struct InstrumentExtra {
- byte a, b, c, d, e, f, g, h;
-};
-
-struct AdlibInstrument {
- byte flags_1;
- byte oplvl_1;
- byte atdec_1;
- byte sustrel_1;
- byte waveform_1;
- byte flags_2;
- byte oplvl_2;
- byte atdec_2;
- byte sustrel_2;
- byte waveform_2;
- byte feedback;
- byte flags_a;
- InstrumentExtra extra_a;
- byte flags_b;
- InstrumentExtra extra_b;
- byte duration;
-
- AdlibInstrument() { memset(this, 0, sizeof(AdlibInstrument)); }
-};
-
-class AdlibPart : public MidiChannel {
- friend class MidiDriver_ADLIB;
-
-protected:
-// AdlibPart *_prev, *_next;
- AdlibVoice *_voice;
- int16 _pitchbend;
- byte _pitchbend_factor;
- int8 _transpose_eff;
- byte _vol_eff;
- int8 _detune_eff;
- byte _modwheel;
- bool _pedal;
- byte _program;
- byte _pri_eff;
- AdlibInstrument _part_instr;
-
-protected:
- MidiDriver_ADLIB *_owner;
- bool _allocated;
- byte _channel;
-
- void init(MidiDriver_ADLIB *owner, byte channel);
- void allocate() { _allocated = true; }
-
-public:
- AdlibPart() {
- _voice = 0;
- _pitchbend = 0;
- _pitchbend_factor = 2;
- _transpose_eff = 0;
- _vol_eff = 0;
- _detune_eff = 0;
- _modwheel = 0;
- _pedal = 0;
- _program = 0;
- _pri_eff = 0;
-
- _owner = 0;
- _allocated = false;
- _channel = 0;
- }
-
- MidiDriver *device();
- byte getNumber() { return _channel; }
- void release() { _allocated = false; }
-
- void send (uint32 b);
-
- // Regular messages
- void noteOff(byte note);
- void noteOn(byte note, byte velocity);
- void programChange(byte program);
- void pitchBend(int16 bend);
-
- // Control Change messages
- void controlChange(byte control, byte value);
- void modulationWheel(byte value);
- void volume(byte value);
- void panPosition(byte value) { return; } // Not supported
- void pitchBendFactor(byte value);
- void detune(byte value);
- void priority(byte value);
- void sustain(bool value);
- void effectLevel(byte value) { return; } // Not supported
- void chorusLevel(byte value) { return; } // Not supported
- void allNotesOff();
-
- // SysEx messages
- void sysEx_customInstrument(uint32 type, byte *instr);
-};
-
-// FYI (Jamieson630)
-// It is assumed that any invocation to AdlibPercussionChannel
-// will be done through the MidiChannel base class as opposed to the
-// AdlibPart base class. If this were NOT the case, all the functions
-// listed below would need to be virtual in AdlibPart as well as MidiChannel.
-class AdlibPercussionChannel : public AdlibPart {
- friend class MidiDriver_ADLIB;
-
-protected:
- void init(MidiDriver_ADLIB *owner, byte channel);
-
-public:
- void noteOff(byte note);
- void noteOn(byte note, byte velocity);
- void programChange(byte program) { }
- void pitchBend(int16 bend) { }
-
- // Control Change messages
- void controlChange(byte control, byte value) { }
- void modulationWheel(byte value) { }
- void pitchBendFactor(byte value) { }
- void detune(byte value) { }
- void priority(byte value) { }
- void sustain(bool value) { }
-
- // SysEx messages
- void sysEx_customInstrument(uint32 type, byte *instr) { }
-};
-
-struct Struct10 {
- byte active;
- int16 cur_val;
- int16 count;
- uint16 max_value;
- int16 start_value;
- byte loop;
- byte table_a[4];
- byte table_b[4];
- int8 unk3;
- int8 modwheel;
- int8 modwheel_last;
- uint16 speed_lo_max;
- uint16 num_steps;
- int16 speed_hi;
- int8 direction;
- uint16 speed_lo;
- uint16 speed_lo_counter;
-};
-
-struct Struct11 {
- int16 modify_val;
- byte param, flag0x40, flag0x10;
- Struct10 *s10;
-};
-
-struct AdlibVoice {
- AdlibPart *_part;
- AdlibVoice *_next, *_prev;
- byte _waitforpedal;
- byte _note;
- byte _channel;
- byte _twochan;
- byte _vol_1, _vol_2;
- int16 _duration;
-
- Struct10 _s10a;
- Struct11 _s11a;
- Struct10 _s10b;
- Struct11 _s11b;
-
- AdlibVoice() { memset(this, 0, sizeof(AdlibVoice)); }
-};
-
-struct AdlibSetParams {
- byte a, b, c, d;
-};
-
-static const byte channel_mappings[9] = {
- 0, 1, 2, 8,
- 9, 10, 16, 17,
- 18
-};
-
-static const byte channel_mappings_2[9] = {
- 3, 4, 5, 11,
- 12, 13, 19, 20,
- 21
-};
-
-static const AdlibSetParams adlib_setparam_table[] = {
- {0x40, 0, 63, 63}, // level
- {0xE0, 2, 0, 0}, // unused
- {0x40, 6, 192, 0}, // level key scaling
- {0x20, 0, 15, 0}, // modulator frequency multiple
- {0x60, 4, 240, 15}, // attack rate
- {0x60, 0, 15, 15}, // decay rate
- {0x80, 4, 240, 15}, // sustain level
- {0x80, 0, 15, 15}, // release rate
- {0xE0, 0, 3, 0}, // waveform select
- {0x20, 7, 128, 0}, // amp mod
- {0x20, 6, 64, 0}, // vib
- {0x20, 5, 32, 0}, // eg typ
- {0x20, 4, 16, 0}, // ksr
- {0xC0, 0, 1, 0}, // decay alg
- {0xC0, 1, 14, 0} // feedback
-};
-
-const byte param_table_1[16] = {
- 29, 28, 27, 0,
- 3, 4, 7, 8,
- 13, 16, 17, 20,
- 21, 30, 31, 0
-};
-
-const uint16 maxval_table[16] = {
- 0x2FF, 0x1F, 0x7, 0x3F,
- 0x0F, 0x0F, 0x0F, 0x3,
- 0x3F, 0x0F, 0x0F, 0x0F,
- 0x3, 0x3E, 0x1F, 0
-};
-
-static const uint16 num_steps_table[] = {
- 1, 2, 4, 5,
- 6, 7, 8, 9,
- 10, 12, 14, 16,
- 18, 21, 24, 30,
- 36, 50, 64, 82,
- 100, 136, 160, 192,
- 240, 276, 340, 460,
- 600, 860, 1200, 1600
-};
-
-static const byte note_to_f_num[] = {
- 90, 91, 92, 92, 93, 94, 94, 95,
- 96, 96, 97, 98, 98, 99, 100, 101,
- 101, 102, 103, 104, 104, 105, 106, 107,
- 107, 108, 109, 110, 111, 111, 112, 113,
- 114, 115, 115, 116, 117, 118, 119, 120,
- 121, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 132, 133, 134,
- 135, 136, 137, 138, 139, 140, 141, 142,
- 143, 145, 146, 147, 148, 149, 150, 151,
- 152, 153, 154, 155, 157, 158, 159, 160,
- 161, 162, 163, 165, 166, 167, 168, 169,
- 171, 172, 173, 174, 176, 177, 178, 180,
- 181, 182, 184, 185, 186, 188, 189, 190,
- 192, 193, 194, 196, 197, 199, 200, 202,
- 203, 205, 206, 208, 209, 211, 212, 214,
- 215, 217, 218, 220, 222, 223, 225, 226,
- 228, 230, 231, 233, 235, 236, 238, 240,
- 242, 243, 245, 247, 249, 251, 252, 254,
-};
-
-static const byte map_gm_to_fm[128][30] = {
- // 0x00
-{ 0xC2, 0xC5, 0x2B, 0x99, 0x58, 0xC2, 0x1F, 0x1E, 0xC8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x23 },
-{ 0x22, 0x53, 0x0E, 0x8A, 0x30, 0x14, 0x06, 0x1D, 0x7A, 0x5C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x06, 0x00, 0x1C, 0x79, 0x40, 0x02, 0x00, 0x4B, 0x79, 0x58, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x89, 0x2A, 0x89, 0x49, 0xC2, 0x16, 0x1C, 0xB8, 0x7C, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x23 },
-{ 0xC2, 0x17, 0x3D, 0x6A, 0x00, 0xC4, 0x2E, 0x2D, 0xC9, 0x20, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x06, 0x1E, 0x1C, 0x99, 0x00, 0x02, 0x3A, 0x4C, 0x79, 0x00, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x84, 0x40, 0x3B, 0x5A, 0x6F, 0x81, 0x0E, 0x3B, 0x5A, 0x7F, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x84, 0x40, 0x3B, 0x5A, 0x63, 0x81, 0x00, 0x3B, 0x5A, 0x7F, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x8C, 0x80, 0x05, 0xEA, 0x59, 0x82, 0x0A, 0x3C, 0xAA, 0x64, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x85, 0x40, 0x0D, 0xEC, 0x71, 0x84, 0x58, 0x3E, 0xCB, 0x7C, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x8A, 0xC0, 0x0C, 0xDC, 0x50, 0x88, 0x58, 0x3D, 0xDA, 0x7C, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC9, 0x40, 0x2B, 0x78, 0x42, 0xC2, 0x04, 0x4C, 0x8A, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x1A },
-{ 0x2A, 0x0E, 0x17, 0x89, 0x28, 0x22, 0x0C, 0x1B, 0x09, 0x70, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE7, 0x9B, 0x08, 0x08, 0x26, 0xE2, 0x06, 0x0A, 0x08, 0x70, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC5, 0x05, 0x00, 0xFC, 0x40, 0x84, 0x00, 0x00, 0xDC, 0x50, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x86, 0x40, 0x5D, 0x5A, 0x41, 0x81, 0x00, 0x0B, 0x5A, 0x7F, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x10
-{ 0xED, 0x00, 0x7B, 0xC8, 0x40, 0xE1, 0x99, 0x4A, 0xE9, 0x7E, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE8, 0x4F, 0x3A, 0xD7, 0x7C, 0xE2, 0x97, 0x49, 0xF9, 0x7D, 0x05, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x10, 0x2F, 0xF7, 0x7D, 0xF3, 0x45, 0x8F, 0xC7, 0x62, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x01, 0x8C, 0x9F, 0xDA, 0x70, 0xE4, 0x50, 0x9F, 0xDA, 0x6A, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x08, 0xD5, 0x9D, 0xA5, 0x45, 0xE2, 0x3F, 0x9F, 0xD6, 0x49, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE5, 0x0F, 0x7D, 0xB8, 0x2E, 0xA2, 0x0F, 0x7C, 0xC7, 0x61, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x2A, 0x9F, 0xDB, 0x01, 0xE1, 0x04, 0x8F, 0xD7, 0x62, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x88, 0x9C, 0x50, 0x64, 0xE2, 0x18, 0x70, 0xC4, 0x7C, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x02, 0xA3, 0x0D, 0xDA, 0x01, 0xC2, 0x35, 0x5D, 0x58, 0x00, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x18 },
-{ 0x42, 0x55, 0x3E, 0xEB, 0x24, 0xD4, 0x08, 0x0D, 0xA9, 0x71, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x18 },
-{ 0xC2, 0x00, 0x2B, 0x17, 0x51, 0xC2, 0x1E, 0x4D, 0x97, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x19 },
-{ 0xC6, 0x01, 0x2D, 0xA7, 0x44, 0xC2, 0x06, 0x0E, 0xA7, 0x79, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x0C, 0x06, 0x06, 0x55, 0xC2, 0x3F, 0x09, 0x86, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0A },
-{ 0xC2, 0x2E, 0x4F, 0x77, 0x00, 0xC4, 0x08, 0x0E, 0x98, 0x59, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x30, 0x4F, 0xCA, 0x01, 0xC4, 0x0D, 0x0E, 0xB8, 0x7F, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC4, 0x29, 0x4F, 0xCA, 0x03, 0xC8, 0x0D, 0x0C, 0xB7, 0x7D, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0B },
- // 0x20
-{ 0xC2, 0x40, 0x3C, 0x96, 0x58, 0xC4, 0xDE, 0x0E, 0xC7, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x20 },
-{ 0x31, 0x13, 0x2D, 0xD7, 0x3C, 0xE2, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x22, 0x86, 0x0D, 0xD7, 0x50, 0xE4, 0x18, 0x5E, 0xB8, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x28 },
-{ 0xF2, 0x0A, 0x0D, 0xD7, 0x40, 0xE4, 0x1F, 0x5E, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x09, 0x4B, 0xD6, 0x48, 0xE4, 0x1F, 0x1C, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x28 },
-{ 0x62, 0x11, 0x0C, 0xE6, 0x3C, 0xE4, 0x1F, 0x0C, 0xC8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x12, 0x3D, 0xE6, 0x34, 0xE4, 0x1F, 0x7D, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x13, 0x3D, 0xE6, 0x34, 0xE4, 0x1F, 0x5D, 0xB8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xA2, 0x40, 0x5D, 0xBA, 0x3F, 0xE2, 0x00, 0x8F, 0xD8, 0x79, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x40, 0x3D, 0xDA, 0x3B, 0xE1, 0x00, 0x7E, 0xD8, 0x7A, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x00, 0x6D, 0xFA, 0x5D, 0xE2, 0x00, 0x8F, 0xC8, 0x79, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x4E, 0xDB, 0x4A, 0xE3, 0x18, 0x6F, 0xE9, 0x7E, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x4E, 0xDB, 0x66, 0xE2, 0x00, 0x7F, 0xE9, 0x7E, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x02, 0x0F, 0x66, 0xAA, 0x51, 0x02, 0x64, 0x29, 0xF9, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x16, 0x4A, 0x04, 0xBA, 0x39, 0xC2, 0x58, 0x2D, 0xCA, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x02, 0x00, 0x01, 0x7A, 0x79, 0x02, 0x3F, 0x28, 0xEA, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
- // 0x30
-{ 0x62, 0x53, 0x9C, 0xBA, 0x31, 0x62, 0x5B, 0xAD, 0xC9, 0x55, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x40, 0x6E, 0xDA, 0x49, 0xE2, 0x13, 0x8F, 0xF9, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x40, 0x8F, 0xFA, 0x50, 0xF2, 0x04, 0x7F, 0xFA, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0xA0, 0xCE, 0x5B, 0x02, 0xE2, 0x32, 0x7F, 0xFB, 0x3D, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE6, 0x80, 0x9C, 0x99, 0x42, 0xE2, 0x04, 0x7D, 0x78, 0x60, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEA, 0xA0, 0xAC, 0x67, 0x02, 0xE2, 0x00, 0x7C, 0x7A, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE7, 0x94, 0xAD, 0xB7, 0x03, 0xE2, 0x00, 0x7C, 0xBA, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC3, 0x3F, 0x4B, 0xE9, 0x7E, 0xC1, 0x3F, 0x9B, 0xF9, 0x7F, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0xB2, 0x20, 0xAD, 0xE9, 0x00, 0x62, 0x05, 0x8F, 0xC8, 0x68, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x00, 0x8F, 0xFB, 0x50, 0xF6, 0x47, 0x8F, 0xE9, 0x68, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x00, 0xAF, 0x88, 0x58, 0xF2, 0x54, 0x6E, 0xC9, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x2A, 0x9F, 0x98, 0x01, 0xE2, 0x84, 0x4E, 0x78, 0x6C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x02, 0x9F, 0xB8, 0x48, 0x22, 0x89, 0x9F, 0xE8, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x2A, 0x7F, 0xB8, 0x01, 0xE4, 0x00, 0x0D, 0xC5, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x28, 0x8E, 0xE8, 0x01, 0xF2, 0x00, 0x4D, 0xD6, 0x7D, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x23, 0x8F, 0xEA, 0x00, 0xF2, 0x00, 0x5E, 0xD9, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x40
-{ 0xB4, 0x26, 0x6E, 0x98, 0x01, 0x62, 0x00, 0x7D, 0xC8, 0x7D, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x2E, 0x20, 0xD9, 0x01, 0xF2, 0x0F, 0x90, 0xF8, 0x78, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xB8, 0x28, 0x9E, 0x98, 0x01, 0x62, 0x00, 0x3D, 0xC8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x00, 0x8E, 0xC9, 0x3D, 0xE6, 0x00, 0x7E, 0xD8, 0x68, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x00, 0x5F, 0xF9, 0x48, 0xE6, 0x98, 0x8F, 0xF8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x0C, 0x6E, 0xD8, 0x3D, 0x2A, 0x06, 0x7D, 0xD8, 0x58, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x7E, 0x89, 0x38, 0xE6, 0x84, 0x80, 0xF8, 0x68, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x80, 0x6C, 0xD9, 0x30, 0xE2, 0x00, 0x8D, 0xC8, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x80, 0x88, 0x48, 0x40, 0xE2, 0x0A, 0x7D, 0xA8, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x77, 0xC5, 0x54, 0xE2, 0x00, 0x9E, 0xD7, 0x70, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x80, 0x86, 0xB9, 0x64, 0xE2, 0x05, 0x9F, 0xD7, 0x78, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x00, 0x68, 0x68, 0x56, 0xE2, 0x08, 0x9B, 0xB3, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0xA6, 0x87, 0x41, 0xE2, 0x0A, 0x7E, 0xC9, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x80, 0x9A, 0xB8, 0x48, 0xE2, 0x00, 0x9E, 0xF9, 0x60, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x80, 0x8E, 0x64, 0x68, 0xE2, 0x28, 0x6F, 0x73, 0x7C, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x50
-{ 0xE8, 0x00, 0x7D, 0x99, 0x54, 0xE6, 0x80, 0x80, 0xF8, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE6, 0x00, 0x9F, 0xB9, 0x6D, 0xE1, 0x00, 0x8F, 0xC8, 0x7D, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x09, 0x68, 0x4A, 0xE2, 0x2B, 0x9E, 0xF3, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC4, 0x00, 0x99, 0xE8, 0x3B, 0xE2, 0x25, 0x6F, 0x93, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE6, 0x00, 0x6F, 0xDA, 0x69, 0xE2, 0x05, 0x2F, 0xD8, 0x6A, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEC, 0x60, 0x9D, 0xC7, 0x00, 0xE2, 0x21, 0x7F, 0xC9, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE3, 0x00, 0x0F, 0xF7, 0x7D, 0xE1, 0x3F, 0x0F, 0xA7, 0x01, 0x0D, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0xA9, 0x0F, 0xA8, 0x02, 0xE2, 0x3C, 0x5F, 0xDA, 0x3C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE8, 0x40, 0x0D, 0x89, 0x7D, 0xE2, 0x17, 0x7E, 0xD9, 0x7C, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0xDF, 0x8A, 0x56, 0xE2, 0x5E, 0xCF, 0xBA, 0x7E, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x00, 0x0B, 0x68, 0x60, 0xE2, 0x01, 0x9E, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEA, 0x00, 0xAE, 0xAB, 0x49, 0xE2, 0x00, 0xAE, 0xBA, 0x6C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEB, 0x80, 0x8C, 0xCB, 0x3A, 0xE2, 0x86, 0xAF, 0xCA, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE5, 0x40, 0xDB, 0x3B, 0x3C, 0xE2, 0x80, 0xBE, 0xCA, 0x71, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x9E, 0xAA, 0x3D, 0xE1, 0x43, 0x0F, 0xBA, 0x7E, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE7, 0x40, 0xEC, 0xCA, 0x44, 0xE2, 0x03, 0xBF, 0xBA, 0x66, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x60
-{ 0xEA, 0x00, 0x68, 0xB8, 0x48, 0xE2, 0x0A, 0x8E, 0xB8, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x61, 0x00, 0xBE, 0x99, 0x7E, 0xE3, 0x40, 0xCF, 0xCA, 0x7D, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xCD, 0x00, 0x0B, 0x00, 0x48, 0xC2, 0x58, 0x0C, 0x00, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x1C },
-{ 0xE2, 0x00, 0x0E, 0x00, 0x52, 0xE2, 0x58, 0x5F, 0xD0, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xCC, 0x00, 0x7D, 0xDA, 0x40, 0xC2, 0x00, 0x5E, 0x9B, 0x58, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE9, 0xC0, 0xEE, 0xD8, 0x43, 0xE2, 0x05, 0xDD, 0xAA, 0x70, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xDA, 0x00, 0x8F, 0xAC, 0x4A, 0x22, 0x05, 0x8D, 0x8A, 0x75, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x8A, 0xCB, 0x7A, 0x74, 0xE6, 0x56, 0xAF, 0xDB, 0x70, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x41, 0xAC, 0x5B, 0x5B, 0xC2, 0x80, 0x0D, 0xCB, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x12 },
-{ 0x75, 0x00, 0x0E, 0xCB, 0x5A, 0xE2, 0x1E, 0x0A, 0xC9, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10 },
-{ 0x41, 0x00, 0x0E, 0xEA, 0x53, 0xC2, 0x00, 0x08, 0xCA, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0xC1, 0x40, 0x0C, 0x59, 0x6A, 0xC2, 0x80, 0x3C, 0xAB, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0D },
-{ 0x4B, 0x00, 0x0A, 0xF5, 0x61, 0xC2, 0x19, 0x0C, 0xE9, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0x62, 0x00, 0x7F, 0xD8, 0x54, 0xEA, 0x00, 0x8F, 0xD8, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x7F, 0xD9, 0x56, 0xE1, 0x00, 0x8F, 0xD8, 0x7E, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x7F, 0xD9, 0x56, 0xE1, 0x00, 0x8F, 0xD8, 0x7E, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x70
-{ 0xCF, 0x40, 0x09, 0xEA, 0x54, 0xC4, 0x00, 0x0C, 0xDB, 0x64, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x40, 0x0C, 0xAA, 0x54, 0xC4, 0x00, 0x18, 0xF9, 0x64, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xC9, 0x0E, 0x88, 0xD9, 0x3E, 0xC2, 0x08, 0x1A, 0xEA, 0x6C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x03, 0x00, 0x15, 0x00, 0x64, 0x02, 0x00, 0x08, 0x00, 0x7C, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x01, 0x00, 0x47, 0xD7, 0x6C, 0x01, 0x3F, 0x0C, 0xFB, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x00, 0x00, 0x36, 0x67, 0x7C, 0x01, 0x3F, 0x0E, 0xFA, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x02, 0x00, 0x36, 0x68, 0x7C, 0x01, 0x3F, 0x0E, 0xFA, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0xCB, 0x00, 0xAF, 0x00, 0x7E, 0xC0, 0x00, 0xC0, 0x06, 0x7F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0F },
-{ 0x05, 0x0D, 0x80, 0xA6, 0x7F, 0x0B, 0x38, 0xA9, 0xD8, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x0F, 0x00, 0x90, 0xFA, 0x68, 0x06, 0x00, 0xA7, 0x39, 0x54, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0xC9, 0x15, 0xDD, 0xFF, 0x7C, 0x00, 0x00, 0xE7, 0xFC, 0x6C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x38 },
-{ 0x48, 0x3C, 0x30, 0xF6, 0x03, 0x0A, 0x38, 0x97, 0xE8, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x07, 0x80, 0x0B, 0xC8, 0x65, 0x02, 0x3F, 0x0C, 0xEA, 0x7C, 0x0F, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x00, 0x21, 0x66, 0x40, 0x03, 0x00, 0x3F, 0x47, 0x00, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x08, 0x00, 0x0B, 0x3C, 0x7C, 0x08, 0x3F, 0x06, 0xF3, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x00, 0x3F, 0x4C, 0xFB, 0x00, 0x00, 0x3F, 0x0A, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 }
-};
-
-static byte gm_percussion_to_fm[39][30] = {
-{ 0x1A, 0x3F, 0x15, 0x05, 0x7C, 0x02, 0x21, 0x2B, 0xE4, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0x11, 0x12, 0x04, 0x07, 0x7C, 0x02, 0x23, 0x0B, 0xE5, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x0A, 0x3F, 0x0B, 0x01, 0x7C, 0x1F, 0x1C, 0x46, 0xD0, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x01 },
-{ 0x00, 0x3F, 0x0F, 0x00, 0x7C, 0x10, 0x12, 0x07, 0x00, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x0F, 0x3F, 0x0B, 0x00, 0x7C, 0x1F, 0x0F, 0x19, 0xD0, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x00, 0x3F, 0x1F, 0x00, 0x7E, 0x1F, 0x16, 0x07, 0x00, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x12, 0x3F, 0x05, 0x06, 0x7C, 0x03, 0x1F, 0x4A, 0xD9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x7F, 0x08, 0xFF, 0x7E, 0x00, 0xC7, 0x2D, 0xF7, 0x73, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x12, 0x3F, 0x05, 0x06, 0x7C, 0x43, 0x21, 0x0C, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x7F, 0x08, 0xCF, 0x7E, 0x00, 0x45, 0x2A, 0xF8, 0x4B, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0C },
-{ 0x12, 0x3F, 0x06, 0x17, 0x7C, 0x03, 0x27, 0x0B, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x7F, 0x08, 0xCD, 0x7E, 0x00, 0x40, 0x1A, 0x69, 0x63, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0C },
-{ 0x13, 0x3F, 0x05, 0x06, 0x7C, 0x03, 0x17, 0x0A, 0xD9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x15, 0x3F, 0x05, 0x06, 0x7C, 0x03, 0x21, 0x0C, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x3F, 0x2B, 0xFB, 0x7E, 0xC0, 0x1E, 0x1A, 0xCA, 0x7F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10 },
-{ 0x17, 0x3F, 0x04, 0x09, 0x7C, 0x03, 0x22, 0x0D, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x3F, 0x0F, 0x5E, 0x7C, 0xC6, 0x13, 0x00, 0xCA, 0x7F, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x3F, 0x7E, 0x9D, 0x7C, 0xC8, 0xC0, 0x0A, 0xBA, 0x74, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0xCF, 0x3F, 0x4D, 0x9F, 0x7C, 0xC6, 0x00, 0x08, 0xDA, 0x5B, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0xCF, 0x3F, 0x5D, 0xAA, 0x7A, 0xC0, 0xA4, 0x67, 0x99, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x3F, 0x4A, 0xFD, 0x7C, 0xCF, 0x00, 0x59, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x0F, 0x18, 0x0A, 0xFA, 0x57, 0x06, 0x07, 0x06, 0x39, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x3F, 0x2B, 0xFC, 0x7C, 0xCC, 0xC6, 0x0B, 0xEA, 0x7F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10 },
-{ 0x05, 0x1A, 0x04, 0x00, 0x7C, 0x12, 0x10, 0x0C, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0x04, 0x19, 0x04, 0x00, 0x7C, 0x12, 0x10, 0x2C, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x04, 0x0A, 0x04, 0x00, 0x6C, 0x01, 0x07, 0x0D, 0xFA, 0x74, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0x15, 0x14, 0x05, 0x00, 0x7D, 0x01, 0x07, 0x5C, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x10, 0x10, 0x05, 0x08, 0x7C, 0x01, 0x08, 0x0D, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x11, 0x00, 0x06, 0x87, 0x7F, 0x02, 0x40, 0x09, 0x59, 0x68, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x08 },
-{ 0x13, 0x26, 0x04, 0x6A, 0x7F, 0x01, 0x00, 0x08, 0x5A, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x08 },
-{ 0xCF, 0x4E, 0x0C, 0xAA, 0x50, 0xC4, 0x00, 0x18, 0xF9, 0x54, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x4E, 0x0C, 0xAA, 0x50, 0xC3, 0x00, 0x18, 0xF8, 0x54, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCB, 0x3F, 0x8F, 0x00, 0x7E, 0xC5, 0x00, 0x98, 0xD6, 0x5F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0D },
-{ 0x0C, 0x18, 0x87, 0xB3, 0x7F, 0x19, 0x10, 0x55, 0x75, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x05, 0x11, 0x15, 0x00, 0x64, 0x02, 0x08, 0x08, 0x00, 0x5C, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x04, 0x08, 0x15, 0x00, 0x48, 0x01, 0x08, 0x08, 0x00, 0x60, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xDA, 0x00, 0x53, 0x30, 0x68, 0x07, 0x1E, 0x49, 0xC4, 0x7E, 0x03, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x1C, 0x00, 0x07, 0xBC, 0x6C, 0x0C, 0x14, 0x0B, 0x6A, 0x7E, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x0A, 0x0E, 0x7F, 0x00, 0x7D, 0x13, 0x20, 0x28, 0x03, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 }
-};
-
-static const byte gm_percussion_lookup[128] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
- 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0xFF, 0xFF, 0x17, 0x18, 0x19, 0x1A,
- 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x21, 0x22, 0x23, 0xFF, 0xFF,
- 0x24, 0x25, 0xFF, 0xFF, 0xFF, 0x26, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-};
-
-static byte lookup_table[64][32];
-static const byte volume_table[] = {
- 0, 4, 7, 11,
- 13, 16, 18, 20,
- 22, 24, 26, 27,
- 29, 30, 31, 33,
- 34, 35, 36, 37,
- 38, 39, 40, 41,
- 42, 43, 44, 44,
- 45, 46, 47, 47,
- 48, 49, 49, 50,
- 51, 51, 52, 53,
- 53, 54, 54, 55,
- 55, 56, 56, 57,
- 57, 58, 58, 59,
- 59, 60, 60, 60,
- 61, 61, 62, 62,
- 62, 63, 63, 63
-};
-
-static int lookup_volume(int a, int b) {
- if (b == 0)
- return 0;
-
- if (b == 31)
- return a;
-
- if (a < -63 || a > 63) {
- return b * (a + 1) >> 5;
- }
-
- if (b < 0) {
- if (a < 0) {
- return lookup_table[-a][-b];
- } else {
- return -lookup_table[a][-b];
- }
- } else {
- if (a < 0) {
- return -lookup_table[-a][b];
- } else {
- return lookup_table[a][b];
- }
- }
-}
-
-static void create_lookup_table() {
- int i, j;
- int sum;
-
- for (i = 0; i < 64; i++) {
- sum = i;
- for (j = 0; j < 32; j++) {
- lookup_table[i][j] = sum >> 5;
- sum += i;
- }
- }
- for (i = 0; i < 64; i++)
- lookup_table[i][0] = 0;
-}
-
-////////////////////////////////////////
-//
-// Adlib MIDI driver
-//
-////////////////////////////////////////
-
-class MidiDriver_ADLIB : public MidiDriver_Emulated {
- friend class AdlibPart;
- friend class AdlibPercussionChannel;
-
-public:
- MidiDriver_ADLIB(SoundMixer *mixer);
-
- int open();
- void close();
- void send(uint32 b);
- void send(byte channel, uint32 b); // Supports higher than channel 15
- uint32 property(int prop, uint32 param);
-
- void setPitchBendRange(byte channel, uint range);
- void sysEx_customInstrument(byte channel, uint32 type, byte *instr);
-
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel() { return &_percussion; } // Percussion partially supported
-
-
- // AudioStream API
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
-private:
- bool _game_SmallHeader;
-
- FM_OPL *_opl;
- byte *_adlib_reg_cache;
-
- int _adlib_timer_counter;
-
- uint16 channel_table_2[9];
- int _voice_index;
- int _timer_p;
- int _timer_q;
- uint16 curnote_table[9];
- AdlibVoice _voices[9];
- AdlibPart _parts[32];
- AdlibPercussionChannel _percussion;
-
- void generateSamples(int16 *buf, int len);
- void onTimer();
- void part_key_on(AdlibPart *part, AdlibInstrument *instr, byte note, byte velocity);
- void part_key_off(AdlibPart *part, byte note);
-
- void adlib_key_off(int chan);
- void adlib_note_on(int chan, byte note, int mod);
- void adlib_note_on_ex(int chan, byte note, int mod);
- int adlib_read_param(int chan, byte data);
- void adlib_setup_channel(int chan, AdlibInstrument * instr, byte vol_1, byte vol_2);
- byte adlib_read(byte port) {
- return _adlib_reg_cache[port];
- }
- void adlib_set_param(int channel, byte param, int value);
- void adlib_key_onoff(int channel);
- void adlib_write(byte port, byte value);
- void adlib_playnote(int channel, int note);
-
- AdlibVoice *allocate_voice(byte pri);
-
- void mc_off(AdlibVoice * voice);
-
- static void link_mc(AdlibPart *part, AdlibVoice *voice);
- void mc_inc_stuff(AdlibVoice *voice, Struct10 * s10, Struct11 * s11);
- void mc_init_stuff(AdlibVoice *voice, Struct10 * s10, Struct11 * s11, byte flags,
- InstrumentExtra * ie);
-
- void struct10_init(Struct10 * s10, InstrumentExtra * ie);
- static byte struct10_ontimer(Struct10 * s10, Struct11 * s11);
- static void struct10_setup(Struct10 * s10);
- static int random_nr(int a);
- void mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte note, byte velocity);
-};
-
-// MidiChannel method implementations
-
-void AdlibPart::init(MidiDriver_ADLIB *owner, byte channel) {
- _owner = owner;
- _channel = channel;
- _pri_eff = 127;
-}
-
-MidiDriver *AdlibPart::device() {
- return _owner;
-}
-
-void AdlibPart::send(uint32 b) {
- _owner->send(_channel, b);
-}
-
-void AdlibPart::noteOff(byte note) {
-#ifdef DEBUG_ADLIB
- debug(6, "%10d: noteOff(%d)", tick, note);
-#endif
- _owner->part_key_off(this, note);
-}
-
-void AdlibPart::noteOn(byte note, byte velocity) {
-#ifdef DEBUG_ADLIB
- debug(6, "%10d: noteOn(%d,%d)", tick, note, velocity);
-#endif
- _owner->part_key_on(this, &_part_instr, note, velocity);
-}
-
-void AdlibPart::programChange(byte program) {
- if (program > 127)
- return;
-
- uint i;
- uint count = 0;
- for (i = 0; i < ARRAYSIZE(map_gm_to_fm[0]); ++i)
- count += map_gm_to_fm[program][i];
- if (!count)
- warning("No Adlib instrument defined for GM program %d", (int) program);
- _program = program;
- memcpy(&_part_instr, &map_gm_to_fm[program], sizeof(AdlibInstrument));
-}
-
-void AdlibPart::pitchBend(int16 bend) {
- AdlibVoice *voice;
-
- _pitchbend = bend;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff,
- (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
- }
-}
-
-void AdlibPart::controlChange(byte control, byte value) {
- switch (control) {
- case 1: modulationWheel(value); break;
- case 7: volume(value); break;
- case 10: break; // Pan position. Not supported.
- case 16: pitchBendFactor(value); break;
- case 17: detune(value); break;
- case 18: priority(value); break;
- case 64: sustain(value > 0); break;
- case 91: break; // Effects level. Not supported.
- case 93: break; // Chorus level. Not supported.
- case 119: break; // Unknown, used in Simon the Sorcerer 2
- case 121: break; // Unknown, used in Simon the Sorcerer 1
- case 123: allNotesOff(); break;
- default:
- warning("Adlib: Unknown control change message %d", (int) control);
- }
-}
-
-void AdlibPart::modulationWheel(byte value) {
- AdlibVoice *voice;
-
- _modwheel = value;
- for (voice = _voice; voice; voice = voice->_next) {
- if (voice->_s10a.active && voice->_s11a.flag0x40)
- voice->_s10a.modwheel = _modwheel >> 2;
- if (voice->_s10b.active && voice->_s11b.flag0x40)
- voice->_s10b.modwheel = _modwheel >> 2;
- }
-}
-
-void AdlibPart::volume(byte value) {
- AdlibVoice *voice;
-
- _vol_eff = value;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_set_param(voice->_channel, 0, volume_table[lookup_table[voice->_vol_2][_vol_eff >> 2]]);
- if (voice->_twochan) {
- _owner->adlib_set_param(voice->_channel, 13, volume_table[lookup_table[voice->_vol_1][_vol_eff >> 2]]);
- }
- }
-}
-
-void AdlibPart::pitchBendFactor(byte value) {
- AdlibVoice *voice;
-
- _pitchbend_factor = value;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff,
- (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
- }
-}
-
-void AdlibPart::detune(byte value) {
- AdlibVoice *voice;
-
- _detune_eff = value;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff,
- (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
- }
-}
-
-void AdlibPart::priority(byte value) {
- _pri_eff = value;
-}
-
-void AdlibPart::sustain(bool value) {
- AdlibVoice *voice;
-
- _pedal = value;
- if (!value) {
- for (voice = _voice; voice; voice = voice->_next) {
- if (voice->_waitforpedal)
- _owner->mc_off(voice);
- }
- }
-}
-
-void AdlibPart::allNotesOff() {
- while (_voice)
- _owner->mc_off(_voice);
-}
-
-void AdlibPart::sysEx_customInstrument(uint32 type, byte *instr) {
- if (type == 'ADL ') {
- AdlibInstrument *i = &_part_instr;
- memcpy(i, instr, sizeof(AdlibInstrument));
- }
-}
-
-// MidiChannel method implementations for percussion
-
-void AdlibPercussionChannel::init(MidiDriver_ADLIB *owner, byte channel) {
- AdlibPart::init(owner, channel);
- _pri_eff = 0;
- _vol_eff = 127;
-}
-
-void AdlibPercussionChannel::noteOff(byte note) {
- // Jamieson630: Unless I run into a specific instrument that
- // may require a key off, I'm going to ignore this message.
- // The rationale is that a percussion instrument should
- // fade out of its own accord, and the Adlib instrument
- // definitions used should follow this rule. Since
- // percussion voices are allocated at the lowest priority
- // anyway, we know that "hanging" percussion sounds will
- // not prevent later musical instruments (or even other
- // percussion sounds) from playing.
-/*
- _owner->part_key_off(this, note);
-*/
-}
-
-void AdlibPercussionChannel::noteOn(byte note, byte velocity) {
- byte key = gm_percussion_lookup[note];
- if (key == 0xFF) {
- debug(2, "No FM map for GM percussion key %d", (int) note);
- return;
- }
- _owner->part_key_on(this, (AdlibInstrument *) &gm_percussion_to_fm[key], note, velocity);
-}
-
-// MidiDriver method implementations
-
-MidiDriver_ADLIB::MidiDriver_ADLIB(SoundMixer *mixer)
- : MidiDriver_Emulated(mixer) {
- uint i;
-
- _game_SmallHeader = false;
-
- _adlib_reg_cache = 0;
-
- _adlib_timer_counter = 0;
- _voice_index = 0;
- for (i = 0; i < ARRAYSIZE(curnote_table); ++i) {
- curnote_table[i] = 0;
- }
-
- for (i = 0; i < ARRAYSIZE(_parts); ++i) {
- _parts[i].init(this, i + ((i >= 9) ? 1 : 0));
- }
- _percussion.init(this, 9);
- _timer_p = 0xD69;
- _timer_q = 0x411B;
-}
-
-int MidiDriver_ADLIB::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- int i;
- AdlibVoice *voice;
-
- for (i = 0, voice = _voices; i != ARRAYSIZE(_voices); i++, voice++) {
- voice->_channel = i;
- voice->_s11a.s10 = &voice->_s10b;
- voice->_s11b.s10 = &voice->_s10a;
- }
-
- _adlib_reg_cache = (byte *)calloc(256, 1);
-
- _opl = makeAdlibOPL(getRate());
-
- adlib_write(1, 0x20);
- adlib_write(8, 0x40);
- adlib_write(0xBD, 0x00);
- create_lookup_table();
-
- _mixer->setupPremix(this);
-
- return 0;
-}
-
-void MidiDriver_ADLIB::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- // Detach the premix callback handler
- _mixer->setupPremix(0);
-
- uint i;
- for (i = 0; i < ARRAYSIZE(_voices); ++i) {
- if (_voices[i]._part)
- mc_off(&_voices[i]);
- }
-
- // Turn off the OPL emulation
-// YM3812Shutdown();
-
- free(_adlib_reg_cache);
-}
-
-void MidiDriver_ADLIB::send(uint32 b) {
- send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void MidiDriver_ADLIB::send(byte chan, uint32 b) {
- //byte param3 = (byte) ((b >> 24) & 0xFF);
- byte param2 = (byte) ((b >> 16) & 0xFF);
- byte param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
-
- AdlibPart *part;
- if (chan == 9)
- part = &_percussion;
- else
- part = &_parts[chan];
-
- switch (cmd) {
- case 0x80:// Note Off
- part->noteOff(param1);
- break;
- case 0x90: // Note On
- part->noteOn(param1, param2);
- break;
- case 0xA0: // Aftertouch
- break; // Not supported.
- case 0xB0: // Control Change
- part->controlChange(param1, param2);
- break;
- case 0xC0: // Program Change
- part->programChange(param1);
- break;
- case 0xD0: // Channel Pressure
- break; // Not supported.
- case 0xE0: // Pitch Bend
- part->pitchBend((param1 | (param2 << 7)) - 0x2000);
- break;
- case 0xF0: // SysEx
- // We should never get here! SysEx information has to be
- // sent via high-level semantic methods.
- warning("MidiDriver_ADLIB: Receiving SysEx command on a send() call");
- break;
-
- default:
- warning("MidiDriver_ADLIB: Unknown send() command 0x%02X", cmd);
- }
-}
-
-uint32 MidiDriver_ADLIB::property(int prop, uint32 param) {
- switch (prop) {
- case PROP_OLD_ADLIB: // Older games used a different operator volume algorithm
- _game_SmallHeader = (param > 0);
- if (_game_SmallHeader) {
- _timer_p = 473;
- _timer_q = 1000;
- } else {
- _timer_p = 0xD69;
- _timer_q = 0x411B;
- }
- return 1;
- }
-
- return 0;
-}
-
-void MidiDriver_ADLIB::setPitchBendRange(byte channel, uint range) {
- AdlibVoice *voice;
- AdlibPart *part = &_parts[channel];
-
- part->_pitchbend_factor = range;
- for (voice = part->_voice; voice; voice = voice->_next) {
- adlib_note_on(voice->_channel, voice->_note + part->_transpose_eff,
- (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff);
- }
-}
-
-void MidiDriver_ADLIB::sysEx_customInstrument(byte channel, uint32 type, byte *instr) {
- _parts[channel].sysEx_customInstrument(type, instr);
-}
-
-MidiChannel *MidiDriver_ADLIB::allocateChannel() {
- AdlibPart *part;
- uint i;
-
- for (i = 0; i < ARRAYSIZE(_parts); ++i) {
- part = &_parts[i];
- if (!part->_allocated) {
- part->allocate();
- return part;
- }
- }
- return NULL;
-}
-
-MidiDriver *MidiDriver_ADLIB_create(SoundMixer *mixer) {
- return new MidiDriver_ADLIB(mixer);
-}
-
-// All the code brought over from IMuseAdlib
-
-void MidiDriver_ADLIB::adlib_write(byte port, byte value) {
- if (_adlib_reg_cache[port] == value)
- return;
-#ifdef DEBUG_ADLIB
- debug(6, "%10d: adlib_write[%x] = %x", tick, port, value);
-#endif
- _adlib_reg_cache[port] = value;
-
- OPLWriteReg(_opl, port, value);
-}
-
-void MidiDriver_ADLIB::generateSamples(int16 *data, int len) {
- memset(data, 0, sizeof(int16) * len);
- YM3812UpdateOne(_opl, data, len);
-}
-
-void MidiDriver_ADLIB::onTimer() {
- AdlibVoice *voice;
- int i;
-
- _adlib_timer_counter += _timer_p;
- while (_adlib_timer_counter >= _timer_q) {
- _adlib_timer_counter -= _timer_q;
-#ifdef DEBUG_ADLIB
- tick++;
-#endif
- voice = _voices;
- for (i = 0; i != ARRAYSIZE(_voices); i++, voice++) {
- if (!voice->_part)
- continue;
- if (voice->_duration && (voice->_duration -= 0x11) <= 0) {
- mc_off(voice);
- return;
- }
- if (voice->_s10a.active) {
- mc_inc_stuff(voice, &voice->_s10a, &voice->_s11a);
- }
- if (voice->_s10b.active) {
- mc_inc_stuff(voice, &voice->_s10b, &voice->_s11b);
- }
- }
- }
-}
-
-void MidiDriver_ADLIB::mc_off(AdlibVoice *voice) {
- AdlibVoice *tmp;
-
- adlib_key_off(voice->_channel);
-
- tmp = voice->_prev;
-
- if (voice->_next)
- voice->_next->_prev = tmp;
- if (tmp)
- tmp->_next = voice->_next;
- else
- voice->_part->_voice = voice->_next;
- voice->_part = NULL;
-}
-
-void MidiDriver_ADLIB::mc_inc_stuff(AdlibVoice *voice, Struct10 *s10, Struct11 *s11) {
- byte code;
- AdlibPart *part = voice->_part;
-
- code = struct10_ontimer(s10, s11);
-
- if (code & 1) {
- switch (s11->param) {
- case 0:
- voice->_vol_2 = s10->start_value + s11->modify_val;
- if (!_game_SmallHeader) {
- adlib_set_param(voice->_channel, 0,
- volume_table[lookup_table[voice->_vol_2]
- [part->_vol_eff >> 2]]);
- } else {
- adlib_set_param(voice->_channel, 0, voice->_vol_2);
- }
- break;
- case 13:
- voice->_vol_1 = s10->start_value + s11->modify_val;
- if (voice->_twochan && !_game_SmallHeader) {
- adlib_set_param(voice->_channel, 13,
- volume_table[lookup_table[voice->_vol_1]
- [part->_vol_eff >> 2]]);
- } else {
- adlib_set_param(voice->_channel, 13, voice->_vol_1);
- }
- break;
- case 30:
- s11->s10->modwheel = (char)s11->modify_val;
- break;
- case 31:
- s11->s10->unk3 = (char)s11->modify_val;
- break;
- default:
- adlib_set_param(voice->_channel, s11->param,
- s10->start_value + s11->modify_val);
- break;
- }
- }
-
- if (code & 2 && s11->flag0x10)
- adlib_key_onoff(voice->_channel);
-}
-
-void MidiDriver_ADLIB::adlib_key_off(int chan){
- byte port = chan + 0xB0;
- adlib_write(port, adlib_read(port) & ~0x20);
-}
-
-byte MidiDriver_ADLIB::struct10_ontimer(Struct10 *s10, Struct11 *s11) {
- byte result = 0;
- int i;
-
- if (s10->count && (s10->count -= 17) <= 0) {
- s10->active = 0;
- return 0;
- }
-
- i = s10->cur_val + s10->speed_hi;
- s10->speed_lo_counter += s10->speed_lo;
- if (s10->speed_lo_counter >= s10->speed_lo_max) {
- s10->speed_lo_counter -= s10->speed_lo_max;
- i += s10->direction;
- }
- if (s10->cur_val != i || s10->modwheel != s10->modwheel_last) {
- s10->cur_val = i;
- s10->modwheel_last = s10->modwheel;
- i = lookup_volume(i, s10->modwheel_last);
- if (i != s11->modify_val) {
- s11->modify_val = i;
- result = 1;
- }
- }
-
- if (!--s10->num_steps) {
- s10->active++;
- if (s10->active > 4) {
- if (s10->loop) {
- s10->active = 1;
- result |= 2;
- struct10_setup(s10);
- } else {
- s10->active = 0;
- }
- } else {
- struct10_setup(s10);
- }
- }
-
- return result;
-}
-
-void MidiDriver_ADLIB::adlib_set_param(int channel, byte param, int value) {
- const AdlibSetParams *as;
- byte port;
-
- assert(channel >= 0 && channel < 9);
-
- if (param <= 12) {
- port = channel_mappings_2[channel];
- } else if (param <= 25) {
- param -= 13;
- port = channel_mappings[channel];
- } else if (param <= 27) {
- param -= 13;
- port = channel;
- } else if (param == 28 || param == 29) {
- if (param == 28)
- value -= 15;
- else
- value -= 383;
- value <<= 4;
- channel_table_2[channel] = value;
- adlib_playnote(channel, curnote_table[channel] + value);
- return;
- } else {
- return;
- }
-
- as = &adlib_setparam_table[param];
- if (as->d)
- value = as->d - value;
- port += as->a;
- adlib_write(port, (adlib_read(port) & ~as->c) | (((byte)value) << as->b));
-}
-
-void MidiDriver_ADLIB::adlib_key_onoff(int channel) {
- byte val;
- byte port = channel + 0xB0;
- assert(channel >= 0 && channel < 9);
-
- val = adlib_read(port);
- adlib_write(port, val & ~0x20);
- adlib_write(port, val | 0x20);
-}
-
-void MidiDriver_ADLIB::struct10_setup(Struct10 *s10) {
- int b, c, d, e, f, g, h;
- byte t;
-
- b = s10->unk3;
- f = s10->active - 1;
-
- t = s10->table_a[f];
- e = num_steps_table[lookup_table[t & 0x7F][b]];
- if (t & 0x80) {
- e = random_nr(e);
- }
- if (e == 0)
- e++;
-
- s10->num_steps = s10->speed_lo_max = e;
-
- if (f != 2) {
- c = s10->max_value;
- g = s10->start_value;
- t = s10->table_b[f];
- d = lookup_volume(c, (t & 0x7F) - 31);
- if (t & 0x80) {
- d = random_nr(d);
- }
- if (d + g > c) {
- h = c - g;
- } else {
- h = d;
- if (d + g < 0)
- h = -g;
- }
- h -= s10->cur_val;
- } else {
- h = 0;
- }
-
- s10->speed_hi = h / e;
- if (h < 0) {
- h = -h;
- s10->direction = -1;
- } else {
- s10->direction = 1;
- }
-
- s10->speed_lo = h % e;
- s10->speed_lo_counter = 0;
-}
-
-void MidiDriver_ADLIB::adlib_playnote(int channel, int note) {
- byte old, oct, notex;
- int note2;
- int i;
-
- note2 = (note >> 7) - 4;
- note2 = (note2 < 128) ? note2 : 0;
-
- oct = (note2 / 12);
- if (oct > 7)
- oct = 7 << 2;
- else
- oct <<= 2;
- notex = note2 % 12 + 3;
-
- old = adlib_read(channel + 0xB0);
- if (old & 0x20) {
- old &= ~0x20;
- if (oct > old) {
- if (notex < 6) {
- notex += 12;
- oct -= 4;
- }
- } else if (oct < old) {
- if (notex > 11) {
- notex -= 12;
- oct += 4;
- }
- }
- }
-
- i = (notex << 3) + ((note >> 4) & 0x7);
- adlib_write(channel + 0xA0, note_to_f_num[i]);
- adlib_write(channel + 0xB0, oct | 0x20);
-}
-
-// TODO: Replace this with RandomSource? But if so, please note that this
-// function will be called with negative parameters - getRandomNumber(-1) will
-// crash ScummVM, random_nr(-1) won't.
-
-int MidiDriver_ADLIB::random_nr(int a) {
- static byte _rand_seed = 1;
- if (_rand_seed & 1) {
- _rand_seed >>= 1;
- _rand_seed ^= 0xB8;
- } else {
- _rand_seed >>= 1;
- }
- return _rand_seed * a >> 8;
-}
-
-void MidiDriver_ADLIB::part_key_off(AdlibPart *part, byte note) {
- AdlibVoice *voice;
-
- for (voice = part->_voice; voice; voice = voice->_next) {
- if (voice->_note == note) {
- if (part->_pedal)
- voice->_waitforpedal = true;
- else
- mc_off(voice);
- }
- }
-}
-
-void MidiDriver_ADLIB::part_key_on(AdlibPart *part, AdlibInstrument *instr, byte note, byte velocity) {
- AdlibVoice *voice;
-
- voice = allocate_voice(part->_pri_eff);
- if (!voice)
- return;
-
- link_mc(part, voice);
- mc_key_on(voice, instr, note, velocity);
-}
-
-AdlibVoice *MidiDriver_ADLIB::allocate_voice(byte pri) {
- AdlibVoice *ac, *best = NULL;
- int i;
-
- for (i = 0; i < 9; i++) {
- if (++_voice_index >= 9)
- _voice_index = 0;
- ac = &_voices[_voice_index];
- if (!ac->_part)
- return ac;
- if (!ac->_next) {
- if (ac->_part->_pri_eff <= pri) {
- pri = ac->_part->_pri_eff;
- best = ac;
- }
- }
- }
-
- /* V3 games don't have note priorities, first comes wins. */
- if (_game_SmallHeader)
- return NULL;
-
- if (best)
- mc_off(best);
- return best;
-}
-
-void MidiDriver_ADLIB::link_mc(AdlibPart *part, AdlibVoice *voice) {
- voice->_part = part;
- voice->_next = (AdlibVoice *)part->_voice;
- part->_voice = voice;
- voice->_prev = NULL;
-
- if (voice->_next)
- voice->_next->_prev = voice;
-}
-
-void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte note, byte velocity) {
- AdlibPart *part = voice->_part;
- int c;
- byte vol_1, vol_2;
-
- voice->_twochan = instr->feedback & 1;
- voice->_note = note;
- voice->_waitforpedal = false;
- voice->_duration = instr->duration;
- if (voice->_duration != 0)
- voice->_duration *= 63;
-
- if (!_game_SmallHeader)
- vol_1 = (instr->oplvl_1 & 0x3F) + lookup_table[velocity >> 1][instr->waveform_1 >> 2];
- else
- vol_1 = 0x3f - (instr->oplvl_1 & 0x3F);
- if (vol_1 > 0x3F)
- vol_1 = 0x3F;
- voice->_vol_1 = vol_1;
-
- if (!_game_SmallHeader)
- vol_2 = (instr->oplvl_2 & 0x3F) + lookup_table[velocity >> 1][instr->waveform_2 >> 2];
- else
- vol_2 = 0x3f - (instr->oplvl_2 & 0x3F);
- if (vol_2 > 0x3F)
- vol_2 = 0x3F;
- voice->_vol_2 = vol_2;
-
- c = part->_vol_eff >> 2;
-
- if (!_game_SmallHeader) {
- vol_2 = volume_table[lookup_table[vol_2][c]];
- if (voice->_twochan)
- vol_1 = volume_table[lookup_table[vol_1][c]];
- }
-
- adlib_setup_channel(voice->_channel, instr, vol_1, vol_2);
- adlib_note_on_ex(voice->_channel, part->_transpose_eff + note, part->_detune_eff + (part->_pitchbend * part->_pitchbend_factor >> 6));
-
- if (instr->flags_a & 0x80) {
- mc_init_stuff(voice, &voice->_s10a, &voice->_s11a, instr->flags_a, &instr->extra_a);
- } else {
- voice->_s10a.active = 0;
- }
-
- if (instr->flags_b & 0x80) {
- mc_init_stuff(voice, &voice->_s10b, &voice->_s11b, instr->flags_b, &instr->extra_b);
- } else {
- voice->_s10b.active = 0;
- }
-}
-
-void MidiDriver_ADLIB::adlib_setup_channel(int chan, AdlibInstrument *instr, byte vol_1, byte vol_2) {
- byte port;
-
- assert(chan >= 0 && chan < 9);
-
- port = channel_mappings[chan];
- adlib_write(port + 0x20, instr->flags_1);
- adlib_write(port + 0x40, (instr->oplvl_1 | 0x3F) - vol_1 );
- adlib_write(port + 0x60, 0xff & (~instr->atdec_1));
- adlib_write(port + 0x80, 0xff & (~instr->sustrel_1));
- adlib_write(port + 0xE0, instr->waveform_1);
-
- port = channel_mappings_2[chan];
- adlib_write(port + 0x20, instr->flags_2);
- adlib_write(port + 0x40, (instr->oplvl_2 | 0x3F) - vol_2 );
- adlib_write(port + 0x60, 0xff & (~instr->atdec_2));
- adlib_write(port + 0x80, 0xff & (~instr->sustrel_2));
- adlib_write(port + 0xE0, instr->waveform_2);
-
- adlib_write((byte)chan + 0xC0, instr->feedback);
-}
-
-void MidiDriver_ADLIB::adlib_note_on_ex(int chan, byte note, int mod)
-{
- int code;
- assert(chan >= 0 && chan < 9);
- code = (note << 7) + mod;
- curnote_table[chan] = code;
- channel_table_2[chan] = 0;
- adlib_playnote(chan, code);
-}
-
-void MidiDriver_ADLIB::mc_init_stuff(AdlibVoice *voice, Struct10 * s10,
- Struct11 * s11, byte flags, InstrumentExtra * ie) {
- AdlibPart *part = voice->_part;
- s11->modify_val = 0;
- s11->flag0x40 = flags & 0x40;
- s10->loop = flags & 0x20;
- s11->flag0x10 = flags & 0x10;
- s11->param = param_table_1[flags & 0xF];
- s10->max_value = maxval_table[flags & 0xF];
- s10->unk3 = 31;
- if (s11->flag0x40) {
- s10->modwheel = part->_modwheel >> 2;
- } else {
- s10->modwheel = 31;
- }
-
- switch (s11->param) {
- case 0:
- s10->start_value = voice->_vol_2;
- break;
- case 13:
- s10->start_value = voice->_vol_1;
- break;
- case 30:
- s10->start_value = 31;
- s11->s10->modwheel = 0;
- break;
- case 31:
- s10->start_value = 0;
- s11->s10->unk3 = 0;
- break;
- default:
- s10->start_value = adlib_read_param(voice->_channel, s11->param);
- }
-
- struct10_init(s10, ie);
-}
-
-void MidiDriver_ADLIB::struct10_init(Struct10 *s10, InstrumentExtra *ie) {
- s10->active = 1;
- if (!_game_SmallHeader) {
- s10->cur_val = 0;
- } else {
- s10->cur_val = s10->start_value;
- s10->start_value = 0;
- }
- s10->modwheel_last = 31;
- s10->count = ie->a;
- if (s10->count)
- s10->count *= 63;
- s10->table_a[0] = ie->b;
- s10->table_a[1] = ie->d;
- s10->table_a[2] = ie->f;
- s10->table_a[3] = ie->g;
-
- s10->table_b[0] = ie->c;
- s10->table_b[1] = ie->e;
- s10->table_b[2] = 0;
- s10->table_b[3] = ie->h;
-
- struct10_setup(s10);
-}
-
-int MidiDriver_ADLIB::adlib_read_param(int chan, byte param) {
- const AdlibSetParams *as;
- byte val;
- byte port;
-
- assert(chan >= 0 && chan < 9);
-
- if (param <= 12) {
- port = channel_mappings_2[chan];
- } else if (param <= 25) {
- param -= 13;
- port = channel_mappings[chan];
- } else if (param <= 27) {
- param -= 13;
- port = chan;
- } else if (param == 28) {
- return 0xF;
- } else if (param == 29) {
- return 0x17F;
- } else {
- return 0;
- }
-
- as = &adlib_setparam_table[param];
- val = adlib_read(port + as->a);
- val &= as->c;
- val >>= as->b;
- if (as->d)
- val = as->d - val;
-
- return val;
-}
-
-void MidiDriver_ADLIB::adlib_note_on(int chan, byte note, int mod) {
- int code;
- assert(chan >= 0 && chan < 9);
- code = (note << 7) + mod;
- curnote_table[chan] = code;
- adlib_playnote(chan, (int16) channel_table_2[chan] + code);
-}
diff --git a/backends/midi/emumidi.h b/backends/midi/emumidi.h
deleted file mode 100644
index 34cd4b0983..0000000000
--- a/backends/midi/emumidi.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2001-2004 The ScummVM project
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * $Header$
- */
-
-#include "stdafx.h"
-#include "sound/audiostream.h"
-#include "sound/mididrv.h"
-#include "sound/mixer.h"
-
-#define FIXP_SHIFT 16
-
-class MidiDriver_Emulated : public AudioStream, public MidiDriver {
-protected:
- bool _isOpen;
- SoundMixer *_mixer;
-
-private:
- Timer::TimerProc _timerProc;
- void *_timerParam;
-
- int _nextTick;
- int _samplesPerTick;
-
-protected:
- virtual void generateSamples(int16 *buf, int len) = 0;
- virtual void onTimer() {}
-
- int _baseFreq;
-
-public:
- MidiDriver_Emulated(SoundMixer *mixer) : _mixer(mixer) {
- _isOpen = false;
-
- _timerProc = 0;
- _timerParam = 0;
-
- _nextTick = 0;
- _samplesPerTick = 0;
-
- _baseFreq = 250;
- }
-
- int open() {
- _isOpen = true;
-
- int d = getRate() / _baseFreq;
- int r = getRate() % _baseFreq;
-
- // This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
- // but less prone to arithmetic overflow.
-
- _samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
- return 0;
- }
-
- void setTimerCallback(void *timer_param, Timer::TimerProc timer_proc) {
- _timerProc = timer_proc;
- _timerParam = timer_param;
- }
-
- uint32 getBaseTempo() { return 1000000 / _baseFreq; }
-
-
- // AudioStream API
- int readBuffer(int16 *data, const int numSamples) {
- const int stereoFactor = isStereo() ? 2 : 1;
- int len = numSamples / stereoFactor;
- int step;
-
- do {
- step = len;
- if (step > (_nextTick >> FIXP_SHIFT))
- step = (_nextTick >> FIXP_SHIFT);
-
- generateSamples(data, step);
-
- _nextTick -= step << FIXP_SHIFT;
- if (!(_nextTick >> FIXP_SHIFT)) {
- if (_timerProc)
- (*_timerProc)(_timerParam);
- onTimer();
- _nextTick += _samplesPerTick;
- }
- data += step * stereoFactor;
- len -= step;
- } while (len);
-
- return numSamples;
- }
- bool endOfData() const { return false; }
-};
diff --git a/backends/midi/mt32.cpp b/backends/midi/mt32.cpp
deleted file mode 100644
index 8bf3807603..0000000000
--- a/backends/midi/mt32.cpp
+++ /dev/null
@@ -1,486 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2001-2004 The ScummVM project
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * $Header$
- */
-
-#include "stdafx.h"
-#include "common/scummsys.h"
-
-#ifdef USE_MT32EMU
-
-#include "backends/midi/mt32/mt32emu.h"
-
-#include "backends/midi/emumidi.h"
-#include "sound/mpu401.h"
-
-#include "common/util.h"
-#include "common/file.h"
-#include "common/config-manager.h"
-
-#include "graphics/font.h"
-#include "graphics/surface.h"
-
-class MidiChannel_MT32 : public MidiChannel_MPU401 {
- void effectLevel(byte value) { }
- void chorusLevel(byte value) { }
-};
-
-class MidiDriver_MT32 : public MidiDriver_Emulated {
-private:
- PlayingSoundHandle _handle;
- MidiChannel_MT32 _midiChannels[16];
- uint16 _channelMask;
- MT32Emu::Synth *_synth;
-
- int _outputRate;
-
-protected:
- void generateSamples(int16 *buf, int len);
-
-public:
- bool _initialising;
-
- MidiDriver_MT32(SoundMixer *mixer);
- virtual ~MidiDriver_MT32();
-
- int open();
- void close();
- void send(uint32 b);
- void setPitchBendRange (byte channel, uint range);
- void sysEx(byte *msg, uint16 length);
-
- uint32 property(int prop, uint32 param);
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel();
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _outputRate; }
-};
-
-typedef File SFile;
-
-class MT32File: public MT32Emu::File {
- SFile file;
-public:
- bool open(const char *filename, OpenMode mode) {
- SFile::AccessMode accessMode = mode == OpenMode_read ? SFile::kFileReadMode : SFile::kFileWriteMode;
- return file.open(filename, accessMode);
- }
- void close() {
- return file.close();
- }
- size_t read(void *in, size_t size) {
- return file.read(in, size);
- }
- bool readLine(char *in, size_t size) {
- return file.gets(in, size) != NULL;
- }
- bool readBit8u(MT32Emu::Bit8u *in) {
- byte b = file.readByte();
- if (file.eof())
- return false;
- *in = b;
- return true;
- }
- size_t write(const void *in, size_t size) {
- return file.write(in, size);
- }
- bool writeBit8u(MT32Emu::Bit8u out) {
- file.writeByte(out);
- return !file.ioFailed();
- }
- bool isEOF() {
- return file.eof();
- }
-};
-
-static int eatSystemEvents() {
- OSystem::Event event;
- while (g_system->pollEvent(event)) {
- switch (event.type) {
- case OSystem::EVENT_QUIT:
- return 1;
- default:
- break;
- }
- }
- return 0;
-}
-
-static void drawProgress(float progress) {
- Graphics::Surface surf;
- uint32 borderColor = 0x2;
- uint32 fillColor = 0x4;
- surf.w = g_system->getWidth() / 7 * 5;
- surf.h = Graphics::g_scummfont.getFontHeight();
- int x = g_system->getWidth() / 7;
- int y = g_system->getHeight() / 2 - surf.h / 2;
- surf.pitch = surf.w;
- surf.bytesPerPixel = 1;
- surf.pixels = calloc(surf.w, surf.h);
- Common::Rect r(surf.w, surf.h);
- surf.frameRect(r, borderColor);
- r.grow(-1);
- r.right = r.left + (uint16)(r.width() * progress);
- surf.fillRect(r, fillColor);
- g_system->copyRectToScreen((byte *)surf.pixels, surf.pitch, x, y, surf.w, surf.h);
- g_system->updateScreen();
- free(surf.pixels);
-}
-
-static void drawMessage(int offset, const Common::String &text) {
- const Graphics::Font &font(Graphics::g_scummfont);
- Graphics::Surface surf;
- uint32 color = 0x2;
- surf.w = g_system->getWidth();
- surf.h = font.getFontHeight();
- surf.pitch = surf.w;
- surf.bytesPerPixel = 1;
- surf.pixels = calloc(surf.w, surf.h);
- font.drawString(&surf, text, 0, 0, surf.w, color, Graphics::kTextAlignCenter);
- int y = g_system->getHeight() / 2 - font.getFontHeight() / 2 + offset * (font.getFontHeight() + 1);
- g_system->copyRectToScreen((byte *)surf.pixels, surf.pitch, 0, y, surf.w, surf.h);
- g_system->updateScreen();
- free(surf.pixels);
-}
-
-static MT32Emu::File *MT32_OpenFile(void *userData, const char *filename, MT32Emu::File::OpenMode mode) {
- MT32File *file = new MT32File();
- if (!file->open(filename, mode)) {
- delete file;
- return NULL;
- }
- return file;
-}
-
-static void MT32_PrintDebug(void *userData, const char *fmt, va_list list) {
- char buf[512];
- if (((MidiDriver_MT32 *)userData)->_initialising) {
- vsprintf(buf, fmt, list);
- buf[70] = 0; // Truncate to a reasonable length
- drawMessage(1, buf);
- }
- //vdebug(0, fmt, list); // FIXME: Use a higher debug level
-}
-
-static int MT32_Report(void *userData, MT32Emu::ReportType type, const void *reportData) {
- switch(type) {
- case MT32Emu::ReportType_lcdMessage:
- g_system->displayMessageOnOSD((const char *)reportData);
- break;
- case MT32Emu::ReportType_errorControlROM:
- error("Failed to load MT32_CONTROL.ROM");
- break;
- case MT32Emu::ReportType_errorPCMROM:
- error("Failed to load MT32_PCM.ROM");
- break;
- case MT32Emu::ReportType_progressInit:
- if (((MidiDriver_MT32 *)userData)->_initialising) {
- drawProgress(*((const float *)reportData));
- return eatSystemEvents();
- }
- break;
- default:
- break;
- }
- return 0;
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_MT32
-//
-////////////////////////////////////////
-
-MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer) : MidiDriver_Emulated(mixer) {
- _channelMask = 0xFFFF; // Permit all 16 channels by default
- uint i;
- for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) {
- _midiChannels[i].init(this, i);
- }
- _synth = NULL;
- // A higher baseFreq reduces the length used in generateSamples(),
- // and means that the timer callback will be called more often.
- // That results in more accurate timing.
- _baseFreq = 10000;
- // Unfortunately bugs in the emulator cause inaccurate tuning
- // at rates other than 32KHz, thus we produce data at 32KHz and
- // rely on SoundMixer to convert.
- _outputRate = 32000; //_mixer->getOutputRate();
- _initialising = false;
-}
-
-MidiDriver_MT32::~MidiDriver_MT32() {
- if (_synth != NULL)
- delete _synth;
-}
-
-int MidiDriver_MT32::open() {
- MT32Emu::SynthProperties prop;
-
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- memset(&prop, 0, sizeof(prop));
- prop.sampleRate = getRate();
- prop.useReverb = true;
- prop.useDefaultReverb = false;
- prop.reverbType = 0;
- prop.reverbTime = 5;
- prop.reverbLevel = 3;
- prop.userData = this;
- prop.printDebug = MT32_PrintDebug;
- prop.report = MT32_Report;
- prop.openFile = MT32_OpenFile;
- _synth = new MT32Emu::Synth();
- _initialising = true;
- const byte dummy_palette[] = {
- 0, 0, 0, 0,
- 0, 0, 171, 0,
- 0, 171, 0, 0,
- 0, 171, 171, 0,
- 171, 0, 0, 0
- };
-
- g_system->setPalette(dummy_palette, 0, 5);
- drawMessage(-1, "Initialising MT-32 Emulator");
- if (!_synth->open(prop))
- return MERR_DEVICE_NOT_AVAILABLE;
- _initialising = false;
- g_system->clearScreen();
- g_system->updateScreen();
- _mixer->playInputStream(&_handle, this, false, -1, 255, 0, false, true);
- return 0;
-}
-
-void MidiDriver_MT32::send(uint32 b) {
- _synth->playMsg(b);
-}
-
-void MidiDriver_MT32::setPitchBendRange(byte channel, uint range) {
- if (range > 24) {
- printf("setPitchBendRange() called with range > 24: %d", range);
- }
- byte benderRangeSysex[9];
- benderRangeSysex[0] = 0x41; // Roland
- benderRangeSysex[1] = channel;
- benderRangeSysex[2] = 0x16; // MT-32
- benderRangeSysex[3] = 0x12; // Write
- benderRangeSysex[4] = 0x00;
- benderRangeSysex[5] = 0x00;
- benderRangeSysex[6] = 0x04;
- benderRangeSysex[7] = (byte)range;
- benderRangeSysex[8] = MT32Emu::Synth::calcSysexChecksum(&benderRangeSysex[4], 4, 0);
- sysEx(benderRangeSysex, 9);
-}
-
-void MidiDriver_MT32::sysEx(byte *msg, uint16 length) {
- if (msg[0] == 0xf0) {
- _synth->playSysex(msg, length);
- } else {
- _synth->playSysexWithoutFraming(msg, length);
- }
-}
-
-void MidiDriver_MT32::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- // Detach the player callback handler
- setTimerCallback(NULL, NULL);
- // Detach the mixer callback handler
- _mixer->stopHandle(_handle);
-
- _synth->close();
- delete _synth;
- _synth = NULL;
-}
-
-void MidiDriver_MT32::generateSamples(int16 *data, int len) {
- _synth->render(data, len);
-}
-
-uint32 MidiDriver_MT32::property(int prop, uint32 param) {
- switch (prop) {
- case PROP_CHANNEL_MASK:
- _channelMask = param & 0xFFFF;
- return 1;
- }
-
- return 0;
-}
-
-MidiChannel *MidiDriver_MT32::allocateChannel() {
- MidiChannel_MT32 *chan;
- uint i;
-
- for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) {
- if (i == 9 || !(_channelMask & (1 << i)))
- continue;
- chan = &_midiChannels[i];
- if (chan->allocate()) {
- return chan;
- }
- }
- return NULL;
-}
-
-MidiChannel *MidiDriver_MT32::getPercussionChannel() {
- return &_midiChannels[9];
-}
-
-// This code should be used when calling the timer callback from the mixer thread is undesirable.
-// Note that it results in less accurate timing.
-#if 0
-class MidiEvent_MT32 {
-public:
- MidiEvent_MT32 *_next;
- uint32 _msg; // 0xFFFFFFFF indicates a sysex message
- byte *_data;
- uint32 _len;
-
- MidiEvent_MT32(uint32 msg, byte *data, uint32 len) {
- _msg = msg;
- if (len > 0) {
- _data = new byte[len];
- memcpy(_data, data, len);
- }
- _len = len;
- _next = NULL;
- }
-
- MidiEvent_MT32() {
- if (_len > 0)
- delete _data;
- }
-};
-
-class MidiDriver_ThreadedMT32 : public MidiDriver_MT32 {
-private:
- OSystem::MutexRef _eventMutex;
- MidiEvent_MT32 *_events;
- Timer::TimerProc _timer_proc;
-
- void pushMidiEvent(MidiEvent_MT32 *event);
- MidiEvent_MT32 *popMidiEvent();
-
-protected:
- void send(uint32 b);
- void sysEx(byte *msg, uint16 length);
-
-public:
- MidiDriver_ThreadedMT32(SoundMixer *mixer);
- virtual ~MidiDriver_ThreadedMT32();
-
- void onTimer();
- void close();
- void setTimerCallback(void *timer_param, Timer::TimerProc timer_proc);
-};
-
-
-MidiDriver_ThreadedMT32::MidiDriver_ThreadedMT32(SoundMixer *mixer) : MidiDriver_MT32(mixer) {
- _eventMutex = g_system->createMutex();
- _events = NULL;
- _timer_proc = NULL;
-}
-
-MidiDriver_ThreadedMT32::~MidiDriver_ThreadedMT32() {
- g_system->deleteMutex(_eventMutex);
-}
-
-void MidiDriver_ThreadedMT32::close() {
- MidiDriver_MT32::close();
- while ((popMidiEvent() != NULL)) {
- // Just eat any leftover events
- }
-}
-
-void MidiDriver_ThreadedMT32::setTimerCallback(void *timer_param, Timer::TimerProc timer_proc) {
- if (!_timer_proc || !timer_proc) {
- if (_timer_proc)
- g_timer->removeTimerProc(_timer_proc);
- _timer_proc = timer_proc;
- if (timer_proc)
- g_timer->installTimerProc(timer_proc, getBaseTempo(), timer_param);
- }
-}
-
-void MidiDriver_ThreadedMT32::pushMidiEvent(MidiEvent_MT32 *event) {
- g_system->lockMutex(_eventMutex);
- if (_events == NULL) {
- _events = event;
- } else {
- MidiEvent_MT32 *last = _events;
- while (last->_next != NULL)
- last = last->_next;
- last->_next = event;
- }
- g_system->unlockMutex(_eventMutex);
-}
-
-MidiEvent_MT32 *MidiDriver_ThreadedMT32::popMidiEvent() {
- MidiEvent_MT32 *event;
- g_system->lockMutex(_eventMutex);
- event = _events;
- if (event != NULL)
- _events = event->_next;
- g_system->unlockMutex(_eventMutex);
- return event;
-}
-
-void MidiDriver_ThreadedMT32::send(uint32 b) {
- MidiEvent_MT32 *event = new MidiEvent_MT32(b, NULL, 0);
- pushMidiEvent(event);
-}
-
-void MidiDriver_ThreadedMT32::sysEx(byte *msg, uint16 length) {
- MidiEvent_MT32 *event = new MidiEvent_MT32(0xFFFFFFFF, msg, length);
- pushMidiEvent(event);
-}
-
-void MidiDriver_ThreadedMT32::onTimer() {
- MidiEvent_MT32 *event;
- while ((event = popMidiEvent()) != NULL) {
- if (event->_msg == 0xFFFFFFFF) {
- MidiDriver_MT32::sysEx(event->_data, event->_len);
- } else {
- MidiDriver_MT32::send(event->_msg);
- }
- delete event;
- }
-}
-#endif
-
-////////////////////////////////////////
-//
-// MidiDriver_MT32 factory
-//
-////////////////////////////////////////
-
-MidiDriver *MidiDriver_MT32_create(SoundMixer *mixer) {
- // HACK: It will stay here until engine plugin loader overhaul
- if (ConfMan.hasKey("extrapath"))
- File::addDefaultDirectory(ConfMan.get("extrapath"));
- return new MidiDriver_MT32(mixer);
-}
-
-#endif
diff --git a/backends/midi/mt32/.cvsignore b/backends/midi/mt32/.cvsignore
deleted file mode 100644
index 39a06683b7..0000000000
--- a/backends/midi/mt32/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-.deps
diff --git a/backends/midi/mt32/freeverb.cpp b/backends/midi/mt32/freeverb.cpp
deleted file mode 100644
index df3e3bf2a2..0000000000
--- a/backends/midi/mt32/freeverb.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2004 The ScummVM project
- * Copyright (C) 2000 Jezar at Dreampoint
- *
- * This code is public domain
- *
- * Parts of this code are:
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * $Header$
- *
- */
-
-// Comb filter implementation
-//
-// Written by
-// http://www.dreampoint.co.uk
-// This code is public domain
-
-#include "stdafx.h"
-#include "backends/midi/mt32/freeverb.h"
-
-comb::comb() {
- filterstore = 0;
- bufidx = 0;
-}
-
-void comb::setbuffer(float *buf, int size) {
- buffer = buf;
- bufsize = size;
-}
-
-void comb::mute() {
- for (int i = 0; i < bufsize; i++)
- buffer[i] = 0;
-}
-
-void comb::setdamp(float val) {
- damp1 = val;
- damp2 = 1 - val;
-}
-
-float comb::getdamp() {
- return damp1;
-}
-
-void comb::setfeedback(float val) {
- feedback = val;
-}
-
-float comb::getfeedback() {
- return feedback;
-}
-
-// Allpass filter implementation
-
-allpass::allpass() {
- bufidx = 0;
-}
-
-void allpass::setbuffer(float *buf, int size) {
- buffer = buf;
- bufsize = size;
-}
-
-void allpass::mute() {
- for (int i = 0; i < bufsize; i++)
- buffer[i] = 0;
-}
-
-void allpass::setfeedback(float val) {
- feedback = val;
-}
-
-float allpass::getfeedback() {
- return feedback;
-}
-
-// Reverb model implementation
-
-revmodel::revmodel() {
- // Tie the components to their buffers
- combL[0].setbuffer(bufcombL1,combtuningL1);
- combR[0].setbuffer(bufcombR1,combtuningR1);
- combL[1].setbuffer(bufcombL2,combtuningL2);
- combR[1].setbuffer(bufcombR2,combtuningR2);
- combL[2].setbuffer(bufcombL3,combtuningL3);
- combR[2].setbuffer(bufcombR3,combtuningR3);
- combL[3].setbuffer(bufcombL4,combtuningL4);
- combR[3].setbuffer(bufcombR4,combtuningR4);
- combL[4].setbuffer(bufcombL5,combtuningL5);
- combR[4].setbuffer(bufcombR5,combtuningR5);
- combL[5].setbuffer(bufcombL6,combtuningL6);
- combR[5].setbuffer(bufcombR6,combtuningR6);
- combL[6].setbuffer(bufcombL7,combtuningL7);
- combR[6].setbuffer(bufcombR7,combtuningR7);
- combL[7].setbuffer(bufcombL8,combtuningL8);
- combR[7].setbuffer(bufcombR8,combtuningR8);
- allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
- allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
- allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
- allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
- allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
- allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
- allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
- allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);
-
- // Set default values
- allpassL[0].setfeedback(0.5f);
- allpassR[0].setfeedback(0.5f);
- allpassL[1].setfeedback(0.5f);
- allpassR[1].setfeedback(0.5f);
- allpassL[2].setfeedback(0.5f);
- allpassR[2].setfeedback(0.5f);
- allpassL[3].setfeedback(0.5f);
- allpassR[3].setfeedback(0.5f);
- setwet(initialwet);
- setroomsize(initialroom);
- setdry(initialdry);
- setdamp(initialdamp);
- setwidth(initialwidth);
- setmode(initialmode);
-
- // Buffer will be full of rubbish - so we MUST mute them
- mute();
-}
-
-void revmodel::mute() {
- int i;
-
- if (getmode() >= freezemode)
- return;
-
- for (i = 0; i < numcombs; i++) {
- combL[i].mute();
- combR[i].mute();
- }
-
- for (i = 0; i < numallpasses; i++) {
- allpassL[i].mute();
- allpassR[i].mute();
- }
-}
-
-void revmodel::processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip) {
- float outL, outR, input;
-
- while(numsamples-- > 0) {
- int i;
-
- outL = outR = 0;
- input = (*inputL + *inputR) * gain;
-
- // Accumulate comb filters in parallel
- for (i = 0; i < numcombs; i++) {
- outL += combL[i].process(input);
- outR += combR[i].process(input);
- }
-
- // Feed through allpasses in series
- for (i = 0; i < numallpasses; i++) {
- outL = allpassL[i].process(outL);
- outR = allpassR[i].process(outR);
- }
-
- // Calculate output REPLACING anything already there
- *outputL = outL * wet1 + outR * wet2 + *inputL * dry;
- *outputR = outR * wet1 + outL * wet2 + *inputR * dry;
-
- // Increment sample pointers, allowing for interleave (if any)
- inputL += skip;
- inputR += skip;
- outputL += skip;
- outputR += skip;
- }
-}
-
-void revmodel::processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip) {
- float outL, outR, input;
-
- while (numsamples-- > 0) {
- int i;
-
- outL = outR = 0;
- input = (*inputL + *inputR) * gain;
-
- // Accumulate comb filters in parallel
- for (i = 0; i < numcombs; i++) {
- outL += combL[i].process(input);
- outR += combR[i].process(input);
- }
-
- // Feed through allpasses in series
- for (i = 0; i < numallpasses; i++) {
- outL = allpassL[i].process(outL);
- outR = allpassR[i].process(outR);
- }
-
- // Calculate output MIXING with anything already there
- *outputL += outL * wet1 + outR * wet2 + *inputL * dry;
- *outputR += outR * wet1 + outL * wet2 + *inputR * dry;
-
- // Increment sample pointers, allowing for interleave (if any)
- inputL += skip;
- inputR += skip;
- outputL += skip;
- outputR += skip;
- }
-}
-
-void revmodel::update() {
- // Recalculate internal values after parameter change
-
- int i;
-
- wet1 = wet * (width / 2 + 0.5f);
- wet2 = wet * ((1 - width) / 2);
-
- if (mode >= freezemode) {
- roomsize1 = 1;
- damp1 = 0;
- gain = muted;
- } else {
- roomsize1 = roomsize;
- damp1 = damp;
- gain = fixedgain;
- }
-
- for (i = 0; i < numcombs; i++) {
- combL[i].setfeedback(roomsize1);
- combR[i].setfeedback(roomsize1);
- }
-
- for (i = 0; i < numcombs; i++) {
- combL[i].setdamp(damp1);
- combR[i].setdamp(damp1);
- }
-}
-
-// The following get/set functions are not inlined, because
-// speed is never an issue when calling them, and also
-// because as you develop the reverb model, you may
-// wish to take dynamic action when they are called.
-
-void revmodel::setroomsize(float value) {
- roomsize = (value * scaleroom) + offsetroom;
- update();
-}
-
-float revmodel::getroomsize() {
- return (roomsize - offsetroom) / scaleroom;
-}
-
-void revmodel::setdamp(float value) {
- damp = value * scaledamp;
- update();
-}
-
-float revmodel::getdamp() {
- return damp / scaledamp;
-}
-
-void revmodel::setwet(float value) {
- wet = value * scalewet;
- update();
-}
-
-float revmodel::getwet() {
- return wet / scalewet;
-}
-
-void revmodel::setdry(float value) {
- dry = value * scaledry;
-}
-
-float revmodel::getdry() {
- return dry / scaledry;
-}
-
-void revmodel::setwidth(float value) {
- width = value;
- update();
-}
-
-float revmodel::getwidth() {
- return width;
-}
-
-void revmodel::setmode(float value) {
- mode = value;
- update();
-}
-
-float revmodel::getmode() {
- if (mode >= freezemode)
- return 1;
- else
- return 0;
-}
diff --git a/backends/midi/mt32/freeverb.h b/backends/midi/mt32/freeverb.h
deleted file mode 100644
index d618f79670..0000000000
--- a/backends/midi/mt32/freeverb.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2004 The ScummVM project
- * Copyright (C) 2000 Jezar at Dreampoint
- *
- * This code is public domain
- *
- * Parts of this code are:
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * $Header$
- *
- */
-
-// Macro for killing denormalled numbers
-//
-// Written by Jezar at Dreampoint, June 2000
-// http://www.dreampoint.co.uk
-// Based on IS_DENORMAL macro by Jon Watte
-// This code is public domain
-
-#ifndef FREEVERB_H
-#define FREEVERB_H
-
-#define undenormalise(sample) if (((*(unsigned int*)&sample) & 0x7f800000) == 0) sample = 0.0f
-
-// Comb filter class declaration
-
-class comb {
-public:
- comb();
- void setbuffer(float *buf, int size);
- inline float process(float inp);
- void mute();
- void setdamp(float val);
- float getdamp();
- void setfeedback(float val);
- float getfeedback();
-private:
- float feedback;
- float filterstore;
- float damp1;
- float damp2;
- float *buffer;
- int bufsize;
- int bufidx;
-};
-
-
-// Big to inline - but crucial for speed
-
-inline float comb::process(float input) {
- float output;
-
- output = buffer[bufidx];
- undenormalise(output);
-
- filterstore = (output * damp2) + (filterstore * damp1);
- undenormalise(filterstore);
-
- buffer[bufidx] = input + (filterstore * feedback);
-
- if (++bufidx >= bufsize)
- bufidx = 0;
-
- return output;
-}
-
-// Allpass filter declaration
-
-class allpass {
-public:
- allpass();
- void setbuffer(float *buf, int size);
- inline float process(float inp);
- void mute();
- void setfeedback(float val);
- float getfeedback();
-private:
- float feedback;
- float *buffer;
- int bufsize;
- int bufidx;
-};
-
-
-// Big to inline - but crucial for speed
-
-inline float allpass::process(float input) {
- float output;
- float bufout;
-
- bufout = buffer[bufidx];
- undenormalise(bufout);
-
- output = -input + bufout;
- buffer[bufidx] = input + (bufout * feedback);
-
- if (++bufidx >= bufsize)
- bufidx = 0;
-
- return output;
-}
-
-
-// Reverb model tuning values
-
-const int numcombs = 8;
-const int numallpasses = 4;
-const float muted = 0;
-const float fixedgain = 0.015f;
-const float scalewet = 3;
-const float scaledry = 2;
-const float scaledamp = 0.4f;
-const float scaleroom = 0.28f;
-const float offsetroom = 0.7f;
-const float initialroom = 0.5f;
-const float initialdamp = 0.5f;
-const float initialwet = 1 / scalewet;
-const float initialdry = 0;
-const float initialwidth = 1;
-const float initialmode = 0;
-const float freezemode = 0.5f;
-const int stereospread = 23;
-
-// These values assume 44.1KHz sample rate
-// they will probably be OK for 48KHz sample rate
-// but would need scaling for 96KHz (or other) sample rates.
-// The values were obtained by listening tests.
-const int combtuningL1 = 1116;
-const int combtuningR1 = 1116 + stereospread;
-const int combtuningL2 = 1188;
-const int combtuningR2 = 1188 + stereospread;
-const int combtuningL3 = 1277;
-const int combtuningR3 = 1277 + stereospread;
-const int combtuningL4 = 1356;
-const int combtuningR4 = 1356 + stereospread;
-const int combtuningL5 = 1422;
-const int combtuningR5 = 1422 + stereospread;
-const int combtuningL6 = 1491;
-const int combtuningR6 = 1491 + stereospread;
-const int combtuningL7 = 1557;
-const int combtuningR7 = 1557 + stereospread;
-const int combtuningL8 = 1617;
-const int combtuningR8 = 1617 + stereospread;
-const int allpasstuningL1 = 556;
-const int allpasstuningR1 = 556 + stereospread;
-const int allpasstuningL2 = 441;
-const int allpasstuningR2 = 441 + stereospread;
-const int allpasstuningL3 = 341;
-const int allpasstuningR3 = 341 + stereospread;
-const int allpasstuningL4 = 225;
-const int allpasstuningR4 = 225 + stereospread;
-
-
-// Reverb model declaration
-
-class revmodel {
-public:
- revmodel();
- void mute();
- void processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
- void processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
- void setroomsize(float value);
- float getroomsize();
- void setdamp(float value);
- float getdamp();
- void setwet(float value);
- float getwet();
- void setdry(float value);
- float getdry();
- void setwidth(float value);
- float getwidth();
- void setmode(float value);
- float getmode();
-private:
- void update();
-
- float gain;
- float roomsize, roomsize1;
- float damp, damp1;
- float wet, wet1, wet2;
- float dry;
- float width;
- float mode;
-
- // The following are all declared inline
- // to remove the need for dynamic allocation
- // with its subsequent error-checking messiness
-
- // Comb filters
- comb combL[numcombs];
- comb combR[numcombs];
-
- // Allpass filters
- allpass allpassL[numallpasses];
- allpass allpassR[numallpasses];
-
- // Buffers for the combs
- float bufcombL1[combtuningL1];
- float bufcombR1[combtuningR1];
- float bufcombL2[combtuningL2];
- float bufcombR2[combtuningR2];
- float bufcombL3[combtuningL3];
- float bufcombR3[combtuningR3];
- float bufcombL4[combtuningL4];
- float bufcombR4[combtuningR4];
- float bufcombL5[combtuningL5];
- float bufcombR5[combtuningR5];
- float bufcombL6[combtuningL6];
- float bufcombR6[combtuningR6];
- float bufcombL7[combtuningL7];
- float bufcombR7[combtuningR7];
- float bufcombL8[combtuningL8];
- float bufcombR8[combtuningR8];
-
- // Buffers for the allpasses
- float bufallpassL1[allpasstuningL1];
- float bufallpassR1[allpasstuningR1];
- float bufallpassL2[allpasstuningL2];
- float bufallpassR2[allpasstuningR2];
- float bufallpassL3[allpasstuningL3];
- float bufallpassR3[allpasstuningR3];
- float bufallpassL4[allpasstuningL4];
- float bufallpassR4[allpasstuningR4];
-};
-
-#endif
diff --git a/backends/midi/mt32/i386.cpp b/backends/midi/mt32/i386.cpp
deleted file mode 100644
index e2e4b0f790..0000000000
--- a/backends/midi/mt32/i386.cpp
+++ /dev/null
@@ -1,817 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include "mt32emu.h"
-
-#ifdef MT32EMU_HAVE_X86
-
-namespace MT32Emu {
-
-#ifndef _MSC_VER
-
-#define eflag(value) __asm__ __volatile__("pushfl \n popfl \n" : : "a"(value))
-#define cpuid_flag (1 << 21)
-
-static inline bool atti386_DetectCPUID() {
- unsigned int result;
-
- // Is there a cpuid?
- result = cpuid_flag; // set test
- eflag(result);
- if (!(result & cpuid_flag))
- return false;
-
- result = 0; // clear test
- eflag(result);
- if (result & cpuid_flag)
- return false;
-
- return true;
-}
-
-static inline bool atti386_DetectSIMD() {
- unsigned int result;
-
- if (atti386_DetectCPUID() == false)
- return false;
-
- /* check cpuid */
- __asm__ __volatile__(
- "movl $1, %%eax \n" \
- "cpuid \n" \
- "movl %%edx, %0 \n" \
- : "=r"(result) : : "eax", "ebx", "ecx", "edx");
-
- if (result & (1 << 25))
- return true;
-
- return false;
-}
-
-static inline bool atti386_Detect3DNow() {
- unsigned int result;
-
- if (atti386_DetectCPUID() == false)
- return false;
-
- // get cpuid
- __asm__ __volatile__(
- "movl $0x80000001, %%eax \n" \
- "cpuid \n" \
- "movl %%edx, %0 \n" \
- : "=r"(result) : : "eax", "ebx", "ecx", "edx");
-
- if (result & 0x80000000)
- return true;
-
- return false;
-}
-
-
-static inline float atti386_iir_filter_sse(float *output, float *hist1_ptr, float *coef_ptr) {
- __asm__ __volatile__ (
- "pushl %1 \n" \
- "pushl %2 \n" \
- "movss 0(%0), %%xmm1 \n" \
- "movups 0(%1), %%xmm2 \n" \
- "movlps 0(%2), %%xmm3 \n" \
- " \n" \
- "shufps $0x44, %%xmm3, %%xmm3 \n" \
- " \n" \
- "mulps %%xmm3, %%xmm2 \n" \
- " \n" \
- "subss %%xmm2, %%xmm1 \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "subss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm1, 0(%2) \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm3, 4(%2) \n" \
- " \n" \
- "addl $16, %1 \n" \
- "addl $8, %2 \n" \
- " \n" \
- "movups 0(%1), %%xmm2 \n" \
- " \n" \
- "movlps 0(%2), %%xmm3 \n" \
- "shufps $0x44, %%xmm3, %%xmm3 \n" \
- " \n" \
- "mulps %%xmm3, %%xmm2 \n" \
- " \n" \
- "subss %%xmm2, %%xmm1 \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "subss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm1, 0(%2) \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm3, 4(%2) \n" \
- "movss %%xmm1, 0(%0) \n" \
- "popl %2 \n" \
- "popl %1 \n" \
- : : "r"(output), "r"(coef_ptr), "r"(hist1_ptr)
- : "xmm1", "xmm2", "xmm3", "memory");
-
- return *output;
-}
-
-static inline float atti386_iir_filter_3DNow(float output, float *hist1_ptr, float *coef_ptr) {
- float tmp;
-
- __asm__ __volatile__ (
- "movq %0, %%mm1 \n" \
- " \n" \
- "movl %1, %%ebx \n" \
- "movq 0(%%ebx), %%mm2 \n" \
- " \n" \
- "movl %2, %%eax; \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "movd %%mm1, %3 \n" \
- " \n" \
- "addl $8, %%ebx \n" \
- "movq 0(%%ebx), %%mm2 \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "pushl %3 \n" \
- "popl 0(%%eax) \n" \
- " \n" \
- "movd %%mm3, 4(%%eax) \n" \
- " \n" \
- "addl $8, %%ebx \n" \
- "addl $8, %%eax \n" \
- " \n" \
- "movq 0(%%ebx), %%mm2 \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "movd %%mm1, %3 \n" \
- " \n" \
- "addl $8, %%ebx \n" \
- "movq 0(%%ebx), %%mm2 \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "pushl %3 \n" \
- "popl 0(%%eax) \n" \
- "movd %%mm3, 4(%%eax) \n" \
- " \n" \
- "movd %%mm1, %0 \n" \
- "femms \n" \
- : "=m"(output) : "g"(coef_ptr), "g"(hist1_ptr), "m"(tmp)
- : "eax", "ebx", "mm1", "mm2", "mm3", "memory");
-
- return output;
-}
-
-static inline void atti386_produceOutput1(int tmplen, Bit16s myvolume, Bit16s *useBuf, Bit16s *snd) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movw %1, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %1, %%ax \n" \
- "movd %%eax, %%mm3 \n" \
- "movd %%eax, %%mm2 \n" \
- "psllq $32, %%mm3 \n" \
- "por %%mm2, %%mm3 \n" \
- "movl %2, %%esi \n" \
- "movl %3, %%edi \n" \
- "1: \n" \
- "movq 0(%%esi), %%mm1 \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "pmulhw %%mm3, %%mm1 \n" \
- "paddw %%mm2, %%mm1 \n" \
- "movq %%mm1, 0(%%edi) \n" \
- " \n" \
- "addl $8, %%esi \n" \
- "addl $8, %%edi \n" \
- " \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(tmplen), "g"(myvolume), "g"(useBuf), "g"(snd)
- : "eax", "ecx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
-}
-
-static inline void atti386_produceOutput2(Bit32u len, Bit16s *snd, float *sndbufl, float *sndbufr, float *multFactor) {
- __asm__ __volatile__(
- "movl %4, %%ecx \n" \
- "shrl $1, %%ecx \n" \
- "addl $4, %%ecx \n" \
- "pushl %%ecx \n" \
- " \n" \
- "movl %0, %%esi \n" \
- "movups 0(%%esi), %%xmm1 \n" \
- " \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "xorl %%eax, %%eax \n" \
- "movw 0(%1), %%ax \n" \
- "cwde \n" \
- "incl %1 \n" \
- "incl %1 \n" \
- "movd %%eax, %%mm1 \n" \
- "psrlq $32, %%mm1 \n" \
- "movw 0(%1), %%ax \n" \
- "incl %1 \n" \
- "incl %1 \n" \
- "movd %%eax, %%mm2 \n" \
- "por %%mm2, %%mm1 \n" \
- " \n" \
- "decl %%ecx \n" \
- "jnz 1b \n" \
- " \n" \
- "popl %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %3, %%edi \n" \
- "incl %%esi \n" \
- "2: \n" \
- "decl %%ecx \n" \
- "jnz 2b \n" \
- : : "g"(multFactor), "r"(snd), "g"(sndbufl), "g"(sndbufr), "g"(len)
- : "eax", "ecx", "edi", "esi", "mm1", "mm2", "xmm1", "memory");
-}
-
-static inline void atti386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "movq 0(%%edi), %%mm1 \n" \
- "movq 0(%%esi), %%mm2 \n" \
- "paddw %%mm2, %%mm1 \n" \
- "movq %%mm1, 0(%%esi) \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%esi \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(len), "g"(buf1), "g"(buf2)
- : "ecx", "edi", "esi", "mm1", "mm2", "memory");
-}
-
-static inline void atti386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "movq 0(%%esi), %%mm1 \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "movq %%mm1, %%mm3 \n" \
- "pmulhw %%mm2, %%mm1 \n" \
- "paddw %%mm3, %%mm1 \n" \
- "movq %%mm1, 0(%%esi) \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%esi \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(len), "g"(buf1), "g"(buf2)
- : "ecx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
-}
-
-static inline void atti386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "movq 0(%%esi), %%mm1 \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "pmulhw %%mm2, %%mm1 \n" \
- "movq %%mm1, 0(%%esi) \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%esi \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(len), "g"(buf1), "g"(buf2)
- : "ecx", "edi", "esi", "mm1", "mm2", "memory");
-}
-
-static inline void atti386_partialProductOutput(int quadlen, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *p1buf) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movw %1, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %2, %%ax \n" \
- "movd %%eax, %%mm1 \n" \
- "movd %%eax, %%mm2 \n" \
- "psllq $32, %%mm1 \n" \
- "por %%mm2, %%mm1 \n" \
- "movl %3, %%edi \n" \
- "movl %4, %%esi \n" \
- "1: \n" \
- "movw 0(%%esi), %%bx \n" \
- "addl $2, %%esi \n" \
- "movw 0(%%esi), %%dx \n" \
- "addl $2, %%esi \n" \
- "" \
- "movw %%dx, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %%dx, %%ax \n" \
- "movd %%eax, %%mm2 \n" \
- "psllq $32, %%mm2 \n" \
- "movw %%bx, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %%bx, %%ax \n" \
- "movd %%eax, %%mm3 \n" \
- "por %%mm3, %%mm2 \n" \
- "" \
- "pmulhw %%mm1, %%mm2 \n" \
- "movq %%mm2, 0(%%edi) \n" \
- "addl $8, %%edi \n" \
- "" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(quadlen), "g"(leftvol), "g"(rightvol), "g"(partialBuf), "g"(p1buf)
- : "eax", "ebx", "ecx", "edx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
-}
-
-#endif
-
-bool DetectSIMD() {
-#ifdef _MSC_VER
- bool found_simd;
- __asm {
- pushfd
- pop eax // get EFLAGS into eax
- mov ebx,eax // keep a copy
- xor eax,0x200000
- // toggle CPUID bit
-
- push eax
- popfd // set new EFLAGS
- pushfd
- pop eax // EFLAGS back into eax
-
- xor eax,ebx
- // have we changed the ID bit?
-
- je NO_SIMD
- // No, no CPUID instruction
-
- // we could toggle the
- // ID bit so CPUID is present
- mov eax,1
-
- cpuid // get processor features
- test edx,1<<25 // check the SIMD bit
- jz NO_SIMD
- mov found_simd,1
- jmp DONE
- NO_SIMD:
- mov found_simd,0
- DONE:
- }
- return found_simd;
-#else
- return atti386_DetectSIMD();
-#endif
-}
-
-bool Detect3DNow() {
-#ifdef _MSC_VER
- bool found3D = false;
- __asm {
- pushfd
- pop eax
- mov edx, eax
- xor eax, 00200000h
- push eax
- popfd
- pushfd
- pop eax
- xor eax, edx
- jz NO_3DNOW
-
- mov eax, 80000000h
- cpuid
-
- cmp eax, 80000000h
- jbe NO_3DNOW
-
- mov eax, 80000001h
- cpuid
- test edx, 80000000h
- jz NO_3DNOW
- mov found3D, 1
-NO_3DNOW:
-
- }
- return found3D;
-#else
- return atti386_Detect3DNow();
-#endif
-}
-
-float iir_filter_sse(float input,float *hist1_ptr, float *coef_ptr, int revLevel) {
- float output;
-
- // 1st number of coefficients array is overall input scale factor, or filter gain
- output = input * (*coef_ptr++);
-
-#ifdef _MSC_VER
- __asm {
-
- movss xmm1, output
-
- mov eax, coef_ptr
- movups xmm2, [eax]
-
- mov eax, hist1_ptr
- movlps xmm3, [eax]
- shufps xmm3, xmm3, 44h
- // hist1_ptr+1, hist1_ptr, hist1_ptr+1, hist1_ptr
-
- mulps xmm2, xmm3
-
- subss xmm1, xmm2
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- subss xmm1, xmm2
-
- // Store new_hist
- movss DWORD PTR [eax], xmm1
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Store previous hist
- movss DWORD PTR [eax+4], xmm3
-
- add coef_ptr, 16
- add hist1_ptr, 8
-
- mov eax, coef_ptr
- movups xmm2, [eax]
-
- mov eax, hist1_ptr
- movlps xmm3, [eax]
- shufps xmm3, xmm3, 44h
- // hist1_ptr+1, hist1_ptr, hist1_ptr+1, hist1_ptr
-
- mulps xmm2, xmm3
-
- subss xmm1, xmm2
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- subss xmm1, xmm2
-
- // Store new_hist
- movss DWORD PTR [eax], xmm1
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Store previous hist
- movss DWORD PTR [eax+4], xmm3
-
- movss output, xmm1
- }
-#else
- output = atti386_iir_filter_sse(&output, hist1_ptr, coef_ptr);
-#endif
- output *= ResonInv[revLevel];
- return output;
-}
-
-float iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr, int revLevel) {
- float output;
-
- // 1st number of coefficients array is overall input scale factor, or filter gain
- output = input * (*coef_ptr++);
-
- // I find it very sad that 3DNow requires twice as many instructions as Intel's SSE
- // Intel does have the upper hand here.
-#ifdef _MSC_VER
- float tmp;
- __asm {
- movq mm1, output
- mov ebx, coef_ptr
- movq mm2, [ebx]
-
- mov eax, hist1_ptr;
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfsub mm1, mm2
-
- psrlq mm2, 32
- pfsub mm1, mm2
-
- // Store new hist
- movd tmp, mm1
-
- add ebx, 8
- movq mm2, [ebx]
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfadd mm1, mm2
-
- psrlq mm2, 32
- pfadd mm1, mm2
-
- push tmp
- pop DWORD PTR [eax]
-
- movd DWORD PTR [eax+4], mm3
-
- add ebx, 8
- add eax, 8
-
- movq mm2, [ebx]
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfsub mm1, mm2
-
- psrlq mm2, 32
- pfsub mm1, mm2
-
- // Store new hist
- movd tmp, mm1
-
- add ebx, 8
- movq mm2, [ebx]
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfadd mm1, mm2
-
- psrlq mm2, 32
- pfadd mm1, mm2
-
- push tmp
- pop DWORD PTR [eax]
- movd DWORD PTR [eax+4], mm3
-
- movd output, mm1
-
- femms
- }
-#else
- output = atti386_iir_filter_3DNow(output, hist1_ptr, coef_ptr);
-#endif
- output *= ResonInv[revLevel];
- return output;
-}
-
-#if MT32EMU_USE_MMX > 0
-
-int i386_partialProductOutput(int len, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *mixedBuf) {
- int tmplen = len >> 1;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx,tmplen
- mov ax, leftvol
- shl eax,16
- mov ax, rightvol
- movd mm1, eax
- movd mm2, eax
- psllq mm1, 32
- por mm1, mm2
- mov edi, partialBuf
- mov esi, mixedBuf
-mmxloop1:
- mov bx, [esi]
- add esi,2
- mov dx, [esi]
- add esi,2
-
- mov ax, dx
- shl eax, 16
- mov ax, dx
- movd mm2,eax
- psllq mm2, 32
- mov ax, bx
- shl eax, 16
- mov ax, bx
- movd mm3,eax
- por mm2,mm3
-
- pmulhw mm2, mm1
- movq [edi], mm2
- add edi, 8
-
- dec ecx
- cmp ecx,0
- jg mmxloop1
- emms
- }
-#else
- atti386_partialProductOutput(tmplen, leftvol, rightvol, partialBuf, mixedBuf);
-#endif
- return tmplen << 1;
-}
-
-int i386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
- int tmplen = len >> 2;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov esi, buf1
- mov edi, buf2
-
-mixloop1:
- movq mm1, [edi]
- movq mm2, [esi]
- paddw mm1,mm2
- movq [esi],mm1
- add edi,8
- add esi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop1
- emms
- }
-#else
- atti386_mixBuffers(buf1, buf2, tmplen);
-#endif
- return tmplen << 2;
-}
-
-
-int i386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
- int tmplen = len >> 2;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov esi, buf1
- mov edi, buf2
-
-mixloop2:
- movq mm1, [esi]
- movq mm2, [edi]
- movq mm3, mm1
- pmulhw mm1, mm2
- paddw mm1,mm3
- movq [esi],mm1
- add edi,8
- add esi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop2
- emms
- }
-#else
- atti386_mixBuffersRingMix(buf1, buf2, tmplen);
-#endif
- return tmplen << 2;
-}
-
-int i386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
- int tmplen = len >> 2;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov esi, buf1
- mov edi, buf2
-
-mixloop3:
- movq mm1, [esi]
- movq mm2, [edi]
- pmulhw mm1, mm2
- movq [esi],mm1
- add edi,8
- add esi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop3
- emms
- }
-#else
- atti386_mixBuffersRing(buf1, buf2, tmplen);
-#endif
- return tmplen << 2;
-}
-
-int i386_produceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume) {
- int tmplen = (len >> 1);
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov ax,volume
- shl eax,16
- mov ax,volume
- movd mm3,eax
- movd mm2,eax
- psllq mm3, 32
- por mm3,mm2
- mov esi, useBuf
- mov edi, stream
-mixloop4:
- movq mm1, [esi]
- movq mm2, [edi]
- pmulhw mm1, mm3
- paddw mm1,mm2
- movq [edi], mm1
-
- add esi,8
- add edi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop4
- emms
- }
-#else
- atti386_produceOutput1(tmplen, volume, useBuf, stream);
-#endif
- return tmplen << 1;
-}
-
-#endif
-
-}
-
-#endif
diff --git a/backends/midi/mt32/i386.h b/backends/midi/mt32/i386.h
deleted file mode 100644
index c26fcb4110..0000000000
--- a/backends/midi/mt32/i386.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_I386_H
-#define MT32EMU_I386_H
-
-namespace MT32Emu {
-#ifdef MT32EMU_HAVE_X86
-
-// Function that detects the availablity of SSE SIMD instructions
-bool DetectSIMD();
-// Function that detects the availablity of 3DNow instructions
-bool Detect3DNow();
-
-float iir_filter_sse(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
-float iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
-float iir_filter_normal(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
-
-#if MT32EMU_USE_MMX > 0
-int i386_partialProductOutput(int len, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *mixedBuf);
-int i386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len);
-int i386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len);
-int i386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len);
-int i386_produceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume);
-#endif
-
-#endif
-
-}
-
-#endif
diff --git a/backends/midi/mt32/module.mk b/backends/midi/mt32/module.mk
deleted file mode 100644
index 9f0594190f..0000000000
--- a/backends/midi/mt32/module.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-MODULE := backends/midi/mt32
-
-MODULE_OBJS := \
- backends/midi/mt32/mt32_file.o \
- backends/midi/mt32/i386.o \
- backends/midi/mt32/part.o \
- backends/midi/mt32/partial.o \
- backends/midi/mt32/partialManager.o \
- backends/midi/mt32/synth.o \
- backends/midi/mt32/tables.o \
- backends/midi/mt32/freeverb.o
-
-MODULE_DIRS += \
- backends/midi/mt32
-
-# Include common rules
-include $(srcdir)/common.rules
diff --git a/backends/midi/mt32/mt32_file.cpp b/backends/midi/mt32/mt32_file.cpp
deleted file mode 100644
index 8cf4e14a7d..0000000000
--- a/backends/midi/mt32/mt32_file.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <stdio.h>
-
-#include "mt32emu.h"
-
-namespace MT32Emu {
-
- bool ANSIFile::open(const char *filename, OpenMode mode) {
- const char *fmode;
- if (mode == OpenMode_read) {
- fmode = "rb";
- } else {
- fmode = "wb";
- }
- fp = fopen(filename, fmode);
- return (fp != NULL);
- }
-
- void ANSIFile::close() {
- fclose(fp);
- }
-
- size_t ANSIFile::read(void *in, size_t size) {
- return fread(in, 1, size, fp);
- }
-
- bool ANSIFile::readLine(char *in, size_t size) {
- return fgets(in, (int)size, fp) != NULL;
- }
-
- bool ANSIFile::readBit8u(Bit8u *in) {
- int c = fgetc(fp);
- if (c == EOF)
- return false;
- *in = (Bit8u)c;
- return true;
- }
-
- bool File::readBit16u(Bit16u *in) {
- Bit8u b[2];
- if (read(&b[0], 2) != 2)
- return false;
- *in = ((b[0] << 8) | b[1]);
- return true;
- }
-
- bool File::readBit32u(Bit32u *in) {
- Bit8u b[4];
- if (read(&b[0], 4) != 4)
- return false;
- *in = ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
- return true;
- }
-
- size_t ANSIFile::write(const void *out, size_t size) {
- return fwrite(out, 1, size, fp);
- }
-
- bool ANSIFile::writeBit8u(Bit8u out) {
- return fputc(out, fp) != EOF;
- }
-
- bool File::writeBit16u(Bit16u out) {
- if (!writeBit8u((Bit8u)((out & 0xFF00) >> 8))) {
- return false;
- }
- if (!writeBit8u((Bit8u)(out & 0x00FF))) {
- return false;
- }
- return true;
- }
-
- bool File::writeBit32u(Bit32u out) {
- if (!writeBit8u((Bit8u)((out & 0xFF000000) >> 24))) {
- return false;
- }
- if (!writeBit8u((Bit8u)((out & 0x00FF0000) >> 16))) {
- return false;
- }
- if (!writeBit8u((Bit8u)((out & 0x0000FF00) >> 8))) {
- return false;
- }
- if (!writeBit8u((Bit8u)(out & 0x000000FF))) {
- return false;
- }
- return true;
- }
-
- bool ANSIFile::isEOF() {
- return feof(fp) != 0;
- }
-}
diff --git a/backends/midi/mt32/mt32_file.h b/backends/midi/mt32/mt32_file.h
deleted file mode 100644
index 7ebb6449b6..0000000000
--- a/backends/midi/mt32/mt32_file.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_FILE_H
-#define MT32EMU_FILE_H
-
-#include <stdio.h>
-
-namespace MT32Emu {
-
-class File {
-public:
- enum OpenMode {
- OpenMode_read = 0,
- OpenMode_write = 1
- };
- virtual ~File() {}
- virtual void close() = 0;
- virtual size_t read(void *in, size_t size) = 0;
- virtual bool readLine(char *in, size_t size) = 0;
- virtual bool readBit8u(Bit8u *in) = 0;
- virtual bool readBit16u(Bit16u *in);
- virtual bool readBit32u(Bit32u *in);
- virtual size_t write(const void *out, size_t size) = 0;
- virtual bool writeBit8u(Bit8u out) = 0;
- // Note: May write a single byte to the file before failing
- virtual bool writeBit16u(Bit16u out);
- // Note: May write some (<4) bytes to the file before failing
- virtual bool writeBit32u(Bit32u out);
- virtual bool isEOF() = 0;
-};
-
-class ANSIFile: public File {
-private:
- FILE *fp;
-public:
- bool open(const char *filename, OpenMode mode);
- void close();
- size_t read(void *in, size_t size);
- bool readLine(char *in, size_t size);
- bool readBit8u(Bit8u *in);
- size_t write(const void *out, size_t size);
- bool writeBit8u(unsigned char out);
- bool isEOF();
-};
-
-}
-
-#endif
diff --git a/backends/midi/mt32/mt32emu.h b/backends/midi/mt32/mt32emu.h
deleted file mode 100644
index 9fffa721f5..0000000000
--- a/backends/midi/mt32/mt32emu.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_MT32EMU_H
-#define MT32EMU_MT32EMU_H
-
-// Debugging
-// Show the instruments played
-#define MT32EMU_MONITOR_INSTRUMENTS 1
-// Shows number of partials MT-32 is playing, and on which parts
-#define MT32EMU_MONITOR_PARTIALS 0
-// Determines how the waveform cache file is handled (must be regenerated after sampling rate change)
-#define MT32EMU_WAVECACHEMODE 0 // Load existing cache if possible, otherwise generate and save cache
-//#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generage but don't save cache
-//#define MT32EMU_WAVECACHEMODE 2 // Ignore existing cache, generate and save cache
-//#define MT32EMU_WAVECACHEMODE 3 // Ignore existing cache, generate but don't save cache
-
-// Configuration
-// The maximum number of partials playing simultaneously
-#define MT32EMU_MAX_PARTIALS 32
-// The maximum number of notes playing simultaneously per part.
-// No point making it more than MT32EMU_MAX_PARTIALS, since each note needs at least one partial.
-#define MT32EMU_MAX_POLY 32
-// This calculates the exact frequencies of notes as they are played, instead of offsetting from pre-cached semitones. Potentially very slow.
-#define MT32EMU_ACCURATENOTES 0
-
-#if (defined (_MSC_VER) && defined(_M_IX86))
-#define MT32EMU_HAVE_X86
-#elif defined(__GNUC__)
-#if __GNUC__ >= 3 && defined(__i386__)
-#define MT32EMU_HAVE_X86
-#endif
-#endif
-
-#ifdef MT32EMU_HAVE_X86
-#define MT32EMU_USE_MMX 1
-#else
-#define MT32EMU_USE_MMX 0
-#endif
-
-#include "freeverb.h"
-
-#include "structures.h"
-#include "i386.h"
-#include "mt32_file.h"
-#include "tables.h"
-#include "partial.h"
-#include "partialManager.h"
-#include "part.h"
-#include "synth.h"
-
-#endif
diff --git a/backends/midi/mt32/part.cpp b/backends/midi/mt32/part.cpp
deleted file mode 100644
index 5aee1202b2..0000000000
--- a/backends/midi/mt32/part.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <string.h>
-#include <math.h>
-
-#include "mt32emu.h"
-
-namespace MT32Emu {
-
-static const Bit8u PartialStruct[13] = {
- 0, 0, 2, 2, 1, 3,
- 3, 0, 3, 0, 2, 1, 3 };
-
-static const Bit8u PartialMixStruct[13] = {
- 0, 1, 0, 1, 1, 0,
- 1, 3, 3, 2, 2, 2, 2 };
-
-static const float floatKeyfollow[17] = {
- -1.0f, -1.0f/2.0f, -1.0f/4.0f, 0.0f,
- 1.0f/8.0f, 1.0f/4.0f, 3.0f/8.0f, 1.0f/2.0f, 5.0f/8.0f, 3.0f/4.0f, 7.0f/8.0f, 1.0f,
- 5.0f/4.0f, 3.0f/2.0f, 2.0f,
- 1.0009765625f, 1.0048828125f
-};
-
-//FIXME:KG: Put this dpoly stuff somewhere better
-bool dpoly::isActive() const {
- return partials[0] != NULL || partials[1] != NULL || partials[2] != NULL || partials[3] != NULL;
-}
-
-Bit32u dpoly::getAge() const {
- for (int i = 0; i < 4; i++) {
- if (partials[i] != NULL) {
- return partials[i]->age;
- }
- }
- return 0;
-}
-
-RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) {
- strcpy(name, "Rhythm");
- rhythmTemp = &synth->mt32ram.rhythmSettings[0];
- refresh();
-}
-
-Part::Part(Synth *useSynth, unsigned int usePartNum) {
- this->synth = useSynth;
- this->partNum = usePartNum;
- patchCache[0].dirty = true;
- holdpedal = false;
- if (usePartNum == 8) {
- // Nasty hack for rhythm
- patchTemp = NULL;
- timbreTemp = NULL;
- } else {
- sprintf(name, "Part %d", partNum + 1);
- patchTemp = &synth->mt32ram.patchSettings[partNum];
- timbreTemp = &synth->mt32ram.timbreSettings[partNum];
- }
- currentInstr[0] = 0;
- currentInstr[10] = 0;
- volume = voltable[102]; //FIXME:KG: Original was just volume=102; I assume this is intended
- volumesetting.leftvol = 32767;
- volumesetting.rightvol = 32767;
- bend = 0.0f;
- memset(polyTable,0,sizeof(polyTable));
- memset(patchCache, 0, sizeof(patchCache));
-}
-
-void Part::setHoldPedal(bool pedalval) {
- if (holdpedal && !pedalval)
- stopPedalHold();
- holdpedal = pedalval;
-}
-
-void RhythmPart::setBend(unsigned int midiBend) {
- synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend);
- return;
-}
-
-void Part::setBend(unsigned int midiBend) {
- // FIXME:KG: Slightly unbalanced increments, but I wanted min -1.0, centre 0.0 and max 1.0
- if (midiBend <= 0x2000) {
- bend = ((signed int)midiBend - 0x2000) / (float)0x2000;
- } else {
- bend = ((signed int)midiBend - 0x2000) / (float)0x1FFF;
- }
- // Loop through all partials to update their bend
- for (int i = 0; i < MT32EMU_MAX_POLY; i++) {
- for (int j = 0; j < 4; j++) {
- if (polyTable[i].partials[j] != NULL) {
- polyTable[i].partials[j]->setBend(bend);
- }
- }
- }
-}
-
-void RhythmPart::setModulation(unsigned int midiModulation) {
- synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, midiModulation);
-}
-
-void Part::setModulation(unsigned int midiModulation) {
- // Just a bloody guess, as always, before I get things figured out
- for (int t = 0; t < 4; t++) {
- if (patchCache[t].playPartial) {
- int newrate = (patchCache[t].modsense * midiModulation) >> 7;
- //patchCache[t].lfoperiod = lfotable[newrate];
- patchCache[t].lfodepth = newrate;
- //FIXME:KG: timbreTemp->partial[t].lfo.depth =
- }
- }
-}
-
-void RhythmPart::refresh() {
- // (Re-)cache all the mapped timbres ahead of time
- for (unsigned int drumNum = 0; drumNum < 64; drumNum++) {
- int drumTimbreNum = rhythmTemp[drumNum].timbre;
- if (drumTimbreNum >= 94)
- continue;
- Bit16s pan = rhythmTemp[drumNum].panpot; // They use R-L 0-14...
- // FIXME:KG: Panning cache should be backed up to partials using it, too
- // FIXME:KG: If I don't have left/right mixed up here, it's pure luck
- if (pan < 7) {
- drumPan[drumNum].leftvol = 32767;
- drumPan[drumNum].rightvol = pan * 4681;
- } else {
- drumPan[drumNum].rightvol = 32767;
- drumPan[drumNum].leftvol = (14 - pan) * 4681;
- }
- PatchCache *cache = drumCache[drumNum];
- backupCacheToPartials(cache);
- for (int t = 0; t < 4; t++) {
- // Common parameters, stored redundantly
- cache[t].dirty = true;
- cache[t].pitchShift = 0.0f;
- cache[t].benderRange = 0.0f;
- cache[t].pansetptr = &drumPan[drumNum];
- cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0;
- }
- }
-}
-
-void Part::refresh() {
- backupCacheToPartials(patchCache);
- for (int t = 0; t < 4; t++) {
- // Common parameters, stored redundantly
- patchCache[t].dirty = true;
- patchCache[t].pitchShift = (patchTemp->patch.keyShift - 24) + (patchTemp->patch.fineTune - 50) / 100.0f;
- patchCache[t].benderRange = patchTemp->patch.benderRange;
- patchCache[t].pansetptr = &volumesetting;
- patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0;
- }
- memcpy(currentInstr, timbreTemp->common.name, 10);
-}
-
-void RhythmPart::refreshTimbre(unsigned int absTimbreNum) {
- for (int m = 0; m < 64; m++) {
- if (rhythmTemp[m].timbre == absTimbreNum - 128)
- drumCache[m][0].dirty = true;
- }
-}
-
-void Part::refreshTimbre(unsigned int absTimbreNum) {
- if (getAbsTimbreNum() == absTimbreNum) {
- memcpy(currentInstr, timbreTemp->common.name, 10);
- patchCache[0].dirty = true;
- }
-}
-
-int Part::fixBiaslevel(int srcpnt, int *dir) {
- int noteat = srcpnt & 0x3F;
- int outnote;
- if (srcpnt < 64)
- *dir = 0;
- else
- *dir = 1;
- outnote = 33 + noteat;
- //synth->printDebug("Bias note %d, dir %d", outnote, *dir);
-
- return outnote;
-}
-
-int Part::fixKeyfollow(int srckey) {
- if (srckey>=0 && srckey<=16) {
- int keyfix[17] = { -256*16, -128*16, -64*16, 0, 32*16, 64*16, 96*16, 128*16, (128+32)*16, 192*16, (192+32)*16, 256*16, (256+64)*16, (256+128)*16, (512)*16, 4100, 4116};
- return keyfix[srckey];
- } else {
- //LOG(LOG_ERROR|LOG_MISC,"Missed key: %d", srckey);
- return 256;
- }
-}
-
-void Part::abortPoly(dpoly *poly) {
- if (!poly->isPlaying) {
- return;
- }
- for (int i = 0; i < 4; i++) {
- Partial *partial = poly->partials[i];
- if (partial != NULL) {
- partial->deactivate();
- }
- }
- poly->isPlaying = false;
-}
-
-void Part::setPatch(const PatchParam *patch) {
- patchTemp->patch = *patch;
-}
-
-void Part::setTimbre(TimbreParam *timbre) {
- *timbreTemp = *timbre;
-}
-
-unsigned int RhythmPart::getAbsTimbreNum() const {
- synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm");
- return 0;
-}
-
-unsigned int Part::getAbsTimbreNum() const {
- return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum;
-}
-
-void RhythmPart::setProgram(unsigned int patchNum) {
- synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum);
-}
-
-void Part::setProgram(unsigned int patchNum) {
- setPatch(&synth->mt32ram.patches[patchNum]);
- setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre);
-#if 0
- // Immediately stop all partials on this part (this is apparently *not* the correct behaviour)
- for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
- AbortPoly(poly);
- }
-#endif
-
- refresh();
-
- allStop(); //FIXME:KG: Is this correct?
-}
-
-void Part::backupCacheToPartials(PatchCache cache[4]) {
- // check if any partials are still playing with the old patch cache
- // if so then duplicate the cached data from the part to the partial so that
- // we can change the part's cache without affecting the partial.
- // We delay this until now to avoid a copy operation with every note played
- for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
- for (int i = 0; i < 4; i++) {
- Partial *partial = polyTable[m].partials[i];
- if (partial != NULL && partial->patchCache == &cache[i]) {
- partial->cachebackup = cache[i];
- partial->patchCache = &partial->cachebackup;
- }
- }
- }
-}
-
-void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) {
- backupCacheToPartials(cache);
- int partialCount = 0;
- for (int t = 0; t < 4; t++) {
- if (((timbre->common.pmute >> t) & 0x1) == 1) {
- cache[t].playPartial = true;
- partialCount++;
- } else {
- cache[t].playPartial = false;
- continue;
- }
-
- // Calculate and cache common parameters
-
- cache[t].pcm = timbre->partial[t].wg.pcmwave;
- cache[t].useBender = (timbre->partial[t].wg.bender == 1);
-
- switch (t) {
- case 0:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x2) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
- cache[t].structurePosition = 0;
- cache[t].structurePair = 1;
- break;
- case 1:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x1) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
- cache[t].structurePosition = 1;
- cache[t].structurePair = 0;
- break;
- case 2:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x2) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
- cache[t].structurePosition = 0;
- cache[t].structurePair = 3;
- break;
- case 3:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x1) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
- cache[t].structurePosition = 1;
- cache[t].structurePair = 2;
- break;
- default:
- break;
- }
-
- cache[t].waveform = timbre->partial[t].wg.waveform;
- cache[t].pulsewidth = timbre->partial[t].wg.pulsewid;
- cache[t].pwsens = timbre->partial[t].wg.pwvelo;
- if (timbre->partial[t].wg.keyfollow > 16) {
- synth->printDebug("Bad keyfollow value in timbre!");
- cache[t].pitchKeyfollow = 1.0f;
- } else {
- cache[t].pitchKeyfollow = floatKeyfollow[timbre->partial[t].wg.keyfollow];
- }
-
- cache[t].pitch = timbre->partial[t].wg.coarse + (timbre->partial[t].wg.fine - 50) / 100.0f + 24.0f;
- cache[t].pitchEnv = timbre->partial[t].env;
- cache[t].pitchEnv.sensitivity = (char)((float)cache[t].pitchEnv.sensitivity * 1.27f);
- cache[t].pitchsustain = cache[t].pitchEnv.level[3];
-
- // Calculate and cache TVA envelope stuff
- cache[t].ampEnv = timbre->partial[t].tva;
- for (int i = 0; i < 4; i++)
- cache[t].ampEnv.envlevel[i] = (char)((float)cache[t].ampEnv.envlevel[i] * 1.27f);
- cache[t].ampEnv.level = (char)((float)cache[t].ampEnv.level * 1.27f);
- float tvelo = ((float)timbre->partial[t].tva.velosens / 100.0f);
- float velo = fabs(tvelo-0.5f) * 2.0f;
- velo *= 63.0f;
- cache[t].ampEnv.velosens = (char)velo;
- if (tvelo<0.5f)
- cache[t].ampenvdir = 1;
- else
- cache[t].ampenvdir = 0;
-
- cache[t].ampbias[0] = fixBiaslevel(cache[t].ampEnv.biaspoint1, &cache[t].ampdir[0]);
- cache[t].ampblevel[0] = 12 - cache[t].ampEnv.biaslevel1;
- cache[t].ampbias[1] = fixBiaslevel(cache[t].ampEnv.biaspoint2, &cache[t].ampdir[1]);
- cache[t].ampblevel[1] = 12 - cache[t].ampEnv.biaslevel2;
- cache[t].ampdepth = cache[t].ampEnv.envvkf * cache[t].ampEnv.envvkf;
- cache[t].ampsustain = cache[t].ampEnv.envlevel[3];
- cache[t].amplevel = cache[t].ampEnv.level;
-
- // Calculate and cache filter stuff
- cache[t].filtEnv = timbre->partial[t].tvf;
- cache[t].tvfdepth = cache[t].filtEnv.envdkf;
- cache[t].filtkeyfollow = fixKeyfollow(cache[t].filtEnv.keyfollow);
- cache[t].filtEnv.envdepth = (char)((float)cache[t].filtEnv.envdepth * 1.27);
- cache[t].tvfbias = fixBiaslevel(cache[t].filtEnv.biaspoint, &cache[t].tvfdir);
- cache[t].tvfblevel = cache[t].filtEnv.biaslevel;
- cache[t].filtsustain = cache[t].filtEnv.envlevel[3];
-
- // Calculate and cache LFO stuff
- cache[t].lfodepth = timbre->partial[t].lfo.depth;
- cache[t].lfoperiod = lfotable[(int)timbre->partial[t].lfo.rate];
- cache[t].lforate = timbre->partial[t].lfo.rate;
- cache[t].modsense = timbre->partial[t].lfo.modsense;
- }
- for (int t = 0; t < 4; t++) {
- // Common parameters, stored redundantly
- cache[t].dirty = false;
- cache[t].partialCount = partialCount;
- cache[t].sustain = (timbre->common.nosustain == 0);
- }
- //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform);
-
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): Recached timbre", name, currentInstr);
- for (int i = 0; i < 4; i++) {
- synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, cache[i].playPartial ? "YES" : "NO", cache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmwave, timbre->partial[i].wg.waveform);
- }
-#endif
-}
-
-const char *Part::getName() const {
- return name;
-}
-
-void Part::setVolume(int vol) {
- volume = voltable[vol];
-}
-
-void RhythmPart::setPan(unsigned int midiPan)
-{
- // FIXME:KG: This is unchangeable for drums (they always use drumPan), is that correct?
- synth->printDebug("%s: Setting pan (%d) not supported on rhythm", name, midiPan);
-}
-
-void Part::setPan(unsigned int midiPan) {
- // FIXME:KG: Tweaked this a bit so that we have a left 100%, centre and right 100%
- // (But this makes the range somewhat skewed)
- if (midiPan < 64) {
- volumesetting.leftvol = 32767;
- volumesetting.rightvol = (Bit16s)(midiPan * 512);
- } else if (midiPan == 64) {
- volumesetting.leftvol = 32767;
- volumesetting.rightvol = 32767;
- } else {
- volumesetting.rightvol = 32767;
- volumesetting.leftvol = (Bit16s)((127 - midiPan) * 520);
- }
- //synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot);
-}
-
-void RhythmPart::playNote(unsigned int key, int vel) {
- if (key < 24 || key > 87) {
- synth->printDebug("%s: Attempted to play invalid key %d", name, key);
- return;
- }
- int drumNum = key - 24;
- int drumTimbreNum = rhythmTemp[drumNum].timbre;
- if (drumTimbreNum >= 94) {
- synth->printDebug("%s: Attempted to play unmapped key %d", name, key);
- return;
- }
- int absTimbreNum = drumTimbreNum + 128;
- TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre;
- memcpy(currentInstr, timbre->common.name, 10);
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): starting poly (drum %d, timbre %d) - Vel %d Key %d Vol %d", name, currentInstr, drumNum, absTimbreNum, vel, key, volume);
-#endif
- if (drumCache[drumNum][0].dirty) {
- cacheTimbre(drumCache[drumNum], timbre);
- }
- playPoly(drumCache[drumNum], key, MIDDLEC, vel);
-}
-
-void Part::playNote(unsigned int key, int vel) {
- int freqNum = key;
- if (freqNum < 12) {
- synth->printDebug("%s (%s): Attempted to play invalid key %d < 12; moving up by octave", name, currentInstr, key);
- freqNum += 12;
- } else if (freqNum > 108) {
- synth->printDebug("%s (%s): Attempted to play invalid key %d > 108; moving down by octave", name, currentInstr, key);
- while (freqNum > 108) {
- freqNum -= 12;
- }
- }
- // POLY1 mode, Single Assign
- // Haven't found any software that uses any of the other poly modes
- // FIXME:KG: Should this also apply to rhythm?
- for (unsigned int i = 0; i < MT32EMU_MAX_POLY; i++) {
- if (polyTable[i].isActive() && (polyTable[i].key == key)) {
- //AbortPoly(&polyTable[i]);
- stopNote(key);
- break;
- }
- }
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): starting poly - Vel %d Key %d Vol %d", name, currentInstr, vel, key, volume);
-#endif
- if (patchCache[0].dirty) {
- cacheTimbre(patchCache, timbreTemp);
- }
- playPoly(patchCache, key, freqNum, vel);
-}
-
-void Part::playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel) {
- unsigned int needPartials = cache[0].partialCount;
- unsigned int freePartials = synth->partialManager->getFreePartialCount();
-
- if (freePartials < needPartials) {
- if (!synth->partialManager->freePartials(needPartials - freePartials, partNum)) {
- synth->printDebug("%s (%s): Insufficient free partials to play key %d (vel=%d); needed=%d, free=%d", name, currentInstr, key, vel, needPartials, synth->partialManager->getFreePartialCount());
- return;
- }
- }
- // Find free poly
- int m;
- for (m = 0; m < MT32EMU_MAX_POLY; m++) {
- if (!polyTable[m].isActive()) {
- break;
- }
- }
- if (m == MT32EMU_MAX_POLY) {
- synth->printDebug("%s (%s): No free poly to play key %d (vel %d)", name, currentInstr, key, vel);
- return;
- }
-
- dpoly *tpoly = &polyTable[m];
-
- tpoly->isPlaying = true;
- tpoly->key = key;
- tpoly->isDecay = false;
- tpoly->freqnum = freqNum;
- tpoly->vel = vel;
- tpoly->pedalhold = false;
-
- bool allnull = true;
- for (int x = 0; x < 4; x++) {
- if (cache[x].playPartial) {
- tpoly->partials[x] = synth->partialManager->allocPartial(partNum);
- allnull = false;
- } else {
- tpoly->partials[x] = NULL;
- }
- }
-
- if (allnull)
- synth->printDebug("%s (%s): No partials to play for this instrument", name, this->currentInstr);
-
- tpoly->sustain = cache[0].sustain;
- tpoly->volumeptr = &volume;
-
- for (int x = 0; x < 4; x++) {
- if (tpoly->partials[x] != NULL) {
- tpoly->partials[x]->startPartial(tpoly, &cache[x], tpoly->partials[cache[x].structurePair]);
- tpoly->partials[x]->setBend(bend);
- }
- }
-}
-
-static void startDecayPoly(dpoly *tpoly) {
- if (tpoly->isDecay) {
- return;
- }
- tpoly->isDecay = true;
-
- for (int t = 0; t < 4; t++) {
- Partial *partial = tpoly->partials[t];
- if (partial == NULL)
- continue;
- partial->startDecayAll();
- }
- tpoly->isPlaying = false;
-}
-
-void Part::allStop() {
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
- if (tpoly->isPlaying) {
- startDecayPoly(tpoly);
- }
- }
-}
-
-void Part::stopPedalHold() {
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly;
- tpoly = &polyTable[q];
- if (tpoly->isActive() && tpoly->pedalhold)
- stopNote(tpoly->key);
- }
-}
-
-void Part::stopNote(unsigned int key) {
- // Non-sustaining instruments ignore stop commands.
- // They die away eventually anyway
-
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): stopping key %d", name, currentInstr, key);
-#endif
-
- if (key != 255) {
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
- if (tpoly->isPlaying && tpoly->key == key) {
- if (holdpedal)
- tpoly->pedalhold = true;
- else if (tpoly->sustain)
- startDecayPoly(tpoly);
- }
- }
- return;
- }
-
- // Find oldest poly... yes, the MT-32 can be reconfigured to kill different poly first
- // This is simplest
- int oldest = -1;
- Bit32u oldage = 0;
-
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
-
- if (tpoly->isPlaying && !tpoly->isDecay) {
- if (tpoly->getAge() >= oldage) {
- oldage = tpoly->getAge();
- oldest = q;
- }
- }
- }
-
- if (oldest != -1) {
- startDecayPoly(&polyTable[oldest]);
- }
-}
-
-}
diff --git a/backends/midi/mt32/part.h b/backends/midi/mt32/part.h
deleted file mode 100644
index 1214ec52f9..0000000000
--- a/backends/midi/mt32/part.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_PART_H
-#define MT32EMU_PART_H
-
-namespace MT32Emu {
-
-class PartialManager;
-class Synth;
-
-class Part {
-private:
- // Pointers to the areas of the MT-32's memory dedicated to this part (for parts 1-8)
- MemParams::PatchTemp *patchTemp;
- TimbreParam *timbreTemp;
-
- // 0=Part 1, .. 7=Part 8, 8=Rhythm
- unsigned int partNum;
-
- bool holdpedal;
-
- StereoVolume volumesetting;
-
- PatchCache patchCache[4];
-
- float bend; // -1.0 .. +1.0
-
- dpoly polyTable[MT32EMU_MAX_POLY];
-
- void abortPoly(dpoly *poly);
-
- static int fixKeyfollow(int srckey);
- static int fixBiaslevel(int srcpnt, int *dir);
-
- void setPatch(const PatchParam *patch);
-
-protected:
- Synth *synth;
- char name[8]; // "Part 1".."Part 8", "Rhythm"
- char currentInstr[11];
- Bit32u volume;
- void backupCacheToPartials(PatchCache cache[4]);
- void cacheTimbre(PatchCache cache[4], const TimbreParam *timbre);
- void playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel);
- const char *getName() const;
-
-public:
- Part(Synth *synth, unsigned int usePartNum);
- virtual void playNote(unsigned int key, int vel);
- void stopNote(unsigned int key);
- void allStop();
- void setVolume(int vol);
- virtual void setPan(unsigned int midiPan);
- virtual void setBend(unsigned int midiBend);
- virtual void setModulation(unsigned int midiModulation);
- virtual void setProgram(unsigned int patchNum);
- void setHoldPedal(bool pedalval);
- void stopPedalHold();
- virtual void refresh();
- virtual void refreshTimbre(unsigned int absTimbreNum);
- void setTimbre(TimbreParam *timbre);
- virtual unsigned int getAbsTimbreNum() const;
-};
-
-class RhythmPart: public Part {
- // Pointer to the area of the MT-32's memory dedicated to rhythm
- const MemParams::RhythmTemp *rhythmTemp;
-
- // This caches the timbres/settings in use by the rhythm part
- PatchCache drumCache[64][4];
- StereoVolume drumPan[64];
-public:
- RhythmPart(Synth *synth, unsigned int usePartNum);
- void refreshTimbre(unsigned int timbreNum);
- void refresh();
- void playNote(unsigned int key, int vel);
- unsigned int getAbsTimbreNum() const;
- void setPan(unsigned int midiPan);
- void setBend(unsigned int midiBend);
- void setModulation(unsigned int midiModulation);
- void setProgram(unsigned int patchNum);
-};
-
-}
-#endif
diff --git a/backends/midi/mt32/partial.cpp b/backends/midi/mt32/partial.cpp
deleted file mode 100644
index 32ff9e9af7..0000000000
--- a/backends/midi/mt32/partial.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-
-#include "mt32emu.h"
-
-#define FIXEDPOINT_UDIV(x, y, point) (((x) << (point)) / ((y)))
-#define FIXEDPOINT_SDIV(x, y, point) (((x) * (1 << point)) / ((y)))
-#define FIXEDPOINT_UMULT(x, y, point) (((x) * (y)) >> point)
-#define FIXEDPOINT_SMULT(x, y, point) (((x) * (y)) / (1 << point))
-
-using namespace MT32Emu;
-
-Partial::Partial(Synth *useSynth) {
- this->synth = useSynth;
- ownerPart = -1;
- poly = NULL;
- pair = NULL;
-#if MT32EMU_ACCURATENOTES == 1
- for (int i = 0; i < 3; i++) {
- noteLookupStorage.waveforms[i] = new Bit16s[65536];
- }
- noteLookup = &noteLookupStorage;
-#endif
-}
-
-Partial::~Partial() {
-#if MT32EMU_ACCURATENOTES == 1
- for (int i = 0; i < 3; i++) {
- delete[] noteLookupStorage.waveforms[i];
- }
-#endif
-}
-
-int Partial::getOwnerPart() {
- return ownerPart;
-}
-
-bool Partial::isActive() {
- return ownerPart > -1;
-}
-
-void Partial::activate(int part) {
- // This just marks the partial as being assigned to a part
- ownerPart = part;
-}
-
-void Partial::deactivate() {
- ownerPart = -1;
- if (poly != NULL) {
- for (int i = 0; i < 4; i++) {
- if (poly->partials[i] == this) {
- poly->partials[i] = NULL;
- break;
- }
- }
- if (pair != NULL) {
- pair->pair = NULL;
- }
- }
-}
-
-void Partial::initKeyFollow(int key) {
- // Setup partial keyfollow
- // Note follow relative to middle C
-
- // Calculate keyfollow for pitch
-#if 1
- float rel = key == -1 ? 0.0f : (key - MIDDLEC);
- float newPitch = rel * patchCache->pitchKeyfollow + patchCache->pitch + patchCache->pitchShift;
- //FIXME:KG: Does it truncate the keyfollowed pitch to a semitone (towards MIDDLEC)?
- //int newKey = (int)(rel * patchCache->pitchKeyfollow);
- //float newPitch = newKey + patchCache->pitch + patchCache->pitchShift;
-#else
- float rel = key == -1 ? 0.0f : (key + patchCache->pitchShift - MIDDLEC);
- float newPitch = rel * patchCache->pitchKeyfollow + patchCache->pitch;
-#endif
-#if MT32EMU_ACCURATENOTES == 1
- noteVal = newPitch;
- synth->printDebug("key=%d, pitch=%f, pitchKeyfollow=%f, pitchShift=%f, newPitch=%f", key, patchCache->pitch, patchCache->pitchKeyfollow, patchCache->pitchShift, newPitch);
-#else
- float newPitchInt;
- float newPitchFract = modff(newPitch, &newPitchInt);
- if (newPitchFract > 0.5f) {
- newPitchInt += 1.0f;
- newPitchFract -= 1.0f;
- }
- noteVal = (int)newPitchInt;
- fineShift = (int)(powf(2.0f, newPitchFract / 12.0f) * 4096.0f);
- synth->printDebug("key=%d, pitch=%f, pitchKeyfollow=%f, pitchShift=%f, newPitch=%f, noteVal=%d, fineShift=%d", key, patchCache->pitch, patchCache->pitchKeyfollow, patchCache->pitchShift, newPitch, noteVal, fineShift);
-#endif
- // FIXME:KG: Raise/lower by octaves until in the supported range.
- while (noteVal > HIGHEST_NOTE) // FIXME:KG: see tables.cpp: >108?
- noteVal -= 12;
- while (noteVal < LOWEST_NOTE) // FIXME:KG: see tables.cpp: <12?
- noteVal += 12;
- // Calculate keyfollow for filter
- int keyfollow = ((key - MIDDLEC) * patchCache->filtkeyfollow) / 4096;
- if (keyfollow > 108)
- keyfollow = 108;
- if (keyfollow < -108)
- keyfollow = -108;
- filtVal = keytable[keyfollow + 108];
- realVal = keytable[(key - MIDDLEC) + 108];
-}
-
-void Partial::startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial) {
- if (usePoly == NULL || useCache == NULL) {
- synth->printDebug("*** Error: Starting partial for owner %d, usePoly=%s, useCache=%s", ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", useCache == NULL ? "*** NULL ***" : "OK");
- return;
- }
- patchCache = useCache;
- poly = usePoly;
- mixType = patchCache->structureMix;
- structurePosition = patchCache->structurePosition;
-
- play = true;
- initKeyFollow(poly->freqnum); // Initialises noteVal, filtVal and realVal
-#if MT32EMU_ACCURATENOTES == 0
- noteLookup = &noteLookups[noteVal - LOWEST_NOTE];
-#else
- TableInitialiser::initNote(synth, &noteLookupStorage, noteVal, (float)synth->myProp.sampleRate, synth->masterTune, synth->PCMList, NULL);
-#endif
-
- lfoPos = 0;
- pulsewidth = patchCache->pulsewidth + pwveltable[patchCache->pwsens][poly->vel];
- if (pulsewidth > 100) {
- pulsewidth = 100;
- } else if (pulsewidth < 0) {
- pulsewidth = 0;
- }
-
- for (int e = 0; e < 3; e++) {
- envs[e].envpos = 0;
- envs[e].envstat = -1;
- envs[e].envbase = 0;
- envs[e].envdist = 0;
- envs[e].envsize = 0;
- envs[e].sustaining = false;
- envs[e].decaying = false;
- envs[e].prevlevel = 0;
- envs[e].counter = 0;
- envs[e].count = 0;
- }
- ampEnvVal = 0;
- pitchEnvVal = 0;
- pitchSustain = false;
- loopPos = 0;
- partialOff.pcmoffset = partialOff.pcmplace = 0;
- pair = pairPartial;
- useNoisePair = pairPartial == NULL && (mixType == 1 || mixType == 2);
- age = 0;
- alreadyOutputed = false;
- memset(history,0,sizeof(history));
-}
-
-Bit16s *Partial::generateSamples(long length) {
- if (!isActive() || alreadyOutputed) {
- return NULL;
- }
- if (poly == NULL) {
- synth->printDebug("*** ERROR: poly is NULL at Partial::generateSamples()!");
- return NULL;
- }
-
- alreadyOutputed = true;
-
- // Generate samples
-
- Bit16s *partialBuf = &myBuffer[0];
- while (length--) {
- Bit32s envval;
- Bit32s sample = 0;
- if (!envs[EnvelopeType_amp].sustaining) {
- if (envs[EnvelopeType_amp].count <= 0) {
- Bit32u ampval = getAmpEnvelope();
- if (!play) {
- deactivate();
- break;
- }
- if (ampval > 127) {
- ampval = 127;
- }
-
- ampval = voltable[ampval];
- int tmpvel;
- if (patchCache->ampenvdir == 1)
- tmpvel = 127 - poly->vel;
- else
- tmpvel = poly->vel;
- ampval = (ampval * ampveltable[tmpvel][(int)patchCache->ampEnv.velosens]) >> 8;
- //if (envs[EnvelopeType_amp].sustaining)
- ampEnvVal = ampval;
- }
- --envs[EnvelopeType_amp].count;
- }
-
- int lfoat = 0x1000;
- if (pitchSustain) {
- // Calculate LFO position
- // LFO does not kick in completely until pitch envelope sustains
- if (patchCache->lfodepth > 0) {
- lfoPos++;
- if (lfoPos >= patchCache->lfoperiod)
- lfoPos = 0;
- int lfoatm = FIXEDPOINT_UDIV(lfoPos, patchCache->lfoperiod, 16);
- int lfoatr = sintable[lfoatm];
- lfoat = lfoptable[patchCache->lfodepth][lfoatr];
- }
- } else {
- // Calculate Pitch envelope
- envval = getPitchEnvelope();
- int pd = patchCache->pitchEnv.depth;
- pitchEnvVal = penvtable[pd][envval];
- }
-
- int delta;
- // These two are only for PCM partials, obviously
- PCMWaveEntry *pcmWave = NULL; // Initialise to please compiler
- Bit32u pcmAddr = 0; // Initialise to please compiler
-
- // Wrap positions or end if necessary
- if (patchCache->PCMPartial) {
- // PCM partial
- int len;
- pcmWave = &synth->PCMList[patchCache->pcm];
-
- delta = noteLookup->wavTable[patchCache->pcm];
- pcmAddr = pcmWave->addr;
- len = pcmWave->len;
- if (partialOff.pcmplace >= len) {
- if (pcmWave->loop) {
- //partialOff.pcmplace = partialOff.pcmoffset = 0;
- partialOff.pcmplace %= len;
- } else {
- play = false;
- deactivate();
- break;
- }
- }
- } else {
- // Synthesis partial
- delta = 0x10707;
- partialOff.pcmplace %= (Bit16u)(noteLookup->div << 1);
- }
-
- // Build delta for position of next sample
- // Fix delta code
- Bit64u tdelta = (Bit64u)delta;
-#if MT32EMU_ACCURATENOTES == 0
- tdelta = (tdelta * fineShift) >> 12;
-#endif
- tdelta = (tdelta * pitchEnvVal) >> 12;
- tdelta = (tdelta * lfoat) >> 12;
- tdelta = (tdelta * bendShift) >> 12;
- delta = (int)tdelta;
- Bit32u volume = *poly->volumeptr;
-
- // Get waveform - either PCM or synthesized sawtooth or square
- if (ampEnvVal > 0) {
- if (patchCache->PCMPartial) {
- // Render PCM sample
- int ra, rb, dist;
- Bit32u taddr;
- if (delta < 0x10000) {
- // Linear sound interpolation
- taddr = pcmAddr + partialOff.pcmplace;
- ra = synth->romfile[taddr];
- taddr++;
- if (taddr == pcmAddr + pcmWave->len) {
- // Past end of PCM
- if (pcmWave->loop) {
- rb = synth->romfile[pcmAddr];
- } else {
- rb = 0;
- }
- } else {
- rb = synth->romfile[taddr];
- }
- dist = rb - ra;
- sample = (ra + ((dist * (Bit32s)(partialOff.pcmoffset >> 8)) >> 8));
- } else {
- // Sound decimation
- // The right way to do it is to use a lowpass filter on the waveform before selecting
- // a point. This is too slow. The following approximates this as fast as possible
- int idelta = delta >> 16;
- taddr = pcmAddr + partialOff.pcmplace;
- ra = synth->romfile[taddr++];
- for (int ix = 0; ix < idelta - 1; ix++) {
- if (taddr == pcmAddr + pcmWave->len) {
- // Past end of PCM
- if (pcmWave->loop) {
- taddr = pcmAddr;
- } else {
- // Behave as if all subsequent samples were 0
- break;
- }
- }
- ra += synth->romfile[taddr++];
- }
- sample = ra / idelta;
- }
- } else {
- // Render synthesised sample
- Bit32u div = noteLookup->div;
- int wf = patchCache->waveform;
- int toff = partialOff.pcmplace;
- int minorplace = partialOff.pcmoffset >> 14;
-
- Bit32s filtval = getFiltEnvelope();
-
- //synth->printDebug("Filtval: %d", filtval);
-
- if (wf==0) {
- // Square waveform. Made by combining two pregenerated bandlimited
- // sawtooth waveforms
- // Pulse width is not yet correct
- if (div == 0) {
- synth->printDebug("ERROR: div=0 generating square wave, this should never happen!");
- div = 1;
- }
- Bit32u ofsA = toff % div;
- Bit32u ofsB = toff + FIXEDPOINT_UMULT(div, pulsetable[pulsewidth], 8);
- ofsB = ofsB % div;
- Bit16s pa = noteLookup->waveforms[0][(ofsA << 2) + minorplace];
- Bit16s pb = noteLookup->waveforms[0][(ofsB << 2) + minorplace];
- sample = (pa - pb) * 4;
- // Non-bandlimited squarewave
- /*
- ofs = ((div << 1) * pulsetable[patchCache->pulsewidth]) >> 8;
- if (toff < ofs)
- sample = 1 * WGAMP;
- else
- sample = -1 * WGAMP;
- */
- } else {
- // Sawtooth. Made by combining the full cosine and half cosine according
- // to how it looks on the MT-32. What it really does it takes the
- // square wave and multiplies it by a full cosine
- int waveoff = (toff << 2) + minorplace;
- if (toff < noteLookup->sawTable[pulsewidth])
- sample = noteLookup->waveforms[1][waveoff % noteLookup->waveformSize[1]];
- else
- sample = noteLookup->waveforms[2][waveoff % noteLookup->waveformSize[2]];
- sample = sample * 4;
- // This is the correct way
- // Seems slow to me (though bandlimited) -- doesn't seem to
- // sound any better though
- /*
- //int pw = (patchCache->pulsewidth * pulsemod[filtval]) >> 8;
-
- Bit32u ofs = toff % div;
-
- Bit32u ofs3 = toff + FIXEDPOINT_UMULT(div, pulsetable[patchCache->pulsewidth], 8);
- ofs3 = ofs3 % div;
-
- pa = noteLookup->waveforms[0][ofs];
- pb = noteLookup->waveforms[0][ofs3];
- sample = ((pa - pb) * noteLookup->waveforms[2][toff]) / WGAMP;
- sample = sample *4;
- */
- }
-
- //Very exact filter
- if (filtval > ((FILTERGRAN * 15) / 16))
- filtval = ((FILTERGRAN * 15) / 16);
- sample = (Bit32s)floor((synth->iirFilter)((float)sample, &history[0], filtcoeff[filtval][(int)patchCache->filtEnv.resonance], patchCache->filtEnv.resonance));
- }
- }
-
- // Add calculated delta to our waveform offset
- Bit32u absOff = ((partialOff.pcmplace << 16) | partialOff.pcmoffset);
- absOff += delta;
- partialOff.pcmplace = (Bit16u)((absOff & 0xFFFF0000) >> 16);
- partialOff.pcmoffset = (Bit16u)(absOff & 0xFFFF);
-
- // Put volume envelope over generated sample
- sample = FIXEDPOINT_SMULT(sample, ampEnvVal, 9);
- sample = FIXEDPOINT_SMULT(sample, volume, 7);
- envs[EnvelopeType_amp].envpos++;
- envs[EnvelopeType_pitch].envpos++;
- envs[EnvelopeType_filt].envpos++;
-
- *partialBuf++ = (Bit16s)sample;
- }
- // We may have deactivated and broken out of the loop before the end of the buffer,
- // if so then fill the remainder with 0s.
- if (++length > 0)
- memset(partialBuf, 0, length * 2);
- return &myBuffer[0];
-}
-
-void Partial::setBend(float factor) {
- if (!patchCache->useBender || factor == 0.0f) {
- bendShift = 4096;
- return;
- }
- // NOTE:KG: We can't do this smoothly with lookup tables, unless we use several MB.
- // FIXME:KG: Bend should be influenced by pitch key-follow too, according to docs.
- float bendSemitones = factor * patchCache->benderRange; // -24 .. 24
- float mult = powf(2.0f, bendSemitones / 12.0f);
- synth->printDebug("setBend(): factor=%f, benderRange=%f, semitones=%f, mult=%f\n", factor, patchCache->benderRange, bendSemitones, mult);
- bendShift = (int)(mult * 4096.0f);
-}
-
-Bit16s *Partial::mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
- if (buf1 == NULL)
- return buf2;
- if (buf2 == NULL)
- return buf1;
-
- Bit16s *outBuf = buf1;
-#if MT32EMU_USE_MMX >= 1
- // KG: This seems to be fine
- int donelen = i386_mixBuffers(buf1, buf2, len);
- len -= donelen;
- buf1 += donelen;
- buf2 += donelen;
-#endif
- while (len--) {
- *buf1 = *buf1 + *buf2;
- buf1++, buf2++;
- }
- return outBuf;
-}
-
-Bit16s *Partial::mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
- if (buf1 == NULL)
- return NULL;
- if (buf2 == NULL) {
- Bit16s *outBuf = buf1;
- while (len--) {
- if (*buf1 < -8192)
- *buf1 = -8192;
- else if (*buf1 > 8192)
- *buf1 = 8192;
- buf1++;
- }
- return outBuf;
- }
-
- Bit16s *outBuf = buf1;
-#if MT32EMU_USE_MMX >= 1
- // KG: This seems to be fine
- int donelen = i386_mixBuffersRingMix(buf1, buf2, len);
- len -= donelen;
- buf1 += donelen;
- buf2 += donelen;
-#endif
- while (len--) {
- float a, b;
- a = ((float)*buf1) / 8192.0f;
- b = ((float)*buf2) / 8192.0f;
- a = (a * b) + a;
- if (a>1.0)
- a = 1.0;
- if (a<-1.0)
- a = -1.0;
- *buf1 = (Bit16s)(a * 8192.0f);
- buf1++;
- buf2++;
- //buf1[i] = (Bit16s)(((Bit32s)buf1[i] * (Bit32s)buf2[i]) >> 10) + buf1[i];
- }
- return outBuf;
-}
-
-Bit16s *Partial::mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
- if (buf1 == NULL) {
- return NULL;
- }
- if (buf2 == NULL) {
- return NULL;
- }
-
- Bit16s *outBuf = buf1;
-#if MT32EMU_USE_MMX >= 1
- // FIXME:KG: Not really checked as working
- int donelen = i386_mixBuffersRing(buf1, buf2, len);
- len -= donelen;
- buf1 += donelen;
- buf2 += donelen;
-#endif
- while (len--) {
- float a, b;
- a = ((float)*buf1) / 8192.0f;
- b = ((float)*buf2) / 8192.0f;
- a *= b;
- if (a>1.0)
- a = 1.0;
- if (a<-1.0)
- a = -1.0;
- *buf1 = (Bit16s)(a * 8192.0f);
- buf1++;
- buf2++;
- }
- return outBuf;
-}
-
-void Partial::mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len) {
- if (buf2 == NULL) {
- while (len--) {
- *outBuf++ = *buf1++;
- *outBuf++ = 0;
- }
- } else if (buf1 == NULL) {
- while (len--) {
- *outBuf++ = 0;
- *outBuf++ = *buf2++;
- }
- } else {
- while (len--) {
- *outBuf++ = *buf1++;
- *outBuf++ = *buf2++;
- }
- }
-}
-
-bool Partial::produceOutput(Bit16s *partialBuf, long length) {
- if (!isActive() || alreadyOutputed)
- return false;
- if (poly == NULL) {
- synth->printDebug("*** ERROR: poly is NULL at Partial::produceOutput()!");
- return false;
- }
-
- Bit16s *pairBuf = NULL;
- // Check for dependant partial
- if (pair != NULL) {
- if (!pair->alreadyOutputed) {
- // Note: pair may have become NULL after this
- pairBuf = pair->generateSamples(length);
- }
- } else if (useNoisePair) {
- // Generate noise for pairless ring mix
- pairBuf = smallnoise;
- }
-
- Bit16s *myBuf = generateSamples(length);
-
- if (myBuf == NULL && pairBuf == NULL)
- return false;
-
- Bit16s * p1buf, * p2buf;
-
- if (structurePosition == 0 || pairBuf == NULL) {
- p1buf = myBuf;
- p2buf = pairBuf;
- } else {
- p2buf = myBuf;
- p1buf = pairBuf;
- }
-
- //synth->printDebug("mixType: %d", mixType);
-
- Bit16s *mixedBuf;
- switch(mixType) {
- case 0:
- // Standard sound mix
- mixedBuf = mixBuffers(p1buf, p2buf, length);
- break;
-
- case 1:
- // Ring modulation with sound mix
- mixedBuf = mixBuffersRingMix(p1buf, p2buf, length);
- break;
-
- case 2:
- // Ring modulation alone
- mixedBuf = mixBuffersRing(p1buf, p2buf, length);
- break;
-
- case 3:
- // Stereo mixing. One partial to one speaker channel, one to another.
- // FIXME:KG: Surely we should be multiplying by the left/right volumes here?
- mixBuffersStereo(p1buf, p2buf, partialBuf, length);
- return true;
-
- default:
- mixedBuf = mixBuffers(p1buf, p2buf, length);
- break;
- }
-
- if (mixedBuf == NULL)
- return false;
-
- Bit16s leftvol, rightvol;
- leftvol = patchCache->pansetptr->leftvol;
- rightvol = patchCache->pansetptr->rightvol;
-
-#if MT32EMU_USE_MMX >= 2
- // FIXME:KG: This appears to introduce crackle
- int donelen = i386_partialProductOutput(length, leftvol, rightvol, partialBuf, mixedBuf);
- length -= donelen;
- mixedBuf += donelen;
- partialBuf += donelen * 2;
-#endif
- while (length--) {
- *partialBuf++ = (Bit16s)(((Bit32s)*mixedBuf * (Bit32s)leftvol) >> 16);
- *partialBuf++ = (Bit16s)(((Bit32s)*mixedBuf * (Bit32s)rightvol) >> 16);
- mixedBuf++;
- }
- return true;
-}
-
-Bit32s Partial::getFiltEnvelope() {
- int reshigh;
-
- int cutoff,depth,keyfollow, realfollow;
-
- EnvelopeStatus *tStat = &envs[EnvelopeType_filt];
-
- keyfollow = filtVal;
- realfollow = realVal;
-
- if (tStat->decaying) {
- reshigh = tStat->envbase;
- reshigh = (reshigh + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- if (tStat->envpos >= tStat->envsize)
- reshigh = 0;
- } else {
- if (tStat->envstat==4) {
- reshigh = patchCache->filtsustain;
- if (!poly->sustain) {
- startDecay(EnvelopeType_filt, reshigh);
- }
- } else {
- if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
- if (tStat->envstat==-1)
- tStat->envbase = 0;
- else
- tStat->envbase = patchCache->filtEnv.envlevel[tStat->envstat];
- tStat->envstat++;
- tStat->envpos = 0;
- if (tStat->envstat == 3) {
- tStat->envsize = lasttimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]];
- } else {
- tStat->envsize = (envtimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]] * noteLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
- }
-
- tStat->envsize++;
- tStat->envdist = patchCache->filtEnv.envlevel[tStat->envstat] - tStat->envbase;
- }
-
- reshigh = tStat->envbase;
- reshigh = (reshigh + ((tStat->envdist * tStat->envpos) / tStat->envsize));
-
- }
- tStat->prevlevel = reshigh;
- }
-
- cutoff = patchCache->filtEnv.cutoff;
-
- //if (patchCache->waveform==1) reshigh = (reshigh * 3) >> 2;
-
- depth = patchCache->filtEnv.envdepth;
-
- //int sensedep = (depth * 127-patchCache->filtEnv.envsense) >> 7;
- depth = (depth * filveltable[poly->vel][(int)patchCache->filtEnv.envsense]) >> 8;
-
- int bias = patchCache->tvfbias;
- int dist;
-
- if (bias!=0) {
- //FIXME:KG: Is this really based on pitch (as now), or key pressed?
- //synth->printDebug("Cutoff before %d", cutoff);
- if (patchCache->tvfdir == 0) {
- if (noteVal < bias) {
- dist = bias - noteVal;
- cutoff = (cutoff * fbiastable[patchCache->tvfblevel][dist]) >> 8;
- }
- } else {
- // > Bias
- if (noteVal > bias) {
- dist = noteVal - bias;
- cutoff = (cutoff * fbiastable[patchCache->tvfblevel][dist]) >> 8;
- }
-
- }
- //synth->printDebug("Cutoff after %d", cutoff);
- }
-
- depth = (depth * noteLookup->fildepTable[patchCache->tvfdepth]) >> 8;
- reshigh = (reshigh * depth) >> 7;
-
- Bit32s tmp;
-
- cutoff *= keyfollow;
- cutoff /= realfollow;
-
- reshigh *= keyfollow;
- reshigh /= realfollow;
-
- if (cutoff>100)
- cutoff = 100;
- else if (cutoff<0)
- cutoff = 0;
- if (reshigh>100)
- reshigh = 100;
- else if (reshigh<0)
- reshigh = 0;
- tmp = noteLookup->nfiltTable[cutoff][reshigh];
- //tmp *= keyfollow;
- //tmp /= realfollow;
-
- //synth->printDebug("Cutoff %d, tmp %d, freq %d", cutoff, tmp, tmp * 256);
- return tmp;
-}
-
-bool Partial::shouldReverb() {
- if (!isActive())
- return false;
- return patchCache->reverb;
-}
-
-Bit32u Partial::getAmpEnvelope() {
- Bit32s tc;
-
- EnvelopeStatus *tStat = &envs[EnvelopeType_amp];
-
- if (!play)
- return 0;
-
- if (tStat->decaying) {
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- if (tc < 0)
- tc = 0;
- if ((tStat->envpos >= tStat->envsize) || (tc == 0)) {
- play = false;
- // Don't have to worry about prevlevel storage or anything, this partial's about to die
- return 0;
- }
- } else {
- if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
- if (tStat->envstat==-1)
- tStat->envbase = 0;
- else
- tStat->envbase = patchCache->ampEnv.envlevel[tStat->envstat];
- tStat->envstat++;
- tStat->envpos = 0;
-
- switch(tStat->envstat) {
- case 0:
- //Spot for velocity time follow
- //Only used for first attack
- tStat->envsize = (envtimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]] * veltkeytable[(int)patchCache->ampEnv.envvkf][poly->vel]) >> 8;
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- break;
- case 3:
- // Final attack envelope uses same time table as the decay
- //tStat->envsize = decaytimetable[patchCache->ampEnv.envtime[tStat->envstat]];
- tStat->envsize = lasttimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]];
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- break;
- case 4:
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- tc = patchCache->ampsustain;
- if (!poly->sustain)
- startDecay(EnvelopeType_amp, tc);
- else
- tStat->sustaining = true;
-
- goto PastCalc;
- default:
- //Spot for timekey follow
- //Only used in subsquent envelope parameters, including the decay
- tStat->envsize = (envtimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]] * noteLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
-
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- break;
- }
-
- tStat->envsize++;
- tStat->envdist = patchCache->ampEnv.envlevel[tStat->envstat] - tStat->envbase;
-
- if (tStat->envdist != 0) {
- tStat->counter = abs(tStat->envsize / tStat->envdist);
- //synth->printDebug("Pos %d, envsize %d envdist %d", tStat->envstat, tStat->envsize, tStat->envdist);
- } else {
- tStat->counter = 0;
- //synth->printDebug("Pos %d, envsize %d envdist %d", tStat->envstat, tStat->envsize, tStat->envdist);
- }
- }
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- tStat->count = tStat->counter;
-PastCalc:
- tc = (tc * (Bit32s)patchCache->amplevel) >> 7;
- }
-
- // Prevlevel storage is bottle neck
- tStat->prevlevel = tc;
-
- //Bias level crap stuff now
-
- for (int i = 0; i < 2; i++) {
- if (patchCache->ampblevel[i]!=0) {
- int bias = patchCache->ampbias[i];
- if (patchCache->ampdir[i]==0) {
- // < Bias
- if (noteVal < bias) {
- int dist = bias - noteVal;
- tc = (tc * ampbiastable[patchCache->ampblevel[i]][dist]) >> 8;
- }
- } else {
- // > Bias
- if (noteVal > bias) {
- int dist = noteVal - bias;
- tc = (tc * ampbiastable[patchCache->ampblevel[i]][dist]) >> 8;
- }
- }
- }
- }
- if (tc < 0) {
- synth->printDebug("*** ERROR: tc < 0 (%d) at getAmpEnvelope()", tc);
- tc = 0;
- }
- return (Bit32u)tc;
-}
-
-Bit32s Partial::getPitchEnvelope() {
- EnvelopeStatus *tStat = &envs[EnvelopeType_pitch];
-
- Bit32s tc;
- pitchSustain = false;
- if (tStat->decaying) {
- if (tStat->envpos >= tStat->envsize)
- tc = patchCache->pitchEnv.level[4];
- else {
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- }
- } else {
- if (tStat->envstat==3) {
- tc = patchCache->pitchsustain;
- if (poly->sustain)
- pitchSustain = true;
- else
- startDecay(EnvelopeType_pitch, tc);
- } else {
- if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
- tStat->envstat++;
-
- tStat->envbase = patchCache->pitchEnv.level[tStat->envstat];
- tStat->envsize = (envtimetable[(int)patchCache->pitchEnv.time[tStat->envstat]] * noteLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8;
-
- tStat->envpos = 0;
- tStat->envsize++;
- tStat->envdist = patchCache->pitchEnv.level[tStat->envstat + 1] - tStat->envbase;
- }
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- }
- tStat->prevlevel = tc;
- }
- return tc;
-}
-
-void Partial::startDecayAll() {
- startDecay(EnvelopeType_amp, envs[EnvelopeType_amp].prevlevel);
- startDecay(EnvelopeType_filt, envs[EnvelopeType_filt].prevlevel);
- startDecay(EnvelopeType_pitch, envs[EnvelopeType_pitch].prevlevel);
- pitchSustain = false;
-}
-
-void Partial::startDecay(EnvelopeType envnum, Bit32s startval) {
- EnvelopeStatus *tStat = &envs[envnum];
-
- tStat->sustaining = false;
- tStat->decaying = true;
- tStat->envpos = 0;
- tStat->envbase = startval;
-
- switch(envnum) {
- case EnvelopeType_amp:
- tStat->envsize = (decaytimetable[(int)patchCache->ampEnv.envtime[4]] * noteLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
- tStat->envdist = -startval;
- break;
- case EnvelopeType_filt:
- tStat->envsize = (decaytimetable[(int)patchCache->filtEnv.envtime[4]] * noteLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
- tStat->envdist = -startval;
- break;
- case EnvelopeType_pitch:
- tStat->envsize = (decaytimetable[(int)patchCache->pitchEnv.time[3]] * noteLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8 ;
- tStat->envdist = patchCache->pitchEnv.level[4] - startval;
- break;
- default:
- break;
- }
- tStat->envsize++;
-}
diff --git a/backends/midi/mt32/partial.h b/backends/midi/mt32/partial.h
deleted file mode 100644
index 0834a64c15..0000000000
--- a/backends/midi/mt32/partial.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_PARTIAL_H
-#define MT32EMU_PARTIAL_H
-
-namespace MT32Emu {
-
-class Synth;
-struct NoteLookup;
-
-enum EnvelopeType {
- EnvelopeType_amp = 0,
- EnvelopeType_filt = 1,
- EnvelopeType_pitch = 2
-};
-
-struct EnvelopeStatus {
- Bit32s envpos;
- Bit32s envstat;
- Bit32s envbase;
- Bit32s envdist;
- Bit32s envsize;
-
- bool sustaining;
- bool decaying;
- Bit32s prevlevel;
-
- Bit32s counter;
- Bit32s count;
-};
-
-// Class definition of MT-32 partials. 32 in all.
-class Partial {
-private:
- Synth *synth;
-
- int ownerPart; // -1 if unassigned
- int mixType;
- int structurePosition; // 0 or 1 of a structure pair
- bool useNoisePair;
-
- Bit16s myBuffer[MAX_SAMPLE_OUTPUT];
-
- bool play;
-
- // Keyfollowed note value
-#if MT32EMU_ACCURATENOTES == 1
- NoteLookup noteLookupStorage;
- float noteVal;
-#else
- int noteVal;
- int fineShift;
-#endif
- const NoteLookup *noteLookup; // LUTs for this noteVal
-
- // Keyfollowed filter values
- int realVal;
- int filtVal;
-
- EnvelopeStatus envs[3];
-
- int pulsewidth;
-
- Bit32u lfoPos;
- soundaddr partialOff;
-
- Bit32u ampEnvVal;
- Bit32u pitchEnvVal;
-
- float history[32];
-
- bool pitchSustain;
-
- int loopPos;
-
- dpoly *poly;
-
- int bendShift;
-
- Bit16s *mixBuffers(Bit16s *buf1, Bit16s *buf2, int len);
- Bit16s *mixBuffersRingMix(Bit16s *buf1, Bit16s *buf2, int len);
- Bit16s *mixBuffersRing(Bit16s *buf1, Bit16s *buf2, int len);
- void mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len);
-
- Bit32s getFiltEnvelope();
- Bit32u getAmpEnvelope();
- Bit32s getPitchEnvelope();
-
- void initKeyFollow(int freqNum);
-
-public:
- const PatchCache *patchCache;
- PatchCache cachebackup;
-
- Partial *pair;
- bool alreadyOutputed;
- Bit32u age;
-
- Partial(Synth *synth);
- ~Partial();
-
- int getOwnerPart();
- bool isActive();
- void activate(int part);
- void deactivate(void);
- void startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial);
- void startDecay(EnvelopeType envnum, Bit32s startval);
- void startDecayAll();
- void setBend(float factor);
- bool shouldReverb();
-
- // Returns true only if data written to buffer
- // This function (unlike the one below it) returns processed stereo samples
- // made from combining this single partial with its pair, if it has one.
- bool produceOutput(Bit16s * partialBuf, long length);
-
- // This function produces mono sample output using the partial's private internal buffer
- Bit16s *generateSamples(long length);
-};
-
-}
-
-#endif
diff --git a/backends/midi/mt32/partialManager.cpp b/backends/midi/mt32/partialManager.cpp
deleted file mode 100644
index 776276edda..0000000000
--- a/backends/midi/mt32/partialManager.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <memory.h>
-
-#include "mt32emu.h"
-
-using namespace MT32Emu;
-
-PartialManager::PartialManager(Synth *useSynth) {
- this->synth = useSynth;
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- partialTable[i] = new Partial(synth);
-}
-
-PartialManager::~PartialManager(void) {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- delete partialTable[i];
-}
-
-void PartialManager::getPerPartPartialUsage(int usage[9]) {
- memset(usage, 0, 9 * sizeof (int));
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->isActive())
- usage[partialTable[i]->getOwnerPart()]++;
- }
-}
-
-void PartialManager::clearAlreadyOutputed() {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- partialTable[i]->alreadyOutputed = false;
-}
-
-void PartialManager::ageAll() {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- partialTable[i]->age++;
-}
-
-bool PartialManager::shouldReverb(int i) {
- return partialTable[i]->shouldReverb();
-}
-
-bool PartialManager::produceOutput(int i, Bit16s *buffer, Bit32u bufferLength) {
- return partialTable[i]->produceOutput(buffer, bufferLength);
-}
-
-void PartialManager::deactivateAll() {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- partialTable[i]->deactivate();
- }
-}
-
-unsigned int PartialManager::setReserve(Bit8u *rset) {
- unsigned int pr = 0;
- for (int x = 0; x < 9; x++) {
- for (int y = 0; y < rset[x]; y++) {
- partialReserveTable[pr] = x;
- pr++;
- }
- }
- return pr;
-}
-
-Partial *PartialManager::allocPartial(int partNum) {
- Partial *outPartial = NULL;
-
- // Use the first inactive partial reserved for the specified part (if there are any)
- // Otherwise, use the last inactive partial, if any
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (!partialTable[i]->isActive()) {
- outPartial = partialTable[i];
- if (partialReserveTable[i] == partNum)
- break;
- }
- }
- if (outPartial != NULL) {
- outPartial->activate(partNum);
- outPartial->age = 0;
- }
- return outPartial;
-}
-
-unsigned int PartialManager::getFreePartialCount(void) {
- int count = 0;
- memset(partialPart, 0, sizeof(partialPart));
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (!partialTable[i]->isActive())
- count++;
- else
- partialPart[partialTable[i]->getOwnerPart()]++;
- }
- return count;
-}
-
-/*
-bool PartialManager::freePartials(unsigned int needed, int partNum) {
- int i;
- int myPartPrior = (int)mt32ram.system.reserveSettings[partNum];
- if (myPartPrior<partialPart[partNum]) {
- //This can have more parts, must kill off those with less priority
- int most, mostPart;
- while (needed > 0) {
- int selectPart = -1;
- //Find the worst offender with more partials than allocated and kill them
- most = -1;
- mostPart = -1;
- int diff;
-
- for (i=0;i<9;i++) {
- diff = partialPart[i] - (int)mt32ram.system.reserveSettings[i];
-
- if (diff>0) {
- if (diff>most) {
- most = diff;
- mostPart = i;
- }
- }
- }
- selectPart = mostPart;
- if (selectPart == -1) {
- // All parts are within the allocated limits, you suck
- // Look for first partial not of this part that's decaying perhaps?
- return false;
- }
- bool found;
- int oldest;
- int oldnum;
- while (partialPart[selectPart] > (int)mt32ram.system.reserveSettings[selectPart]) {
- oldest = -1;
- oldnum = -1;
- found = false;
- for (i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->isActive) {
- if (partialTable[i]->ownerPart == selectPart) {
- found = true;
- if (partialTable[i]->age > oldest) {
- oldest = partialTable[i]->age;
- oldnum = i;
- }
- }
- }
- }
- if (!found) break;
- partialTable[oldnum]->deactivate();
- --partialPart[selectPart];
- --needed;
- }
-
- }
- return true;
-
- } else {
- //This part has reached its max, must kill off its own
- bool found;
- int oldest;
- int oldnum;
- while (needed > 0) {
- oldest = -1;
- oldnum = -1;
- found = false;
- for (i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->isActive) {
- if (partialTable[i]->ownerPart == partNum) {
- found = true;
- if (partialTable[i]->age > oldest) {
- oldest = partialTable[i]->age;
- oldnum = i;
- }
- }
- }
- }
- if (!found) break;
- partialTable[oldnum]->deactivate();
- --needed;
- }
- // Couldn't free enough partials, sorry
- if (needed>0) return false;
- return true;
- }
-
-}
-*/
-bool PartialManager::freePartials(unsigned int needed, int partNum) {
- if (needed == 0) {
- return true;
- }
- // Reclaim partials reserved for this part
- // Kill those that are already decaying first
- /*
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialReserveTable[i] == partNum) {
- if (partialTable[i]->ownerPart != partNum) {
- if (partialTable[i]->partCache->envs[AMPENV].decaying) {
- partialTable[i]->isActive = false;
- --needed;
- if (needed == 0)
- return true;
- }
- }
- }
- }*/
- // Then kill those with the lowest part priority -- oldest at the moment
- while (needed > 0) {
- Bit32u prior = 0;
- int priornum = -1;
-
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialReserveTable[i] == partNum && partialTable[i]->isActive() && partialTable[i]->getOwnerPart() != partNum) {
- /*
- if (mt32ram.system.reserveSettings[partialTable[i]->ownerPart] < prior) {
- prior = mt32ram.system.reserveSettings[partialTable[i]->ownerPart];
- priornum = i;
- }*/
- if (partialTable[i]->age >= prior) {
- prior = partialTable[i]->age;
- priornum = i;
- }
- }
- }
- if (priornum != -1) {
- partialTable[priornum]->deactivate();
- --needed;
- } else {
- break;
- }
- }
-
- // Kill off the oldest partials within this part
- while (needed > 0) {
- Bit32u oldest = 0;
- int oldlist = -1;
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->getOwnerPart() == partNum && partialTable[i]->isActive()) {
- if (partialTable[i]->age >= oldest) {
- oldest = partialTable[i]->age;
- oldlist = i;
- }
- }
- }
- if (oldlist != -1) {
- partialTable[oldlist]->deactivate();
- --needed;
- } else {
- break;
- }
- }
- return needed == 0;
-}
diff --git a/backends/midi/mt32/partialManager.h b/backends/midi/mt32/partialManager.h
deleted file mode 100644
index ee145d4c9f..0000000000
--- a/backends/midi/mt32/partialManager.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_PARTIALMANAGER_H
-#define MT32EMU_PARTIALMANAGER_H
-
-namespace MT32Emu {
-
-class Synth;
-
-class PartialManager {
-private:
- Synth *synth; // Only used for sending debug output
-
- Partial *partialTable[MT32EMU_MAX_PARTIALS];
- Bit32s partialReserveTable[MT32EMU_MAX_PARTIALS];
- Bit32s partialPart[9]; // The count of partials played per part
-
-public:
- PartialManager(Synth *synth);
- ~PartialManager();
- Partial *allocPartial(int partNum);
- unsigned int getFreePartialCount(void);
- bool freePartials(unsigned int needed, int partNum);
- unsigned int setReserve(Bit8u *rset);
- void deactivateAll();
- void ageAll();
- bool produceOutput(int i, Bit16s *buffer, Bit32u bufferLength);
- bool shouldReverb(int i);
- void clearAlreadyOutputed();
- void getPerPartPartialUsage(int usage[9]);
-};
-
-}
-
-#endif
diff --git a/backends/midi/mt32/structures.h b/backends/midi/mt32/structures.h
deleted file mode 100644
index b04d98b0fd..0000000000
--- a/backends/midi/mt32/structures.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_STRUCTURES_H
-#define MT32EMU_STRUCTURES_H
-
-namespace MT32Emu {
-
-const unsigned int MAX_SAMPLE_OUTPUT = 4096;
-
-#ifdef _MSC_VER
-#define MT32EMU_ALIGN_PACKED __declspec(align(1))
-typedef unsigned __int64 Bit64u;
-typedef signed __int64 Bit64s;
-#else
-#define MT32EMU_ALIGN_PACKED __attribute__((packed))
-typedef unsigned long long Bit64u;
-typedef signed long long Bit64s;
-#endif
-
-typedef unsigned int Bit32u;
-typedef signed int Bit32s;
-typedef unsigned short int Bit16u;
-typedef signed short int Bit16s;
-typedef unsigned char Bit8u;
-typedef signed char Bit8s;
-
-// The following structures represent the MT-32's memory
-// Since sysex allows this memory to be written to in blocks of bytes,
-// we keep this packed so that we can copy data into the various
-// banks directly
-#if defined(_MSC_VER) || defined (__MINGW32__)
-#pragma pack(push, 1)
-#else
-#pragma pack(1)
-#endif
-
-struct TimbreParam {
- struct commonParam {
- char name[10];
- Bit8u pstruct12; // 1&2 0-12 (1-13)
- Bit8u pstruct34; // #3&4 0-12 (1-13)
- Bit8u pmute; // 0-15 (0000-1111)
- Bit8u nosustain; // 0-1(Normal, No sustain)
- } MT32EMU_ALIGN_PACKED common;
-
- struct partialParam {
- struct wgParam {
- Bit8u coarse; // 0-96 (C1,C#1-C9)
- Bit8u fine; // 0-100 (-50 to +50 (cents?))
- Bit8u keyfollow; // 0-16 (-1,-1/2,0,1,1/8,1/4,3/8,1/2,5/8,3/4,7/8,1,5/4,3/2,2.s1,s2)
- Bit8u bender; // 0,1 (ON/OFF)
- Bit8u waveform; // 0-1 (SQU/SAW)
- Bit8u pcmwave; // 0-127 (1-128)
- Bit8u pulsewid; // 0-100
- Bit8u pwvelo; // 0-14 (-7 - +7)
- } MT32EMU_ALIGN_PACKED wg;
-
- struct envParam {
- Bit8u depth; // 0-10
- Bit8u sensitivity; // 1-100
- Bit8u timekeyfollow; // 0-4
- Bit8u time[4]; // 1-100
- Bit8u level[5]; // 1-100 (-50 - +50)
- } MT32EMU_ALIGN_PACKED env;
-
- struct lfoParam {
- Bit8u rate; // 0-100
- Bit8u depth; // 0-100
- Bit8u modsense; // 0-100
- } MT32EMU_ALIGN_PACKED lfo;
-
- struct tvfParam {
- Bit8u cutoff; // 0-100
- Bit8u resonance; // 0-30
- Bit8u keyfollow; // 0-16 (-1,-1/2,1/4,0,1,1/8,1/4,3/8,1/2,5/8,3/2,7/8,1,5/4,3/2,2,s1,s2)
- Bit8u biaspoint; // 0-127 (<1A-<7C >1A-7C)
- Bit8u biaslevel; // 0-14 (-7 - +7)
- Bit8u envdepth; // 0-100
- Bit8u envsense; // 0-100
- Bit8u envdkf; // DEPTH KEY FOLL0W 0-4
- Bit8u envtkf; // TIME KEY FOLLOW 0-4
- Bit8u envtime[5]; // 1-100
- Bit8u envlevel[4]; // 1-100
- } MT32EMU_ALIGN_PACKED tvf;
-
- struct tvaParam {
- Bit8u level; // 0-100
- Bit8u velosens; // 0-100
- Bit8u biaspoint1; // 0-127 (<1A-<7C >1A-7C)
- Bit8u biaslevel1; // 0-12 (-12 - 0)
- Bit8u biaspoint2; // 0-127 (<1A-<7C >1A-7C)
- Bit8u biaslevel2; // 0-12 (-12 - 0)
- Bit8u envtkf; // TIME KEY FOLLOW 0-4
- Bit8u envvkf; // VELOS KEY FOLL0W 0-4
- Bit8u envtime[5]; // 1-100
- Bit8u envlevel[4]; // 1-100
- } MT32EMU_ALIGN_PACKED tva;
- } MT32EMU_ALIGN_PACKED partial[4];
-} MT32EMU_ALIGN_PACKED;
-
-struct PatchParam {
- Bit8u timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm)
- Bit8u timbreNum; // TIMBRE NUMBER 0-63
- Bit8u keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones)
- Bit8u fineTune; // FINE TUNE 0-100 (-50 - +50 cents)
- Bit8u benderRange; // BENDER RANGE 0-24
- Bit8u assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
- Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
- Bit8u dummy; // (DUMMY)
-} MT32EMU_ALIGN_PACKED;
-
-struct MemParams {
- struct PatchTemp {
- PatchParam patch;
- Bit8u outlevel; // OUTPUT LEVEL 0-100
- Bit8u panpot; // PANPOT 0-14 (R-L)
- Bit8u dummyv[6];
- } MT32EMU_ALIGN_PACKED patchSettings[8];
-
- struct RhythmTemp {
- Bit8u timbre; // TIMBRE 0-94 (M1-M64,R1-30,OFF)
- Bit8u outlevel; // OUTPUT LEVEL 0-100
- Bit8u panpot; // PANPOT 0-14 (R-L)
- Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
- } MT32EMU_ALIGN_PACKED rhythmSettings[86]; // FIXME: Was 64, but let's support the next model...
-
- TimbreParam MT32EMU_ALIGN_PACKED timbreSettings[8];
-
- PatchParam MT32EMU_ALIGN_PACKED patches[128];
-
- struct PaddedTimbre {
- TimbreParam timbre;
- Bit8u padding[10];
- } MT32EMU_ALIGN_PACKED timbres[64 + 64 + 64 + 30]; // Group A, Group B, Memory, Rhythm
-
- struct SystemArea {
- Bit8u masterTune; // MASTER TUNE 0-127 432.1-457.6Hz
- Bit8u reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay)
- Bit8u reverbTime; // REVERB TIME 0-7 (1-8)
- Bit8u reverbLevel; // REVERB LEVEL 0-7 (1-8)
- Bit8u reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32
- Bit8u chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
- Bit8u masterVol; // MASTER VOLUME 0-100
- } MT32EMU_ALIGN_PACKED system;
-};
-
-struct MemBanks {
- Bit8u pTemp[8][sizeof(MemParams::PatchTemp)];
- Bit8u rTemp[86][sizeof(MemParams::RhythmTemp)];
- Bit8u tTemp[8][sizeof(TimbreParam)];
- Bit8u patchBank[128][sizeof(PatchParam)];
- Bit8u timbreBank[64 + 64 + 64 + 30][sizeof(MemParams::PaddedTimbre)];
- Bit8u systemBank[sizeof(MemParams::SystemArea)];
- // System memory 0x100000
- // Display 0x200000
- // Reset 0x7F0000
-};
-
-#if defined(_MSC_VER) || defined (__MINGW32__)
-#pragma pack(pop)
-#else
-#pragma pack()
-#endif
-
-struct PCMWaveEntry {
- Bit32u addr;
- Bit32u len;
- double tune;
- bool loop;
-};
-
-struct soundaddr {
- Bit16u pcmplace;
- Bit16u pcmoffset;
-};
-
-struct StereoVolume {
- Bit16s leftvol;
- Bit16s rightvol;
-};
-
-// This is basically a per-partial, pre-processed combination of timbre and patch/rhythm settings
-struct PatchCache {
- bool playPartial;
- bool PCMPartial;
- int pcm;
- char waveform;
- int pulsewidth;
- int pwsens;
-
- float pitch;
-
- int lfodepth;
- int lforate;
- Bit32u lfoperiod;
- int modsense;
-
- float pitchKeyfollow;
-
- int filtkeyfollow;
-
- int tvfbias;
- int tvfblevel;
- int tvfdir;
-
- int ampbias[2];
- int ampblevel[2];
- int ampdir[2];
-
- int ampdepth;
- int ampenvdir;
- int amplevel;
- int tvfdepth;
-
- bool useBender;
- float benderRange; // 0.0, 1.0, .., 24.0 (semitones)
-
- TimbreParam::partialParam::envParam pitchEnv;
- TimbreParam::partialParam::tvaParam ampEnv;
- TimbreParam::partialParam::tvfParam filtEnv;
-
- Bit32s ampsustain;
- Bit32s pitchsustain;
- Bit32s filtsustain;
-
- Bit32u structureMix;
- int structurePosition;
- int structurePair;
-
- // The following fields are actually common to all partials in the timbre
- bool dirty;
- Bit32u partialCount;
- bool sustain;
- float pitchShift;
- bool reverb;
- const StereoVolume *pansetptr;
-};
-
-class Partial; // Forward reference for class defined in partial.h
-
-struct dpoly {
- bool isPlaying;
-
- unsigned int key;
- int freqnum;
- int vel;
-
- bool isDecay;
-
- const Bit32u *volumeptr;
-
- Partial *partials[4];
-
- bool pedalhold; // This marks keys that have been released on the keyboard, but are being held by the pedal
- bool sustain;
-
- bool isActive() const;
- Bit32u getAge() const;
-};
-
-}
-
-#endif
diff --git a/backends/midi/mt32/synth.cpp b/backends/midi/mt32/synth.cpp
deleted file mode 100644
index 1ba543b581..0000000000
--- a/backends/midi/mt32/synth.cpp
+++ /dev/null
@@ -1,1048 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include "mt32emu.h"
-
-namespace MT32Emu {
-
-const int MAX_SYSEX_SIZE = 512;
-
-float iir_filter_normal(float input,float *hist1_ptr, float *coef_ptr, int revLevel) {
- float *hist2_ptr;
- float output,new_hist;
-
- hist2_ptr = hist1_ptr + 1; // next history
-
- // 1st number of coefficients array is overall input scale factor, or filter gain
- output = input * (*coef_ptr++);
-
- output = output - *hist1_ptr * (*coef_ptr++);
- new_hist = output - *hist2_ptr * (*coef_ptr++); // poles
-
- output = new_hist + *hist1_ptr * (*coef_ptr++);
- output = output + *hist2_ptr * (*coef_ptr++); // zeros
-
- *hist2_ptr++ = *hist1_ptr;
- *hist1_ptr++ = new_hist;
- hist1_ptr++;
- hist2_ptr++;
-
- // i = 1
- output = output - *hist1_ptr * (*coef_ptr++);
- new_hist = output - *hist2_ptr * (*coef_ptr++); // poles
-
- output = new_hist + *hist1_ptr * (*coef_ptr++);
- output = output + *hist2_ptr * (*coef_ptr++); // zeros
-
- *hist2_ptr++ = *hist1_ptr;
- *hist1_ptr++ = new_hist;
-
- output *= ResonInv[revLevel];
-
- return(output);
-}
-
-Bit8u Synth::calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum) {
- for (unsigned int i = 0; i < len; i++) {
- checksum = checksum + data[i];
- }
- checksum = checksum & 0x7f;
- if (checksum)
- checksum = 0x80 - checksum;
- return checksum;
-}
-
-Synth::Synth() {
- isOpen = false;
- reverbModel = NULL;
- partialManager = NULL;
- memset(noteLookups, 0, sizeof(noteLookups));
- memset(parts, 0, sizeof(parts));
-}
-
-Synth::~Synth() {
- close(); // Make sure we're closed and everything is freed
-}
-
-int Synth::report(ReportType type, const void *data) {
- if (myProp.report != NULL) {
- return myProp.report(myProp.userData, type, data);
- }
- return 0;
-}
-
-void Synth::printDebug(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- if (myProp.printDebug != NULL) {
- myProp.printDebug(myProp.userData, fmt, ap);
- } else {
- vprintf(fmt, ap);
- printf("\n");
- }
- va_end(ap);
-}
-
-void Synth::initReverb(Bit8u newRevMode, Bit8u newRevTime, Bit8u newRevLevel) {
- // FIXME:KG: I don't think it's necessary to recreate the reverbModel... Just set the parameters
- if (reverbModel != NULL)
- delete reverbModel;
- reverbModel = new revmodel();
-
- switch(newRevMode) {
- case 0:
- reverbModel->setroomsize(.1f);
- reverbModel->setdamp(.75f);
- break;
- case 1:
- reverbModel->setroomsize(.5f);
- reverbModel->setdamp(.5f);
- break;
- case 2:
- reverbModel->setroomsize(.5f);
- reverbModel->setdamp(.1f);
- break;
- case 3:
- reverbModel->setroomsize(1.0f);
- reverbModel->setdamp(.75f);
- break;
- default:
- reverbModel->setroomsize(.1f);
- reverbModel->setdamp(.5f);
- break;
- }
- reverbModel->setdry(1);
- reverbModel->setwet((float)newRevLevel / 8.0f);
- reverbModel->setwidth((float)newRevTime / 8.0f);
-}
-
-File *Synth::openFile(const char *filename, File::OpenMode mode) {
- if (myProp.openFile != NULL) {
- return myProp.openFile(myProp.userData, filename, mode);
- }
- char pathBuf[2048];
- if (myProp.baseDir != NULL) {
- strcpy(&pathBuf[0], myProp.baseDir);
- strcat(&pathBuf[0], filename);
- filename = pathBuf;
- }
- ANSIFile *file = new ANSIFile();
- if (!file->open(filename, mode)) {
- delete file;
- return NULL;
- }
- return file;
-}
-
-void Synth::closeFile(File *file) {
- if (myProp.closeFile != NULL) {
- myProp.closeFile(myProp.userData, file);
- } else {
- file->close();
- delete file;
- }
-}
-
-bool Synth::loadPreset(File *file) {
- bool inSys = false;
- Bit8u sysexBuf[MAX_SYSEX_SIZE];
- Bit16u syslen = 0;
- bool rc = true;
- for (;;) {
- Bit8u c;
- if (!file->readBit8u(&c)) {
- if (!file->isEOF()) {
- rc = false;
- }
- break;
- }
- sysexBuf[syslen] = c;
- if (inSys) {
- syslen++;
- if (c == 0xF7) {
- playSysex(&sysexBuf[0], syslen);
- inSys = false;
- syslen = 0;
- } else if (syslen == MAX_SYSEX_SIZE) {
- printDebug("MAX_SYSEX_SIZE (%d) exceeded while processing preset, ignoring message", MAX_SYSEX_SIZE);
- inSys = false;
- syslen = 0;
- }
- } else if (c == 0xF0) {
- syslen++;
- inSys = true;
- }
- }
- return rc;
-}
-
-bool Synth::loadControlROM(const char *filename) {
- File *file = openFile(filename, File::OpenMode_read); // ROM File
- if (file == NULL) {
- return false;
- }
- bool rc = (file->read(controlROMData, sizeof(controlROMData)) == sizeof(controlROMData));
-
- closeFile(file);
- return rc;
-}
-
-bool Synth::loadPCMROM(const char *filename) {
- File *file = openFile(filename, File::OpenMode_read); // ROM File
- if (file == NULL) {
- return false;
- }
- bool rc = true;
- for (int i = 0; ; i++) {
- Bit8u s;
- if (!file->readBit8u(&s)) {
- if (!file->isEOF()) {
- rc = false;
- }
- break;
- }
- Bit8u c;
- if (!file->readBit8u(&c)) {
- if (!file->isEOF()) {
- rc = false;
- } else {
- printDebug("ROM file has an odd number of bytes! Ignoring last");
- }
- break;
- }
-
- short e;
- int bit;
- int u;
-
- int order[16] = {0, 9, 1 ,2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8};
-
- e = 0;
- for (u = 0; u < 15; u++) {
- if (order[u] < 8)
- bit = (s >> (7 - order[u])) & 0x1;
- else
- bit = (c >> (7 - (order[u] - 8))) & 0x1;
- e = e | (short)(bit << (15 - u));
- }
-
- /*
- //Bit16s e = ( ((s & 0x7f) << 4) | ((c & 0x40) << 6) | ((s & 0x80) << 6) | ((c & 0x3f))) << 2;
- if (e<0)
- e = -32767 - e;
- int ut = abs(e);
- int dif = 0x7fff - ut;
- x = exp(((float)((float)0x8000-(float)dif) / (float)0x1000));
- e = (int)((float)e * (x/3200));
- */
-
- // File is encoded in dB, convert to PCM
- // MINDB = -96
- // MAXDB = -15
- float testval;
- testval = (float)((~e) & 0x7fff);
- testval = -(testval / 400.00f);
- //testval = -(testval / 341.32291666666666666666666666667);
- float vol = powf(8, testval / 20) * 32767.0f;
-
- if (e > 0)
- vol = -vol;
-
- romfile[i] = (Bit16s)vol;
-
- }
- closeFile(file);
- return rc;
-}
-
-struct ControlROMPCMStruct
-{
- Bit8u pos;
- Bit8u len;
- Bit8u pitchLSB;
- Bit8u pitchMSB;
-};
-
-void Synth::initPCMList() {
- ControlROMPCMStruct *tps = (ControlROMPCMStruct *)&controlROMData[0x3000];
- for (int i = 0; i < 128; i++) {
- int rAddr = tps[i].pos * 0x800;
- int rLenExp = (tps[i].len & 0x70) >> 4;
- int rLen = 0x800 << rLenExp;
- bool rLoop = (tps[i].len & 0x80) != 0;
- //Bit8u rFlag = tps[i].len & 0x0F;
- Bit16u rTuneOffset = (tps[i].pitchMSB << 8) | tps[i].pitchLSB;
- //FIXME:KG: Pick a number, any number. The one below sounded best to me in listening tests, but needs to be confirmed.
- double STANDARDFREQ = 432.1;
- float rTune = (float)(STANDARDFREQ * pow(2.0, (0x5000 - rTuneOffset) / 4096.0 - 9.0 / 12.0));
- //printDebug("%f,%d,%d", pTune, tps[i].pitchCoarse, tps[i].pitchFine);
- PCMList[i].addr = rAddr;
- PCMList[i].len = rLen;
- PCMList[i].loop = rLoop;
- PCMList[i].tune = rTune;
- }
-}
-
-void Synth::initRhythmTimbre(int timbreNum, const Bit8u *mem) {
- TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre;
- memcpy(&timbre->common, mem, 14);
- mem += 14;
- char drumname[11];
- strncpy(drumname, timbre->common.name, 10);
- drumname[10] = 0;
- for (int t = 0; t < 4; t++) {
- if (((timbre->common.pmute >> t) & 0x1) == 0x1) {
- memcpy(&timbre->partial[t], mem, 58);
- mem += 58;
- }
- }
-}
-
-void Synth::initRhythmTimbres() {
- const Bit8u *drumMap = &controlROMData[0x3200];
- int timbreNum = 192;
- for (Bit16u i = 0; i < 60; i += 2) {
- Bit16u address = (drumMap[i + 1] << 8) | drumMap[i];
- initRhythmTimbre(timbreNum++, &controlROMData[address]);
- }
-}
-
-void Synth::initTimbres(Bit16u mapAddress, int startTimbre) {
- for (Bit16u i = mapAddress; i < mapAddress + 0x80; i += 2) {
- Bit16u address = (controlROMData[i + 1] << 8) | controlROMData[i];
- address = address + (mapAddress - 0x8000);
- TimbreParam *timbre = &mt32ram.timbres[startTimbre++].timbre;
- memcpy(timbre, &controlROMData[address], sizeof(TimbreParam));
- }
-}
-
-bool Synth::open(SynthProperties &useProp) {
- if (isOpen)
- return false;
-
- myProp = useProp;
- if (useProp.baseDir != NULL) {
- myProp.baseDir = new char[strlen(useProp.baseDir) + 1];
- strcpy(myProp.baseDir, useProp.baseDir);
- }
-
- // This is to help detect bugs
- memset(&mt32ram, '?', sizeof(mt32ram));
- for (int i = 128; i < 192; i++) {
- // If something sets a patch to point to an uninitialised memory timbre, don't play anything
- mt32ram.timbres[i].timbre.common.pmute = 0;
- }
-
- printDebug("Loading Control ROM");
- if (!loadControlROM("MT32_CONTROL.ROM")) {
- printDebug("Init Error - Missing or invalid MT32_CONTROL.ROM");
- report(ReportType_errorControlROM, &errno);
- return false;
- }
-
- printDebug("Loading PCM ROM");
- if (!loadPCMROM("MT32_PCM.ROM")) {
- printDebug("Init Error - Missing MT32_PCM.ROM");
- report(ReportType_errorPCMROM, &errno);
- return false;
- }
-
- partialManager = new PartialManager(this);
-
- printDebug("Initialising PCM List");
- initPCMList();
-
- printDebug("Initialising Timbre Bank A");
- initTimbres(0x8000, 0);
-
- printDebug("Initialising Timbre Bank B");
- initTimbres(0xC000, 64);
-
- printDebug("Initialising Timbre Bank R");
- initRhythmTimbres();
-
- printDebug("Initialising Rhythm Temp");
- memcpy(mt32ram.rhythmSettings, &controlROMData[0x741C], 344);
-
- printDebug("Initialising Patches");
- for (Bit8u i = 0; i < 128; i++) {
- PatchParam *patch = &mt32ram.patches[i];
- patch->timbreGroup = i / 64;
- patch->timbreNum = i % 64;
- patch->keyShift = 24;
- patch->fineTune = 50;
- patch->benderRange = 12;
- patch->assignMode = 0;
- patch->reverbSwitch = 1;
- patch->dummy = 0;
- }
-
- printDebug("Initialising System");
- //FIXME: Confirm that these are all correct
- // The MT-32 manual claims that "Standard pitch" is 442Hz.
- // I assume they mean this is the MT-32 default pitch, and not concert pitch,
- // since the latter has been internationally defined as 440Hz for decades.
- // Regardless, I'm setting the default masterTune to 440Hz
- mt32ram.system.masterTune = 0x40;
- mt32ram.system.reverbMode = 0;
- mt32ram.system.reverbTime = 5;
- mt32ram.system.reverbLevel = 3;
- memcpy(mt32ram.system.reserveSettings, &controlROMData[0x57E5], 9);
- for (Bit8u i = 0; i < 9; i++) {
- // This is the default: {1, 2, 3, 4, 5, 6, 7, 8, 9}
- // An alternative configuration can be selected by holding "Master Volume"
- // and pressing "PART button 1" on the real MT-32's frontpanel.
- // The channel assignment is then {0, 1, 2, 3, 4, 5, 6, 7, 9}
- mt32ram.system.chanAssign[i] = i + 1;
- }
- mt32ram.system.masterVol = 100;
- if (!refreshSystem())
- return false;
-
- for (int i = 0; i < 8; i++) {
- mt32ram.patchSettings[i].outlevel = 80;
- mt32ram.patchSettings[i].panpot = controlROMData[0x5800 + i];
- memset(mt32ram.patchSettings[i].dummyv, 0, sizeof(mt32ram.patchSettings[i].dummyv));
- parts[i] = new Part(this, i);
- parts[i]->setProgram(controlROMData[0x57EE + i]);
- }
- parts[8] = new RhythmPart(this, 8);
-
- // For resetting mt32 mid-execution
- mt32default = mt32ram;
-
- iirFilter = &iir_filter_normal;
-
-#ifdef MT32EMU_HAVE_X86
- bool availableSSE = DetectSIMD();
- bool available3DNow = Detect3DNow();
-
- if (availableSSE)
- report(ReportType_availableSSE, NULL);
- if (available3DNow)
- report(ReportType_available3DNow, NULL);
-
- if (available3DNow) {
- printDebug("Detected and using SIMD (AMD 3DNow) extensions");
- iirFilter = &iir_filter_3dnow;
- report(ReportType_using3DNow, NULL);
- } else if (availableSSE) {
- printDebug("Detected and using SIMD (Intel SSE) extensions");
- iirFilter = &iir_filter_sse;
- report(ReportType_usingSSE, NULL);
- }
-#endif
-
- isOpen = true;
- isEnabled = false;
-
- printDebug("*** Initialisation complete ***");
- return true;
-}
-
-void Synth::close(void) {
- if (!isOpen)
- return;
-
- TableInitialiser::freeNotes();
- if (partialManager != NULL) {
- delete partialManager;
- partialManager = NULL;
- }
-
- if (reverbModel != NULL) {
- delete reverbModel;
- reverbModel = NULL;
- }
-
- for (int i = 0; i < 9; i++) {
- if (parts[i] != NULL) {
- delete parts[i];
- parts[i] = NULL;
- }
- }
- if (myProp.baseDir != NULL) {
- delete myProp.baseDir;
- myProp.baseDir = NULL;
- }
- isOpen = false;
-}
-
-void Synth::playMsg(Bit32u msg) {
- unsigned char code = (unsigned char)((msg & 0xf0) >> 4);
- unsigned char chan = (unsigned char)(msg & 0xf);
- unsigned char note = (unsigned char)((msg & 0xff00) >> 8);
- unsigned char velocity = (unsigned char)((msg & 0xff0000) >> 16);
- isEnabled = true;
-
- //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note);
-
- char part = chantable[chan];
- if (part < 0 || part > 8) {
- printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity);
- return;
- }
- playMsgOnPart(part, code, note, velocity);
-}
-
-void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity) {
- Bit32u bend;
-
- //printDebug("Synth::playMsg(0x%02x)",msg);
- switch (code) {
- case 0x8:
- //printDebug("Note OFF - Part %d", part);
- // The MT-32 ignores velocity for note off
- parts[part]->stopNote(note);
- break;
- case 0x9:
- //printDebug("Note ON - Part %d, Note %d Vel %d", part, note, velocity);
- if (velocity == 0) {
- // MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40
- parts[part]->stopNote(note);
- } else {
- parts[part]->playNote(note, velocity);
- }
- break;
- case 0xB: // Control change
- switch (note) {
- case 0x01: // Modulation
- //printDebug("Modulation: %d", velocity);
- parts[part]->setModulation(velocity);
- break;
- case 0x07: // Set volume
- //if (part!=3) return;
- //printDebug("Volume set: %d", velocity);
- parts[part]->setVolume(velocity);
- break;
- case 0x0A: // Pan
- //printDebug("Pan set: %d", velocity);
- parts[part]->setPan(velocity);
- break;
- case 0x0B:
- //printDebug("Expression set: %d", velocity);
- parts[part]->setVolume(velocity);
- break;
- case 0x40: // Hold pedal
- //printDebug("Hold pedal set: %d", velocity);
- parts[part]->setHoldPedal(velocity>=64);
- break;
-
- case 0x79: // Reset all controllers
- printDebug("Reset all controllers (NYI)");
- break;
-
- case 0x7B: // All notes off
- //printDebug("All notes off");
- parts[part]->allStop();
- break;
-
- default:
- printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity);
- break;
- }
-
- break;
- case 0xC: // Program change
- //printDebug("Program change %01x", note);
- parts[part]->setProgram(note);
- break;
- case 0xE: // Pitch bender
- bend = (velocity << 7) | (note);
- //printDebug("Pitch bender %02x", bend);
- parts[part]->setBend(bend);
- break;
- default:
- printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity);
- break;
- }
-
- //midiOutShortMsg(m_out, msg);
-}
-
-void Synth::playSysex(const Bit8u * sysex,Bit32u len) {
- if (len < 3) {
- printDebug("playSysex: Message is too short for sysex (%d bytes)", len);
- }
- if (sysex[0] != 0xf0) {
- printDebug("playSysex: Message lacks start-of-sysex (0xf0)");
- return;
- }
- if (sysex[len - 1] != 0xf7) {
- printDebug("playSysex: Message lacks end-of-sysex (0xf7)");
- return;
- }
- playSysexWithoutFraming(sysex + 1, len - 2);
-}
-
-void Synth::playSysexWithoutFraming(const Bit8u * sysex, Bit32u len) {
- if (len < 4) {
- printDebug("playSysexWithoutFraming: Message is too short (%d bytes)!", len);
- return;
- }
- if (sysex[0] != 0x41) {
- printDebug("playSysexWithoutFraming: Header not intended for this device manufacturer: %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
- return;
- }
- if (sysex[2] == 0x14) {
- printDebug("playSysexWithoutFraming: Header is intended for Roland D-50 (not yet supported): %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
- return;
- }
- else if (sysex[2] != 0x16) {
- printDebug("playSysexWithoutFraming: Header not intended for MT-32: %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
- return;
- }
- if (sysex[3] != 0x12) {
- printDebug("playSysexWithoutFraming: Unsupported command %02x", sysex[3]);
- return;
- }
- playSysexWithoutHeader(sysex[1], sysex + 4, len - 4);
-}
-
-// MEMADDR() converts from sysex-padded, SYSEXMEMADDR converts to it
-// Roland provides documentation using the sysex-padded addresses, so we tend to use that int code and output
-#define MEMADDR(x) ((((x) & 0x7f0000) >> 2) | (((x) & 0x7f00) >> 1) | ((x) & 0x7f))
-#define SYSEXMEMADDR(x) ((((x) & 0x1FC000) << 2) | (((x) & 0x3F80) << 1) | ((x) & 0x7f))
-
-#define NUMTOUCHED(x,y) (((x) + sizeof(y) - 1) / sizeof(y))
-
-void Synth::playSysexWithoutHeader(unsigned char device, const Bit8u *sysex, Bit32u len) {
- if (device > 0x10) {
- // We have device ID 0x10 (default, but changeable, on real MT-32), < 0x10 is for channels
- printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", (int)device);
- return;
- }
- if (len < 4) {
- printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len);
- return;
- }
- unsigned char checksum = calcSysexChecksum(sysex, len - 1, 0);
- if (checksum != sysex[len - 1]) {
- printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum);
- return;
- }
- len -= 1; // Exclude checksum
- Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]);
- addr = MEMADDR(addr);
- sysex += 3;
- len -= 3;
- //printDebug("Sysex addr: 0x%06x", SYSEXMEMADDR(addr));
- // NOTE: Please keep both lower and upper bounds in each check, for ease of reading
- if (device < 0x10) {
- printDebug("WRITE-CHANNEL: Channel %d temp area 0x%06x", device, SYSEXMEMADDR(addr));
- if (/*addr >= MEMADDR(0x000000) && */addr < MEMADDR(0x010000)) {
- int offset;
- if (chantable[device] == -1) {
- printDebug(" (Channel not mapped to a partial... 0 offset)");
- offset = 0;
- } else if (chantable[device] == 8) {
- printDebug(" (Channel mapped to rhythm... 0 offset)");
- offset = 0;
- } else {
- offset = chantable[device] * sizeof(MemParams::PatchTemp);
- printDebug(" (Setting extra offset to %d)", offset);
- }
- addr += MEMADDR(0x030000) + offset;
- } else if (/*addr >= 0x010000 && */ addr < MEMADDR(0x020000)) {
- addr += MEMADDR(0x030110) - MEMADDR(0x010000);
- } else if (/*addr >= 0x020000 && */ addr < MEMADDR(0x030000)) {
- int offset;
- if (chantable[device] == -1) {
- printDebug(" (Channel not mapped to a partial... 0 offset)");
- offset = 0;
- } else if (chantable[device] == 8) {
- printDebug(" (Channel mapped to rhythm... 0 offset)");
- offset = 0;
- } else {
- offset = chantable[device] * sizeof(TimbreParam);
- printDebug(" (Setting extra offset to %d)", offset);
- }
- addr += MEMADDR(0x040000) - MEMADDR(0x020000) + offset;
- } else {
- printDebug("PlaySysexWithoutHeader: Invalid channel %d address 0x%06x", device, SYSEXMEMADDR(addr));
- return;
- }
- }
- if (addr >= MEMADDR(0x030000) && addr < MEMADDR(0x030110)) {
- int off = addr - MEMADDR(0x030000);
- if (off + len > sizeof(mt32ram.patchSettings)) {
- printDebug("playSysexWithoutHeader: Message goes beyond bounds of memory region (addr=0x%06x, len=%d)!", SYSEXMEMADDR(addr), len);
- return;
- }
- int firstPart = off / sizeof(MemParams::PatchTemp);
- off %= sizeof(MemParams::PatchTemp);
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.patchSettings[firstPart])[off + m] = sysex[m];
- //printDebug("Patch temp: Patch %d, offset %x, len %d", off/16, off % 16, len);
-
- int lastPart = firstPart + NUMTOUCHED(off + len, MemParams::PatchTemp) - 1;
- for (int i = firstPart; i <= lastPart; i++) {
- int absTimbreNum = mt32ram.patchSettings[i].patch.timbreGroup * 64 + mt32ram.patchSettings[i].patch.timbreNum;
- char timbreName[11];
- memcpy(timbreName, mt32ram.timbres[absTimbreNum].timbre.common.name, 10);
- timbreName[10] = 0;
- printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s)", firstPart, lastPart, off, off + len, i, absTimbreNum, timbreName);
- if (parts[i] != NULL) {
- if (i == firstPart && off > 2) {
- printDebug(" (Not updating timbre, since those values weren't touched)");
- } else {
- // Not sure whether we should do this at all, really.
- parts[i]->setTimbre(&mt32ram.timbres[parts[i]->getAbsTimbreNum()].timbre);
- }
- parts[i]->refresh();
- }
- }
- } else if (addr >= MEMADDR(0x030110) && addr < MEMADDR(0x040000)) {
- int off = addr - MEMADDR(0x030110);
- if (off + len > sizeof(mt32ram.rhythmSettings)) {
- printDebug("playSysexWithoutHeader: Message goes beyond bounds of memory region (addr=0x%06x, len=%d)!", SYSEXMEMADDR(addr), len);
- return;
- }
- int firstDrum = off / sizeof(MemParams::RhythmTemp);
- off %= sizeof(MemParams::RhythmTemp);
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.rhythmSettings[firstDrum])[off + m] = sysex[m];
- int lastDrum = firstDrum + NUMTOUCHED(off + len, MemParams::RhythmTemp) - 1;
- for (int i = firstDrum; i <= lastDrum; i++) {
- int timbreNum = mt32ram.rhythmSettings[i].timbre;
- char timbreName[11];
- if (timbreNum < 94) {
- memcpy(timbreName, mt32ram.timbres[128 + timbreNum].timbre.common.name, 10);
- timbreName[10] = 0;
- } else {
- strcpy(timbreName, "[None]");
- }
- printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", firstDrum, lastDrum, off, off + len, i, mt32ram.rhythmSettings[i].outlevel, mt32ram.rhythmSettings[i].panpot, mt32ram.rhythmSettings[i].reverbSwitch, mt32ram.rhythmSettings[i].timbre, timbreName);
- }
- if (parts[8] != NULL) {
- parts[8]->refresh();
- }
- } else if (addr >= MEMADDR(0x040000) && addr < MEMADDR(0x050000)) {
- int off = addr - MEMADDR(0x040000);
- if (off + len > sizeof(mt32ram.timbreSettings)) {
- printDebug("playSysexWithoutHeader: Message goes beyond bounds of memory region (addr=0x%06x, len=%d)!", SYSEXMEMADDR(addr), len);
- return;
- }
- int firstPart = off / sizeof(TimbreParam);
- off %= sizeof(TimbreParam);
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.timbreSettings[firstPart])[off + m] = sysex[m];
- int lastPart = firstPart + NUMTOUCHED(off + len, TimbreParam) - 1;
- for (int i = firstPart; i <= lastPart; i++) {
- char instrumentName[11];
- memcpy(instrumentName, mt32ram.timbreSettings[i].common.name, 10);
- instrumentName[10] = 0;
- printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", firstPart, lastPart, off, off + len, i, instrumentName);
- if (parts[i] != NULL) {
- parts[i]->refresh();
- }
- }
- }
- else if (addr >= MEMADDR(0x050000) && addr < MEMADDR(0x060000)) {
- int off = addr - MEMADDR(0x050000);
- if (off + len > sizeof(mt32ram.patches)) {
- printDebug("playSysexWithoutHeader: Message goes beyond bounds of memory region (addr=0x%06x, len=%d)!", SYSEXMEMADDR(addr), len);
- return;
- }
- int firstPatch = off / sizeof(PatchParam);
- off %= sizeof(PatchParam);
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.patches[firstPatch])[off + m] = sysex[m];
- int lastPatch = firstPatch + NUMTOUCHED(off + len, PatchParam) - 1;
- for (int i = firstPatch; i <= lastPatch; i++) {
- PatchParam *patch = &mt32ram.patches[i];
- int patchAbsTimbreNum = patch->timbreGroup * 64 + patch->timbreNum;
- char instrumentName[11];
- memcpy(instrumentName, mt32ram.timbres[patchAbsTimbreNum].timbre.common.name, 10);
- instrumentName[10] = 0;
- Bit8u *n = (Bit8u *)patch;
- printDebug("WRITE-PATCH (%d-%d@%d..%d): %d; timbre=%d (%s) %02X%02X%02X%02X%02X%02X%02X%02X", firstPatch, lastPatch, off, off + len, i, patchAbsTimbreNum, instrumentName, n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]);
- // FIXME:KG: The below is definitely dodgy. We just guess that this is the patch that the part was using
- // based on a timbre match (but many patches could have the same timbre!)
- // If this refresh is really correct, we should store the patch number in use by each part.
- /*
- for (int part = 0; part < 8; part++) {
- if (parts[part] != NULL) {
- int partPatchAbsTimbreNum = mt32ram.patchSettings[part].patch.timbreGroup * 64 + mt32ram.patchSettings[part].patch.timbreNum;
- if (parts[part]->getAbsTimbreNum() == patchAbsTimbreNum) {
- parts[part]->setPatch(patch);
- parts[part]->RefreshPatch();
- }
- }
- }
- */
- }
- } else if (addr >= MEMADDR(0x080000) && addr < MEMADDR(0x090000)) {
- // Timbres
- int off = addr - MEMADDR(0x080000);
- if (off + len > sizeof(MemParams::PaddedTimbre) * 64) {
- // You can only write to one group at a time
- printDebug("playSysexWithoutHeader: Message goes beyond bounds of memory region (addr=0x%06x, len=%d)!", SYSEXMEMADDR(addr), len);
- return;
- }
- unsigned int firstTimbre = off / sizeof (MemParams::PaddedTimbre);
- off %= sizeof (MemParams::PaddedTimbre);
- firstTimbre += 128;
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.timbres[firstTimbre])[off + m] = sysex[m];
- unsigned int lastTimbre = firstTimbre + NUMTOUCHED(len + off, MemParams::PaddedTimbre) - 1;
- for (unsigned int i = firstTimbre; i <= lastTimbre; i++) {
- char instrumentName[11];
- memcpy(instrumentName, mt32ram.timbres[i].timbre.common.name, 10);
- instrumentName[10] = 0;
- printDebug("WRITE-TIMBRE (%d-%d@%d..%d): %d; name=\"%s\"", firstTimbre, lastTimbre, off, off + len, i, instrumentName);
- // FIXME:KG: Not sure if the stuff below should be done (for rhythm and/or parts)...
- // Does the real MT-32 automatically do this?
- for (unsigned int part = 0; part < 9; part++) {
- if (parts[part] != NULL) {
- parts[part]->refreshTimbre(i);
- }
- }
- }
- } else if (addr >= MEMADDR(0x100000) && addr < MEMADDR(0x200000)) {
- int off = addr - MEMADDR(0x100000);
- if (off + len > sizeof(mt32ram.system)) {
- printDebug("playSysexWithoutHeader: Message goes beyond bounds of memory region (addr=0x%06x, len=%d)!", SYSEXMEMADDR(addr), len);
- return;
- }
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.system)[m + off] = sysex[m];
-
- report(ReportType_devReconfig, NULL);
-
- printDebug("WRITE-SYSTEM:");
- refreshSystem();
- } else if (addr == MEMADDR(0x200000)) {
- char buf[MAX_SYSEX_SIZE];
- if (len > MAX_SYSEX_SIZE - 1) {
- printDebug("WRITE-LCD sysex length (%d) exceeded MAX_SYSEX_SIZE (%d) - 1; truncating", len, MAX_SYSEX_SIZE);
- len = MAX_SYSEX_SIZE - 1;
- }
- memcpy(&buf, &sysex[0], len);
- buf[len] = 0;
- printDebug("WRITE-LCD: %s", buf);
- report(ReportType_lcdMessage, buf);
- } else if (addr >= MEMADDR(0x7f0000)) {
- printDebug("Reset");
- report(ReportType_devReset, NULL);
- partialManager->deactivateAll();
- mt32ram = mt32default;
- for (int i = 0; i < 9; i++) {
- parts[i]->refresh();
- }
- isEnabled = false;
- } else {
- printDebug("Sysex write to unrecognised address %06x", SYSEXMEMADDR(addr));
- }
-}
-
-bool Synth::refreshSystem() {
- memset(chantable,-1,sizeof(chantable));
-
- for (unsigned int i = 0; i < 9; i++) {
- //LOG(LOG_MISC|LOG_ERROR,"Part %d set to MIDI channel %d",i,mt32ram.system.chanAssign[i]);
- if (mt32ram.system.chanAssign[i] == 16 && parts[i] != NULL) {
- parts[i]->allStop();
- } else {
- chantable[(int)mt32ram.system.chanAssign[i]] = (char)i;
- }
- }
- //FIXME:KG: This is just an educated guess.
- // The LAPC-I documentation claims a range of 427.5Hz-452.6Hz (similar to what we have here)
- // The MT-32 documentation claims a range of 432.1Hz-457.6Hz
- masterTune = 440.0f * powf(2.0f, (mt32ram.system.masterTune - 64.0f) / (128.0f * 12.0f));
- printDebug(" Master Tune: %f", masterTune);
- printDebug(" Reverb: mode=%d, time=%d, level=%d", mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
- report(ReportType_newReverbMode, &mt32ram.system.reverbMode);
- report(ReportType_newReverbTime, &mt32ram.system.reverbTime);
- report(ReportType_newReverbLevel, &mt32ram.system.reverbLevel);
-
- if (myProp.useDefaultReverb) {
- initReverb(mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
- } else {
- initReverb(myProp.reverbType, myProp.reverbTime, mt32ram.system.reverbLevel);
- }
-
- Bit8u *rset = mt32ram.system.reserveSettings;
- printDebug(" Partial reserve: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]);
- int pr = partialManager->setReserve(rset);
- if (pr != 32)
- printDebug(" (Partial Reserve Table with less than 32 partials reserved!)");
- rset = mt32ram.system.chanAssign;
- printDebug(" Part assign: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]);
- printDebug(" Master volume: %d", mt32ram.system.masterVol);
- masterVolume = (Bit16u)(mt32ram.system.masterVol * 327);
- if (!TableInitialiser::initMT32Tables(this, PCMList, (float)myProp.sampleRate, masterTune)) {
- report(ReportType_errorSampleRate, NULL);
- return false;
- }
- return true;
-}
-
-bool Synth::dumpTimbre(File *file, const TimbreParam *timbre, Bit32u address) {
- // Sysex header
- if (!file->writeBit8u(0xF0))
- return false;
- if (!file->writeBit8u(0x41))
- return false;
- if (!file->writeBit8u(0x10))
- return false;
- if (!file->writeBit8u(0x16))
- return false;
- if (!file->writeBit8u(0x12))
- return false;
-
- char lsb = (char)(address & 0x7f);
- char isb = (char)((address >> 7) & 0x7f);
- char msb = (char)(((address >> 14) & 0x7f) | 0x08);
-
- //Address
- if (!file->writeBit8u(msb))
- return false;
- if (!file->writeBit8u(isb))
- return false;
- if (!file->writeBit8u(lsb))
- return false;
-
- //Data
- if (file->write(timbre, 246) != 246)
- return false;
-
- //Checksum
- unsigned char checksum = calcSysexChecksum((const Bit8u *)timbre, 246, msb + isb + lsb);
- if (!file->writeBit8u(checksum))
- return false;
-
- //End of sysex
- if (!file->writeBit8u(0xF7))
- return false;
- return true;
-}
-
-int Synth::dumpTimbres(const char *filename, int start, int len) {
- File *file = openFile(filename, File::OpenMode_write);
- if (file == NULL)
- return -1;
-
- for (int timbreNum = start; timbreNum < start + len; timbreNum++) {
- int useaddr = (timbreNum - start) * 256;
- TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre;
- if (!dumpTimbre(file, timbre, useaddr))
- break;
- }
- closeFile(file);
- return 0;
-}
-
-void ProduceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume) {
-#if MT32EMU_USE_MMX > 2
- //FIXME:KG: This appears to introduce crackle
- int donelen = i386_produceOutput1(useBuf, stream, len, volume);
- len -= donelen;
- stream += donelen * 2;
- useBuf += donelen * 2;
-#endif
- int end = len * 2;
- while (end--) {
- *stream = *stream + (Bit16s)(((Bit32s)*useBuf++ * (Bit32s)volume)>>15);
- stream++;
- }
-}
-
-void Synth::render(Bit16s *stream, Bit32u len) {
- memset(stream, 0, len * sizeof (Bit16s) * 2);
- if (!isEnabled)
- return;
- while (len > 0) {
- Bit32u thisLen = len > MAX_SAMPLE_OUTPUT ? MAX_SAMPLE_OUTPUT : len;
- doRender(stream, thisLen);
- len -= thisLen;
- stream += 2 * thisLen;
- }
-}
-
-void Synth::doRender(Bit16s * stream,Bit32u len) {
- Bit32u m;
-
- partialManager->ageAll();
-
- if (myProp.useReverb) {
- bool hasOutput = false;
- for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialManager->shouldReverb(i)) {
- if (partialManager->produceOutput(i, &tmpBuffer[0], len)) {
- ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
- hasOutput = true;
- }
- }
- }
- // No point in doing reverb on a mute buffer...
- if (hasOutput) {
- m=0;
- for (unsigned int i = 0; i < len; i++) {
- sndbufl[i] = (float)stream[m] / 32767.0f;
- m++;
- sndbufr[i] = (float)stream[m] / 32767.0f;
- m++;
- }
- reverbModel->processreplace(sndbufl, sndbufr, outbufl, outbufr, len, 1);
- m=0;
- for (unsigned int i = 0; i < len; i++) {
- stream[m] = (Bit16s)(outbufl[i] * 32767.0f);
- m++;
- stream[m] = (Bit16s)(outbufr[i] * 32767.0f);
- m++;
- }
- }
- for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (!partialManager->shouldReverb(i)) {
- if (partialManager->produceOutput(i, &tmpBuffer[0], len)) {
- ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
- }
- }
- }
- } else {
- for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialManager->produceOutput(i, &tmpBuffer[0], len))
- ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
- }
- }
-
- partialManager->clearAlreadyOutputed();
-
-#if MT32EMU_MONITOR_PARTIALS == 1
- samplepos += len;
- if (samplepos > myProp.SampleRate * 5) {
- samplepos = 0;
- int partialUsage[9];
- partialManager->GetPerPartPartialUsage(partialUsage);
- printDebug("1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7]);
- printDebug("Rhythm: %02d TOTAL: %02d", partialUsage[8], MT32EMU_MAX_PARTIALS - partialManager->GetFreePartialCount());
- }
-#endif
-}
-
-}
diff --git a/backends/midi/mt32/synth.h b/backends/midi/mt32/synth.h
deleted file mode 100644
index 1501593cbd..0000000000
--- a/backends/midi/mt32/synth.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_SYNTH_H
-#define MT32EMU_SYNTH_H
-
-#include <stdarg.h>
-
-class revmodel;
-
-namespace MT32Emu {
-
-const int ROMSIZE = 512 * 1024;
-const int PCMSIZE = ROMSIZE / 2;
-const int GRAN = 512;
-
-class File;
-class TableInitialiser;
-class Partial;
-class PartialManager;
-class Part;
-
-enum ReportType {
- // Errors
- ReportType_errorControlROM = 1,
- ReportType_errorPCMROM,
- ReportType_errorSampleRate,
-
- // Progress
- ReportType_progressInit,
-
- // HW spec
- ReportType_availableSSE,
- ReportType_available3DNow,
- ReportType_usingSSE,
- ReportType_using3DNow,
-
- // General info
- ReportType_lcdMessage,
- ReportType_devReset,
- ReportType_devReconfig,
- ReportType_newReverbMode,
- ReportType_newReverbTime,
- ReportType_newReverbLevel
-};
-
-struct SynthProperties {
- // Sample rate to use in mixing
- int sampleRate;
-
- // Flag to activate reverb. True = use reverb, False = no reverb
- bool useReverb;
- // True to use software set reverb settings, False to set reverb settings in
- // following parameters
- bool useDefaultReverb;
- // When not using the default settings, this specifies one of the 4 reverb types
- // 1 = Room 2 = Hall 3 = Plate 4 = Tap
- unsigned char reverbType;
- // This specifies the delay time, from 0-7 (not sure of the actual MT-32's measurement)
- unsigned char reverbTime;
- // This specifies the reverb level, from 0-7 (not sure of the actual MT-32's measurement)
- unsigned char reverbLevel;
- // The name of the directory in which the ROM and data files are stored (with trailing slash/backslash)
- // Not used if "openFile" is set. May be NULL in any case.
- char *baseDir;
- // This is used as the first argument to all callbacks
- void *userData;
- // Callback for reporting various errors and information. May be NULL
- int (*report)(void *userData, ReportType type, const void *reportData);
- // Callback for debug messages, in vprintf() format
- void (*printDebug)(void *userData, const char *fmt, va_list list);
- // Callback for providing an implementation of File, opened and ready for use
- // May be NULL, in which case a default implementation will be used.
- File *(*openFile)(void *userData, const char *filename, File::OpenMode mode);
- // Callback for closing a File. May be NULL, in which case the File will automatically be close()d/deleted.
- void (*closeFile)(void *userData, File *file);
-};
-
-// This is the specification of the Callback routine used when calling the RecalcWaveforms
-// function
-typedef void (*recalcStatusCallback)(int percDone);
-
-// This external function recreates the base waveform file (waveforms.raw) using a specifed
-// sampling rate. The callback routine provides interactivity to let the user know what
-// percentage is complete in regenerating the waveforms. When a NULL pointer is used as the
-// callback routine, no status is reported.
-bool RecalcWaveforms(char * baseDir, int sampRate, recalcStatusCallback callBack);
-
-typedef float (*iir_filter_type)(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
-
-class Synth {
-friend class Part;
-friend class RhythmPart;
-friend class Partial;
-friend class TableInitialiser;
-private:
- bool isEnabled;
-
- iir_filter_type iirFilter;
-
- PCMWaveEntry PCMList[128];
-
- Bit8u controlROMData[64 * 1024];
- Bit16s romfile[PCMSIZE + GRAN];
- Bit8s chantable[32];
-
- #if MT32EMU_MONITOR_PARTIALS == 1
- static Bit32s samplepos = 0;
- #endif
-
- MemParams mt32ram, mt32default;
-
- revmodel *reverbModel;
-
- float masterTune;
- Bit16u masterVolume;
-
- bool isOpen;
-
- PartialManager *partialManager;
- Part *parts[9];
-
- Bit16s tmpBuffer[MAX_SAMPLE_OUTPUT * 2];
- float sndbufl[MAX_SAMPLE_OUTPUT];
- float sndbufr[MAX_SAMPLE_OUTPUT];
- float outbufl[MAX_SAMPLE_OUTPUT];
- float outbufr[MAX_SAMPLE_OUTPUT];
-
- SynthProperties myProp;
-
- bool loadPreset(File *file);
- void initReverb(Bit8u newRevMode, Bit8u newRevTime, Bit8u newRevLevel);
- void doRender(Bit16s * stream, Bit32u len);
- void playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity);
- void playSysexWithoutHeader(unsigned char channel, const Bit8u *sysex, Bit32u len);
-
- bool loadControlROM(const char *filename);
- bool loadPCMROM(const char *filename);
- bool dumpTimbre(File *file, const TimbreParam *timbre, Bit32u addr);
- int dumpTimbres(const char *filename, int start, int len);
-
- void initPCMList();
- void initRhythmTimbres();
- void initTimbres(Bit16u mapAddress, int startTimbre);
- void initRhythmTimbre(int drumNum, const Bit8u *mem);
- bool refreshSystem();
-protected:
- int report(ReportType type, const void *reportData);
- File *openFile(const char *filename, File::OpenMode mode);
- void closeFile(File *file);
- void printDebug(const char *fmt, ...);
-
-public:
- static Bit8u calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum);
-
- Synth();
- ~Synth();
-
- // Used to initialise the MT-32. Must be called before any other function.
- // Returns true if initialization was sucessful, otherwise returns false.
- bool open(SynthProperties &useProp);
-
- // Closes the MT-32 and deallocates any memory used by the synthesizer
- void close(void);
-
- // Sends a 4-byte MIDI message to the MT-32 for immediate playback
- void playMsg(Bit32u msg);
-
- // Sends a string of Sysex commands to the MT-32 for immediate interpretation
- // The length is in bytes
- void playSysex(const Bit8u *sysex, Bit32u len);
- void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len);
-
- // This callback routine is used to have the MT-32 generate samples to the specified
- // output stream. The length is in whole samples, not bytes. (I.E. in 16-bit stereo,
- // one sample is 4 bytes)
- void render(Bit16s * stream, Bit32u len);
-};
-
-}
-
-#endif
diff --git a/backends/midi/mt32/tables.cpp b/backends/midi/mt32/tables.cpp
deleted file mode 100644
index 4a17165733..0000000000
--- a/backends/midi/mt32/tables.cpp
+++ /dev/null
@@ -1,729 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "mt32emu.h"
-
-#define FIXEDPOINT_MAKE(x, point) ((Bit32u)((1 << point) * x))
-
-namespace MT32Emu {
-
-//Amplitude time velocity follow exponential coefficients
-const double tvcatconst[5] = {0.0, 0.002791309, 0.005942882, 0.012652792, 0.026938637};
-const double tvcatmult[5] = {1.0, 1.072662811, 1.169129367, 1.288579123, 1.229630539};
-
-// These are division constants for the TVF depth key follow
-static const Bit32u depexp[5] = {3000, 950, 485, 255, 138};
-
-//Envelope time keyfollow exponential coefficients
-static const double tkcatconst[5] = {0.0, 0.005853144, 0.011148054, 0.019086143, 0.043333215};
-static const double tkcatmult[5] = {1.0, 1.058245688, 1.048488989, 1.016049301, 1.097538067};
-
-static float initialisedSampleRate = 0.0f;
-static float initialisedMasterTune = 0.0f;
-
-Bit16s smallnoise[MAX_SAMPLE_OUTPUT];
-
-// Some optimization stuff
-Bit32s keytable[217];
-Bit16s sintable[65536];
-Bit32u lfotable[101];
-Bit32s penvtable[16][101];
-Bit32s filveltable[128][101];
-Bit32s veltkeytable[5][128];
-Bit32s pulsetable[101];
-Bit32s pulseoffset[101];
-Bit32s ampbiastable[13][128];
-Bit32s fbiastable[15][128];
-float filtcoeff[FILTERGRAN][31][8];
-Bit32s finetable[201];
-Bit32u lfoptable[101][101];
-Bit32s ampveltable[128][64];
-Bit32s pwveltable[15][128];
-Bit32s envtimetable[101];
-Bit32s decaytimetable[101];
-Bit32s lasttimetable[101];
-Bit32s voltable[128];
-float ResonFactor[31];
-float ResonInv[31];
-
-NoteLookup noteLookups[NUM_NOTES];
-
-// Begin filter stuff
-
-// Pre-warp the coefficients of a numerator or denominator.
-// Note that a0 is assumed to be 1, so there is no wrapping
-// of it.
-static void prewarp(double *a1, double *a2, double fc, double fs) {
- double wp;
-
- wp = 2.0 * fs * tan(DOUBLE_PI * fc / fs);
-
- *a2 = *a2 / (wp * wp);
- *a1 = *a1 / wp;
-}
-
-// Transform the numerator and denominator coefficients
-// of s-domain biquad section into corresponding
-// z-domain coefficients.
-//
-// Store the 4 IIR coefficients in array pointed by coef
-// in following order:
-// beta1, beta2 (denominator)
-// alpha1, alpha2 (numerator)
-//
-// Arguments:
-// a0-a2 - s-domain numerator coefficients
-// b0-b2 - s-domain denominator coefficients
-// k - filter gain factor. initially set to 1
-// and modified by each biquad section in such
-// a way, as to make it the coefficient by
-// which to multiply the overall filter gain
-// in order to achieve a desired overall filter gain,
-// specified in initial value of k.
-// fs - sampling rate (Hz)
-// coef - array of z-domain coefficients to be filled in.
-//
-// Return:
-// On return, set coef z-domain coefficients
-static void bilinear(double a0, double a1, double a2, double b0, double b1, double b2, double *k, double fs, float *coef) {
- double ad, bd;
-
- // alpha (Numerator in s-domain)
- ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0;
- // beta (Denominator in s-domain)
- bd = 4. * b2 * fs * fs + 2. * b1* fs + b0;
-
- // update gain constant for this section
- *k *= ad/bd;
-
- // Denominator
- *coef++ = (float)((2. * b0 - 8. * b2 * fs * fs) / bd); // beta1
- *coef++ = (float)((4. * b2 * fs * fs - 2. * b1 * fs + b0) / bd); // beta2
-
- // Nominator
- *coef++ = (float)((2. * a0 - 8. * a2 * fs * fs) / ad); // alpha1
- *coef = (float)((4. * a2 * fs * fs - 2. * a1 * fs + a0) / ad); // alpha2
-}
-
-// a0-a2: numerator coefficients
-// b0-b2: denominator coefficients
-// fc: Filter cutoff frequency
-// fs: sampling rate
-// k: overall gain factor
-// coef: pointer to 4 iir coefficients
-static void szxform(double *a0, double *a1, double *a2, double *b0, double *b1, double *b2, double fc, double fs, double *k, float *coef) {
- // Calculate a1 and a2 and overwrite the original values
- prewarp(a1, a2, fc, fs);
- prewarp(b1, b2, fc, fs);
- bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef);
-}
-
-static void initFilter(float fs, float fc, float *icoeff, float Q) {
- float *coef;
- double a0, a1, a2, b0, b1, b2;
-
- double k = 1.5; // Set overall filter gain factor
- coef = icoeff + 1; // Skip k, or gain
-
- // Section 1
- a0 = 1.0;
- a1 = 0;
- a2 = 0;
- b0 = 1.0;
- b1 = 0.765367 / Q; // Divide by resonance or Q
- b2 = 1.0;
- szxform(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &k, coef);
- coef += 4; // Point to next filter section
-
- // Section 2
- a0 = 1.0;
- a1 = 0;
- a2 = 0;
- b0 = 1.0;
- b1 = 1.847759 / Q;
- b2 = 1.0;
- szxform(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &k, coef);
-
- icoeff[0] = (float)k;
-}
-
-static void initFiltCoeff(float samplerate) {
- for (int j = 0; j < FILTERGRAN; j++) {
- for (int res = 0; res < 31; res++) {
- float tres = ResonFactor[res];
- initFilter((float)samplerate, (((float)(j+1.0)/FILTERGRAN)) * ((float)samplerate/2), filtcoeff[j][res], tres);
- }
- }
-}
-
-static void initEnvelopes(float samplerate) {
- for (int lf = 0; lf <= 100; lf++) {
- float elf = (float)lf;
-
- // General envelope
- float logtime = elf * 0.088362939f;
- envtimetable[lf] = (int)((exp(logtime)/312.12) * (float)samplerate);
-
- // Decay envelope -- shorter for some reason
- // This is also the timing for the envelope right before the
- // amp and filter envelope sustains
-
- lasttimetable[lf] = decaytimetable[lf] = (int)((exp(logtime)/(312.12*2)) * (float)samplerate);
- //lasttimetable[lf] = (int)((exp(logtime)/(312.12*6)) * (float)samplerate);
-
- float mv = (float)lf / 100.0f;
- float pt = mv - 0.5f;
- if (pt < 0)
- pt = 0;
-
- pulsetable[lf] = (int)(pt * 215.04f) + 128;
-
- // I am certain of this: Verified by hand LFO log
- lfotable[lf] = (Bit32u)(((float)samplerate) / (powf(1.088883372f,(float)lf) * 0.021236044f));
-
- //LOG(LOG_ERROR|LOG_MISC,"lf %d = lfo %d pulsetable %d", lf, lfotable[lf], pulsetable[lf]);
- }
-}
-
-void TableInitialiser::initMT32ConstantTables(Synth *synth) {
- if (initialisedSampleRate > 0.0f) {
- return;
- }
- int lf;
- synth->printDebug("Initialising Pitch Tables");
- for (lf = -108; lf <= 108; lf++) {
- keytable[lf + 108] = (int)(256 * powf(2.0f, (float)(lf / 24.0f)));
- //synth->printDebug("KT %d = %d", f, keytable[f+108]);
- }
-
- int res;
- float fres;
- for (res = 0; res < 31; res++) {
- fres = (float)res / 30.0f;
- ResonFactor[res] = (powf(2.0f, logf(powf(fres, 16.0f))) * 2.5f) + 1.0f;
- ResonInv[res] = 1 / ResonFactor[res];
- }
-
- int period = 65536;
-
- for (int ang = 0; ang < period; ang++) {
- int halfang = (period / 2);
- int angval = ang % halfang;
- float tval = (((float)angval / (float)halfang) - 0.5f) * 2;
- if (ang >= halfang)
- tval = -tval;
- sintable[ang] = (Bit16s)(tval * 50.0f) + 50;
- }
-
- int velt, dep;
- float tempdep;
- for (velt = 0; velt < 128; velt++) {
- for (dep = 0; dep < 5; dep++) {
- if (dep > 0) {
- float ff = (float)(exp(3.5f*tvcatconst[dep] * (59.0f-(float)velt)) * tvcatmult[dep]);
- tempdep = 256.0f * ff;
- veltkeytable[dep][velt] = (int)tempdep;
- //if ((velt % 16) == 0) {
- // synth->printDebug("Key %d, depth %d, factor %d", velt, dep, (int)tempdep);
- //}
- } else
- veltkeytable[dep][velt] = 256;
- }
-
- for (dep = -7; dep < 8; dep++) {
- float fldep = (float)abs(dep) / 7.0f;
- fldep = powf(fldep,2.5f);
- if (dep < 0)
- fldep = fldep * -1.0f;
- pwveltable[dep+7][velt] = Bit32s((fldep * (float)velt * 100) / 128.0);
- }
- }
-
- for (dep = 0; dep <= 100; dep++) {
- for (velt = 0; velt < 128; velt++) {
- float fdep = (float)dep * 0.000347013f; // Another MT-32 constant
- float fv = ((float)velt - 64.0f)/7.26f;
- float flogdep = powf(10, fdep * fv);
- float fbase;
-
- if (velt > 64)
- filveltable[velt][dep] = (int)(flogdep * 256.0);
- else {
- //lff = 1 - (pow(((128.0 - (float)lf) / 64.0),.25) * ((float)velt / 96));
- fbase = 1 - (powf(((float)dep / 100.0f),.25f) * ((float)(64-velt) / 96.0f));
- filveltable[velt][dep] = (int)(fbase * 256.0);
- }
- //synth->printDebug("Filvel dep %d velt %d = %x", dep, velt, filveltable[velt][dep]);
- }
- }
-
- for (lf = 0; lf <= 200; lf++) {
- //FIXME:KG: I'm fairly sure this is wrong... lf=100 should yield no fine-tuning (4096)?
- finetable[lf] = (int)((powf(2.0f, (((float)lf / 200.0f) - 1.0f) / 12.0f)) * 4096.0f);
-
- // FIXME:KG: This now gives a range of -1 .. 1 semitone. Should be correct, but check
- //finetable[lf] = (int)((powf(2.0f, (((float)lf / 100.0f) - 1.0f) / 12.0f)) * 4096.0f);
- }
-
- float lff;
- for (lf = 0; lf < 128; lf++) {
- for (velt = 0; velt < 64; velt++) {
- lff = 1 - (powf(((128.0f - (float)lf) / 64.0f), 0.25f) * ((float)velt / 96));
- ampveltable[lf][velt] = (int)(lff * 256.0);
- //synth->printDebug("Ampveltable: %d, %d = %d", lf, velt, ampveltable[lf][velt]);
- }
- }
-
- for (lf = 0; lf < 128; lf++) {
- // Converts MIDI velocity to volume.
- voltable[lf] = FIXEDPOINT_MAKE(powf((float)lf / 127.0f, FLOAT_LN), 7);
- }
- for (unsigned int i = 0; i < MAX_SAMPLE_OUTPUT; i++) {
- int myRand;
- myRand = rand();
- int origRand = myRand;
- //myRand = ((myRand - 16383) * WGAMP) >> 16;
- // This one is slower but works with all values of RAND_MAX
- myRand = (int)((origRand - RAND_MAX / 2) / (float)RAND_MAX * (WGAMP / 2));
- //FIXME:KG: Original ultimately set the lowest two bits to 0, for no obvious reason
- smallnoise[i] = (Bit16s)myRand;
- }
-
- float tdist;
- float padjtable[51];
- for (lf = 0; lf <= 50; lf++) {
- if (lf == 0)
- padjtable[lf] = 7;
- else if (lf == 1)
- padjtable[lf] = 6;
- else if (lf == 2)
- padjtable[lf] = 5;
- else if (lf == 3)
- padjtable[lf] = 4;
- else if (lf == 4)
- padjtable[lf] = 4 - (0.333333f);
- else if (lf == 5)
- padjtable[lf] = 4 - (0.333333f * 2);
- else if (lf == 6)
- padjtable[lf] = 3;
- else if ((lf > 6) && (lf <= 12)) {
- tdist = (lf-6.0f) / 6.0f;
- padjtable[lf] = 3.0f - tdist;
- } else if ((lf > 12) && (lf <= 25)) {
- tdist = (lf - 12.0f) / 13.0f;
- padjtable[lf] = 2.0f - tdist;
- } else {
- tdist = (lf - 25.0f) / 25.0f;
- padjtable[lf] = 1.0f - tdist;
- }
- //synth->printDebug("lf %d = padj %f", lf, padjtable[lf]);
- }
-
- float lfp, depf, finalval, tlf;
- int depat, pval, depti;
- for (lf = 0; lf <= 10; lf++) {
- // I believe the depth is cubed or something
-
- for (depat = 0; depat <= 100; depat++) {
- if (lf > 0) {
- depti = abs(depat - 50);
- tlf = (float)lf - padjtable[depti];
- if (tlf < 0)
- tlf = 0;
- lfp = expf(0.713619942f * tlf) / 407.4945111f;
-
- if (depat < 50)
- finalval = 4096.0f * powf(2, -lfp);
- else
- finalval = 4096.0f * powf(2, lfp);
- pval = (int)finalval;
-
- penvtable[lf][depat] = pval;
- //synth->printDebug("lf %d depat %d pval %d tlf %f lfp %f", lf,depat,pval, tlf, lfp);
- } else {
- penvtable[lf][depat] = 4096;
- //synth->printDebug("lf %d depat %d pval 4096", lf, depat);
- }
- }
- }
- for (lf = 0; lf <= 100; lf++) {
- // It's linear - verified on MT-32 - one of the few things linear
- lfp = ((float)lf * 0.1904f) / 310.55f;
-
- for (depat = 0; depat <= 100; depat++) {
- depf = ((float)depat - 50.0f) / 50.0f;
- //finalval = pow(2, lfp * depf * .5);
- finalval = 4096.0f + (4096.0f * lfp * depf);
-
- pval = (int)finalval;
-
- lfoptable[lf][depat] = pval;
-
- //synth->printDebug("lf %d depat %d pval %x", lf,depat,pval);
- }
- }
-
- for (lf = 0; lf <= 12; lf++) {
- for (int distval = 0; distval < 128; distval++) {
- float amplog, dval;
- if (lf == 0) {
- amplog = 0;
- dval = 1;
- ampbiastable[lf][distval] = 256;
- } else {
- amplog = powf(1.431817011f, (float)lf) / FLOAT_PI;
- dval = ((128.0f - (float)distval) / 128.0f);
- amplog = expf(amplog);
- dval = powf(amplog, dval) / amplog;
- ampbiastable[lf][distval] = (int)(dval * 256.0);
- }
- //synth->printDebug("Ampbias lf %d distval %d = %f (%x) %f", lf, distval, dval, ampbiastable[lf][distval],amplog);
- }
- }
-
- for (lf = 0; lf <= 14; lf++) {
- for (int distval = 0; distval < 128; distval++) {
- float filval = fabsf((float)((lf - 7) * 12) / 7.0f);
- float amplog, dval;
- if (lf == 7) {
- amplog = 0;
- dval = 1;
- fbiastable[lf][distval] = 256;
- } else {
- //amplog = pow(1.431817011, filval) / FLOAT_PI;
- amplog = powf(1.531817011f, filval) / FLOAT_PI;
- dval = (128.0f - (float)distval) / 128.0f;
- amplog = expf(amplog);
- dval = powf(amplog,dval)/amplog;
- if (lf < 8) {
- fbiastable[lf][distval] = (int)(dval * 256.0f);
- } else {
- dval = powf(dval, 0.3333333f);
- if (dval < 0.01f)
- dval = 0.01f;
- dval = 1 / dval;
- fbiastable[lf][distval] = (int)(dval * 256.0f);
- }
- }
- //synth->printDebug("Fbias lf %d distval %d = %f (%x) %f", lf, distval, dval, fbiastable[lf][distval],amplog);
- }
- }
-}
-
-// Per-note table initialisation follows
-
-static void initSaw(NoteLookup *noteLookup, Bit32s div) {
- for (int rsaw = 0; rsaw <= 100; rsaw++) {
- float fsaw;
- if (rsaw < 50)
- fsaw = 50.0f;
- else
- fsaw = (float)rsaw;
- int tmpdiv = div << 17;
-
- //(66 - (((A8 - 50) / 50) ^ 0.63) * 50) / 132
- float sawfact = (66.0f - (powf((fsaw - 50.0f) / 50.0f, 0.63f) * 50.0f)) / 132.0f;
- noteLookup->sawTable[rsaw] = (int)(sawfact * (float)tmpdiv) >> 16;
- //synth->printDebug("F %d divtable %d saw %d sawtable %d", f, div, rsaw, sawtable[f][rsaw]);
- }
-}
-
-static void initDep(NoteLookup *noteLookup, float f) {
- for (int dep = 0; dep < 5; dep++) {
- if (dep == 0) {
- noteLookup->fildepTable[dep] = 256;
- noteLookup->timekeyTable[dep] = 256;
- } else {
- float depfac = 3000.0f;
- float ff, tempdep;
- depfac = (float)depexp[dep];
-
- ff = (f - (float)MIDDLEC) / depfac;
- tempdep = powf(2, ff) * 256.0f;
- noteLookup->fildepTable[dep] = (int)tempdep;
-
- ff = (float)(exp(tkcatconst[dep] * ((float)MIDDLEC - f)) * tkcatmult[dep]);
- noteLookup->timekeyTable[dep] = (int)(ff * 256.0f);
- }
- }
- //synth->printDebug("F %f d1 %x d2 %x d3 %x d4 %x d5 %x", f, noteLookup->fildepTable[0], noteLookup->fildepTable[1], noteLookup->fildepTable[2], noteLookup->fildepTable[3], noteLookup->fildepTable[4]);
-}
-
-File *TableInitialiser::initWave(Synth *synth, NoteLookup *noteLookup, float ampsize, float div, File *file) {
- int iDiv = (int)div;
- noteLookup->waveformSize[0] = iDiv << 2;
- noteLookup->waveformSize[1] = iDiv << 2;
- noteLookup->waveformSize[2] = iDiv << 3;
- for (int i = 0; i < 3; i++) {
- if (noteLookup->waveforms[i] == NULL) {
- noteLookup->waveforms[i] = new Bit16s[noteLookup->waveformSize[i]];
- }
- }
- if (file != NULL) {
- for (int i = 0; i < 3 && file != NULL; i++) {
- size_t len = noteLookup->waveformSize[i];
- for (unsigned int j = 0; j < len; j++) {
- if (!file->readBit16u((Bit16u *)&noteLookup->waveforms[i][j])) {
- synth->printDebug("Error reading wave file cache!");
- file->close();
- file = NULL;
- break;
- }
- }
- }
- }
- if (file == NULL) {
- double sd = DOUBLE_PI / (div * 2.0);
-
- for (int fa = 0; fa < (iDiv << 2); fa++) {
- double sa = fa * sd;
-
-#if 0
- //FIXME:KG: Credit Timo Strunk (bastardo on #scummvm) for help with this!
- double saw = 0.5 * DOUBLE_PI - sa / 2;
-#else
- double saw = 0.0;
- for (int sinus = 1; sinus < div; sinus++) {
- double fsinus = (double)sinus;
- saw += sin(fsinus * sa) / fsinus;
- }
-#endif
-
- // This works pretty well
- noteLookup->waveforms[0][fa] = (Bit16s)(saw * -ampsize / 2);
- noteLookup->waveforms[1][fa] = (Bit16s)(cos(sa / 2.0) * -ampsize);
- noteLookup->waveforms[2][fa * 2] = (Bit16s)(cos(sa - DOUBLE_PI) * -ampsize);
- noteLookup->waveforms[2][fa * 2 + 1] = (Bit16s)(cos((sa + (sd / 2)) - DOUBLE_PI) * -ampsize);
- }
- }
- return file;
-}
-
-static void initFiltTable(NoteLookup *noteLookup, float freq, float rate) {
- for (int tr = 0; tr <= 200; tr++) {
- float ftr = (float)tr;
-
- // Verified exact on MT-32
- if (tr > 100)
- ftr = 100.0f + (powf((ftr - 100.0f) / 100.0f, 3.0f) * 100.0f);
-
- // I think this is the one
- float brsq = powf(10.0f, (tr / 50.0f) - 1.0f);
- noteLookup->filtTable[0][tr] = (int)((freq * brsq) / (rate / 2) * FILTERGRAN);
- if (noteLookup->filtTable[0][tr]>=((FILTERGRAN*15)/16))
- noteLookup->filtTable[0][tr] = ((FILTERGRAN*15)/16);
-
- float brsa = powf(10.0f, ((tr / 55.0f) - 1.0f)) / 2.0f;
- noteLookup->filtTable[1][tr] = (int)((freq * brsa) / (rate / 2) * FILTERGRAN);
- if (noteLookup->filtTable[1][tr]>=((FILTERGRAN*15)/16))
- noteLookup->filtTable[1][tr] = ((FILTERGRAN*15)/16);
- }
-}
-
-static void initNFiltTable(NoteLookup *noteLookup, float freq, float rate) {
- for (int cf = 0; cf <= 100; cf++) {
- float cfmult = (float)cf;
-
- for (int tf = 0;tf <= 100; tf++) {
- float tfadd = (float)(tf - 0);
- if (tfadd < 0)
- tfadd = 0;
-
- float freqsum = expf((cfmult + tfadd) / 30.0f) / 4.0f;
-
- noteLookup->nfiltTable[cf][tf] = (int)((freq * freqsum) / (rate / 2) * FILTERGRAN);
- if (noteLookup->nfiltTable[cf][tf] >= ((FILTERGRAN * 15) / 16))
- noteLookup->nfiltTable[cf][tf] = ((FILTERGRAN * 15) / 16);
- }
- }
-}
-
-File *TableInitialiser::initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float masterTune, PCMWaveEntry pcmWaves[128], File *file) {
- float ampsize = WGAMP;
- float freq = (float)(masterTune * pow(2.0, ((double)note - MIDDLEA) / 12.0));
- float div = rate / freq;
- noteLookup->div = (int)div;
-
- if (noteLookup->div == 0)
- noteLookup->div = 1;
-
- initSaw(noteLookup, noteLookup->div);
- initDep(noteLookup, note);
-
- //synth->printDebug("Note %f; freq=%f, div=%f", note, freq, rate / freq);
- file = initWave(synth, noteLookup, ampsize, div, file);
-
- // Create the pitch tables
-
- double rateMult = 32000.0 / rate;
- double tuner = freq * 65536.0f;
- for (int pc = 0; pc < 128; pc++) {
- noteLookup->wavTable[pc] = (int)(tuner / pcmWaves[pc].tune * rateMult);
- }
-
- initFiltTable(noteLookup, freq, rate);
- initNFiltTable(noteLookup, freq, rate);
- return file;
-}
-
-bool TableInitialiser::initNotes(Synth *synth, PCMWaveEntry pcmWaves[128], float rate, float masterTune) {
- const char *NoteNames[12] = {
- "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "
- };
- char filename[64];
- int intRate = (int)rate;
- char version[4] = {0, 0, 0, 3};
- sprintf(filename, "waveformcache-%d-%.2f.raw", intRate, masterTune);
-
- File *file = NULL;
- char header[20];
- strncpy(header, "MT32WAVE", 8);
- int pos = 8;
- // Version...
- for (int i = 0; i < 4; i++)
- header[pos++] = version[i];
- header[pos++] = (char)((intRate >> 24) & 0xFF);
- header[pos++] = (char)((intRate >> 16) & 0xFF);
- header[pos++] = (char)((intRate >> 8) & 0xFF);
- header[pos++] = (char)(intRate & 0xFF);
- int intTuning = (int)masterTune;
- header[pos++] = (char)((intTuning >> 8) & 0xFF);
- header[pos++] = (char)(intTuning & 0xFF);
- header[pos++] = 0;
- header[pos] = (char)((masterTune - intTuning) * 10);
-#if MT32EMU_WAVECACHEMODE < 2
- bool reading = false;
- file = synth->openFile(filename, File::OpenMode_read);
- if (file != NULL) {
- char fileHeader[20];
- if (file->read(fileHeader, 20) == 20) {
- if (memcmp(fileHeader, header, 20) == 0) {
- Bit16u endianCheck;
- if (file->readBit16u(&endianCheck)) {
- if (endianCheck == 1) {
- reading = true;
- } else {
- synth->printDebug("Endian check in %s does not match expected", filename);
- }
- } else {
- synth->printDebug("Unable to read endian check in %s", filename);
- }
- } else {
- synth->printDebug("Header of %s does not match expected", filename);
- }
- } else {
- synth->printDebug("Error reading 16 bytes of %s", filename);
- }
- if (!reading) {
- file->close();
- file = NULL;
- }
- } else {
- synth->printDebug("Unable to open %s for reading", filename);
- }
-#endif
-
- float progress = 0.0f;
- bool abort = false;
- synth->report(ReportType_progressInit, &progress);
- for (int f = LOWEST_NOTE; f <= HIGHEST_NOTE; f++) {
- synth->printDebug("Initialising note %s%d", NoteNames[f % 12], (f / 12) - 1);
- NoteLookup *noteLookup = &noteLookups[f - LOWEST_NOTE];
- file = initNote(synth, noteLookup, (float)f, rate, masterTune, pcmWaves, file);
- progress = (f - LOWEST_NOTE + 1) / (float)NUM_NOTES;
- abort = synth->report(ReportType_progressInit, &progress) != 0;
- if (abort)
- break;
- }
-
-#if MT32EMU_WAVECACHEMODE == 0 || MT32EMU_WAVECACHEMODE == 2
- if (file == NULL) {
- file = synth->openFile(filename, File::OpenMode_write);
- if (file != NULL) {
- if (file->write(header, 20) == 20 && file->writeBit16u(1)) {
- for (int f = 0; f < NUM_NOTES; f++) {
- for (int i = 0; i < 3 && file != NULL; i++) {
- int len = noteLookups[f].waveformSize[i];
- for (int j = 0; j < len; j++) {
- if (!file->writeBit16u(noteLookups[f].waveforms[i][j])) {
- synth->printDebug("Error writing waveform cache file");
- file->close();
- file = NULL;
- break;
- }
- }
- }
- }
- } else {
- synth->printDebug("Error writing 16-byte header to %s - won't continue saving", filename);
- }
- } else {
- synth->printDebug("Unable to open %s for writing - won't be created", filename);
- }
- }
-#endif
-
- if (file != NULL)
- synth->closeFile(file);
- return !abort;
-}
-
-void TableInitialiser::freeNotes() {
- for (int t = 0; t < 3; t++) {
- for (int m = 0; m < NUM_NOTES; m++) {
- if (noteLookups[m].waveforms[t] != NULL) {
- delete[] noteLookups[m].waveforms[t];
- noteLookups[m].waveforms[t] = NULL;
- noteLookups[m].waveformSize[t] = 0;
- }
- }
- }
- initialisedMasterTune = 0.0f;
-}
-
-bool TableInitialiser::initMT32Tables(Synth *synth, PCMWaveEntry pcmWaves[128], float sampleRate, float masterTune) {
- if (sampleRate <= 0.0f) {
- synth->printDebug("Bad sampleRate (%d <= 0.0f)", sampleRate);
- return false;
- }
- if (initialisedSampleRate == 0.0f) {
- initMT32ConstantTables(synth);
- }
- if (initialisedSampleRate != sampleRate) {
- initFiltCoeff(sampleRate);
- initEnvelopes(sampleRate);
- }
- if (initialisedSampleRate != sampleRate || initialisedMasterTune != masterTune) {
- freeNotes();
- if (!initNotes(synth, pcmWaves, sampleRate, masterTune)) {
- return false;
- }
- initialisedSampleRate = sampleRate;
- initialisedMasterTune = masterTune;
- }
- return true;
-}
-
-}
diff --git a/backends/midi/mt32/tables.h b/backends/midi/mt32/tables.h
deleted file mode 100644
index 0c85796f4f..0000000000
--- a/backends/midi/mt32/tables.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Copyright (c) 2003-2004 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_TABLES_H
-#define MT32EMU_TABLES_H
-
-namespace MT32Emu {
-
-// Mathematical constants
-const double DOUBLE_PI = 3.1415926535897932384626433832795;
-const double DOUBLE_LN = 2.3025850929940456840179914546844;
-const float FLOAT_PI = 3.1415926535897932384626433832795f;
-const float FLOAT_LN = 2.3025850929940456840179914546844f;
-
-// Filter settings
-const int FILTERGRAN = 512;
-
-const int MIDDLEC = 60;
-const int MIDDLEA = 69; // By this I mean "A above middle C"
-
-//FIXME:KG: may only need to do 12 to 108
-//12..108 is the range allowed by note on commands, but the key can be modified by pitch keyfollow
-//and adjustment for timbre pitch, so the results can be outside that range. Do move it (by octave) into
-// the 12..108 range, or keep it in 0..127 range, or something else altogether?
-const int LOWEST_NOTE = 12;
-const int HIGHEST_NOTE = 127;
-const int NUM_NOTES = HIGHEST_NOTE - LOWEST_NOTE + 1; // Number of slots for note LUT
-
-// Amplitude of waveform generator
-const int WGAMP = 7168; // 8192?
-
-class Synth;
-
-extern Bit16s smallnoise[MAX_SAMPLE_OUTPUT];
-
-// Some optimization stuff
-extern Bit32s keytable[217];
-extern Bit16s sintable[65536];
-extern Bit32u lfotable[101];
-extern Bit32s penvtable[16][101];
-extern Bit32s filveltable[128][101];
-extern Bit32s veltkeytable[5][128];
-extern Bit32s pulsetable[101];
-extern Bit32s ampbiastable[13][128];
-extern Bit32s fbiastable[15][128];
-extern float filtcoeff[FILTERGRAN][31][8];
-extern Bit32s finetable[201];
-extern Bit32u lfoptable[101][101];
-extern Bit32s ampveltable[128][64];
-extern Bit32s pwveltable[15][128];
-extern Bit32s envtimetable[101];
-extern Bit32s decaytimetable[101];
-extern Bit32s lasttimetable[101];
-extern Bit32s voltable[128];
-extern float ResonInv[31];
-
-struct NoteLookup {
- Bit32u div;
- Bit32u wavTable[128];
- Bit32s sawTable[101];
- Bit32s fildepTable[5];
- Bit32s timekeyTable[5];
- int filtTable[2][201];
- int nfiltTable[101][101];
- Bit16s *waveforms[3];
- Bit32u waveformSize[3];
-};
-
-extern NoteLookup noteLookups[NUM_NOTES];
-
-class TableInitialiser {
- static void initMT32ConstantTables(Synth *synth);
- static File *initWave(Synth *synth, NoteLookup *noteLookup, float ampsize, float div, File *file);
- static bool initNotes(Synth *synth, PCMWaveEntry pcmWaves[128], float rate, float tuning);
-public:
- static bool initMT32Tables(Synth *synth, PCMWaveEntry pcmWaves[128], float sampleRate, float masterTune);
- static File *initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float tuning, PCMWaveEntry pcmWaves[128], File *file);
- static void freeNotes();
-};
-
-}
-
-#endif
diff --git a/backends/midi/ym2612.cpp b/backends/midi/ym2612.cpp
deleted file mode 100644
index b4af3c6854..0000000000
--- a/backends/midi/ym2612.cpp
+++ /dev/null
@@ -1,907 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2001-2004 The ScummVM project
- *
- * YM2612 tone generation code written by Tomoaki Hayasaka.
- * Used under the terms of the GNU General Public License.
- * Adpated to ScummVM by Jamieson Christian.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * $Header$
- */
-
-#include "emumidi.h"
-
-#include <math.h>
-
-
-////////////////////////////////////////
-//
-// Miscellaneous
-//
-////////////////////////////////////////
-
-static int *sintbl = 0;
-static int *powtbl = 0;
-static int *frequencyTable = 0;
-static int *keycodeTable = 0;
-static int *keyscaleTable = 0;
-static int *attackOut = 0;
-
-////////////////////////////////////////
-//
-// Class declarations
-//
-////////////////////////////////////////
-
-class Operator2612;
-class Voice2612;
-class MidiChannel_YM2612;
-class MidiDriver_YM2612;
-
-class Operator2612 {
-protected:
- Voice2612 *_owner;
- enum State { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
- State _state;
- int32 _currentLevel;
- int _frequency;
- uint32 _phase;
- int _lastOutput;
- int _feedbackLevel;
- int _detune;
- int _multiple;
- int32 _totalLevel;
- int _keyScale;
- int _velocity;
- int _specifiedTotalLevel;
- int _specifiedAttackRate;
- int _specifiedDecayRate;
- int _specifiedSustainLevel;
- int _specifiedSustainRate;
- int _specifiedReleaseRate;
- int _tickCount;
- int _attackTime;
- int32 _decayRate;
- int32 _sustainLevel;
- int32 _sustainRate;
- int32 _releaseRate;
-
-public:
- Operator2612 (Voice2612 *owner);
- ~Operator2612();
- void feedbackLevel(int level);
- void setInstrument(byte const *instrument);
- void velocity(int velo);
- void keyOn();
- void keyOff();
- void frequency(int freq);
- void nextTick(const int *phaseShift, int *outbuf, int buflen);
- bool inUse() { return (_state != _s_ready); }
-};
-
-class Voice2612 {
-public:
- Voice2612 *next;
- uint16 _rate;
-
-protected:
- Operator2612 *_opr[4];
- int _velocity;
- int _control7;
- int _note;
- int _frequencyOffs;
- int _frequency;
- int _algorithm;
-
- int *_buffer;
- int _buflen;
-
-public:
- Voice2612();
- ~Voice2612();
- void setControlParameter(int control, int value);
- void setInstrument(byte const *instrument);
- void velocity(int velo);
- void nextTick(int *outbuf, int buflen);
- void noteOn(int n, int onVelo);
- bool noteOff(int note);
- void pitchBend(int value);
- void recalculateFrequency();
-};
-
-class MidiChannel_YM2612 : public MidiChannel {
-protected:
- uint16 _rate;
- Voice2612 *_voices;
- Voice2612 *_next_voice;
-
-public:
- void removeAllVoices();
- void nextTick(int *outbuf, int buflen);
- void rate(uint16 r);
-
-public:
- MidiChannel_YM2612();
- virtual ~MidiChannel_YM2612();
-
- // MidiChannel interface
- MidiDriver *device() { return 0; }
- byte getNumber() { return 0; }
- void release() { }
- void send(uint32 b) { }
- void noteOff(byte note);
- void noteOn(byte note, byte onVelo);
- void programChange(byte program) { }
- void pitchBend(int16 value);
- void controlChange(byte control, byte value);
- void pitchBendFactor(byte value) { }
- void sysEx_customInstrument(uint32 type, byte *instr);
-};
-
-class MidiDriver_YM2612 : public MidiDriver_Emulated {
-protected:
- MidiChannel_YM2612 *_channel[16];
-
- int _next_voice;
- int _volume;
-
-protected:
- static void createLookupTables();
- void nextTick(int16 *buf1, int buflen);
- int volume(int val = -1) { if (val >= 0) _volume = val; return _volume; }
- void rate(uint16 r);
-
- void generateSamples(int16 *buf, int len);
-
-public:
- MidiDriver_YM2612(SoundMixer *mixer);
- virtual ~MidiDriver_YM2612();
-
- int open();
- void close();
- void send(uint32 b);
- void send(byte channel, uint32 b); // Supports higher than channel 15
- uint32 property(int prop, uint32 param) { return 0; }
-
- void setPitchBendRange(byte channel, uint range) { }
- void sysEx(byte *msg, uint16 length);
-
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _mixer->getOutputRate(); }
-};
-
-////////////////////////////////////////
-//
-// Operator2612 implementation
-//
-////////////////////////////////////////
-
-Operator2612::Operator2612 (Voice2612 *owner) :
- _owner (owner),
- _state (_s_ready),
- _currentLevel ((int32)0x7f << 15),
- _phase (0),
- _lastOutput (0),
- _feedbackLevel (0),
- _detune (0),
- _multiple (1),
- _keyScale (0),
- _specifiedTotalLevel (127),
- _specifiedAttackRate (0),
- _specifiedDecayRate (0),
- _specifiedSustainRate (0),
- _specifiedReleaseRate (15) {
- velocity(0);
-}
-
-Operator2612::~Operator2612()
-{ }
-
-void Operator2612::velocity(int velo) {
- _velocity = velo;
- _totalLevel = ((int32)_specifiedTotalLevel << 15) +
- ((int32)(127-_velocity) << 13);
- _sustainLevel = ((int32)_specifiedSustainLevel << 17);
-}
-
-void Operator2612::feedbackLevel(int level) {
- _feedbackLevel = level;
-}
-
-void Operator2612::setInstrument(byte const *instrument) {
- _detune = (instrument[8] >> 4) & 7;
- _multiple = instrument[8] & 15;
- _specifiedTotalLevel = instrument[12] & 127;
- _keyScale = (instrument[16] >> 6) & 3;
- _specifiedAttackRate = instrument[16] & 31;
- _specifiedDecayRate = instrument[20] & 31;
- _specifiedSustainRate = instrument[24] & 31;
- _specifiedSustainLevel = (instrument[28] >> 4) & 15;
- _specifiedReleaseRate = instrument[28] & 15;
- _state = _s_ready; // 本物ではどうなのかな?
- velocity(_velocity);
-}
-
-void Operator2612::keyOn() {
- _state = _s_attacking;
- _tickCount = 0;
- _phase = 0; // どうも、実際こうらしい
- _currentLevel = ((int32)0x7f << 15); // これも、実際こうらしい
-}
-
-void Operator2612::keyOff() {
- if (_state != _s_ready)
- _state = _s_releasing;
-}
-
-void Operator2612::frequency(int freq) {
- double value; // Use for intermediate computations to avoid int64 arithmetic
- int r;
-
- _frequency = freq / _owner->_rate;
-
- r = _specifiedAttackRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63; // するべきなんだろうとは思うんだけど (赤p.207)
- }
-
- r = 63 - r;
- if (_specifiedTotalLevel >= 128)
- value = 0;
- else {
- value = powtbl[(r&3) << 7];
- value *= 1 << (r >> 2);
- value *= 41; // r == 20 のとき、0-96[db] が 10.01[ms] == 41.00096
- value /= 1 << (15 + 5);
- value *= 127 - _specifiedTotalLevel;
- value /= 127;
- }
- _attackTime = (int32) value; // 1 秒 == (1 << 12)
- if (_attackTime > 0)
- _attackTime = (1 << (12+10)) / (_owner->_rate * _attackTime);
-
- r = _specifiedDecayRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _decayRate = (int32) value / _owner->_rate;
-
- r = _specifiedSustainRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _sustainRate = (int32) value / _owner->_rate;
-
- r = _specifiedReleaseRate;
- if (r != 0) {
- r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- // KS による補正はあるらしい。赤p.206 では記述されてないけど。
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _releaseRate = (int32) value / _owner->_rate;
-}
-
-void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) {
- if (_state == _s_ready)
- return;
- if (_state == _s_attacking && _attackTime <= 0) {
- _currentLevel = 0;
- _state = _s_decaying;
- }
-
- int32 levelIncrement = 0;
- int32 target = 0;
- State next_state = _s_ready;
- const int32 zero_level = ((int32)0x7f << 15);
- const int phaseIncrement = (_multiple > 0) ? (_frequency * _multiple) : (_frequency / 2);
-
- int32 output = _lastOutput;
- int32 level = _currentLevel + _totalLevel;
-
- while (buflen) {
- switch (_state) {
- case _s_ready:
- return;
- break;
- case _s_attacking:
- next_state = _s_attacking;
- break;
- case _s_decaying:
- levelIncrement = _decayRate;
- target = _sustainLevel + _totalLevel;
- next_state = _s_sustaining;
- break;
- case _s_sustaining:
- levelIncrement = _sustainRate;
- target = zero_level + _totalLevel;
- next_state = _s_ready;
- break;
- case _s_releasing:
- levelIncrement = _releaseRate;
- target = zero_level + _totalLevel;
- next_state = _s_ready;
- break;
- }
-
- bool switching = false;
- do {
- if (next_state == _s_attacking) {
- // Attack phase
- ++_tickCount;
- int i = (int) (_tickCount * _attackTime);
- if (i >= 1024) {
- level = _totalLevel;
- _state = _s_decaying;
- switching = true;
- } else {
- level = (attackOut[i] << (31 - 8 - 16)) + _totalLevel;
- }
- } else {
- // Decay, Sustain and Release phases
- level += levelIncrement;
- if (level >= target) {
- level = target;
- _state = next_state;
- switching = true;
- }
- }
-
- if (level < zero_level) {
- int phaseShift = *phasebuf >> 2; // 正しい変調量は? 3 じゃ小さすぎで 2 じゃ大きいような。
- if (_feedbackLevel)
- phaseShift += (output << (_feedbackLevel - 1)) / 1024;
- output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff];
- output >>= (level >> 18); // 正しい減衰量は?
- // Here is the original code, which requires 64-bit ints
-// output *= powtbl[511 - ((level>>25)&511)];
-// output >>= 16;
-// output >>= 1;
- // And here's our 32-bit trick for doing it. (Props to Fingolfin!)
- // Result varies from original code by max of 1.
-// int powVal = powtbl[511 - ((level>>9)&511)];
-// int outputHI = output / 256;
-// int powHI = powVal / 256;
-// output = (outputHI * powHI) / 2 + (outputHI * (powVal % 256) + powHI * (output % 256)) / 512;
- // And here's the even faster code.
- // Result varies from original code by max of 8.
- output = ((output >> 4) * (powtbl[511-((level>>9)&511)] >> 3)) / 1024;
-
- _phase += phaseIncrement;
- _phase &= 0x3ffff;
- } else
- output = 0;
-
- *outbuf += output;
- --buflen;
- ++phasebuf;
- ++outbuf;
- } while (buflen && !switching);
- }
- _lastOutput = output;
- _currentLevel = level - _totalLevel;
-}
-
-////////////////////////////////////////
-//
-// Voice2612 implementation
-//
-////////////////////////////////////////
-
-Voice2612::Voice2612() {
- next = 0;
- _control7 = 127;
- _note = 40;
- _frequency = 440;
- _frequencyOffs = 0x2000;
- _algorithm = 7;
-
- _buffer = 0;
- _buflen = 0;
-
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); ++i)
- _opr[i] = new Operator2612 (this);
- velocity(0);
-}
-
-Voice2612::~Voice2612() {
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); ++i)
- delete _opr[i];
- free(_buffer);
-}
-
-void Voice2612::velocity(int velo) {
- _velocity = velo;
-#if 0
- int v = (velo * _control7) >> 7; // これだと精度良くないですね
-#else
- int v = velo + (_control7 - 127) * 4;
-#endif
- bool iscarrier[8][4] = {
- { false, false, false, true, }, //0
- { false, false, false, true, }, //1
- { false, false, false, true, }, //2
- { false, false, false, true, }, //3
- { false, true, false, true, }, //4
- { false, true, true, true, }, //5
- { false, true, true, true, }, //6
- { true, true, true, true, }, //7
- };
- int opr;
- for (opr = 0; opr < 4; opr++)
- if (iscarrier[_algorithm][opr])
- _opr[opr]->velocity(v);
- else
- _opr[opr]->velocity(127);
-}
-
-void Voice2612::setControlParameter(int control, int value) {
- switch (control) {
- case 7:
- _control7 = value;
- velocity(_velocity);
- break;
- case 123:
- // All notes off
- noteOff(_note);
- };
-}
-
-void Voice2612::setInstrument(byte const *instrument) {
- if (instrument == NULL)
- return;
-
- _algorithm = instrument[32] & 7;
- _opr[0]->feedbackLevel((instrument[32] >> 3) & 7);
- _opr[1]->feedbackLevel(0);
- _opr[2]->feedbackLevel(0);
- _opr[3]->feedbackLevel(0);
- _opr[0]->setInstrument(instrument + 0);
- _opr[1]->setInstrument(instrument + 2);
- _opr[2]->setInstrument(instrument + 1);
- _opr[3]->setInstrument(instrument + 3);
-}
-
-void Voice2612::nextTick(int *outbuf, int buflen) {
- if (_velocity == 0)
- return;
-
- if (_buflen < buflen) {
- free(_buffer);
- _buflen = buflen;
- _buffer = (int *) malloc(sizeof(int) * buflen * 2);
- }
-
- int *buf1 = _buffer;
- int *buf2 = _buffer + buflen;
- memset(_buffer, 0, sizeof(int) * buflen * 2);
-
- switch (_algorithm) {
- case 0:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, buf1, buflen);
- memset (buf2, 0, sizeof (int) * buflen);
- _opr[2]->nextTick(buf1, buf2, buflen);
- _opr[3]->nextTick(buf2, outbuf, buflen);
- break;
- case 1:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf1, buf2, buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 2:
- _opr[1]->nextTick(buf1, buf2, buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- memset(buf2, 0, sizeof(int) * buflen);
- _opr[0]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 3:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, buf1, buflen);
- memset(buf2, 0, sizeof(int) * buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 4:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf1, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 5:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf2, outbuf, buflen);
- _opr[3]->nextTick(buf2, outbuf, buflen);
- break;
- case 6:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf1, outbuf, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 7:
- _opr[0]->nextTick(buf1, outbuf, buflen);
- _opr[1]->nextTick(buf1, outbuf, buflen);
- _opr[2]->nextTick(buf1, outbuf, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- };
-}
-
-void Voice2612::noteOn(int n, int onVelo) {
- _note = n;
- velocity(onVelo);
- recalculateFrequency();
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->keyOn();
-}
-
-bool Voice2612::noteOff(int note) {
- if (_note != note)
- return false;
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->keyOff();
- return true;
-}
-
-void Voice2612::pitchBend(int value) {
- _frequencyOffs = value;
- recalculateFrequency();
-}
-
-void Voice2612::recalculateFrequency() {
- // MIDI とも違うし....
- // どういう仕様なんだろうか?
- // と思ったら、なんと、これ (↓) が正解らしい。
- int32 basefreq = frequencyTable[_note];
- int cfreq = frequencyTable[_note - (_note % 12)];
- int oct = _note / 12;
- int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq); // OPL の fnum と同じようなもの。
- fnum += _frequencyOffs - 0x2000;
- if (fnum < 0x2000) {
- fnum += 0x2000;
- oct--;
- }
- if (fnum >= 0x4000) {
- fnum -= 0x2000;
- oct++;
- }
-
- // _frequency は最終的にバイアス 256*1024 倍
- _frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8);
-
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->frequency(_frequency);
-}
-
-////////////////////////////////////////
-//
-// MidiChannel_YM2612
-//
-////////////////////////////////////////
-
-MidiChannel_YM2612::MidiChannel_YM2612() {
- _voices = 0;
- _next_voice = 0;
-}
-
-MidiChannel_YM2612::~MidiChannel_YM2612() {
- removeAllVoices();
-}
-
-void MidiChannel_YM2612::removeAllVoices() {
- if (!_voices)
- return;
- Voice2612 *last, *voice = _voices;
- for (; voice; voice = last) {
- last = voice->next;
- delete voice;
- }
- _voices = _next_voice = 0;
-}
-
-void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
- if (!_voices)
- return;
- _next_voice = _next_voice ? _next_voice : _voices;
- _next_voice->noteOn(note, onVelo);
- _next_voice = _next_voice->next;
-}
-
-void MidiChannel_YM2612::noteOff(byte note) {
- if (!_voices)
- return;
- if (_next_voice == _voices)
- _next_voice = 0;
- Voice2612 *voice = _next_voice;
- do {
- if (!voice)
- voice = _voices;
- if (voice->noteOff(note)) {
- _next_voice = voice;
- break;
- }
- voice = voice->next;
- } while (voice != _next_voice);
-}
-
-void MidiChannel_YM2612::controlChange(byte control, byte value) {
- // いいのかこれで?
- if (control == 121) {
- // Reset controller
- removeAllVoices();
- } else {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->setControlParameter(control, value);
- }
-}
-
-void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, byte *fmInst) {
- if (type != 'EUP ')
- return;
- Voice2612 *voice = new Voice2612;
- voice->next = _voices;
- _voices = voice;
- voice->_rate = _rate;
- voice->setInstrument(fmInst);
-}
-
-void MidiChannel_YM2612::pitchBend(int16 value) {
- // いいのかこれで?
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->pitchBend(value);
-}
-
-void MidiChannel_YM2612::nextTick(int *outbuf, int buflen) {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->nextTick(outbuf, buflen);
-}
-
-void MidiChannel_YM2612::rate(uint16 r) {
- _rate = r;
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->_rate = r;
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_YM2612
-//
-////////////////////////////////////////
-
-MidiDriver_YM2612::MidiDriver_YM2612(SoundMixer *mixer)
- : MidiDriver_Emulated(mixer) {
- _next_voice = 0;
-
- createLookupTables();
- _volume = 256;
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i] = new MidiChannel_YM2612;
- rate(getRate());
-}
-
-MidiDriver_YM2612::~MidiDriver_YM2612() {
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- delete _channel[i];
- delete sintbl;
- delete powtbl;
- delete frequencyTable;
- delete keycodeTable;
- delete keyscaleTable;
- delete attackOut;
- sintbl = powtbl = frequencyTable = keycodeTable = keyscaleTable = attackOut = 0;
-}
-
-int MidiDriver_YM2612::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- _mixer->setupPremix(this);
- return 0;
-}
-
-void MidiDriver_YM2612::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- // Detach the premix callback handler
- _mixer->setupPremix(0);
-}
-
-void MidiDriver_YM2612::send(uint32 b) {
- send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void MidiDriver_YM2612::send(byte chan, uint32 b) {
- //byte param3 = (byte) ((b >> 24) & 0xFF);
- byte param2 = (byte) ((b >> 16) & 0xFF);
- byte param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
- if (chan > ARRAYSIZE(_channel))
- return;
-
- switch (cmd) {
- case 0x80:// Note Off
- _channel[chan]->noteOff(param1);
- break;
- case 0x90: // Note On
- _channel[chan]->noteOn(param1, param2);
- break;
- case 0xA0: // Aftertouch
- break; // Not supported.
- case 0xB0: // Control Change
- _channel[chan]->controlChange(param1, param2);
- break;
- case 0xC0: // Program Change
- _channel[chan]->programChange(param1);
- break;
- case 0xD0: // Channel Pressure
- break; // Not supported.
- case 0xE0: // Pitch Bend
- _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
- break;
- case 0xF0: // SysEx
- // We should never get here! SysEx information has to be
- // sent via high-level semantic methods.
- warning("MidiDriver_YM2612: Receiving SysEx command on a send() call");
- break;
-
- default:
- warning("MidiDriver_YM2612: Unknown send() command 0x%02X", cmd);
- }
-}
-
-void MidiDriver_YM2612::sysEx(byte *msg, uint16 length) {
- if (msg[0] != 0x7C || msg[1] >= ARRAYSIZE(_channel))
- return;
- _channel[msg[1]]->sysEx_customInstrument('EUP ', &msg[2]);
-}
-
-void MidiDriver_YM2612::generateSamples(int16 *data, int len) {
- memset(data, 0, 2 * sizeof(int16) * len);
- nextTick(data, len);
-}
-
-void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) {
- int *buf0 = (int *)buf1;
-
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i]->nextTick(buf0, buflen);
-
- for (i = 0; i < buflen; ++i)
- buf1[i*2+1] = buf1[i*2] = ((buf0[i] * volume()) >> 10) & 0xffff;
-}
-
-void MidiDriver_YM2612::rate(uint16 r)
-{
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i]->rate(r);
-}
-
-void MidiDriver_YM2612::createLookupTables() {
- {
- int i;
- sintbl = new int [2048];
- for (i = 0; i < 2048; i++)
- sintbl[i] = (int)(0xffff * sin(i/2048.0*2.0*PI));
- }
-
- {
- int i;
- powtbl = new int [1025];
- for (i = 0; i <= 1024; i++)
- powtbl[i] = (int)(0x10000 * pow(2.0, (i-512)/512.0));
- }
-
- {
- int i;
- int block;
-
- static int fnum[] = {
- 0x026a, 0x028f, 0x02b6, 0x02df,
- 0x030b, 0x0339, 0x036a, 0x039e,
- 0x03d5, 0x0410, 0x044e, 0x048f,
- };
-
- // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0)); // バイアス 256 倍
- // 0x45 が 440Hz (a4)、0x51 が 880Hz (a5) らしい
- frequencyTable = new int [120];
- for (block = -1; block < 9; block++) {
- for (i = 0; i < 12; i++) {
- double freq = fnum[i] * (166400.0 / 3) * pow(2.0, block-21);
- frequencyTable[(block+1)*12+i] = (int)(256.0 * freq);
- }
- }
-
- keycodeTable = new int [120];
- // detune 量の計算や KS による rate 変換に使うんじゃないかな
- for (block = -1; block < 9; block++) {
- for (i = 0; i < 12; i++) {
- // see p.204
- int f8 = (fnum[i] >> 7) & 1;
- int f9 = (fnum[i] >> 8) & 1;
- int f10 = (fnum[i] >> 9) & 1;
- int f11 = (fnum[i] >> 10) & 1;
- int n4 = f11;
- int n3 = f11&(f10|f9|f8) | (~f11&f10&f9&f8);
- int note = n4*2 + n3;
- // see p.207
- keycodeTable[(block+1)*12+i] = block*4 + note;
- }
- }
- }
-
- {
- int freq;
- keyscaleTable = new int [8192];
- keyscaleTable[0] = 0;
- for (freq = 1; freq < 8192; freq++) {
- keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1;
- // 8368[Hz] (o9c) で 32くらい。9.03 =:= ln 8368
- }
- }
-
- {
- int i;
- attackOut = new int [1024];
- for (i = 0; i < 1024; i++)
- attackOut[i] = (int)(((0x7fff+0x03a5)*30.0) / (30.0+i)) - 0x03a5;
- }
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_YM2612 factory
-//
-////////////////////////////////////////
-
-MidiDriver *MidiDriver_YM2612_create(SoundMixer *mixer) {
- return new MidiDriver_YM2612(mixer);
-}