diff options
author | Jerome Fisher | 2004-11-13 19:24:37 +0000 |
---|---|---|
committer | Jerome Fisher | 2004-11-13 19:24:37 +0000 |
commit | 5e442766e533339c1e2f3389a2859601c6ab1127 (patch) | |
tree | 4df084b6b6756901508bb6c39d4125a6a150102f | |
parent | 2ae3166f2db47b7beb5225d57b5e271de33ab9cd (diff) | |
download | scummvm-rg350-5e442766e533339c1e2f3389a2859601c6ab1127.tar.gz scummvm-rg350-5e442766e533339c1e2f3389a2859601c6ab1127.tar.bz2 scummvm-rg350-5e442766e533339c1e2f3389a2859601c6ab1127.zip |
MT32 MidiDriver:
- Channels now ignore effectLevel() and chorusLevel(), instead of sending unsupported control change messages to MT32Emu (they're not supported in a real MT-32, either, according to docs).
- Implemented setPitchBendRange() by sending a sysex write command to adjust the patch.
- _outputRate is now hard-coded at 32000, until tuning can be fixed for other sample rates.
MT32EMu:
- Extended File interface to deal with reading/writing 16/32-bit values endian-independently (they're always big-endian on file).
- Improved usage of packing-related pragmas.
- Should now be endian-agnostic (without depending on #defines for the endianness).
svn-id: r15800
-rw-r--r-- | backends/midi/mt32.cpp | 83 | ||||
-rw-r--r-- | backends/midi/mt32/mt32_file.cpp | 66 | ||||
-rw-r--r-- | backends/midi/mt32/mt32_file.h | 27 | ||||
-rw-r--r-- | backends/midi/mt32/mt32emu.h | 3 | ||||
-rw-r--r-- | backends/midi/mt32/partial.cpp | 31 | ||||
-rw-r--r-- | backends/midi/mt32/structures.h | 86 | ||||
-rw-r--r-- | backends/midi/mt32/synth.cpp | 136 | ||||
-rw-r--r-- | backends/midi/mt32/synth.h | 1 |
8 files changed, 256 insertions, 177 deletions
diff --git a/backends/midi/mt32.cpp b/backends/midi/mt32.cpp index 6b2d576852..28f331e694 100644 --- a/backends/midi/mt32.cpp +++ b/backends/midi/mt32.cpp @@ -36,9 +36,14 @@ #include "common/file.h" #include "common/config-manager.h" +class MidiChannel_MT32 : public MidiChannel_MPU401 { + void effectLevel(byte value) { } + void chorusLevel(byte value) { } +}; + class MidiDriver_MT32 : public MidiDriver_Emulated { private: - MidiChannel_MPU401 _midiChannels[16]; + MidiChannel_MT32 _midiChannels[16]; uint16 _channelMask; MT32Emu::Synth *_synth; @@ -54,6 +59,7 @@ public: 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); @@ -77,33 +83,32 @@ public: void close() { return file.close(); } - size_t read(void *ptr, size_t size) { - return file.read(ptr, size); + size_t read(void *in, size_t size) { + return file.read(in, size); } - bool readLine(char *ptr, size_t size) { - return file.gets(ptr, size) != NULL; + bool readLine(char *in, size_t size) { + return file.gets(in, size) != NULL; } - size_t write(const void *ptr, size_t size) { - return file.write(ptr, size); - } - int readByte() { + bool readBit8u(MT32Emu::Bit8u *in) { byte b = file.readByte(); if (file.eof()) - return -1; - return b; - } - bool writeByte(unsigned char out) { - file.writeByte(out); - if (file.ioFailed()) 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(); } }; -MT32Emu::File *MT32_OpenFile(void *userData, const char *filename, MT32Emu::File::OpenMode mode) { +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; @@ -112,13 +117,11 @@ MT32Emu::File *MT32_OpenFile(void *userData, const char *filename, MT32Emu::File return file; } -//////////////////////////////////////// -// -// MidiDriver_MT32 -// -//////////////////////////////////////// +static void MT32_PrintDebug(void *userData, const char *fmt, va_list list) { + //vdebug(0, fmt, list); // FIXME: Use a higher debug level +} -static void report(void *userData, MT32Emu::ReportType type, void *reportData) { +static void MT32_Report(void *userData, MT32Emu::ReportType type, void *reportData) { switch(type) { case MT32Emu::ReportType_lcdMessage: g_system->displayMessageOnOSD((char *)reportData); @@ -143,6 +146,12 @@ static void report(void *userData, MT32Emu::ReportType type, void *reportData) { } } +//////////////////////////////////////// +// +// MidiDriver_MT32 +// +//////////////////////////////////////// + MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer) : MidiDriver_Emulated(mixer) { _channelMask = 0xFFFF; // Permit all 16 channels by default uint i; @@ -153,7 +162,7 @@ MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer) : MidiDriver_Emulated(mixer) _baseFreq = 1000; - _outputRate = _mixer->getOutputRate(); + _outputRate = 32000; //_mixer->getOutputRate(); } MidiDriver_MT32::~MidiDriver_MT32() { @@ -161,10 +170,6 @@ MidiDriver_MT32::~MidiDriver_MT32() { delete _synth; } -static void vdebug(void *data, const char *fmt, va_list list) { - // do nothing here now -} - int MidiDriver_MT32::open() { MT32Emu::SynthProperties prop; @@ -180,9 +185,8 @@ int MidiDriver_MT32::open() { prop.RevType = 0; prop.RevTime = 5; prop.RevLevel = 3; - prop.userData = (void *)1; - prop.printDebug = &vdebug; - prop.report = &report; + prop.printDebug = MT32_PrintDebug; + prop.report = MT32_Report; prop.openFile = MT32_OpenFile; _synth = new MT32Emu::Synth(); if (!_synth->open(prop)) @@ -197,6 +201,23 @@ 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); @@ -233,7 +254,7 @@ uint32 MidiDriver_MT32::property(int prop, uint32 param) { } MidiChannel *MidiDriver_MT32::allocateChannel() { - MidiChannel_MPU401 *chan; + MidiChannel_MT32 *chan; uint i; for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) { diff --git a/backends/midi/mt32/mt32_file.cpp b/backends/midi/mt32/mt32_file.cpp index 2a28194333..1537b734e7 100644 --- a/backends/midi/mt32/mt32_file.cpp +++ b/backends/midi/mt32/mt32_file.cpp @@ -21,7 +21,7 @@ #include <stdio.h> -#include "mt32_file.h" +#include "mt32emu.h" namespace MT32Emu { @@ -40,24 +40,70 @@ namespace MT32Emu { fclose(fp); } - int ANSIFile::readByte() { - return fgetc(fp); + size_t ANSIFile::read(void *in, size_t size) { + return fread(in, 1, size, fp); } - size_t ANSIFile::read(void *ptr, size_t size) { - return fread(ptr, 1, size, fp); + bool ANSIFile::readLine(char *in, size_t size) { + return fgets(in, (int)size, fp) != NULL; } - bool ANSIFile::readLine(char *ptr, size_t size) { - return fgets(ptr, (int)size, fp) != NULL; + bool ANSIFile::readBit8u(Bit8u *in) { + int c = fgetc(fp); + if (c == EOF) + return false; + *in = (Bit8u)c; + return true; } - bool ANSIFile::writeByte(unsigned char out) { + bool File::readBit16u(Bit16u *in) { + char b[2]; + if (read(&b[0], 2) != 2) + return false; + *in = ((b[0] << 8) | b[1]); + return true; + } + + bool File::readBit32u(Bit32u *in) { + char 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; } - size_t ANSIFile::write(const void *ptr, size_t size) { - return fwrite(ptr, 1, size, fp); + bool File::writeBit16u(Bit16u out) { + if (!writeBit8u((Bit8u)((out >> 8) & 0xFF))) { + return false; + } + if (!writeBit8u((Bit8u)(out & 0xFF))) { + return false; + } + return true; + } + + bool File::writeBit32u(Bit32u out) { + if (!writeBit8u((Bit8u)((out >> 24) & 0xFF))) { + return false; + } + if (!writeBit8u((Bit8u)((out >> 16) & 0xFF))) { + return false; + } + if (!writeBit8u((Bit8u)((out >> 8) & 0xFF))) { + return false; + } + if (!writeBit8u((Bit8u)(out & 0xFF))) { + return false; + } + return true; } bool ANSIFile::isEOF() { diff --git a/backends/midi/mt32/mt32_file.h b/backends/midi/mt32/mt32_file.h index 6c02712596..f5888db5e3 100644 --- a/backends/midi/mt32/mt32_file.h +++ b/backends/midi/mt32/mt32_file.h @@ -34,12 +34,17 @@ public: }; virtual ~File() {} virtual void close() = 0; - virtual size_t read(void *ptr, size_t size) = 0; - virtual bool readLine(char *ptr, size_t size) = 0; - virtual size_t write(const void *ptr, size_t size) = 0; - // Returns -1 in case of EOF or error - virtual int readByte() = 0; - virtual bool writeByte(unsigned char out) = 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 some 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; }; @@ -49,11 +54,11 @@ private: public: bool open(const char *filename, OpenMode mode); void close(); - size_t read(void *ptr, size_t size); - bool readLine(char *ptr, size_t size); - size_t write(const void *, size_t size); - int readByte(); - bool writeByte(unsigned char out); + 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(); }; diff --git a/backends/midi/mt32/mt32emu.h b/backends/midi/mt32/mt32emu.h index ccf903ef8f..c31afee389 100644 --- a/backends/midi/mt32/mt32emu.h +++ b/backends/midi/mt32/mt32emu.h @@ -22,9 +22,6 @@ #ifndef MT32EMU_MT32EMU_H #define MT32EMU_MT32EMU_H -#include "stdafx.h" -#include "common/scummsys.h" - #include "freeverb.h" #include "structures.h" diff --git a/backends/midi/mt32/partial.cpp b/backends/midi/mt32/partial.cpp index 55daf7efbf..bc5151e565 100644 --- a/backends/midi/mt32/partial.cpp +++ b/backends/midi/mt32/partial.cpp @@ -149,7 +149,7 @@ void Partial::startPartial(dpoly *usePoly, PatchCache *useCache, Partial *pairPa pitchEnvCache = 0; pitchSustain = false; loopPos = 0; - partialOff.pcmabs = 0; + partialOff.pcmoffset = partialOff.pcmplace = 0; pair = pairPartial; useNoisePair = pairPartial == NULL && (mixType == 1 || mixType == 2); age = 0; @@ -238,9 +238,10 @@ Bit16s *Partial::generateSamples(long length) { delta = wavtabler[tPCM->pcmnum][noteVal]; addr = tPCM->addr; len = tPCM->len; - if (partialOff.pcmoffs.pcmplace >= len) { + if (partialOff.pcmplace >= len) { if (tPCM->loop) { - partialOff.pcmabs = 0; + partialOff.pcmplace = partialOff.pcmoffset = 0; + // FIXME:KG: Use this?: partialOff.pcmplace %= len; } else { play = false; deactivate(); @@ -252,11 +253,11 @@ Bit16s *Partial::generateSamples(long length) { delta = looptabler[tPCM->aggSound][loopPos][noteVal]; addr = synth->PCM[tmppcm].addr; len = synth->PCM[tmppcm].len; - if (partialOff.pcmoffs.pcmplace >= len) { + if (partialOff.pcmplace >= len) { loopPos++; if (LoopPatterns[tPCM->aggSound][loopPos]==-1) loopPos=0; - partialOff.pcmabs = 0; + partialOff.pcmplace = partialOff.pcmoffset = 0; } } @@ -265,7 +266,7 @@ Bit16s *Partial::generateSamples(long length) { int taddr; if (delta<0x10000) { // Linear sound interpolation - taddr = addr + partialOff.pcmoffs.pcmplace; + taddr = addr + partialOff.pcmplace; if (taddr >= ROMSIZE) { synth->printDebug("Overflow ROMSIZE!"); taddr = ROMSIZE - 1; @@ -273,16 +274,15 @@ Bit16s *Partial::generateSamples(long length) { ra = synth->romfile[taddr]; rb = synth->romfile[taddr+1]; dist = rb-ra; - ptemp = (ra + ((dist * (Bit32s)(partialOff.pcmoffs.pcmoffset>>8)) >>8)); + ptemp = (ra + ((dist * (Bit32s)(partialOff.pcmoffset >> 8)) >> 8)); } else { - //r = romfile[addr + partialOff.pcmoffs.pcmplace]; // 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 = addr + partialOff.pcmoffs.pcmplace; + taddr = addr + partialOff.pcmplace; ra = 0; - for (int ix=0;ix<idelta;ix++) + for (int ix = 0; ix < idelta; ix++) ra += synth->romfile[taddr++]; ptemp = ra / idelta; } @@ -291,12 +291,12 @@ Bit16s *Partial::generateSamples(long length) { // Synthesis partial int divis = divtable[noteVal] >> 15; - partialOff.pcmoffs.pcmplace %= (Bit16u)divis; + partialOff.pcmplace %= (Bit16u)divis; if (ampval > 0) { int wf = patchCache->waveform ; - int toff = partialOff.pcmoffs.pcmplace; - int minorplace = partialOff.pcmoffs.pcmoffset >> 14; + int toff = partialOff.pcmplace; + int minorplace = partialOff.pcmoffset >> 14; int pa, pb; @@ -381,7 +381,10 @@ Bit16s *Partial::generateSamples(long length) { tdelta = (tdelta * *poly->bendptr)>>12; // Add calculated delta to our waveform offset - partialOff.pcmabs += (int)tdelta; + Bit32u absOff = ((partialOff.pcmplace << 16) | partialOff.pcmoffset); + absOff += (int)tdelta; + partialOff.pcmplace = (Bit16u)((absOff & 0xFFFF0000) >> 16); + partialOff.pcmoffset = (Bit16u)(absOff & 0xFFFF); // Put volume envelope over generated sample ptemp = (ptemp * ampval) >> 9; diff --git a/backends/midi/mt32/structures.h b/backends/midi/mt32/structures.h index 07b170cc89..5b1db5921b 100644 --- a/backends/midi/mt32/structures.h +++ b/backends/midi/mt32/structures.h @@ -36,12 +36,11 @@ namespace MT32Emu { #ifdef _MSC_VER -#define ALIGN_PACKED __declspec(align(1)) +#define MT32EMU_ALIGN_PACKED __declspec(align(1)) typedef unsigned __int64 Bit64u; typedef signed __int64 Bit64s; #else -//#define ALIGN_PACKED __attribute__ ((__packed__)) -#define ALIGN_PACKED __attribute__ ((aligned (1))) +#define MT32EMU_ALIGN_PACKED __attribute__((packed)) typedef unsigned long long Bit64u; typedef signed long long Bit64s; #endif @@ -53,7 +52,16 @@ 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 +#ifdef __GNUC__ +#pragma pack(push, 1) +#else #pragma pack(1) +#endif + struct TimbreParam { struct commonParam { char name[10]; @@ -61,19 +69,19 @@ struct TimbreParam { char pstruct34; // #3&4 0-12 (1-13) char pmute; // 0-15 (0000-1111) char nosustain; // 0-1(Normal, No sustain) - } ALIGN_PACKED common; + } MT32EMU_ALIGN_PACKED common; struct partialParam { struct wgParam { char coarse; // 0-96 (C1,C#1-C9) - char fine; // 0-100 (-50 - +50) + char fine; // 0-100 (-50 to +50 (cents?)) char 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) char bender; // 0,1 (ON/OFF) char waveform; // 0-1 (SQU/SAW) char pcmwave; // 0-127 (1-128) char pulsewid; // 0-100 char pwvelo; // 0-14 (-7 - +7) - } ALIGN_PACKED wg; + } MT32EMU_ALIGN_PACKED wg; struct envParam { char depth; // 0-10 @@ -81,13 +89,13 @@ struct TimbreParam { char timekeyfollow; // 0-4 char time[4]; // 1-100 char level[5]; // 1-100 (-50 - +50) - } ALIGN_PACKED env; + } MT32EMU_ALIGN_PACKED env; struct lfoParam { char rate; // 0-100 char depth; // 0-100 char modsense; // 0-100 - } ALIGN_PACKED lfo; + } MT32EMU_ALIGN_PACKED lfo; struct tvfParam { char cutoff; // 0-100 @@ -101,7 +109,7 @@ struct TimbreParam { char envtkf; // TIME KEY FOLLOW 0-4 char envtime[5]; // 1-100 char envlevel[4]; // 1-100 - } ALIGN_PACKED tvf; + } MT32EMU_ALIGN_PACKED tvf; struct tvaParam { char level; // 0-100 @@ -114,22 +122,20 @@ struct TimbreParam { char envvkf; // VELOS KEY FOLL0W 0-4 char envtime[5]; // 1-100 char envlevel[4]; // 1-100 - } ALIGN_PACKED tva; - - } ALIGN_PACKED partial[4]; - //char dummy[20]; -} ALIGN_PACKED; + } MT32EMU_ALIGN_PACKED tva; + } MT32EMU_ALIGN_PACKED partial[4]; +} MT32EMU_ALIGN_PACKED; struct PatchParam { char timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm) char timbreNum; // TIMBRE NUMBER 0-63 - char keyShift; // KEY SHIFT 0-48 (-24 - +24) - char fineTune; // FINE TUNE 0-100 (-50 - +50) + char keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones) + char fineTune; // FINE TUNE 0-100 (-50 - +50 cents) char benderRange; // BENDER RANGE 0-24 char assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4) char reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON) char dummy; // (DUMMY) -} ALIGN_PACKED; +} MT32EMU_ALIGN_PACKED; struct MemParams { struct PatchTemp { @@ -137,23 +143,23 @@ struct MemParams { char outlevel; // OUTPUT LEVEL 0-100 char panpot; // PANPOT 0-14 (R-L) char dummyv[6]; - } ALIGN_PACKED patchSettings[8]; + } MT32EMU_ALIGN_PACKED patchSettings[8]; struct RhythmTemp { char timbre; // TIMBRE 0-94 (M1-M64,R1-30,OFF) char outlevel; // OUTPUT LEVEL 0-100 char panpot; // PANPOT 0-14 (R-L) char reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON) - } ALIGN_PACKED rhythmSettings[64]; + } MT32EMU_ALIGN_PACKED rhythmSettings[64]; - TimbreParam timbreSettings[8]; + TimbreParam MT32EMU_ALIGN_PACKED timbreSettings[8]; - PatchParam patches[128]; + PatchParam MT32EMU_ALIGN_PACKED patches[128]; struct PaddedTimbre { TimbreParam timbre; char padding[10]; - } ALIGN_PACKED timbres[64 + 64 + 64 + 30]; // Group A, Group B, Memory, Rhythm + } MT32EMU_ALIGN_PACKED timbres[64 + 64 + 64 + 30]; // Group A, Group B, Memory, Rhythm struct SystemArea { char masterTune; // MASTER TUNE 0-127 432.1-457.6Hz @@ -163,8 +169,8 @@ struct MemParams { char reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32 char chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF) char masterVol; // MASTER VOLUME 0-100 - } ALIGN_PACKED system; -} ALIGN_PACKED; + } MT32EMU_ALIGN_PACKED system; +}; struct MemBanks { char pTemp[8][sizeof(MemParams::PatchTemp)]; @@ -173,21 +179,21 @@ struct MemBanks { char patchBank[128][sizeof(PatchParam)]; char timbreBank[64 + 64 + 64 + 30][sizeof(MemParams::PaddedTimbre)]; char systemBank[sizeof(MemParams::SystemArea)]; -} ALIGN_PACKED; + // System memory 0x100000 + // Display 0x200000 + // Reset 0x7F0000 +}; union MT32RAMFormat { MemParams params; MemBanks banks; +} MT32EMU_ALIGN_PACKED; - // System memory 10 - - // Display 20 - - // Reset 7F - -} ALIGN_PACKED; - +#ifdef __GNUC__ +#pragma pack(pop) +#else #pragma pack() +#endif struct sampleFormat { Bit32u addr; @@ -205,17 +211,9 @@ struct sampleTable { Bit32s aggSound; // This variable is for the last 9 PCM samples, which are actually loop combinations }; -union soundaddr { - Bit32u pcmabs; - struct offsets { -#if defined(SCUMM_LITTLE_ENDIAN) - Bit16u pcmoffset; - Bit16u pcmplace; -#else - Bit16u pcmplace; - Bit16u pcmoffset; -#endif - } pcmoffs; +struct soundaddr { + Bit16u pcmplace; + Bit16u pcmoffset; }; struct volset { diff --git a/backends/midi/mt32/synth.cpp b/backends/midi/mt32/synth.cpp index bd84ad076e..2647fdae85 100644 --- a/backends/midi/mt32/synth.cpp +++ b/backends/midi/mt32/synth.cpp @@ -35,10 +35,10 @@ // Used to dump drum patches to syx file for viewing #define DUMPDRUMS 0 -#define SYSEX_SIZE 512 - namespace MT32Emu { +const int MAX_SYSEX_SIZE = 512; + iir_filter_type usefilter; static const Bit8u InitPatches[8] = { @@ -108,6 +108,16 @@ float iir_filter_normal(float input,float *hist1_ptr, float *coef_ptr, int revLe return(output); } +Bit8u Synth::calcSysexChecksum(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; @@ -208,44 +218,38 @@ bool Synth::loadPreset(const char *filename) { return false; } bool inSys = false; - Bit8u sysexBuf[SYSEX_SIZE]; + Bit8u sysexBuf[MAX_SYSEX_SIZE]; Bit16u syslen = 0; - int filePos = 0; bool rc = true; for (;;) { - int fc = file->readByte(); - if (fc == -1) { + Bit8u c; + if (!file->readBit8u(&c)) { if (!file->isEOF()) { rc = false; } break; } - Bit8u c = (Bit8u)fc; sysexBuf[syslen] = c; - syslen++; - filePos++; - if (c==0xf0) + 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 %s, ignoring message", MAX_SYSEX_SIZE, filename); + inSys = false; + syslen = 0; + } + } else if (c == 0xF0) { + syslen++; inSys = true; - if ((c==0xf7) && (inSys)) { - playSysex(&sysexBuf[0],syslen); - inSys = false; - syslen = 0; } } closeFile(file); return rc; } -unsigned char calcChecksum(unsigned char *data, unsigned int len, unsigned char checksum) { - for (unsigned int i = 0; i < len; i++) { - checksum = checksum + data[i]; - } - checksum = checksum & 0x7f; - if (checksum) - checksum = 0x80 - checksum; - return checksum; -} - bool Synth::loadDrums(const char *filename) { File *file = openFile(filename, File::OpenMode_read); if (file == NULL) { @@ -288,15 +292,15 @@ void Synth::dumpDrums(const char *filename) { memset(dumbtext,0,10); for (int drumnum=0;drumnum<30;drumnum++) { // Sysex header - if (!file->writeByte(0xf0)) + if (!file->writeBit8u(0xf0)) break; - if (!file->writeByte(0x41)) + if (!file->writeBit8u(0x41)) break; - if (!file->writeByte(0x10)) + if (!file->writeBit8u(0x10)) break; - if (!file->writeByte(0x16)) + if (!file->writeBit8u(0x16)) break; - if (!file->writeByte(0x12)) + if (!file->writeBit8u(0x12)) break; int useaddr = drumnum * 256; @@ -304,11 +308,11 @@ void Synth::dumpDrums(const char *filename) { char isb = (char)((useaddr >> 7) & 0x7f); char msb = (char)(((useaddr >> 14) & 0x7f) | 0x08); //Address - if (!file->writeByte(msb)) + if (!file->writeBit8u(msb)) break; - if (!file->writeByte(isb)) + if (!file->writeBit8u(isb)) break; - if (!file->writeByte(lsb)) + if (!file->writeBit8u(lsb)) break; TimbreParam *timbre = &mt32ram.params.timbres[192 + drumnum].timbre; @@ -325,12 +329,12 @@ void Synth::dumpDrums(const char *filename) { break; //Checksum unsigned char *dat = (unsigned char *)timbre; - unsigned char checksum = calcChecksum(dat, 246, msb + isb + lsb); - if (!file->writeByte(checksum)) + unsigned char checksum = calcSysexChecksum(dat, 246, msb + isb + lsb); + if (!file->writeBit8u(checksum)) break; //End of sysex - if (!file->writeByte(0xf7)) + if (!file->writeBit8u(0xf7)) break; } closeFile(file); @@ -470,16 +474,15 @@ bool Synth::loadROM(const char *filename) { #endif bool rc = true; for (int i = 0; ; i++) { - int fc = file->readByte(); - if (fc == -1) { + Bit8u s; + if (!file->readBit8u(&s)) { if (!file->isEOF()) { rc = false; } break; } - Bit16s s = (Bit16s)fc; - fc = file->readByte(); - if (fc == -1) { + Bit8u c; + if (!file->readBit8u(&c)) { if (!file->isEOF()) { rc = false; } else { @@ -487,7 +490,6 @@ bool Synth::loadROM(const char *filename) { } break; } - Bit16s c = (Bit16s)fc; short e; int bit; @@ -515,8 +517,8 @@ bool Synth::loadROM(const char *filename) { */ #ifdef MT32OUT - outFile->writeByte(e & 0xff); - outFile->writeByte(((e >> 8) & 0x7f)); + outFile->writeBit8u(e & 0xff); + outFile->writeBit8u(((e >> 8) & 0x7f)); #endif // File is encoded in dB, convert to PCM // MINDB = -96 @@ -533,8 +535,8 @@ bool Synth::loadROM(const char *filename) { romfile[i] = (Bit16s)vol; #ifdef MT32OUT - outFileB->writeByte(romfile[i] & 0xff); - outFileB->writeByte(romfile[i] >> 8); + outFileB->writeBit8u(romfile[i] & 0xff); + outFileB->writeBit8u(romfile[i] >> 8); #endif } #ifdef MT32OUT @@ -636,9 +638,11 @@ bool Synth::open(SynthProperties &useProp) { if (available3DNow) { printDebug("Detected and using SIMD (AMD 3DNow) extensions"); usefilter = &iir_filter_3dnow; + report(ReportType_using3DNow, NULL); } else if (availableSSE) { printDebug("Detected and using SIMD (Intel SSE) extensions"); usefilter = &iir_filter_sse; + report(ReportType_usingSSE, NULL); } #endif @@ -695,13 +699,13 @@ void Synth::close(void) { } } if (partialManager != NULL) { - partialManager = NULL; delete partialManager; + partialManager = NULL; } if (reverbModel != NULL) { - reverbModel = NULL; delete reverbModel; + reverbModel = NULL; } for (int i = 0; i < 9; i++) { @@ -721,7 +725,7 @@ void Synth::playMsg(Bit32u msg) { unsigned char velocity = (unsigned char)((msg & 0xff0000) >> 16); isEnabled = true; - //if (code!=0xf) printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note); + //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note); char part = chantable[chan]; if (part < 0 || part > 8) { @@ -865,7 +869,7 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len); return; } - unsigned char checksum = calcChecksum(sysex, len - 1, 0); + 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; @@ -875,7 +879,7 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le addr = MEMADDR(addr); sysex += 3; len -= 3; - printDebug("Sysex addr: 0x%06x", SYSEXMEMADDR(addr)); + //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)); @@ -1108,10 +1112,14 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le printDebug(" Master volume: %d", mt32ram.params.system.masterVol); mastervolume = (Bit16s)((float)mt32ram.params.system.masterVol * 327.0); } else if (addr == MEMADDR(0x200000)) { - char buf[SYSEX_SIZE]; - memset(&buf, 0, SYSEX_SIZE); + 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); - printDebug("LCD Display: %s", buf); + buf[len] = 0; + printDebug("WRITE-LCD: %s", buf); report(ReportType_lcdMessage, buf); } else if (addr >= MEMADDR(0x7f0000)) { printDebug("Reset"); @@ -1136,15 +1144,15 @@ int Synth::dumpSysex(char *filename) { int patchnum; for (patchnum=0;patchnum<64;patchnum++) { // Sysex header - if (!file->writeByte(0xF0)) + if (!file->writeBit8u(0xF0)) break; - if (!file->writeByte(0x41)) + if (!file->writeBit8u(0x41)) break; - if (!file->writeByte(0x10)) + if (!file->writeBit8u(0x10)) break; - if (!file->writeByte(0x16)) + if (!file->writeBit8u(0x16)) break; - if (!file->writeByte(0x12)) + if (!file->writeBit8u(0x12)) break; int useaddr = patchnum * 256; @@ -1152,11 +1160,11 @@ int Synth::dumpSysex(char *filename) { char isb = (char)((useaddr >> 7) & 0x7f); char msb = (char)(((useaddr >> 14) & 0x7f) | 0x08); //Address - if (!file->writeByte(msb)) + if (!file->writeBit8u(msb)) break; - if (!file->writeByte(isb)) + if (!file->writeBit8u(isb)) break; - if (!file->writeByte(lsb)) + if (!file->writeBit8u(lsb)) break; //Data @@ -1172,13 +1180,13 @@ int Synth::dumpSysex(char *filename) { break; //Checksum unsigned char *dat = (unsigned char *)&mt32ram.params.timbres[patchnum + 128].timbre; - unsigned char checksum = calcChecksum(dat, 246, msb + isb + lsb); + unsigned char checksum = calcSysexChecksum(dat, 246, msb + isb + lsb); - if (!file->writeByte(checksum)) + if (!file->writeBit8u(checksum)) break; //End of sysex - if (!file->writeByte(0xF7)) + if (!file->writeBit8u(0xF7)) break; } closeFile(file); diff --git a/backends/midi/mt32/synth.h b/backends/midi/mt32/synth.h index 8d3305e0d4..f2fc3ffae6 100644 --- a/backends/midi/mt32/synth.h +++ b/backends/midi/mt32/synth.h @@ -185,6 +185,7 @@ public: // Sends a 4-byte MIDI message to the MT-32 for immediate playback void playMsg(Bit32u msg); + static Bit8u calcSysexChecksum(Bit8u *data, Bit32u len, Bit8u checksum); // Sends a string of Sysex commands to the MT-32 for immediate interpretation // The length is in bytes void playSysex(Bit8u *sysex, Bit32u len); |