mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 01:38:36 +00:00
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:
parent
2ae3166f2d
commit
5e442766e5
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user