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
This commit is contained in:
Jerome Fisher 2004-11-13 19:24:37 +00:00
parent 2ae3166f2d
commit 5e442766e5
8 changed files with 256 additions and 177 deletions

View File

@ -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) {

View File

@ -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() {

View File

@ -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();
};

View File

@ -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"

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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);