MT32: Update Munt to 2.0.1-pre
This update uses upstream commit f88ef828a600ce66d1f730c8fb2a7f580f6f6165. This update switches to use the new Munt C++ interface, which will allow ScummVM to link to an external Munt library instead of requiring it to be built-in in the future. For the moment, the emulator is still built-in, since it is not available from most package repositories. The Munt driver in ScummVM now uses writeSysex instead of the (now-private) playSysexWithoutFraming, per recommendation from the Munt team <https://github.com/munt/munt/pull/30>. This changeset also removes direct modifications that used to be made to Munt code, to ease future updates. To update Munt code in the future: 1. Replace all source files in the `softsynth/mt32` directory with new files from the upstream `mt32emu/src` directory; 2. Update `config.h` with the correct version number for the new version of Munt; 3. Update `module.mk` to add any new source files that need to be built.
This commit is contained in:
parent
ffea222f5b
commit
b8d70d26fa
56 changed files with 4425 additions and 991 deletions
28
COPYING.BSD
28
COPYING.BSD
|
@ -91,3 +91,31 @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|||
PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
|
||||
BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
|
||||
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
|
||||
Parts of the MT-32 emulator use the following license:
|
||||
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
1
NEWS
1
NEWS
|
@ -7,6 +7,7 @@ For a more comprehensive changelog of the latest experimental code, see:
|
|||
the current or a specified directory.
|
||||
- Many options in GUI could be applied without closing the dialog.
|
||||
- On-the-fly language switching was implemented.
|
||||
- Updated Munt MT-32 emulation code to version 2.0.0.
|
||||
|
||||
AGOS:
|
||||
- Fixed subtitle speed setting in the Hebrew version of Simon the Sorcerer 1.
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
|
||||
#ifdef USE_MT32EMU
|
||||
|
||||
#include "audio/softsynth/mt32/mt32emu.h"
|
||||
#include "audio/softsynth/mt32/ROMInfo.h"
|
||||
|
||||
#include "audio/softsynth/emumidi.h"
|
||||
#include "audio/musicplugin.h"
|
||||
#include "audio/mpu401.h"
|
||||
|
@ -52,16 +49,12 @@
|
|||
|
||||
#include "gui/message.h"
|
||||
|
||||
#include "audio/softsynth/mt32/c_interface/cpp_interface.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class ReportHandlerScummVM : public ReportHandler {
|
||||
friend class Synth;
|
||||
|
||||
class ScummVMReportHandler : public MT32Emu::IReportHandler {
|
||||
public:
|
||||
virtual ~ReportHandlerScummVM() {}
|
||||
|
||||
protected:
|
||||
|
||||
// Callback for debug messages, in vprintf() format
|
||||
void printDebug(const char *fmt, va_list list) {
|
||||
Common::String out = Common::String::vformat(fmt, list);
|
||||
|
@ -70,18 +63,30 @@ protected:
|
|||
|
||||
// Callbacks for reporting various errors and information
|
||||
void onErrorControlROM() {
|
||||
GUI::MessageDialog dialog("MT32emu: Init Error - Missing or invalid Control ROM image", "OK");
|
||||
GUI::MessageDialog dialog("MT32Emu: Init Error - Missing or invalid Control ROM image", "OK");
|
||||
dialog.runModal();
|
||||
error("MT32emu: Init Error - Missing or invalid Control ROM image");
|
||||
}
|
||||
void onErrorPCMROM() {
|
||||
GUI::MessageDialog dialog("MT32emu: Init Error - Missing PCM ROM image", "OK");
|
||||
GUI::MessageDialog dialog("MT32Emu: Init Error - Missing PCM ROM image", "OK");
|
||||
dialog.runModal();
|
||||
error("MT32emu: Init Error - Missing PCM ROM image");
|
||||
}
|
||||
void showLCDMessage(const char *message) {
|
||||
Common::OSDMessageQueue::instance().addMessage(message);
|
||||
}
|
||||
|
||||
// Unused callbacks
|
||||
virtual void onMIDIMessagePlayed() {}
|
||||
virtual bool onMIDIQueueOverflow() { return false; }
|
||||
virtual void onMIDISystemRealtime(Bit8u /* system_realtime */) {}
|
||||
virtual void onDeviceReset() {}
|
||||
virtual void onDeviceReconfig() {}
|
||||
virtual void onNewReverbMode(Bit8u /* mode */) {}
|
||||
virtual void onNewReverbTime(Bit8u /* time */) {}
|
||||
virtual void onNewReverbLevel(Bit8u /* level */) {}
|
||||
virtual void onPolyStateChanged(Bit8u /* part_num */) {}
|
||||
virtual void onProgramChanged(Bit8u /* part_num */, const char * /* sound_group_name */, const char * /* patch_name */) {}
|
||||
};
|
||||
|
||||
} // end of namespace MT32Emu
|
||||
|
@ -95,10 +100,9 @@ class MidiDriver_MT32 : public MidiDriver_Emulated {
|
|||
private:
|
||||
MidiChannel_MT32 _midiChannels[16];
|
||||
uint16 _channelMask;
|
||||
MT32Emu::Synth *_synth;
|
||||
MT32Emu::ReportHandlerScummVM *_reportHandler;
|
||||
const MT32Emu::ROMImage *_controlROM, *_pcmROM;
|
||||
Common::File *_controlFile, *_pcmFile;
|
||||
MT32Emu::Service *_service;
|
||||
MT32Emu::ScummVMReportHandler *_reportHandler;
|
||||
byte *_controlData, *_pcmData;
|
||||
void deleteMuntStructures();
|
||||
|
||||
int _outputRate;
|
||||
|
@ -107,15 +111,13 @@ protected:
|
|||
void generateSamples(int16 *buf, int len);
|
||||
|
||||
public:
|
||||
bool _initializing;
|
||||
|
||||
MidiDriver_MT32(Audio::Mixer *mixer);
|
||||
virtual ~MidiDriver_MT32();
|
||||
|
||||
int open();
|
||||
void close();
|
||||
void send(uint32 b);
|
||||
void setPitchBendRange (byte channel, uint range);
|
||||
void setPitchBendRange(byte channel, uint range);
|
||||
void sysEx(const byte *msg, uint16 length);
|
||||
|
||||
uint32 property(int prop, uint32 param);
|
||||
|
@ -139,16 +141,11 @@ MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixe
|
|||
for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) {
|
||||
_midiChannels[i].init(this, i);
|
||||
}
|
||||
_reportHandler = NULL;
|
||||
_synth = NULL;
|
||||
_service = nullptr;
|
||||
_reportHandler = nullptr;
|
||||
_outputRate = 0;
|
||||
_initializing = false;
|
||||
|
||||
// Initialized in open()
|
||||
_controlROM = NULL;
|
||||
_pcmROM = NULL;
|
||||
_controlFile = NULL;
|
||||
_pcmFile = NULL;
|
||||
_controlData = nullptr;
|
||||
_pcmData = nullptr;
|
||||
}
|
||||
|
||||
MidiDriver_MT32::~MidiDriver_MT32() {
|
||||
|
@ -156,31 +153,20 @@ MidiDriver_MT32::~MidiDriver_MT32() {
|
|||
}
|
||||
|
||||
void MidiDriver_MT32::deleteMuntStructures() {
|
||||
delete _synth;
|
||||
_synth = NULL;
|
||||
delete _service;
|
||||
_service = nullptr;
|
||||
delete _reportHandler;
|
||||
_reportHandler = NULL;
|
||||
|
||||
if (_controlROM)
|
||||
MT32Emu::ROMImage::freeROMImage(_controlROM);
|
||||
_controlROM = NULL;
|
||||
if (_pcmROM)
|
||||
MT32Emu::ROMImage::freeROMImage(_pcmROM);
|
||||
_pcmROM = NULL;
|
||||
|
||||
delete _controlFile;
|
||||
_controlFile = NULL;
|
||||
delete _pcmFile;
|
||||
_pcmFile = NULL;
|
||||
_reportHandler = nullptr;
|
||||
delete _controlData;
|
||||
_controlData = nullptr;
|
||||
delete _pcmData;
|
||||
_pcmData = nullptr;
|
||||
}
|
||||
|
||||
int MidiDriver_MT32::open() {
|
||||
if (_isOpen)
|
||||
return MERR_ALREADY_OPEN;
|
||||
|
||||
_reportHandler = new MT32Emu::ReportHandlerScummVM();
|
||||
_synth = new MT32Emu::Synth(_reportHandler);
|
||||
|
||||
Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
|
||||
|
||||
if (screenFormat.bytesPerPixel == 1) {
|
||||
|
@ -193,75 +179,90 @@ int MidiDriver_MT32::open() {
|
|||
g_system->getPaletteManager()->setPalette(dummy_palette, 0, 3);
|
||||
}
|
||||
|
||||
_initializing = true;
|
||||
debug(4, _s("Initializing MT-32 Emulator"));
|
||||
_controlFile = new Common::File();
|
||||
if (!_controlFile->open("CM32L_CONTROL.ROM") && !_controlFile->open("MT32_CONTROL.ROM"))
|
||||
error("Error opening MT32_CONTROL.ROM / CM32L_CONTROL.ROM");
|
||||
_pcmFile = new Common::File();
|
||||
if (!_pcmFile->open("CM32L_PCM.ROM") && !_pcmFile->open("MT32_PCM.ROM"))
|
||||
error("Error opening MT32_PCM.ROM / CM32L_PCM.ROM");
|
||||
_controlROM = MT32Emu::ROMImage::makeROMImage(_controlFile);
|
||||
_pcmROM = MT32Emu::ROMImage::makeROMImage(_pcmFile);
|
||||
if (!_synth->open(*_controlROM, *_pcmROM))
|
||||
|
||||
Common::File controlFile;
|
||||
if (!controlFile.open("CM32L_CONTROL.ROM") && !controlFile.open("MT32_CONTROL.ROM"))
|
||||
error("Error opening MT32_CONTROL.ROM / CM32L_CONTROL.ROM. Check that your Extra Path in Paths settings is set to the correct directory");
|
||||
|
||||
Common::File pcmFile;
|
||||
if (!pcmFile.open("CM32L_PCM.ROM") && !pcmFile.open("MT32_PCM.ROM"))
|
||||
error("Error opening MT32_PCM.ROM / CM32L_PCM.ROM. Check that your Extra Path in Paths settings is set to the correct directory");
|
||||
|
||||
_controlData = new byte[controlFile.size()];
|
||||
controlFile.read(_controlData, controlFile.size());
|
||||
_pcmData = new byte[pcmFile.size()];
|
||||
pcmFile.read(_pcmData, pcmFile.size());
|
||||
|
||||
_reportHandler = new MT32Emu::ScummVMReportHandler();
|
||||
_service = new MT32Emu::Service();
|
||||
_service->createContext(*_reportHandler);
|
||||
|
||||
if (_service->addROMData(_controlData, controlFile.size()) != MT32EMU_RC_ADDED_CONTROL_ROM) {
|
||||
error("Adding control ROM failed. Check that your control ROM is valid");
|
||||
}
|
||||
|
||||
controlFile.close();
|
||||
|
||||
if (_service->addROMData(_pcmData, pcmFile.size()) != MT32EMU_RC_ADDED_PCM_ROM) {
|
||||
error("Adding PCM ROM failed. Check that your PCM ROM is valid");
|
||||
}
|
||||
|
||||
pcmFile.close();
|
||||
|
||||
if (_service->openSynth() != MT32EMU_RC_OK)
|
||||
return MERR_DEVICE_NOT_AVAILABLE;
|
||||
|
||||
double gain = (double)ConfMan.getInt("midi_gain") / 100.0;
|
||||
_synth->setOutputGain(1.0f * gain);
|
||||
_synth->setReverbOutputGain(0.68f * gain);
|
||||
_service->setOutputGain(1.0f * gain);
|
||||
_service->setReverbOutputGain(1.0f * gain);
|
||||
// We let the synthesizer play MIDI messages immediately. Our MIDI
|
||||
// handling is synchronous to sample generation. This makes delaying MIDI
|
||||
// events result in odd sound output in some cases. For example, the
|
||||
// shattering window in the Indiana Jones and the Fate of Atlantis intro
|
||||
// will sound like a bell if we use any delay here.
|
||||
// Bug #6242 "AUDIO: Built-In MT-32 MUNT Produces Wrong Sounds".
|
||||
_synth->setMIDIDelayMode(MT32Emu::MIDIDelayMode_IMMEDIATE);
|
||||
_service->setMIDIDelayMode(MT32Emu::MIDIDelayMode_IMMEDIATE);
|
||||
|
||||
// We need to report the sample rate MUNT renders at as sample rate of our
|
||||
// AudioStream.
|
||||
_outputRate = _synth->getStereoOutputSampleRate();
|
||||
_outputRate = _service->getActualStereoOutputSamplerate();
|
||||
|
||||
MidiDriver_Emulated::open();
|
||||
|
||||
_initializing = false;
|
||||
|
||||
if (screenFormat.bytesPerPixel > 1)
|
||||
g_system->fillScreen(screenFormat.RGBToColor(0, 0, 0));
|
||||
else
|
||||
g_system->fillScreen(0);
|
||||
|
||||
g_system->updateScreen();
|
||||
|
||||
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MidiDriver_MT32::send(uint32 b) {
|
||||
_synth->playMsg(b);
|
||||
_service->playMsg(b);
|
||||
}
|
||||
|
||||
// Indiana Jones and the Fate of Atlantis (including the demo) uses
|
||||
// setPitchBendRange, if you need a game for testing purposes
|
||||
void MidiDriver_MT32::setPitchBendRange(byte channel, uint range) {
|
||||
if (range > 24) {
|
||||
warning("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);
|
||||
byte benderRangeSysex[4] = { 0, 0, 4, (uint8)range };
|
||||
_service->writeSysex(channel, benderRangeSysex, 4);
|
||||
}
|
||||
|
||||
void MidiDriver_MT32::sysEx(const byte *msg, uint16 length) {
|
||||
if (msg[0] == 0xf0) {
|
||||
_synth->playSysex(msg, length);
|
||||
_service->playSysex(msg, length);
|
||||
} else {
|
||||
_synth->playSysexWithoutFraming(msg, length);
|
||||
enum {
|
||||
SYSEX_CMD_DT1 = 0x12,
|
||||
SYSEX_CMD_DAT = 0x42
|
||||
};
|
||||
|
||||
if (msg[3] == SYSEX_CMD_DT1 || msg[3] == SYSEX_CMD_DAT) {
|
||||
_service->writeSysex(msg[1], msg + 4, length - 5);
|
||||
} else {
|
||||
warning("Unused sysEx command %d", msg[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,12 +276,12 @@ void MidiDriver_MT32::close() {
|
|||
// Detach the mixer callback handler
|
||||
_mixer->stopHandle(_mixerSoundHandle);
|
||||
|
||||
_synth->close();
|
||||
_service->closeSynth();
|
||||
deleteMuntStructures();
|
||||
}
|
||||
|
||||
void MidiDriver_MT32::generateSamples(int16 *data, int len) {
|
||||
_synth->render(data, len);
|
||||
_service->renderBit16s(data, len);
|
||||
}
|
||||
|
||||
uint32 MidiDriver_MT32::property(int prop, uint32 param) {
|
||||
|
|
48
audio/softsynth/mt32/Analog.cpp
Normal file → Executable file
48
audio/softsynth/mt32/Analog.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,8 +15,12 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cstring>
|
||||
#include <cstring>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "Analog.h"
|
||||
#include "Synth.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -106,7 +110,6 @@ static const Bit32u ACCURATE_LPF_DELTAS_OVERSAMPLED[][ACCURATE_LPF_NUMBER_OF_PHA
|
|||
class AbstractLowPassFilter {
|
||||
public:
|
||||
static AbstractLowPassFilter &createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF);
|
||||
static void muteRingBuffer(SampleEx *ringBuffer, unsigned int length);
|
||||
|
||||
virtual ~AbstractLowPassFilter() {}
|
||||
virtual SampleEx process(SampleEx sample) = 0;
|
||||
|
@ -152,9 +155,9 @@ public:
|
|||
void addPositionIncrement(unsigned int positionIncrement);
|
||||
};
|
||||
|
||||
Analog::Analog(const AnalogOutputMode mode, const ControlROMFeatureSet *controlROMFeatures) :
|
||||
leftChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, controlROMFeatures->isOldMT32AnalogLPF())),
|
||||
rightChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, controlROMFeatures->isOldMT32AnalogLPF())),
|
||||
Analog::Analog(const AnalogOutputMode mode, const bool oldMT32AnalogLPF) :
|
||||
leftChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, oldMT32AnalogLPF)),
|
||||
rightChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, oldMT32AnalogLPF)),
|
||||
synthGain(0),
|
||||
reverbGain(0)
|
||||
{}
|
||||
|
@ -164,7 +167,7 @@ Analog::~Analog() {
|
|||
delete &rightChannelLPF;
|
||||
}
|
||||
|
||||
void Analog::process(Sample **outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength) {
|
||||
void Analog::process(Sample *outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength) {
|
||||
if (outStream == NULL) {
|
||||
leftChannelLPF.addPositionIncrement(outLength);
|
||||
rightChannelLPF.addPositionIncrement(outLength);
|
||||
|
@ -179,8 +182,8 @@ void Analog::process(Sample **outStream, const Sample *nonReverbLeft, const Samp
|
|||
outSampleL = leftChannelLPF.process(0);
|
||||
outSampleR = rightChannelLPF.process(0);
|
||||
} else {
|
||||
SampleEx inSampleL = ((SampleEx)*(nonReverbLeft++) + (SampleEx)*(reverbDryLeft++)) * synthGain + (SampleEx)*(reverbWetLeft++) * reverbGain;
|
||||
SampleEx inSampleR = ((SampleEx)*(nonReverbRight++) + (SampleEx)*(reverbDryRight++)) * synthGain + (SampleEx)*(reverbWetRight++) * reverbGain;
|
||||
SampleEx inSampleL = (SampleEx(*(nonReverbLeft++)) + SampleEx(*(reverbDryLeft++))) * synthGain + SampleEx(*(reverbWetLeft++)) * reverbGain;
|
||||
SampleEx inSampleR = (SampleEx(*(nonReverbRight++)) + SampleEx(*(reverbDryRight++))) * synthGain + SampleEx(*(reverbWetRight++)) * reverbGain;
|
||||
|
||||
#if !MT32EMU_USE_FLOAT_SAMPLES
|
||||
inSampleL >>= OUTPUT_GAIN_FRACTION_BITS;
|
||||
|
@ -191,8 +194,8 @@ void Analog::process(Sample **outStream, const Sample *nonReverbLeft, const Samp
|
|||
outSampleR = rightChannelLPF.process(inSampleR);
|
||||
}
|
||||
|
||||
*((*outStream)++) = Synth::clipSampleEx(outSampleL);
|
||||
*((*outStream)++) = Synth::clipSampleEx(outSampleR);
|
||||
*(outStream++) = Synth::clipSampleEx(outSampleL);
|
||||
*(outStream++) = Synth::clipSampleEx(outSampleR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,23 +239,6 @@ AbstractLowPassFilter &AbstractLowPassFilter::createLowPassFilter(AnalogOutputMo
|
|||
}
|
||||
}
|
||||
|
||||
void AbstractLowPassFilter::muteRingBuffer(SampleEx *ringBuffer, unsigned int length) {
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
|
||||
SampleEx *p = ringBuffer;
|
||||
while (length--) {
|
||||
*(p++) = 0.0f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
memset(ringBuffer, 0, length * sizeof(SampleEx));
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool AbstractLowPassFilter::hasNextSample() const {
|
||||
return false;
|
||||
}
|
||||
|
@ -273,7 +259,7 @@ CoarseLowPassFilter::CoarseLowPassFilter(bool oldMT32AnalogLPF) :
|
|||
LPF_TAPS(oldMT32AnalogLPF ? COARSE_LPF_TAPS_MT32 : COARSE_LPF_TAPS_CM32L),
|
||||
ringBufferPosition(0)
|
||||
{
|
||||
muteRingBuffer(ringBuffer, COARSE_LPF_DELAY_LINE_LENGTH);
|
||||
Synth::muteSampleBuffer(ringBuffer, COARSE_LPF_DELAY_LINE_LENGTH);
|
||||
}
|
||||
|
||||
SampleEx CoarseLowPassFilter::process(const SampleEx inSample) {
|
||||
|
@ -303,7 +289,7 @@ AccurateLowPassFilter::AccurateLowPassFilter(const bool oldMT32AnalogLPF, const
|
|||
ringBufferPosition(0),
|
||||
phase(0)
|
||||
{
|
||||
muteRingBuffer(ringBuffer, ACCURATE_LPF_DELAY_LINE_LENGTH);
|
||||
Synth::muteSampleBuffer(ringBuffer, ACCURATE_LPF_DELAY_LINE_LENGTH);
|
||||
}
|
||||
|
||||
SampleEx AccurateLowPassFilter::process(const SampleEx inSample) {
|
||||
|
@ -345,4 +331,4 @@ void AccurateLowPassFilter::addPositionIncrement(const unsigned int positionIncr
|
|||
phase = (phase + positionIncrement * phaseIncrement) % ACCURATE_LPF_NUMBER_OF_PHASES;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
15
audio/softsynth/mt32/Analog.h
Normal file → Executable file
15
audio/softsynth/mt32/Analog.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,7 +18,10 @@
|
|||
#ifndef MT32EMU_ANALOG_H
|
||||
#define MT32EMU_ANALOG_H
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
#include "Types.h"
|
||||
#include "Enumerations.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -35,9 +38,9 @@ class AbstractLowPassFilter;
|
|||
*/
|
||||
class Analog {
|
||||
public:
|
||||
Analog(AnalogOutputMode mode, const ControlROMFeatureSet *controlROMFeatures);
|
||||
Analog(const AnalogOutputMode mode, const bool oldMT32AnalogLPF);
|
||||
~Analog();
|
||||
void process(Sample **outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, const Bit32u outLength);
|
||||
void process(Sample *outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength);
|
||||
unsigned int getOutputSampleRate() const;
|
||||
Bit32u getDACStreamsLength(Bit32u outputLength) const;
|
||||
void setSynthOutputGain(float synthGain);
|
||||
|
@ -52,6 +55,6 @@ private:
|
|||
Analog(Analog &);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_ANALOG_H
|
||||
|
|
107
audio/softsynth/mt32/BReverbModel.cpp
Normal file → Executable file
107
audio/softsynth/mt32/BReverbModel.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,9 +15,12 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cstring>
|
||||
#include "mt32emu.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "BReverbModel.h"
|
||||
#include "Synth.h"
|
||||
|
||||
// Analysing of state of reverb RAM address lines gives exact sizes of the buffers of filters used. This also indicates that
|
||||
// the reverb model implemented in the real devices consists of three series allpass filters preceded by a non-feedback comb (or a delay with a LPF)
|
||||
|
@ -43,14 +46,14 @@ const BReverbSettings &BReverbModel::getCM32L_LAPCSettings(const ReverbMode mode
|
|||
static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632};
|
||||
static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960};
|
||||
static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145};
|
||||
static const Bit32u MODE_0_COMB_FACTOR[] = {0xA0, 0x60, 0x60, 0x60};
|
||||
static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
static const Bit8u MODE_0_COMB_FACTOR[] = {0xA0, 0x60, 0x60, 0x60};
|
||||
static const Bit8u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98};
|
||||
static const Bit32u MODE_0_DRY_AMP[] = {0xA0, 0xA0, 0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xD0};
|
||||
static const Bit32u MODE_0_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0};
|
||||
static const Bit32u MODE_0_LPF_AMP = 0x60;
|
||||
static const Bit8u MODE_0_DRY_AMP[] = {0xA0, 0xA0, 0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xD0};
|
||||
static const Bit8u MODE_0_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0};
|
||||
static const Bit8u MODE_0_LPF_AMP = 0x60;
|
||||
|
||||
static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3;
|
||||
static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176};
|
||||
|
@ -58,14 +61,14 @@ const BReverbSettings &BReverbModel::getCM32L_LAPCSettings(const ReverbMode mode
|
|||
static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519};
|
||||
static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518};
|
||||
static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274};
|
||||
static const Bit32u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60};
|
||||
static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
static const Bit8u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60};
|
||||
static const Bit8u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98};
|
||||
static const Bit32u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0};
|
||||
static const Bit32u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0};
|
||||
static const Bit32u MODE_1_LPF_AMP = 0x60;
|
||||
static const Bit8u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0};
|
||||
static const Bit8u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0};
|
||||
static const Bit8u MODE_1_LPF_AMP = 0x60;
|
||||
|
||||
static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3;
|
||||
static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157};
|
||||
|
@ -73,25 +76,25 @@ const BReverbSettings &BReverbModel::getCM32L_LAPCSettings(const ReverbMode mode
|
|||
static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539};
|
||||
static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769};
|
||||
static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1};
|
||||
static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20};
|
||||
static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
static const Bit8u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20};
|
||||
static const Bit8u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0,
|
||||
0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0,
|
||||
0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0};
|
||||
static const Bit32u MODE_2_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xC0, 0xE0};
|
||||
static const Bit32u MODE_2_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0};
|
||||
static const Bit32u MODE_2_LPF_AMP = 0x80;
|
||||
static const Bit8u MODE_2_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xC0, 0xE0};
|
||||
static const Bit8u MODE_2_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0};
|
||||
static const Bit8u MODE_2_LPF_AMP = 0x80;
|
||||
|
||||
static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0;
|
||||
static const Bit32u MODE_3_NUMBER_OF_COMBS = 1;
|
||||
static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY};
|
||||
static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000};
|
||||
static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000};
|
||||
static const Bit32u MODE_3_COMB_FACTOR[] = {0x68};
|
||||
static const Bit32u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60};
|
||||
static const Bit32u MODE_3_DRY_AMP[] = {0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
static const Bit8u MODE_3_COMB_FACTOR[] = {0x68};
|
||||
static const Bit8u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60};
|
||||
static const Bit8u MODE_3_DRY_AMP[] = {0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50};
|
||||
static const Bit32u MODE_3_WET_AMP[] = {0x18, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8};
|
||||
static const Bit8u MODE_3_WET_AMP[] = {0x18, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8};
|
||||
|
||||
static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP};
|
||||
static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP};
|
||||
|
@ -112,14 +115,14 @@ const BReverbSettings &BReverbModel::getMT32Settings(const ReverbMode mode) {
|
|||
static const Bit32u MODE_0_COMBS[] = {575 + PROCESS_DELAY, 2040, 2752, 3629};
|
||||
static const Bit32u MODE_0_OUTL[] = {2040, 687, 1814};
|
||||
static const Bit32u MODE_0_OUTR[] = {1019, 2072, 1};
|
||||
static const Bit32u MODE_0_COMB_FACTOR[] = {0xB0, 0x60, 0x60, 0x60};
|
||||
static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
static const Bit8u MODE_0_COMB_FACTOR[] = {0xB0, 0x60, 0x60, 0x60};
|
||||
static const Bit8u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98};
|
||||
static const Bit32u MODE_0_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
|
||||
static const Bit32u MODE_0_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0};
|
||||
static const Bit32u MODE_0_LPF_AMP = 0x80;
|
||||
static const Bit8u MODE_0_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
|
||||
static const Bit8u MODE_0_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0};
|
||||
static const Bit8u MODE_0_LPF_AMP = 0x80;
|
||||
|
||||
static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3;
|
||||
static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176};
|
||||
|
@ -127,14 +130,14 @@ const BReverbSettings &BReverbModel::getMT32Settings(const ReverbMode mode) {
|
|||
static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519};
|
||||
static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518};
|
||||
static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274};
|
||||
static const Bit32u MODE_1_COMB_FACTOR[] = {0x90, 0x60, 0x60, 0x60};
|
||||
static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
static const Bit8u MODE_1_COMB_FACTOR[] = {0x90, 0x60, 0x60, 0x60};
|
||||
static const Bit8u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98};
|
||||
static const Bit32u MODE_1_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
|
||||
static const Bit32u MODE_1_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0};
|
||||
static const Bit32u MODE_1_LPF_AMP = 0x80;
|
||||
static const Bit8u MODE_1_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
|
||||
static const Bit8u MODE_1_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0};
|
||||
static const Bit8u MODE_1_LPF_AMP = 0x80;
|
||||
|
||||
static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3;
|
||||
static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157};
|
||||
|
@ -142,25 +145,25 @@ const BReverbSettings &BReverbModel::getMT32Settings(const ReverbMode mode) {
|
|||
static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539};
|
||||
static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769};
|
||||
static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1};
|
||||
static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x60, 0x60, 0x60};
|
||||
static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
static const Bit8u MODE_2_COMB_FACTOR[] = {0, 0x60, 0x60, 0x60};
|
||||
static const Bit8u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98,
|
||||
0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98};
|
||||
static const Bit32u MODE_2_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
|
||||
static const Bit32u MODE_2_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0};
|
||||
static const Bit32u MODE_2_LPF_AMP = 0x80;
|
||||
static const Bit8u MODE_2_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
|
||||
static const Bit8u MODE_2_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0};
|
||||
static const Bit8u MODE_2_LPF_AMP = 0x80;
|
||||
|
||||
static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0;
|
||||
static const Bit32u MODE_3_NUMBER_OF_COMBS = 1;
|
||||
static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY};
|
||||
static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000};
|
||||
static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000};
|
||||
static const Bit32u MODE_3_COMB_FACTOR[] = {0x68};
|
||||
static const Bit32u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60};
|
||||
static const Bit32u MODE_3_DRY_AMP[] = {0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
static const Bit8u MODE_3_COMB_FACTOR[] = {0x68};
|
||||
static const Bit8u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60};
|
||||
static const Bit8u MODE_3_DRY_AMP[] = {0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x10, 0x20, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10};
|
||||
static const Bit32u MODE_3_WET_AMP[] = {0x08, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8};
|
||||
static const Bit8u MODE_3_WET_AMP[] = {0x08, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8};
|
||||
|
||||
static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP};
|
||||
static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP};
|
||||
|
@ -189,7 +192,7 @@ static Sample weirdMul(Sample a, Bit8u addMask, Bit8u carryMask) {
|
|||
}
|
||||
return res;
|
||||
#else
|
||||
return Sample(((Bit32s)a * addMask) >> 8);
|
||||
return Sample((Bit32s(a) * addMask) >> 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -252,7 +255,7 @@ Sample AllpassFilter::process(const Sample in) {
|
|||
#endif
|
||||
}
|
||||
|
||||
CombFilter::CombFilter(const Bit32u useSize, const Bit32u useFilterFactor) : RingBuffer(useSize), filterFactor(useFilterFactor) {}
|
||||
CombFilter::CombFilter(const Bit32u useSize, const Bit8u useFilterFactor) : RingBuffer(useSize), filterFactor(useFilterFactor) {}
|
||||
|
||||
void CombFilter::process(const Sample in) {
|
||||
// This model corresponds to the comb filter implementation of the real CM-32L device
|
||||
|
@ -271,11 +274,11 @@ Sample CombFilter::getOutputAt(const Bit32u outIndex) const {
|
|||
return buffer[(size + index - outIndex) % size];
|
||||
}
|
||||
|
||||
void CombFilter::setFeedbackFactor(const Bit32u useFeedbackFactor) {
|
||||
void CombFilter::setFeedbackFactor(const Bit8u useFeedbackFactor) {
|
||||
feedbackFactor = useFeedbackFactor;
|
||||
}
|
||||
|
||||
DelayWithLowPassFilter::DelayWithLowPassFilter(const Bit32u useSize, const Bit32u useFilterFactor, const Bit32u useAmp)
|
||||
DelayWithLowPassFilter::DelayWithLowPassFilter(const Bit32u useSize, const Bit8u useFilterFactor, const Bit8u useAmp)
|
||||
: CombFilter(useSize, useFilterFactor), amp(useAmp) {}
|
||||
|
||||
void DelayWithLowPassFilter::process(const Sample in) {
|
||||
|
@ -292,7 +295,7 @@ void DelayWithLowPassFilter::process(const Sample in) {
|
|||
buffer[index] = weirdMul(lpfOut, amp, 0xFF);
|
||||
}
|
||||
|
||||
TapDelayCombFilter::TapDelayCombFilter(const Bit32u useSize, const Bit32u useFilterFactor) : CombFilter(useSize, useFilterFactor) {}
|
||||
TapDelayCombFilter::TapDelayCombFilter(const Bit32u useSize, const Bit8u useFilterFactor) : CombFilter(useSize, useFilterFactor) {}
|
||||
|
||||
void TapDelayCombFilter::process(const Sample in) {
|
||||
// the previously stored value
|
||||
|
@ -430,7 +433,7 @@ bool BReverbModel::isMT32Compatible(const ReverbMode mode) const {
|
|||
return ¤tSettings == &getMT32Settings(mode);
|
||||
}
|
||||
|
||||
void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, unsigned long numSamples) {
|
||||
void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, Bit32u numSamples) {
|
||||
if (combs == NULL) {
|
||||
Synth::muteSampleBuffer(outLeft, numSamples);
|
||||
Synth::muteSampleBuffer(outRight, numSamples);
|
||||
|
@ -501,9 +504,9 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *
|
|||
* Analysing of the algorithm suggests that the overflow is most probable when the combs output is added below.
|
||||
* So, despite this isn't actually accurate, we only add the check here for performance reasons.
|
||||
*/
|
||||
Sample outSample = Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx((SampleEx)outL1 + SampleEx(outL1 >> 1)) + (SampleEx)outL2) + SampleEx(outL2 >> 1)) + (SampleEx)outL3);
|
||||
Sample outSample = Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(SampleEx(outL1) + (SampleEx(outL1) >> 1)) + SampleEx(outL2)) + (SampleEx(outL2) >> 1)) + SampleEx(outL3));
|
||||
#else
|
||||
Sample outSample = Synth::clipSampleEx((SampleEx)outL1 + SampleEx(outL1 >> 1) + (SampleEx)outL2 + SampleEx(outL2 >> 1) + (SampleEx)outL3);
|
||||
Sample outSample = Synth::clipSampleEx(SampleEx(outL1) + (SampleEx(outL1) >> 1) + SampleEx(outL2) + (SampleEx(outL2) >> 1) + SampleEx(outL3));
|
||||
#endif
|
||||
*(outLeft++) = weirdMul(outSample, wetLevel, 0xFF);
|
||||
}
|
||||
|
@ -515,9 +518,9 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *
|
|||
Sample outSample = 1.5f * (outR1 + outR2) + outR3;
|
||||
#elif MT32EMU_BOSS_REVERB_PRECISE_MODE
|
||||
// See the note above for the left channel output.
|
||||
Sample outSample = Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx((SampleEx)outR1 + SampleEx(outR1 >> 1)) + (SampleEx)outR2) + SampleEx(outR2 >> 1)) + (SampleEx)outR3);
|
||||
Sample outSample = Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(SampleEx(outR1) + (SampleEx(outR1) >> 1)) + SampleEx(outR2)) + (SampleEx(outR2) >> 1)) + SampleEx(outR3));
|
||||
#else
|
||||
Sample outSample = Synth::clipSampleEx((SampleEx)outR1 + SampleEx(outR1 >> 1) + (SampleEx)outR2 + SampleEx(outR2 >> 1) + (SampleEx)outR3);
|
||||
Sample outSample = Synth::clipSampleEx(SampleEx(outR1) + (SampleEx(outR1) >> 1) + SampleEx(outR2) + (SampleEx(outR2) >> 1) + SampleEx(outR3));
|
||||
#endif
|
||||
*(outRight++) = weirdMul(outSample, wetLevel, 0xFF);
|
||||
}
|
||||
|
@ -525,4 +528,4 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
42
audio/softsynth/mt32/BReverbModel.h
Normal file → Executable file
42
audio/softsynth/mt32/BReverbModel.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,6 +18,10 @@
|
|||
#ifndef MT32EMU_B_REVERB_MODEL_H
|
||||
#define MT32EMU_B_REVERB_MODEL_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
struct BReverbSettings {
|
||||
|
@ -27,11 +31,11 @@ struct BReverbSettings {
|
|||
const Bit32u * const combSizes;
|
||||
const Bit32u * const outLPositions;
|
||||
const Bit32u * const outRPositions;
|
||||
const Bit32u * const filterFactors;
|
||||
const Bit32u * const feedbackFactors;
|
||||
const Bit32u * const dryAmps;
|
||||
const Bit32u * const wetLevels;
|
||||
const Bit32u lpfAmp;
|
||||
const Bit8u * const filterFactors;
|
||||
const Bit8u * const feedbackFactors;
|
||||
const Bit8u * const dryAmps;
|
||||
const Bit8u * const wetLevels;
|
||||
const Bit8u lpfAmp;
|
||||
};
|
||||
|
||||
class RingBuffer {
|
||||
|
@ -56,23 +60,23 @@ public:
|
|||
|
||||
class CombFilter : public RingBuffer {
|
||||
protected:
|
||||
const Bit32u filterFactor;
|
||||
Bit32u feedbackFactor;
|
||||
const Bit8u filterFactor;
|
||||
Bit8u feedbackFactor;
|
||||
|
||||
public:
|
||||
CombFilter(const Bit32u size, const Bit32u useFilterFactor);
|
||||
CombFilter(const Bit32u size, const Bit8u useFilterFactor);
|
||||
virtual void process(const Sample in);
|
||||
Sample getOutputAt(const Bit32u outIndex) const;
|
||||
void setFeedbackFactor(const Bit32u useFeedbackFactor);
|
||||
void setFeedbackFactor(const Bit8u useFeedbackFactor);
|
||||
};
|
||||
|
||||
class DelayWithLowPassFilter : public CombFilter {
|
||||
Bit32u amp;
|
||||
Bit8u amp;
|
||||
|
||||
public:
|
||||
DelayWithLowPassFilter(const Bit32u useSize, const Bit32u useFilterFactor, const Bit32u useAmp);
|
||||
DelayWithLowPassFilter(const Bit32u useSize, const Bit8u useFilterFactor, const Bit8u useAmp);
|
||||
void process(const Sample in);
|
||||
void setFeedbackFactor(const Bit32u) {}
|
||||
void setFeedbackFactor(const Bit8u) {}
|
||||
};
|
||||
|
||||
class TapDelayCombFilter : public CombFilter {
|
||||
|
@ -80,7 +84,7 @@ class TapDelayCombFilter : public CombFilter {
|
|||
Bit32u outR;
|
||||
|
||||
public:
|
||||
TapDelayCombFilter(const Bit32u useSize, const Bit32u useFilterFactor);
|
||||
TapDelayCombFilter(const Bit32u useSize, const Bit8u useFilterFactor);
|
||||
void process(const Sample in);
|
||||
Sample getLeftOutput() const;
|
||||
Sample getRightOutput() const;
|
||||
|
@ -93,8 +97,8 @@ class BReverbModel {
|
|||
|
||||
const BReverbSettings ¤tSettings;
|
||||
const bool tapDelayMode;
|
||||
Bit32u dryAmp;
|
||||
Bit32u wetLevel;
|
||||
Bit8u dryAmp;
|
||||
Bit8u wetLevel;
|
||||
|
||||
static const BReverbSettings &getCM32L_LAPCSettings(const ReverbMode mode);
|
||||
static const BReverbSettings &getMT32Settings(const ReverbMode mode);
|
||||
|
@ -108,11 +112,11 @@ public:
|
|||
void close();
|
||||
void mute();
|
||||
void setParameters(Bit8u time, Bit8u level);
|
||||
void process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, unsigned long numSamples);
|
||||
void process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, Bit32u numSamples);
|
||||
bool isActive() const;
|
||||
bool isMT32Compatible(const ReverbMode mode) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_B_REVERB_MODEL_H
|
||||
|
|
155
audio/softsynth/mt32/Enumerations.h
Executable file
155
audio/softsynth/mt32/Enumerations.h
Executable file
|
@ -0,0 +1,155 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Using two guards since this file may be included twice with different MT32EMU_C_ENUMERATIONS define. */
|
||||
|
||||
#if (!defined MT32EMU_CPP_ENUMERATIONS_H && !defined MT32EMU_C_ENUMERATIONS) || (!defined MT32EMU_C_ENUMERATIONS_H && defined MT32EMU_C_ENUMERATIONS)
|
||||
|
||||
#ifdef MT32EMU_C_ENUMERATIONS
|
||||
|
||||
#define MT32EMU_C_ENUMERATIONS_H
|
||||
|
||||
#define MT32EMU_DAC_INPUT_MODE_NAME mt32emu_dac_input_mode
|
||||
#define MT32EMU_DAC_INPUT_MODE(ident) MT32EMU_DAC_##ident
|
||||
|
||||
#define MT32EMU_MIDI_DELAY_MODE_NAME mt32emu_midi_delay_mode
|
||||
#define MT32EMU_MIDI_DELAY_MODE(ident) MT32EMU_MDM_##ident
|
||||
|
||||
#define MT32EMU_ANALOG_OUTPUT_MODE_NAME mt32emu_analog_output_mode
|
||||
#define MT32EMU_ANALOG_OUTPUT_MODE(ident) MT32EMU_AOM_##ident
|
||||
|
||||
#define MT32EMU_PARTIAL_STATE_NAME mt32emu_partial_state
|
||||
#define MT32EMU_PARTIAL_STATE(ident) MT32EMU_PS_##ident
|
||||
|
||||
#else /* #ifdef MT32EMU_C_ENUMERATIONS */
|
||||
|
||||
#define MT32EMU_CPP_ENUMERATIONS_H
|
||||
|
||||
#define MT32EMU_DAC_INPUT_MODE_NAME DACInputMode
|
||||
#define MT32EMU_DAC_INPUT_MODE(ident) DACInputMode_##ident
|
||||
|
||||
#define MT32EMU_MIDI_DELAY_MODE_NAME MIDIDelayMode
|
||||
#define MT32EMU_MIDI_DELAY_MODE(ident) MIDIDelayMode_##ident
|
||||
|
||||
#define MT32EMU_ANALOG_OUTPUT_MODE_NAME AnalogOutputMode
|
||||
#define MT32EMU_ANALOG_OUTPUT_MODE(ident) AnalogOutputMode_##ident
|
||||
|
||||
#define MT32EMU_PARTIAL_STATE_NAME PartialState
|
||||
#define MT32EMU_PARTIAL_STATE(ident) PartialState_##ident
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
#endif /* #ifdef MT32EMU_C_ENUMERATIONS */
|
||||
|
||||
/**
|
||||
* Methods for emulating the connection between the LA32 and the DAC, which involves
|
||||
* some hacks in the real devices for doubling the volume.
|
||||
* See also http://en.wikipedia.org/wiki/Roland_MT-32#Digital_overflow
|
||||
*/
|
||||
enum MT32EMU_DAC_INPUT_MODE_NAME {
|
||||
/**
|
||||
* Produces samples at double the volume, without tricks.
|
||||
* Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)
|
||||
* Higher quality than the real devices
|
||||
*/
|
||||
MT32EMU_DAC_INPUT_MODE(NICE),
|
||||
|
||||
/**
|
||||
* Produces samples that exactly match the bits output from the emulated LA32.
|
||||
* Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)
|
||||
* Much less likely to overdrive than any other mode.
|
||||
* Half the volume of any of the other modes.
|
||||
* Output gain is ignored for both LA32 and reverb output.
|
||||
* Perfect for developers while debugging :)
|
||||
*/
|
||||
MT32EMU_DAC_INPUT_MODE(PURE),
|
||||
|
||||
/**
|
||||
* Re-orders the LA32 output bits as in early generation MT-32s (according to Wikipedia).
|
||||
* Bit order at DAC (where each number represents the original LA32 output bit number, and XX means the bit is always low):
|
||||
* 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX
|
||||
*/
|
||||
MT32EMU_DAC_INPUT_MODE(GENERATION1),
|
||||
|
||||
/**
|
||||
* Re-orders the LA32 output bits as in later generations (personally confirmed on my CM-32L - KG).
|
||||
* Bit order at DAC (where each number represents the original LA32 output bit number):
|
||||
* 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14
|
||||
*/
|
||||
MT32EMU_DAC_INPUT_MODE(GENERATION2)
|
||||
};
|
||||
|
||||
/** Methods for emulating the effective delay of incoming MIDI messages introduced by a MIDI interface. */
|
||||
enum MT32EMU_MIDI_DELAY_MODE_NAME {
|
||||
/** Process incoming MIDI events immediately. */
|
||||
MT32EMU_MIDI_DELAY_MODE(IMMEDIATE),
|
||||
|
||||
/**
|
||||
* Delay incoming short MIDI messages as if they where transferred via a MIDI cable to a real hardware unit and immediate sysex processing.
|
||||
* This ensures more accurate timing of simultaneous NoteOn messages.
|
||||
*/
|
||||
MT32EMU_MIDI_DELAY_MODE(DELAY_SHORT_MESSAGES_ONLY),
|
||||
|
||||
/** Delay all incoming MIDI events as if they where transferred via a MIDI cable to a real hardware unit.*/
|
||||
MT32EMU_MIDI_DELAY_MODE(DELAY_ALL)
|
||||
};
|
||||
|
||||
/** Methods for emulating the effects of analogue circuits of real hardware units on the output signal. */
|
||||
enum MT32EMU_ANALOG_OUTPUT_MODE_NAME {
|
||||
/** Only digital path is emulated. The output samples correspond to the digital signal at the DAC entrance. */
|
||||
MT32EMU_ANALOG_OUTPUT_MODE(DIGITAL_ONLY),
|
||||
/** Coarse emulation of LPF circuit. High frequencies are boosted, sample rate remains unchanged. */
|
||||
MT32EMU_ANALOG_OUTPUT_MODE(COARSE),
|
||||
/**
|
||||
* Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz to allow emulation of audible mirror spectra above 16 kHz,
|
||||
* which is passed through the LPF circuit without significant attenuation.
|
||||
*/
|
||||
MT32EMU_ANALOG_OUTPUT_MODE(ACCURATE),
|
||||
/**
|
||||
* Same as AnalogOutputMode_ACCURATE mode but the output signal is 2x oversampled, i.e. the output sample rate is 96 kHz.
|
||||
* This makes subsequent resampling easier. Besides, due to nonlinear passband of the LPF emulated, it takes fewer number of MACs
|
||||
* compared to a regular LPF FIR implementations.
|
||||
*/
|
||||
MT32EMU_ANALOG_OUTPUT_MODE(OVERSAMPLED)
|
||||
};
|
||||
|
||||
enum MT32EMU_PARTIAL_STATE_NAME {
|
||||
MT32EMU_PARTIAL_STATE(INACTIVE),
|
||||
MT32EMU_PARTIAL_STATE(ATTACK),
|
||||
MT32EMU_PARTIAL_STATE(SUSTAIN),
|
||||
MT32EMU_PARTIAL_STATE(RELEASE)
|
||||
};
|
||||
|
||||
#ifndef MT32EMU_C_ENUMERATIONS
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
|
||||
#undef MT32EMU_DAC_INPUT_MODE_NAME
|
||||
#undef MT32EMU_DAC_INPUT_MODE
|
||||
|
||||
#undef MT32EMU_MIDI_DELAY_MODE_NAME
|
||||
#undef MT32EMU_MIDI_DELAY_MODE
|
||||
|
||||
#undef MT32EMU_ANALOG_OUTPUT_MODE_NAME
|
||||
#undef MT32EMU_ANALOG_OUTPUT_MODE
|
||||
|
||||
#undef MT32EMU_PARTIAL_STATE_NAME
|
||||
#undef MT32EMU_PARTIAL_STATE
|
||||
|
||||
#endif /* #if (!defined MT32EMU_CPP_ENUMERATIONS_H && !defined MT32EMU_C_ENUMERATIONS) || (!defined MT32EMU_C_ENUMERATIONS_H && defined MT32EMU_C_ENUMERATIONS) */
|
73
audio/softsynth/mt32/File.cpp
Executable file
73
audio/softsynth/mt32/File.cpp
Executable file
|
@ -0,0 +1,73 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "sha1/sha1.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
AbstractFile::AbstractFile() : sha1DigestCalculated(false), reserved(NULL) {
|
||||
sha1Digest[0] = 0;
|
||||
}
|
||||
|
||||
AbstractFile::AbstractFile(const SHA1Digest &useSHA1Digest) : sha1DigestCalculated(true), reserved(NULL) {
|
||||
memcpy(sha1Digest, useSHA1Digest, sizeof(SHA1Digest) - 1);
|
||||
sha1Digest[sizeof(SHA1Digest) - 1] = 0; // Ensure terminator char.
|
||||
}
|
||||
|
||||
const File::SHA1Digest &AbstractFile::getSHA1() {
|
||||
if (sha1DigestCalculated) {
|
||||
return sha1Digest;
|
||||
}
|
||||
sha1DigestCalculated = true;
|
||||
|
||||
size_t size = getSize();
|
||||
if (size == 0) {
|
||||
return sha1Digest;
|
||||
}
|
||||
|
||||
const Bit8u *data = getData();
|
||||
if (data == NULL) {
|
||||
return sha1Digest;
|
||||
}
|
||||
|
||||
unsigned char fileDigest[20];
|
||||
|
||||
sha1::calc(data, int(size), fileDigest);
|
||||
sha1::toHexString(fileDigest, sha1Digest);
|
||||
return sha1Digest;
|
||||
}
|
||||
|
||||
ArrayFile::ArrayFile(const Bit8u *useData, size_t useSize) : data(useData), size(useSize)
|
||||
{}
|
||||
|
||||
ArrayFile::ArrayFile(const Bit8u *useData, size_t useSize, const SHA1Digest &useSHA1Digest) : AbstractFile(useSHA1Digest), data(useData), size(useSize)
|
||||
{}
|
||||
|
||||
size_t ArrayFile::getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
const Bit8u *ArrayFile::getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace MT32Emu
|
73
audio/softsynth/mt32/File.h
Executable file
73
audio/softsynth/mt32/File.h
Executable file
|
@ -0,0 +1,73 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_FILE_H
|
||||
#define MT32EMU_FILE_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class MT32EMU_EXPORT File {
|
||||
public:
|
||||
// Includes terminator char.
|
||||
typedef char SHA1Digest[41];
|
||||
|
||||
virtual ~File() {}
|
||||
virtual size_t getSize() = 0;
|
||||
virtual const Bit8u *getData() = 0;
|
||||
virtual const SHA1Digest &getSHA1() = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
};
|
||||
|
||||
class MT32EMU_EXPORT AbstractFile : public File {
|
||||
public:
|
||||
const SHA1Digest &getSHA1();
|
||||
|
||||
protected:
|
||||
AbstractFile();
|
||||
AbstractFile(const SHA1Digest &sha1Digest);
|
||||
|
||||
private:
|
||||
bool sha1DigestCalculated;
|
||||
SHA1Digest sha1Digest;
|
||||
|
||||
// Binary compatibility helper.
|
||||
void *reserved;
|
||||
};
|
||||
|
||||
class MT32EMU_EXPORT ArrayFile : public AbstractFile {
|
||||
public:
|
||||
ArrayFile(const Bit8u *data, size_t size);
|
||||
ArrayFile(const Bit8u *data, size_t size, const SHA1Digest &sha1Digest);
|
||||
|
||||
size_t getSize();
|
||||
const Bit8u *getData();
|
||||
void close() {}
|
||||
|
||||
private:
|
||||
const Bit8u *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // #ifndef MT32EMU_FILE_H
|
83
audio/softsynth/mt32/FileStream.cpp
Executable file
83
audio/softsynth/mt32/FileStream.cpp
Executable file
|
@ -0,0 +1,83 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "FileStream.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
using std::ios_base;
|
||||
|
||||
FileStream::FileStream() : ifsp(*new std::ifstream), data(NULL), size(0)
|
||||
{}
|
||||
|
||||
FileStream::~FileStream() {
|
||||
// destructor closes ifsp
|
||||
delete &ifsp;
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
size_t FileStream::getSize() {
|
||||
if (size != 0) {
|
||||
return size;
|
||||
}
|
||||
if (!ifsp.is_open()) {
|
||||
return 0;
|
||||
}
|
||||
ifsp.seekg(0, ios_base::end);
|
||||
size = size_t(ifsp.tellg());
|
||||
return size;
|
||||
}
|
||||
|
||||
const Bit8u *FileStream::getData() {
|
||||
if (data != NULL) {
|
||||
return data;
|
||||
}
|
||||
if (!ifsp.is_open()) {
|
||||
return NULL;
|
||||
}
|
||||
if (getSize() == 0) {
|
||||
return NULL;
|
||||
}
|
||||
Bit8u *fileData = new Bit8u[size];
|
||||
if (fileData == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ifsp.seekg(0);
|
||||
ifsp.read(reinterpret_cast<char *>(fileData), std::streamsize(size));
|
||||
if (size_t(ifsp.tellg()) != size) {
|
||||
delete[] fileData;
|
||||
return NULL;
|
||||
}
|
||||
data = fileData;
|
||||
close();
|
||||
return data;
|
||||
}
|
||||
|
||||
bool FileStream::open(const char *filename) {
|
||||
ifsp.clear();
|
||||
ifsp.open(filename, ios_base::in | ios_base::binary);
|
||||
return !ifsp.fail();
|
||||
}
|
||||
|
||||
void FileStream::close() {
|
||||
ifsp.close();
|
||||
ifsp.clear();
|
||||
}
|
||||
|
||||
} // namespace MT32Emu
|
46
audio/softsynth/mt32/FileStream.h
Executable file
46
audio/softsynth/mt32/FileStream.h
Executable file
|
@ -0,0 +1,46 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_FILE_STREAM_H
|
||||
#define MT32EMU_FILE_STREAM_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
#include "File.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class FileStream : public AbstractFile {
|
||||
public:
|
||||
MT32EMU_EXPORT FileStream();
|
||||
MT32EMU_EXPORT ~FileStream();
|
||||
MT32EMU_EXPORT size_t getSize();
|
||||
MT32EMU_EXPORT const Bit8u *getData();
|
||||
MT32EMU_EXPORT bool open(const char *filename);
|
||||
MT32EMU_EXPORT void close();
|
||||
|
||||
private:
|
||||
std::ifstream &ifsp;
|
||||
const Bit8u *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // #ifndef MT32EMU_FILE_STREAM_H
|
41
audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
Normal file → Executable file
41
audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,10 +15,11 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cmath>
|
||||
#include "mt32emu.h"
|
||||
#ifndef MT32EMU_LA32_WAVE_GENERATOR_CPP
|
||||
#error This file should be included from LA32WaveGenerator.cpp only.
|
||||
#endif
|
||||
|
||||
#include "mmath.h"
|
||||
#include "internals.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -38,10 +39,10 @@ float LA32WaveGenerator::getPCMSample(unsigned int position) {
|
|||
return ((pcmSample & 32768) == 0) ? sampleValue : -sampleValue;
|
||||
}
|
||||
|
||||
void LA32WaveGenerator::initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) {
|
||||
this->sawtoothWaveform = sawtoothWaveform;
|
||||
this->pulseWidth = pulseWidth;
|
||||
this->resonance = resonance;
|
||||
void LA32WaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance) {
|
||||
sawtoothWaveform = useSawtoothWaveform;
|
||||
pulseWidth = usePulseWidth;
|
||||
resonance = useResonance;
|
||||
|
||||
wavePos = 0.0f;
|
||||
lastFreq = 0.0f;
|
||||
|
@ -50,24 +51,24 @@ void LA32WaveGenerator::initSynth(const bool sawtoothWaveform, const Bit8u pulse
|
|||
active = true;
|
||||
}
|
||||
|
||||
void LA32WaveGenerator::initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated) {
|
||||
this->pcmWaveAddress = pcmWaveAddress;
|
||||
this->pcmWaveLength = pcmWaveLength;
|
||||
this->pcmWaveLooped = pcmWaveLooped;
|
||||
this->pcmWaveInterpolated = pcmWaveInterpolated;
|
||||
void LA32WaveGenerator::initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated) {
|
||||
pcmWaveAddress = usePCMWaveAddress;
|
||||
pcmWaveLength = usePCMWaveLength;
|
||||
pcmWaveLooped = usePCMWaveLooped;
|
||||
pcmWaveInterpolated = usePCMWaveInterpolated;
|
||||
|
||||
pcmPosition = 0.0f;
|
||||
active = true;
|
||||
}
|
||||
|
||||
// ampVal - Logarithmic amp of the wave generator
|
||||
// pitch - Logarithmic frequency of the resulting wave
|
||||
// cutoffRampVal - Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier
|
||||
float LA32WaveGenerator::generateNextSample(const Bit32u ampVal, const Bit16u pitch, const Bit32u cutoffRampVal) {
|
||||
if (!active) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
this->amp = amp;
|
||||
this->pitch = pitch;
|
||||
|
||||
float sample = 0.0f;
|
||||
|
||||
// SEMI-CONFIRMED: From sample analysis:
|
||||
|
@ -284,9 +285,9 @@ bool LA32WaveGenerator::isPCMWave() const {
|
|||
return pcmWaveAddress != NULL;
|
||||
}
|
||||
|
||||
void LA32PartialPair::init(const bool ringModulated, const bool mixed) {
|
||||
this->ringModulated = ringModulated;
|
||||
this->mixed = mixed;
|
||||
void LA32PartialPair::init(const bool useRingModulated, const bool useMixed) {
|
||||
ringModulated = useRingModulated;
|
||||
mixed = useMixed;
|
||||
masterOutputSample = 0.0f;
|
||||
slaveOutputSample = 0.0f;
|
||||
}
|
||||
|
@ -354,4 +355,4 @@ bool LA32PartialPair::isActive(const PairType useMaster) const {
|
|||
return useMaster == MASTER ? master.isActive() : slave.isActive();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
22
audio/softsynth/mt32/LA32FloatWaveGenerator.h
Normal file → Executable file
22
audio/softsynth/mt32/LA32FloatWaveGenerator.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -16,14 +16,15 @@
|
|||
*/
|
||||
|
||||
#ifndef MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
#define MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
#error This file should be included from LA32WaveGenerator.h only.
|
||||
#endif
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
/**
|
||||
* LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator.
|
||||
* The output square wave is created by adding high / low linear segments in-between
|
||||
* the rising and falling cosine segments. Basically, it’s very similar to the phase distortion synthesis.
|
||||
* the rising and falling cosine segments. Basically, it's very similar to the phase distortion synthesis.
|
||||
* Behaviour of a true resonance filter is emulated by adding decaying sine wave.
|
||||
* The beginning and the ending of the resonant sine is multiplied by a cosine window.
|
||||
* To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave.
|
||||
|
@ -38,12 +39,6 @@ class LA32WaveGenerator {
|
|||
// True means the resulting square wave is to be multiplied by the synchronous cosine
|
||||
bool sawtoothWaveform;
|
||||
|
||||
// Logarithmic amp of the wave generator
|
||||
Bit32u amp;
|
||||
|
||||
// Logarithmic frequency of the resulting wave
|
||||
Bit16u pitch;
|
||||
|
||||
// Values in range [1..31]
|
||||
// Value 1 correspong to the minimum resonance
|
||||
Bit8u resonance;
|
||||
|
@ -53,9 +48,6 @@ class LA32WaveGenerator {
|
|||
// Value 255 corresponds to the maximum possible asymmetric of the resulting wave
|
||||
Bit8u pulseWidth;
|
||||
|
||||
// Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier
|
||||
Bit32u cutoffVal;
|
||||
|
||||
// Logarithmic PCM sample start address
|
||||
const Bit16s *pcmWaveAddress;
|
||||
|
||||
|
@ -96,7 +88,7 @@ public:
|
|||
|
||||
// Return true if the WG engine generates PCM wave samples
|
||||
bool isPCMWave() const;
|
||||
};
|
||||
}; // class LA32WaveGenerator
|
||||
|
||||
// LA32PartialPair contains a structure of two partials being mixed / ring modulated
|
||||
class LA32PartialPair {
|
||||
|
@ -135,8 +127,6 @@ public:
|
|||
|
||||
// Return active state of the WG engine
|
||||
bool isActive(const PairType master) const;
|
||||
};
|
||||
}; // class LA32PartialPair
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
|
|
10
audio/softsynth/mt32/LA32Ramp.cpp
Normal file → Executable file
10
audio/softsynth/mt32/LA32Ramp.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -47,12 +47,12 @@ We haven't fully explored:
|
|||
- Values when ramping between levels (though this is probably correct).
|
||||
- Transition timing (may not be 100% accurate, especially for very fast ramps).
|
||||
*/
|
||||
//#include <cmath>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "LA32Ramp.h"
|
||||
#include "Tables.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// SEMI-CONFIRMED from sample analysis.
|
||||
|
@ -152,4 +152,4 @@ void LA32Ramp::reset() {
|
|||
interruptRaised = false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
9
audio/softsynth/mt32/LA32Ramp.h
Normal file → Executable file
9
audio/softsynth/mt32/LA32Ramp.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,6 +18,9 @@
|
|||
#ifndef MT32EMU_LA32RAMP_H
|
||||
#define MT32EMU_LA32RAMP_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class LA32Ramp {
|
||||
|
@ -38,6 +41,6 @@ public:
|
|||
void reset();
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif /* TVA_H_ */
|
||||
#endif // #ifndef MT32EMU_LA32RAMP_H
|
||||
|
|
36
audio/softsynth/mt32/LA32WaveGenerator.cpp
Normal file → Executable file
36
audio/softsynth/mt32/LA32WaveGenerator.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,15 +15,19 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
#include "LA32FloatWaveGenerator.cpp"
|
||||
#else
|
||||
#include <cstddef>
|
||||
|
||||
//#include <cmath>
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "LA32WaveGenerator.h"
|
||||
#include "Tables.h"
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
#define MT32EMU_LA32_WAVE_GENERATOR_CPP
|
||||
#include "LA32FloatWaveGenerator.cpp"
|
||||
#undef MT32EMU_LA32_WAVE_GENERATOR_CPP
|
||||
#else
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
static const Bit32u SINE_SEGMENT_RELATIVE_LENGTH = 1 << 18;
|
||||
|
@ -50,7 +54,7 @@ Bit16s LA32Utilites::unlog(const LogSample &logSample) {
|
|||
|
||||
void LA32Utilites::addLogSamples(LogSample &logSample1, const LogSample &logSample2) {
|
||||
Bit32u logSampleValue = logSample1.logValue + logSample2.logValue;
|
||||
logSample1.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
|
||||
logSample1.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535;
|
||||
logSample1.sign = logSample1.sign == logSample2.sign ? LogSample::POSITIVE : LogSample::NEGATIVE;
|
||||
}
|
||||
|
||||
|
@ -130,9 +134,7 @@ void LA32WaveGenerator::advancePosition() {
|
|||
Bit32u lowLinearLength = (resonanceWaveLengthFactor << 8) - 4 * SINE_SEGMENT_RELATIVE_LENGTH - highLinearLength;
|
||||
computePositions(highLinearLength, lowLinearLength, resonanceWaveLengthFactor);
|
||||
|
||||
// resonancePhase computation hack
|
||||
int *resonancePhaseAlias = (int *)&resonancePhase;
|
||||
*resonancePhaseAlias = ((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3;
|
||||
resonancePhase = ResonancePhase(((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3);
|
||||
}
|
||||
|
||||
void LA32WaveGenerator::generateNextSquareWaveLogSample() {
|
||||
|
@ -158,7 +160,7 @@ void LA32WaveGenerator::generateNextSquareWaveLogSample() {
|
|||
logSampleValue += (MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9;
|
||||
}
|
||||
|
||||
squareLogSample.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
|
||||
squareLogSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535;
|
||||
squareLogSample.sign = phase < NEGATIVE_FALLING_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE;
|
||||
}
|
||||
|
||||
|
@ -198,7 +200,7 @@ void LA32WaveGenerator::generateNextResonanceWaveLogSample() {
|
|||
// After all the amp decrements are added, it should be safe now to adjust the amp of the resonance wave to what we see on captures
|
||||
logSampleValue -= 1 << 12;
|
||||
|
||||
resonanceLogSample.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
|
||||
resonanceLogSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535;
|
||||
resonanceLogSample.sign = resonancePhase < NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE;
|
||||
}
|
||||
|
||||
|
@ -216,7 +218,7 @@ void LA32WaveGenerator::generateNextSawtoothCosineLogSample(LogSample &logSample
|
|||
void LA32WaveGenerator::pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const {
|
||||
Bit32u logSampleValue = (32787 - (pcmSample & 32767)) << 1;
|
||||
logSampleValue += amp >> 10;
|
||||
logSample.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
|
||||
logSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535;
|
||||
logSample.sign = pcmSample < 0 ? LogSample::NEGATIVE : LogSample::POSITIVE;
|
||||
}
|
||||
|
||||
|
@ -377,7 +379,7 @@ Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg) {
|
|||
Bit16s firstSample = LA32Utilites::unlog(wg.getOutputLogSample(true));
|
||||
Bit16s secondSample = LA32Utilites::unlog(wg.getOutputLogSample(false));
|
||||
if (wg.isPCMWave()) {
|
||||
return Bit16s(firstSample + ((Bit32s(secondSample - firstSample) * wg.getPCMInterpolationFactor()) >> 7));
|
||||
return Bit16s(firstSample + (((Bit32s(secondSample) - Bit32s(firstSample)) * wg.getPCMInterpolationFactor()) >> 7));
|
||||
}
|
||||
return firstSample + secondSample;
|
||||
}
|
||||
|
@ -407,7 +409,7 @@ Bit16s LA32PartialPair::nextOutSample() {
|
|||
Bit16s slaveSample = slave.isPCMWave() ? LA32Utilites::unlog(slave.getOutputLogSample(true)) : unlogAndMixWGOutput(slave);
|
||||
slaveSample <<= 2;
|
||||
slaveSample >>= 2;
|
||||
Bit16s ringModulatedSample = Bit16s(((Bit32s)masterSample * (Bit32s)slaveSample) >> 13);
|
||||
Bit16s ringModulatedSample = Bit16s((Bit32s(masterSample) * Bit32s(slaveSample)) >> 13);
|
||||
return mixed ? nonOverdrivenMasterSample + ringModulatedSample : ringModulatedSample;
|
||||
}
|
||||
|
||||
|
@ -423,6 +425,6 @@ bool LA32PartialPair::isActive(const PairType useMaster) const {
|
|||
return useMaster == MASTER ? master.isActive() : slave.isActive();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // #if MT32EMU_USE_FLOAT_SAMPLES
|
||||
|
|
24
audio/softsynth/mt32/LA32WaveGenerator.h
Normal file → Executable file
24
audio/softsynth/mt32/LA32WaveGenerator.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,13 +15,17 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
#define MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
#include "Types.h"
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
#include "LA32FloatWaveGenerator.h"
|
||||
#else
|
||||
|
||||
#ifndef MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
#define MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
/**
|
||||
|
@ -55,7 +59,7 @@ public:
|
|||
/**
|
||||
* LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator.
|
||||
* The output square wave is created by adding high / low linear segments in-between
|
||||
* the rising and falling cosine segments. Basically, it’s very similar to the phase distortion synthesis.
|
||||
* the rising and falling cosine segments. Basically, it's very similar to the phase distortion synthesis.
|
||||
* Behaviour of a true resonance filter is emulated by adding decaying sine wave.
|
||||
* The beginning and the ending of the resonant sine is multiplied by a cosine window.
|
||||
* To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave.
|
||||
|
@ -143,7 +147,7 @@ class LA32WaveGenerator {
|
|||
} phase;
|
||||
|
||||
// Current phase of the resonance wave
|
||||
enum {
|
||||
enum ResonancePhase {
|
||||
POSITIVE_RISING_RESONANCE_SINE_SEGMENT,
|
||||
POSITIVE_FALLING_RESONANCE_SINE_SEGMENT,
|
||||
NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT,
|
||||
|
@ -200,7 +204,7 @@ public:
|
|||
|
||||
// Return current PCM interpolation factor
|
||||
Bit32u getPCMInterpolationFactor() const;
|
||||
};
|
||||
}; // class LA32WaveGenerator
|
||||
|
||||
// LA32PartialPair contains a structure of two partials being mixed / ring modulated
|
||||
class LA32PartialPair {
|
||||
|
@ -239,10 +243,10 @@ public:
|
|||
|
||||
// Return active state of the WG engine
|
||||
bool isActive(const PairType master) const;
|
||||
};
|
||||
}; // class LA32PartialPair
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
|
||||
#endif // #if MT32EMU_USE_FLOAT_SAMPLES
|
||||
|
||||
#endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
|
||||
|
|
18
audio/softsynth/mt32/MemoryRegion.h
Normal file → Executable file
18
audio/softsynth/mt32/MemoryRegion.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,12 +18,20 @@
|
|||
#ifndef MT32EMU_MEMORY_REGION_H
|
||||
#define MT32EMU_MEMORY_REGION_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
#include "Structures.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
enum MemoryRegionType {
|
||||
MR_PatchTemp, MR_RhythmTemp, MR_TimbreTemp, MR_Patches, MR_Timbres, MR_System, MR_Display, MR_Reset
|
||||
};
|
||||
|
||||
class Synth;
|
||||
|
||||
class MemoryRegion {
|
||||
private:
|
||||
Synth *synth;
|
||||
|
@ -84,7 +92,7 @@ public:
|
|||
}
|
||||
void read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const;
|
||||
void write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init = false) const;
|
||||
};
|
||||
}; // class MemoryRegion
|
||||
|
||||
class PatchTempMemoryRegion : public MemoryRegion {
|
||||
public:
|
||||
|
@ -112,13 +120,13 @@ public:
|
|||
};
|
||||
class DisplayMemoryRegion : public MemoryRegion {
|
||||
public:
|
||||
DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), MAX_SYSEX_SIZE - 1, 1) {}
|
||||
DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), SYSEX_BUFFER_SIZE - 1, 1) {}
|
||||
};
|
||||
class ResetMemoryRegion : public MemoryRegion {
|
||||
public:
|
||||
ResetMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1) {}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_MEMORY_REGION_H
|
||||
|
|
10
audio/softsynth/mt32/MidiEventQueue.h
Normal file → Executable file
10
audio/softsynth/mt32/MidiEventQueue.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,6 +18,9 @@
|
|||
#ifndef MT32EMU_MIDI_EVENT_QUEUE_H
|
||||
#define MT32EMU_MIDI_EVENT_QUEUE_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
/**
|
||||
|
@ -60,8 +63,9 @@ public:
|
|||
const MidiEvent *peekMidiEvent();
|
||||
void dropMidiEvent();
|
||||
bool isFull() const;
|
||||
bool inline isEmpty() const;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_MIDI_EVENT_QUEUE_H
|
||||
|
|
289
audio/softsynth/mt32/MidiStreamParser.cpp
Executable file
289
audio/softsynth/mt32/MidiStreamParser.cpp
Executable file
|
@ -0,0 +1,289 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "MidiStreamParser.h"
|
||||
#include "Synth.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
|
||||
DefaultMidiStreamParser::DefaultMidiStreamParser(Synth &useSynth, Bit32u initialStreamBufferCapacity) :
|
||||
MidiStreamParser(initialStreamBufferCapacity), synth(useSynth), timestampSet(false) {}
|
||||
|
||||
void DefaultMidiStreamParser::setTimestamp(const Bit32u useTimestamp) {
|
||||
timestampSet = true;
|
||||
timestamp = useTimestamp;
|
||||
}
|
||||
|
||||
void DefaultMidiStreamParser::resetTimestamp() {
|
||||
timestampSet = false;
|
||||
}
|
||||
|
||||
void DefaultMidiStreamParser::handleShortMessage(const Bit32u message) {
|
||||
do {
|
||||
if (timestampSet) {
|
||||
if (synth.playMsg(message, timestamp)) return;
|
||||
}
|
||||
else {
|
||||
if (synth.playMsg(message)) return;
|
||||
}
|
||||
} while (synth.reportHandler->onMIDIQueueOverflow());
|
||||
}
|
||||
|
||||
void DefaultMidiStreamParser::handleSysex(const Bit8u *stream, const Bit32u length) {
|
||||
do {
|
||||
if (timestampSet) {
|
||||
if (synth.playSysex(stream, length, timestamp)) return;
|
||||
}
|
||||
else {
|
||||
if (synth.playSysex(stream, length)) return;
|
||||
}
|
||||
} while (synth.reportHandler->onMIDIQueueOverflow());
|
||||
}
|
||||
|
||||
void DefaultMidiStreamParser::handleSystemRealtimeMessage(const Bit8u realtime) {
|
||||
synth.reportHandler->onMIDISystemRealtime(realtime);
|
||||
}
|
||||
|
||||
void DefaultMidiStreamParser::printDebug(const char *debugMessage) {
|
||||
synth.printDebug("%s", debugMessage);
|
||||
}
|
||||
|
||||
MidiStreamParser::MidiStreamParser(Bit32u initialStreamBufferCapacity) :
|
||||
MidiStreamParserImpl(*this, *this, initialStreamBufferCapacity) {}
|
||||
|
||||
MidiStreamParserImpl::MidiStreamParserImpl(MidiReceiver &useReceiver, MidiReporter &useReporter, Bit32u initialStreamBufferCapacity) :
|
||||
midiReceiver(useReceiver), midiReporter(useReporter)
|
||||
{
|
||||
if (initialStreamBufferCapacity < SYSEX_BUFFER_SIZE) initialStreamBufferCapacity = SYSEX_BUFFER_SIZE;
|
||||
if (MAX_STREAM_BUFFER_SIZE < initialStreamBufferCapacity) initialStreamBufferCapacity = MAX_STREAM_BUFFER_SIZE;
|
||||
streamBufferCapacity = initialStreamBufferCapacity;
|
||||
streamBuffer = new Bit8u[streamBufferCapacity];
|
||||
streamBufferSize = 0;
|
||||
runningStatus = 0;
|
||||
|
||||
reserved = NULL;
|
||||
}
|
||||
|
||||
MidiStreamParserImpl::~MidiStreamParserImpl() {
|
||||
delete[] streamBuffer;
|
||||
}
|
||||
|
||||
void MidiStreamParserImpl::parseStream(const Bit8u *stream, Bit32u length) {
|
||||
while (length > 0) {
|
||||
Bit32u parsedMessageLength = 0;
|
||||
if (0xF8 <= *stream) {
|
||||
// Process System Realtime immediately and go on
|
||||
midiReceiver.handleSystemRealtimeMessage(*stream);
|
||||
parsedMessageLength = 1;
|
||||
// No effect on the running status
|
||||
} else if (streamBufferSize > 0) {
|
||||
// Check if there is something in streamBuffer waiting for being processed
|
||||
if (*streamBuffer == 0xF0) {
|
||||
parsedMessageLength = parseSysexFragment(stream, length);
|
||||
} else {
|
||||
parsedMessageLength = parseShortMessageDataBytes(stream, length);
|
||||
}
|
||||
} else {
|
||||
if (*stream == 0xF0) {
|
||||
runningStatus = 0; // SysEx clears the running status
|
||||
parsedMessageLength = parseSysex(stream, length);
|
||||
} else {
|
||||
parsedMessageLength = parseShortMessageStatus(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// Parsed successfully
|
||||
stream += parsedMessageLength;
|
||||
length -= parsedMessageLength;
|
||||
}
|
||||
}
|
||||
|
||||
void MidiStreamParserImpl::processShortMessage(const Bit32u message) {
|
||||
// Adds running status to the MIDI message if it doesn't contain one
|
||||
Bit8u status = Bit8u(message);
|
||||
if (0xF8 <= status) {
|
||||
midiReceiver.handleSystemRealtimeMessage(status);
|
||||
} else if (processStatusByte(status)) {
|
||||
midiReceiver.handleShortMessage((message << 8) | status);
|
||||
} else if (0x80 <= status) { // If no running status available yet, skip this message
|
||||
midiReceiver.handleShortMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
// We deal with SysEx messages below 512 bytes long in most cases. Nevertheless, it seems reasonable to support a possibility
|
||||
// to load bulk dumps using a single message. However, this is known to fail with a real device due to limited input buffer size.
|
||||
bool MidiStreamParserImpl::checkStreamBufferCapacity(const bool preserveContent) {
|
||||
if (streamBufferSize < streamBufferCapacity) return true;
|
||||
if (streamBufferCapacity < MAX_STREAM_BUFFER_SIZE) {
|
||||
Bit8u *oldStreamBuffer = streamBuffer;
|
||||
streamBufferCapacity = MAX_STREAM_BUFFER_SIZE;
|
||||
streamBuffer = new Bit8u[streamBufferCapacity];
|
||||
if (preserveContent) memcpy(streamBuffer, oldStreamBuffer, streamBufferSize);
|
||||
delete[] oldStreamBuffer;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks input byte whether it is a status byte. If not, replaces it with running status when available.
|
||||
// Returns true if the input byte was changed to running status.
|
||||
bool MidiStreamParserImpl::processStatusByte(Bit8u &status) {
|
||||
if (status < 0x80) {
|
||||
// First byte isn't status, try running status
|
||||
if (runningStatus < 0x80) {
|
||||
// No running status available yet
|
||||
midiReporter.printDebug("processStatusByte: No valid running status yet, MIDI message ignored");
|
||||
return false;
|
||||
}
|
||||
status = runningStatus;
|
||||
return true;
|
||||
} else if (status < 0xF0) {
|
||||
// Store current status as running for a Voice message
|
||||
runningStatus = status;
|
||||
} else if (status < 0xF8) {
|
||||
// System Common clears running status
|
||||
runningStatus = 0;
|
||||
} // System Realtime doesn't affect running status
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns # of bytes parsed
|
||||
Bit32u MidiStreamParserImpl::parseShortMessageStatus(const Bit8u stream[]) {
|
||||
Bit8u status = *stream;
|
||||
Bit32u parsedLength = processStatusByte(status) ? 0 : 1;
|
||||
if (0x80 <= status) { // If no running status available yet, skip one byte
|
||||
*streamBuffer = status;
|
||||
++streamBufferSize;
|
||||
}
|
||||
return parsedLength;
|
||||
}
|
||||
|
||||
// Returns # of bytes parsed
|
||||
Bit32u MidiStreamParserImpl::parseShortMessageDataBytes(const Bit8u stream[], Bit32u length) {
|
||||
const Bit32u shortMessageLength = Synth::getShortMessageLength(*streamBuffer);
|
||||
Bit32u parsedLength = 0;
|
||||
|
||||
// Append incoming bytes to streamBuffer
|
||||
while ((streamBufferSize < shortMessageLength) && (length-- > 0)) {
|
||||
Bit8u dataByte = *(stream++);
|
||||
if (dataByte < 0x80) {
|
||||
// Add data byte to streamBuffer
|
||||
streamBuffer[streamBufferSize++] = dataByte;
|
||||
} else if (dataByte < 0xF8) {
|
||||
// Discard invalid bytes and start over
|
||||
char s[128];
|
||||
sprintf(s, "parseShortMessageDataBytes: Invalid short message: status %02x, expected length %i, actual %i -> ignored", *streamBuffer, shortMessageLength, streamBufferSize);
|
||||
midiReporter.printDebug(s);
|
||||
streamBufferSize = 0; // Clear streamBuffer
|
||||
return parsedLength;
|
||||
} else {
|
||||
// Bypass System Realtime message
|
||||
midiReceiver.handleSystemRealtimeMessage(dataByte);
|
||||
}
|
||||
++parsedLength;
|
||||
}
|
||||
if (streamBufferSize < shortMessageLength) return parsedLength; // Still lacks data bytes
|
||||
|
||||
// Assemble short message
|
||||
Bit32u shortMessage = streamBuffer[0];
|
||||
for (Bit32u i = 1; i < shortMessageLength; ++i) {
|
||||
shortMessage |= streamBuffer[i] << (i << 3);
|
||||
}
|
||||
midiReceiver.handleShortMessage(shortMessage);
|
||||
streamBufferSize = 0; // Clear streamBuffer
|
||||
return parsedLength;
|
||||
}
|
||||
|
||||
// Returns # of bytes parsed
|
||||
Bit32u MidiStreamParserImpl::parseSysex(const Bit8u stream[], const Bit32u length) {
|
||||
// Find SysEx length
|
||||
Bit32u sysexLength = 1;
|
||||
while (sysexLength < length) {
|
||||
Bit8u nextByte = stream[sysexLength++];
|
||||
if (0x80 <= nextByte) {
|
||||
if (nextByte == 0xF7) {
|
||||
// End of SysEx
|
||||
midiReceiver.handleSysex(stream, sysexLength);
|
||||
return sysexLength;
|
||||
}
|
||||
if (0xF8 <= nextByte) {
|
||||
// The System Realtime message must be processed right after return
|
||||
// but the SysEx is actually fragmented and to be reconstructed in streamBuffer
|
||||
--sysexLength;
|
||||
break;
|
||||
}
|
||||
// Illegal status byte in SysEx message, aborting
|
||||
midiReporter.printDebug("parseSysex: SysEx message lacks end-of-sysex (0xf7), ignored");
|
||||
// Continue parsing from that point
|
||||
return sysexLength - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Store incomplete SysEx message for further processing
|
||||
streamBufferSize = sysexLength;
|
||||
if (checkStreamBufferCapacity(false)) {
|
||||
memcpy(streamBuffer, stream, sysexLength);
|
||||
} else {
|
||||
// Not enough buffer capacity, don't care about the real buffer content, just mark the first byte
|
||||
*streamBuffer = *stream;
|
||||
streamBufferSize = streamBufferCapacity;
|
||||
}
|
||||
return sysexLength;
|
||||
}
|
||||
|
||||
// Returns # of bytes parsed
|
||||
Bit32u MidiStreamParserImpl::parseSysexFragment(const Bit8u stream[], const Bit32u length) {
|
||||
Bit32u parsedLength = 0;
|
||||
while (parsedLength < length) {
|
||||
Bit8u nextByte = stream[parsedLength++];
|
||||
if (nextByte < 0x80) {
|
||||
// Add SysEx data byte to streamBuffer
|
||||
if (checkStreamBufferCapacity(true)) streamBuffer[streamBufferSize++] = nextByte;
|
||||
continue;
|
||||
}
|
||||
if (0xF8 <= nextByte) {
|
||||
// Bypass System Realtime message
|
||||
midiReceiver.handleSystemRealtimeMessage(nextByte);
|
||||
continue;
|
||||
}
|
||||
if (nextByte != 0xF7) {
|
||||
// Illegal status byte in SysEx message, aborting
|
||||
midiReporter.printDebug("parseSysexFragment: SysEx message lacks end-of-sysex (0xf7), ignored");
|
||||
// Clear streamBuffer and continue parsing from that point
|
||||
streamBufferSize = 0;
|
||||
--parsedLength;
|
||||
break;
|
||||
}
|
||||
// End of SysEx
|
||||
if (checkStreamBufferCapacity(true)) {
|
||||
streamBuffer[streamBufferSize++] = nextByte;
|
||||
midiReceiver.handleSysex(streamBuffer, streamBufferSize);
|
||||
streamBufferSize = 0; // Clear streamBuffer
|
||||
break;
|
||||
}
|
||||
// Encountered streamBuffer overrun
|
||||
midiReporter.printDebug("parseSysexFragment: streamBuffer overrun while receiving SysEx message, ignored. Max allowed size of fragmented SysEx is 32768 bytes.");
|
||||
streamBufferSize = 0; // Clear streamBuffer
|
||||
break;
|
||||
}
|
||||
return parsedLength;
|
||||
}
|
124
audio/softsynth/mt32/MidiStreamParser.h
Executable file
124
audio/softsynth/mt32/MidiStreamParser.h
Executable file
|
@ -0,0 +1,124 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_MIDI_STREAM_PARSER_H
|
||||
#define MT32EMU_MIDI_STREAM_PARSER_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class Synth;
|
||||
|
||||
// Interface for a user-supplied class to receive parsed well-formed MIDI messages.
|
||||
class MT32EMU_EXPORT MidiReceiver {
|
||||
public:
|
||||
// Invoked when a complete short MIDI message is parsed in the input MIDI stream.
|
||||
virtual void handleShortMessage(const Bit32u message) = 0;
|
||||
|
||||
// Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream.
|
||||
virtual void handleSysex(const Bit8u stream[], const Bit32u length) = 0;
|
||||
|
||||
// Invoked when a System Realtime MIDI message is parsed in the input MIDI stream.
|
||||
virtual void handleSystemRealtimeMessage(const Bit8u realtime) = 0;
|
||||
|
||||
protected:
|
||||
~MidiReceiver() {}
|
||||
};
|
||||
|
||||
// Interface for a user-supplied class to receive notifications of input MIDI stream parse errors.
|
||||
class MT32EMU_EXPORT MidiReporter {
|
||||
public:
|
||||
// Invoked when an error occurs during processing the input MIDI stream.
|
||||
virtual void printDebug(const char *debugMessage) = 0;
|
||||
|
||||
protected:
|
||||
~MidiReporter() {}
|
||||
};
|
||||
|
||||
// Provides a context for parsing a stream of MIDI events coming from a single source.
|
||||
// There can be multiple MIDI sources feeding MIDI events to a single Synth object.
|
||||
// NOTE: Calls from multiple threads which feed a single Synth object with data must be explicitly synchronised,
|
||||
// although, no synchronisation is required with the rendering thread.
|
||||
class MT32EMU_EXPORT MidiStreamParserImpl {
|
||||
public:
|
||||
// The first two arguments provide for implementations of essential interfaces needed.
|
||||
// The third argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected.
|
||||
// If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes).
|
||||
// Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use.
|
||||
MidiStreamParserImpl(MidiReceiver &, MidiReporter &, Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE);
|
||||
virtual ~MidiStreamParserImpl();
|
||||
|
||||
// Parses a block of raw MIDI bytes. All the parsed MIDI messages are sent in sequence to the user-supplied methods for further processing.
|
||||
// SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages.
|
||||
// NOTE: the total length of a SysEx message being fragmented shall not exceed MAX_STREAM_BUFFER_SIZE (32768 bytes).
|
||||
void parseStream(const Bit8u *stream, Bit32u length);
|
||||
|
||||
// Convenience method which accepts a Bit32u-encoded short MIDI message and sends it to the user-supplied method for further processing.
|
||||
// The short MIDI message may contain no status byte, the running status is used in this case.
|
||||
void processShortMessage(const Bit32u message);
|
||||
|
||||
private:
|
||||
Bit8u runningStatus;
|
||||
Bit8u *streamBuffer;
|
||||
Bit32u streamBufferCapacity;
|
||||
Bit32u streamBufferSize;
|
||||
MidiReceiver &midiReceiver;
|
||||
MidiReporter &midiReporter;
|
||||
|
||||
// Binary compatibility helper.
|
||||
void *reserved;
|
||||
|
||||
bool checkStreamBufferCapacity(const bool preserveContent);
|
||||
bool processStatusByte(Bit8u &status);
|
||||
Bit32u parseShortMessageStatus(const Bit8u stream[]);
|
||||
Bit32u parseShortMessageDataBytes(const Bit8u stream[], Bit32u length);
|
||||
Bit32u parseSysex(const Bit8u stream[], const Bit32u length);
|
||||
Bit32u parseSysexFragment(const Bit8u stream[], const Bit32u length);
|
||||
}; // class MidiStreamParserImpl
|
||||
|
||||
// An abstract class that provides a context for parsing a stream of MIDI events coming from a single source.
|
||||
class MT32EMU_EXPORT MidiStreamParser : public MidiStreamParserImpl, protected MidiReceiver, protected MidiReporter {
|
||||
public:
|
||||
// The argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected.
|
||||
// If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes).
|
||||
// Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use.
|
||||
explicit MidiStreamParser(Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE);
|
||||
};
|
||||
|
||||
class MT32EMU_EXPORT DefaultMidiStreamParser : public MidiStreamParser {
|
||||
public:
|
||||
explicit DefaultMidiStreamParser(Synth &synth, Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE);
|
||||
void setTimestamp(const Bit32u useTimestamp);
|
||||
void resetTimestamp();
|
||||
|
||||
protected:
|
||||
void handleShortMessage(const Bit32u message);
|
||||
void handleSysex(const Bit8u *stream, const Bit32u length);
|
||||
void handleSystemRealtimeMessage(const Bit8u realtime);
|
||||
void printDebug(const char *debugMessage);
|
||||
|
||||
private:
|
||||
Synth &synth;
|
||||
bool timestampSet;
|
||||
Bit32u timestamp;
|
||||
};
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // MT32EMU_MIDI_STREAM_PARSER_H
|
62
audio/softsynth/mt32/Part.cpp
Normal file → Executable file
62
audio/softsynth/mt32/Part.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,12 +15,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cstdio>
|
||||
//#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "Part.h"
|
||||
#include "Partial.h"
|
||||
#include "PartialManager.h"
|
||||
#include "Poly.h"
|
||||
#include "Synth.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -112,7 +116,7 @@ Bit32s Part::getPitchBend() const {
|
|||
|
||||
void Part::setBend(unsigned int midiBend) {
|
||||
// CONFIRMED:
|
||||
pitchBend = (((signed)midiBend - 8192) * pitchBenderRange) >> 14; // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
pitchBend = ((signed(midiBend) - 8192) * pitchBenderRange) >> 14; // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
}
|
||||
|
||||
Bit8u Part::getModulation() const {
|
||||
|
@ -120,7 +124,7 @@ Bit8u Part::getModulation() const {
|
|||
}
|
||||
|
||||
void Part::setModulation(unsigned int midiModulation) {
|
||||
modulation = (Bit8u)midiModulation;
|
||||
modulation = Bit8u(midiModulation);
|
||||
}
|
||||
|
||||
void Part::resetAllControllers() {
|
||||
|
@ -162,7 +166,7 @@ void Part::refresh() {
|
|||
patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0;
|
||||
}
|
||||
memcpy(currentInstr, timbreTemp->common.name, 10);
|
||||
synth->newTimbreSet(partNum, patchTemp->patch.timbreGroup, currentInstr);
|
||||
synth->newTimbreSet(partNum, patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, currentInstr);
|
||||
updatePitchBenderRange();
|
||||
}
|
||||
|
||||
|
@ -255,26 +259,26 @@ void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) {
|
|||
|
||||
switch (t) {
|
||||
case 0:
|
||||
cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure12] & 0x2) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure12];
|
||||
cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure12)] & 0x2) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure12)];
|
||||
cache[t].structurePosition = 0;
|
||||
cache[t].structurePair = 1;
|
||||
break;
|
||||
case 1:
|
||||
cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure12] & 0x1) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure12];
|
||||
cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure12)] & 0x1) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure12)];
|
||||
cache[t].structurePosition = 1;
|
||||
cache[t].structurePair = 0;
|
||||
break;
|
||||
case 2:
|
||||
cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure34] & 0x2) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure34];
|
||||
cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure34)] & 0x2) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure34)];
|
||||
cache[t].structurePosition = 0;
|
||||
cache[t].structurePair = 3;
|
||||
break;
|
||||
case 3:
|
||||
cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure34] & 0x1) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure34];
|
||||
cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure34)] & 0x1) ? true : false;
|
||||
cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure34)];
|
||||
cache[t].structurePosition = 1;
|
||||
cache[t].structurePair = 2;
|
||||
break;
|
||||
|
@ -308,7 +312,7 @@ const char *Part::getName() const {
|
|||
|
||||
void Part::setVolume(unsigned int midiVolume) {
|
||||
// CONFIRMED: This calculation matches the table used in the control ROM
|
||||
patchTemp->outputLevel = (Bit8u)(midiVolume * 100 / 127);
|
||||
patchTemp->outputLevel = Bit8u(midiVolume * 100 / 127);
|
||||
//synth->printDebug("%s (%s): Set volume to %d", name, currentInstr, midiVolume);
|
||||
}
|
||||
|
||||
|
@ -322,7 +326,7 @@ Bit8u Part::getExpression() const {
|
|||
|
||||
void Part::setExpression(unsigned int midiExpression) {
|
||||
// CONFIRMED: This calculation matches the table used in the control ROM
|
||||
expression = (Bit8u)(midiExpression * 100 / 127);
|
||||
expression = Bit8u(midiExpression * 100 / 127);
|
||||
}
|
||||
|
||||
void RhythmPart::setPan(unsigned int midiPan) {
|
||||
|
@ -337,9 +341,9 @@ void Part::setPan(unsigned int midiPan) {
|
|||
// NOTE: Panning is inverted compared to GM.
|
||||
|
||||
// CM-32L: Divide by 8.5
|
||||
patchTemp->panpot = (Bit8u)((midiPan << 3) / 68);
|
||||
patchTemp->panpot = Bit8u((midiPan << 3) / 68);
|
||||
// FIXME: MT-32: Divide by 9
|
||||
//patchTemp->panpot = (Bit8u)(midiPan / 9);
|
||||
//patchTemp->panpot = Bit8u(midiPan / 9);
|
||||
|
||||
//synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot);
|
||||
}
|
||||
|
@ -507,7 +511,7 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt
|
|||
#if MT32EMU_MONITOR_PARTIALS > 1
|
||||
synth->printPartialUsage();
|
||||
#endif
|
||||
synth->polyStateChanged(partNum);
|
||||
synth->reportHandler->onPolyStateChanged(Bit8u(partNum));
|
||||
}
|
||||
|
||||
void Part::allNotesOff() {
|
||||
|
@ -593,16 +597,14 @@ void Part::partialDeactivated(Poly *poly) {
|
|||
if (!poly->isActive()) {
|
||||
activePolys.remove(poly);
|
||||
synth->partialManager->polyFreed(poly);
|
||||
synth->polyStateChanged(partNum);
|
||||
synth->reportHandler->onPolyStateChanged(Bit8u(partNum));
|
||||
}
|
||||
}
|
||||
|
||||
//#define POLY_LIST_DEBUG
|
||||
|
||||
PolyList::PolyList() : firstPoly(NULL), lastPoly(NULL) {}
|
||||
|
||||
bool PolyList::isEmpty() const {
|
||||
#ifdef POLY_LIST_DEBUG
|
||||
#ifdef MT32EMU_POLY_LIST_DEBUG
|
||||
if ((firstPoly == NULL || lastPoly == NULL) && firstPoly != lastPoly) {
|
||||
printf("PolyList: desynchronised firstPoly & lastPoly pointers\n");
|
||||
}
|
||||
|
@ -619,7 +621,7 @@ Poly *PolyList::getLast() const {
|
|||
}
|
||||
|
||||
void PolyList::prepend(Poly *poly) {
|
||||
#ifdef POLY_LIST_DEBUG
|
||||
#ifdef MT32EMU_POLY_LIST_DEBUG
|
||||
if (poly->getNext() != NULL) {
|
||||
printf("PolyList: Non-NULL next field in a Poly being prepended is ignored\n");
|
||||
}
|
||||
|
@ -632,14 +634,14 @@ void PolyList::prepend(Poly *poly) {
|
|||
}
|
||||
|
||||
void PolyList::append(Poly *poly) {
|
||||
#ifdef POLY_LIST_DEBUG
|
||||
#ifdef MT32EMU_POLY_LIST_DEBUG
|
||||
if (poly->getNext() != NULL) {
|
||||
printf("PolyList: Non-NULL next field in a Poly being appended is ignored\n");
|
||||
}
|
||||
#endif
|
||||
poly->setNext(NULL);
|
||||
if (lastPoly != NULL) {
|
||||
#ifdef POLY_LIST_DEBUG
|
||||
#ifdef MT32EMU_POLY_LIST_DEBUG
|
||||
if (lastPoly->getNext() != NULL) {
|
||||
printf("PolyList: Non-NULL next field in the lastPoly\n");
|
||||
}
|
||||
|
@ -656,7 +658,7 @@ Poly *PolyList::takeFirst() {
|
|||
Poly *oldFirst = firstPoly;
|
||||
firstPoly = oldFirst->getNext();
|
||||
if (firstPoly == NULL) {
|
||||
#ifdef POLY_LIST_DEBUG
|
||||
#ifdef MT32EMU_POLY_LIST_DEBUG
|
||||
if (lastPoly != oldFirst) {
|
||||
printf("PolyList: firstPoly != lastPoly in a list with a single Poly\n");
|
||||
}
|
||||
|
@ -675,7 +677,7 @@ void PolyList::remove(Poly * const polyToRemove) {
|
|||
for (Poly *poly = firstPoly; poly != NULL; poly = poly->getNext()) {
|
||||
if (poly->getNext() == polyToRemove) {
|
||||
if (polyToRemove == lastPoly) {
|
||||
#ifdef POLY_LIST_DEBUG
|
||||
#ifdef MT32EMU_POLY_LIST_DEBUG
|
||||
if (lastPoly->getNext() != NULL) {
|
||||
printf("PolyList: Non-NULL next field in the lastPoly\n");
|
||||
}
|
||||
|
@ -689,4 +691,4 @@ void PolyList::remove(Poly * const polyToRemove) {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
16
audio/softsynth/mt32/Part.h
Normal file → Executable file
16
audio/softsynth/mt32/Part.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,9 +18,14 @@
|
|||
#ifndef MT32EMU_PART_H
|
||||
#define MT32EMU_PART_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
#include "Types.h"
|
||||
#include "Structures.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class PartialManager;
|
||||
class Poly;
|
||||
class Synth;
|
||||
|
||||
class PolyList {
|
||||
|
@ -123,7 +128,7 @@ public:
|
|||
// Abort the first poly in PolyState_HELD, or if none exists, the first active poly in any state.
|
||||
bool abortFirstPolyPreferHeld();
|
||||
bool abortFirstPoly();
|
||||
};
|
||||
}; // class Part
|
||||
|
||||
class RhythmPart: public Part {
|
||||
// Pointer to the area of the MT-32's memory dedicated to rhythm
|
||||
|
@ -143,5 +148,6 @@ public:
|
|||
void setProgram(unsigned int patchNum);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif // #ifndef MT32EMU_PART_H
|
||||
|
|
27
audio/softsynth/mt32/Partial.cpp
Normal file → Executable file
27
audio/softsynth/mt32/Partial.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,14 +15,19 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cmath>
|
||||
//#include <cstdlib>
|
||||
//#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "Partial.h"
|
||||
#include "Part.h"
|
||||
#include "Poly.h"
|
||||
#include "Synth.h"
|
||||
#include "Tables.h"
|
||||
#include "TVA.h"
|
||||
#include "TVF.h"
|
||||
#include "TVP.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
static const Bit8u PAN_NUMERATOR_MASTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
@ -54,7 +59,7 @@ int Partial::debugGetPartialNum() const {
|
|||
}
|
||||
|
||||
// Only used for debugging purposes
|
||||
unsigned long Partial::debugGetSampleNum() const {
|
||||
Bit32u Partial::debugGetSampleNum() const {
|
||||
return sampleNum;
|
||||
}
|
||||
|
||||
|
@ -266,7 +271,7 @@ void Partial::backupCache(const PatchCache &cache) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long length) {
|
||||
bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, Bit32u length) {
|
||||
if (!isActive() || alreadyOutputed || isRingModulatingSlave()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -313,8 +318,8 @@ bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long len
|
|||
// Though, it is unknown whether this overflow is exploited somewhere.
|
||||
Sample leftOut = Sample((sample * leftPanValue) >> 8);
|
||||
Sample rightOut = Sample((sample * rightPanValue) >> 8);
|
||||
*leftBuf = Synth::clipSampleEx((SampleEx)*leftBuf + (SampleEx)leftOut);
|
||||
*rightBuf = Synth::clipSampleEx((SampleEx)*rightBuf + (SampleEx)rightOut);
|
||||
*leftBuf = Synth::clipSampleEx(SampleEx(*leftBuf) + SampleEx(leftOut));
|
||||
*rightBuf = Synth::clipSampleEx(SampleEx(*rightBuf) + SampleEx(rightOut));
|
||||
leftBuf++;
|
||||
rightBuf++;
|
||||
#endif
|
||||
|
@ -341,4 +346,4 @@ void Partial::startDecayAll() {
|
|||
tvf->startDecay();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
26
audio/softsynth/mt32/Partial.h
Normal file → Executable file
26
audio/softsynth/mt32/Partial.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,11 +18,21 @@
|
|||
#ifndef MT32EMU_PARTIAL_H
|
||||
#define MT32EMU_PARTIAL_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
#include "Types.h"
|
||||
#include "Structures.h"
|
||||
#include "LA32Ramp.h"
|
||||
#include "LA32WaveGenerator.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class Synth;
|
||||
class Part;
|
||||
class Poly;
|
||||
class Synth;
|
||||
class TVA;
|
||||
class TVF;
|
||||
class TVP;
|
||||
struct ControlROMPCMStruct;
|
||||
|
||||
// A partial represents one of up to four waveform generators currently playing within a poly.
|
||||
|
@ -32,7 +42,7 @@ private:
|
|||
const int debugPartialNum; // Only used for debugging
|
||||
// Number of the sample currently being rendered by produceOutput(), or 0 if no run is in progress
|
||||
// This is only kept available for debugging purposes.
|
||||
unsigned long sampleNum;
|
||||
Bit32u sampleNum;
|
||||
|
||||
// Actually, this is a 4-bit register but we abuse this to emulate inverted mixing.
|
||||
// Also we double the value to enable INACCURATE_SMOOTH_PAN, with respect to MoK.
|
||||
|
@ -77,7 +87,7 @@ public:
|
|||
~Partial();
|
||||
|
||||
int debugGetPartialNum() const;
|
||||
unsigned long debugGetSampleNum() const;
|
||||
Bit32u debugGetSampleNum() const;
|
||||
|
||||
int getOwnerPart() const;
|
||||
const Poly *getPoly() const;
|
||||
|
@ -100,9 +110,9 @@ public:
|
|||
// 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(Sample *leftBuf, Sample *rightBuf, unsigned long length);
|
||||
};
|
||||
bool produceOutput(Sample *leftBuf, Sample *rightBuf, Bit32u length);
|
||||
}; // class Partial
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_PARTIAL_H
|
||||
|
|
15
audio/softsynth/mt32/PartialManager.cpp
Normal file → Executable file
15
audio/softsynth/mt32/PartialManager.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,11 +15,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "PartialManager.h"
|
||||
#include "Part.h"
|
||||
#include "Partial.h"
|
||||
#include "Poly.h"
|
||||
#include "Synth.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -275,7 +280,7 @@ void PartialManager::polyFreed(Poly *poly) {
|
|||
const Poly *activePoly = synth->getPart(partNum)->getFirstActivePoly();
|
||||
Bit32u polyCount = 0;
|
||||
while (activePoly != NULL) {
|
||||
activePoly->getNext();
|
||||
activePoly = activePoly->getNext();
|
||||
polyCount++;
|
||||
}
|
||||
synth->printDebug("Part: %i, active poly count: %i\n", partNum, polyCount);
|
||||
|
@ -286,4 +291,4 @@ void PartialManager::polyFreed(Poly *poly) {
|
|||
freePolys[firstFreePolyIndex] = poly;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
15
audio/softsynth/mt32/PartialManager.h
Normal file → Executable file
15
audio/softsynth/mt32/PartialManager.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,8 +18,15 @@
|
|||
#ifndef MT32EMU_PARTIALMANAGER_H
|
||||
#define MT32EMU_PARTIALMANAGER_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class Part;
|
||||
class Partial;
|
||||
class Poly;
|
||||
class Synth;
|
||||
|
||||
class PartialManager {
|
||||
|
@ -49,8 +56,8 @@ public:
|
|||
const Partial *getPartial(unsigned int partialNum) const;
|
||||
Poly *assignPolyToPart(Part *part);
|
||||
void polyFreed(Poly *poly);
|
||||
};
|
||||
}; // class PartialManager
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_PARTIALMANAGER_H
|
||||
|
|
12
audio/softsynth/mt32/Poly.cpp
Normal file → Executable file
12
audio/softsynth/mt32/Poly.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,9 +15,15 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "Poly.h"
|
||||
#include "Part.h"
|
||||
#include "Partial.h"
|
||||
#include "Synth.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
Poly::Poly() {
|
||||
|
@ -181,4 +187,4 @@ void Poly::setNext(Poly *poly) {
|
|||
next = poly;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
19
audio/softsynth/mt32/Poly.h
Normal file → Executable file
19
audio/softsynth/mt32/Poly.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,17 +18,14 @@
|
|||
#ifndef MT32EMU_POLY_H
|
||||
#define MT32EMU_POLY_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "internals.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class Part;
|
||||
class Partial;
|
||||
|
||||
enum PolyState {
|
||||
POLY_Playing,
|
||||
POLY_Held, // This marks keys that have been released on the keyboard, but are being held by the pedal
|
||||
POLY_Releasing,
|
||||
POLY_Inactive
|
||||
};
|
||||
struct PatchCache;
|
||||
|
||||
class Poly {
|
||||
private:
|
||||
|
@ -66,8 +63,8 @@ public:
|
|||
|
||||
Poly *getNext() const;
|
||||
void setNext(Poly *poly);
|
||||
};
|
||||
}; // class Poly
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif /* POLY_H_ */
|
||||
#endif // #ifndef MT32EMU_POLY_H
|
||||
|
|
90
audio/softsynth/mt32/ROMInfo.cpp
Normal file → Executable file
90
audio/softsynth/mt32/ROMInfo.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,27 +15,27 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cstring>
|
||||
#include <cstring>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#include "ROMInfo.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
static const ROMInfo *getKnownROMInfoFromList(unsigned int index) {
|
||||
static const ControlROMFeatureSet MT32_COMPATIBLE(true, true);
|
||||
static const ControlROMFeatureSet CM32L_COMPATIBLE(false, false);
|
||||
|
||||
static const ROMInfo *getKnownROMInfoFromList(Bit32u index) {
|
||||
// Known ROMs
|
||||
static const ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL, &MT32_COMPATIBLE};
|
||||
static const ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL, &MT32_COMPATIBLE};
|
||||
static const ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL, &MT32_COMPATIBLE};
|
||||
static const ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL, &MT32_COMPATIBLE};
|
||||
static const ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL, &MT32_COMPATIBLE};
|
||||
static const ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL};
|
||||
static const ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL};
|
||||
static const ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL};
|
||||
static const ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL};
|
||||
static const ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL};
|
||||
|
||||
static const ROMInfo CTRL_CM32L_V1_00 = {65536, "73683d585cd6948cc19547942ca0e14a0319456d", ROMInfo::Control, "ctrl_cm32l_1_00", "CM-32L/LAPC-I Control v1.00", ROMInfo::Full, NULL, &CM32L_COMPATIBLE};
|
||||
static const ROMInfo CTRL_CM32L_V1_02 = {65536, "a439fbb390da38cada95a7cbb1d6ca199cd66ef8", ROMInfo::Control, "ctrl_cm32l_1_02", "CM-32L/LAPC-I Control v1.02", ROMInfo::Full, NULL, &CM32L_COMPATIBLE};
|
||||
static const ROMInfo CTRL_CM32L_V1_00 = {65536, "73683d585cd6948cc19547942ca0e14a0319456d", ROMInfo::Control, "ctrl_cm32l_1_00", "CM-32L/LAPC-I Control v1.00", ROMInfo::Full, NULL};
|
||||
static const ROMInfo CTRL_CM32L_V1_02 = {65536, "a439fbb390da38cada95a7cbb1d6ca199cd66ef8", ROMInfo::Control, "ctrl_cm32l_1_02", "CM-32L/LAPC-I Control v1.02", ROMInfo::Full, NULL};
|
||||
|
||||
static const ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL, NULL};
|
||||
static const ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL, NULL};
|
||||
static const ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL};
|
||||
static const ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL};
|
||||
|
||||
static const ROMInfo * const ROM_INFOS[] = {
|
||||
&CTRL_MT32_V1_04,
|
||||
|
@ -52,23 +52,11 @@ static const ROMInfo *getKnownROMInfoFromList(unsigned int index) {
|
|||
return ROM_INFOS[index];
|
||||
}
|
||||
|
||||
const ROMInfo* ROMInfo::getROMInfo(Common::File *file) {
|
||||
size_t fileSize = file->size();
|
||||
Common::String fileName = file->getName();
|
||||
fileName.toUppercase();
|
||||
bool isCM32LROM = fileName.hasPrefix("CM32L_");
|
||||
// We haven't added the SHA1 checksum code in ScummVM, as the file size
|
||||
// and ROM name suffices for our needs for now.
|
||||
//const char *fileDigest = file->getSHA1();
|
||||
for (int i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
|
||||
const ROMInfo* ROMInfo::getROMInfo(File *file) {
|
||||
size_t fileSize = file->getSize();
|
||||
for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
|
||||
const ROMInfo *romInfo = getKnownROMInfoFromList(i);
|
||||
if (fileSize == romInfo->fileSize /*&& !strcmp(fileDigest, romInfo->sha1Digest)*/) {
|
||||
if (fileSize == 65536) {
|
||||
// If we are looking for a CM-32L ROM, make sure we return the first matching
|
||||
// CM-32L ROM from the list, instead of the first matching MT-32 ROM
|
||||
if (isCM32LROM && romInfo->controlROMFeatures->isDefaultReverbMT32Compatible())
|
||||
continue;
|
||||
}
|
||||
if (fileSize == romInfo->fileSize && !strcmp(file->getSHA1(), romInfo->sha1Digest)) {
|
||||
return romInfo;
|
||||
}
|
||||
}
|
||||
|
@ -79,17 +67,17 @@ void ROMInfo::freeROMInfo(const ROMInfo *romInfo) {
|
|||
(void) romInfo;
|
||||
}
|
||||
|
||||
static int getROMCount() {
|
||||
int count;
|
||||
static Bit32u getROMCount() {
|
||||
Bit32u count;
|
||||
for(count = 0; getKnownROMInfoFromList(count) != NULL; count++) {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const ROMInfo** ROMInfo::getROMInfoList(unsigned int types, unsigned int pairTypes) {
|
||||
const ROMInfo** ROMInfo::getROMInfoList(Bit32u types, Bit32u pairTypes) {
|
||||
const ROMInfo **romInfoList = new const ROMInfo*[getROMCount() + 1];
|
||||
const ROMInfo **currentROMInList = romInfoList;
|
||||
for(int i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
|
||||
for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
|
||||
const ROMInfo *romInfo = getKnownROMInfoFromList(i);
|
||||
if ((types & (1 << romInfo->type)) && (pairTypes & (1 << romInfo->pairType))) {
|
||||
*currentROMInList++ = romInfo;
|
||||
|
@ -103,19 +91,22 @@ void ROMInfo::freeROMInfoList(const ROMInfo **romInfoList) {
|
|||
delete[] romInfoList;
|
||||
}
|
||||
|
||||
const ROMImage* ROMImage::makeROMImage(Common::File *file) {
|
||||
ROMImage *romImage = new ROMImage;
|
||||
romImage->file = file;
|
||||
romImage->romInfo = ROMInfo::getROMInfo(romImage->file);
|
||||
return romImage;
|
||||
ROMImage::ROMImage(File *useFile) : file(useFile), romInfo(ROMInfo::getROMInfo(file))
|
||||
{}
|
||||
|
||||
ROMImage::~ROMImage() {
|
||||
ROMInfo::freeROMInfo(romInfo);
|
||||
}
|
||||
|
||||
const ROMImage* ROMImage::makeROMImage(File *file) {
|
||||
return new ROMImage(file);
|
||||
}
|
||||
|
||||
void ROMImage::freeROMImage(const ROMImage *romImage) {
|
||||
ROMInfo::freeROMInfo(romImage->romInfo);
|
||||
delete romImage;
|
||||
}
|
||||
|
||||
Common::File* ROMImage::getFile() const {
|
||||
File* ROMImage::getFile() const {
|
||||
return file;
|
||||
}
|
||||
|
||||
|
@ -123,17 +114,4 @@ const ROMInfo* ROMImage::getROMInfo() const {
|
|||
return romInfo;
|
||||
}
|
||||
|
||||
ControlROMFeatureSet::ControlROMFeatureSet(bool useDefaultReverbMT32Compatible, bool useOldMT32AnalogLPF) :
|
||||
defaultReverbMT32Compatible(useDefaultReverbMT32Compatible),
|
||||
oldMT32AnalogLPF(useOldMT32AnalogLPF)
|
||||
{}
|
||||
|
||||
bool ControlROMFeatureSet::isDefaultReverbMT32Compatible() const {
|
||||
return defaultReverbMT32Compatible;
|
||||
}
|
||||
|
||||
bool ControlROMFeatureSet::isOldMT32AnalogLPF() const {
|
||||
return oldMT32AnalogLPF;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
52
audio/softsynth/mt32/ROMInfo.h
Normal file → Executable file
52
audio/softsynth/mt32/ROMInfo.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,73 +18,63 @@
|
|||
#ifndef MT32EMU_ROMINFO_H
|
||||
#define MT32EMU_ROMINFO_H
|
||||
|
||||
//#include <cstddef>
|
||||
#include "common/file.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "globals.h"
|
||||
#include "File.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
struct ControlROMFeatureSet;
|
||||
|
||||
// Defines vital info about ROM file to be used by synth and applications
|
||||
|
||||
struct ROMInfo {
|
||||
public:
|
||||
size_t fileSize;
|
||||
const char *sha1Digest;
|
||||
const File::SHA1Digest &sha1Digest;
|
||||
enum Type {PCM, Control, Reverb} type;
|
||||
const char *shortName;
|
||||
const char *description;
|
||||
enum PairType {Full, FirstHalf, SecondHalf, Mux0, Mux1} pairType;
|
||||
ROMInfo *pairROMInfo;
|
||||
const ControlROMFeatureSet *controlROMFeatures;
|
||||
|
||||
// Returns a ROMInfo struct by inspecting the size and the SHA1 hash
|
||||
static const ROMInfo* getROMInfo(Common::File *file);
|
||||
MT32EMU_EXPORT static const ROMInfo* getROMInfo(File *file);
|
||||
|
||||
// Currently no-op
|
||||
static void freeROMInfo(const ROMInfo *romInfo);
|
||||
MT32EMU_EXPORT static void freeROMInfo(const ROMInfo *romInfo);
|
||||
|
||||
// Allows retrieving a NULL-terminated list of ROMInfos for a range of types and pairTypes
|
||||
// (specified by bitmasks)
|
||||
// Useful for GUI/console app to output information on what ROMs it supports
|
||||
static const ROMInfo** getROMInfoList(unsigned int types, unsigned int pairTypes);
|
||||
MT32EMU_EXPORT static const ROMInfo** getROMInfoList(Bit32u types, Bit32u pairTypes);
|
||||
|
||||
// Frees the list of ROMInfos given
|
||||
static void freeROMInfoList(const ROMInfo **romInfos);
|
||||
MT32EMU_EXPORT static void freeROMInfoList(const ROMInfo **romInfos);
|
||||
};
|
||||
|
||||
// Synth::open() is to require a full control ROMImage and a full PCM ROMImage to work
|
||||
|
||||
class ROMImage {
|
||||
private:
|
||||
Common::File *file;
|
||||
const ROMInfo *romInfo;
|
||||
File * const file;
|
||||
const ROMInfo * const romInfo;
|
||||
|
||||
ROMImage(File *file);
|
||||
~ROMImage();
|
||||
|
||||
public:
|
||||
|
||||
// Creates a ROMImage object given a ROMInfo and a File. Keeps a reference
|
||||
// to the File and ROMInfo given, which must be freed separately by the user
|
||||
// after the ROMImage is freed
|
||||
static const ROMImage* makeROMImage(Common::File *file);
|
||||
MT32EMU_EXPORT static const ROMImage* makeROMImage(File *file);
|
||||
|
||||
// Must only be done after all Synths using the ROMImage are deleted
|
||||
static void freeROMImage(const ROMImage *romImage);
|
||||
MT32EMU_EXPORT static void freeROMImage(const ROMImage *romImage);
|
||||
|
||||
Common::File *getFile() const;
|
||||
const ROMInfo *getROMInfo() const;
|
||||
MT32EMU_EXPORT File *getFile() const;
|
||||
MT32EMU_EXPORT const ROMInfo *getROMInfo() const;
|
||||
};
|
||||
|
||||
struct ControlROMFeatureSet {
|
||||
private:
|
||||
unsigned int defaultReverbMT32Compatible : 1;
|
||||
unsigned int oldMT32AnalogLPF : 1;
|
||||
} // namespace MT32Emu
|
||||
|
||||
public:
|
||||
ControlROMFeatureSet(bool defaultReverbMT32Compatible, bool oldMT32AnalogLPF);
|
||||
bool isDefaultReverbMT32Compatible() const;
|
||||
bool isOldMT32AnalogLPF() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_ROMINFO_H
|
||||
|
|
41
audio/softsynth/mt32/Structures.h
Normal file → Executable file
41
audio/softsynth/mt32/Structures.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,6 +18,9 @@
|
|||
#ifndef MT32EMU_STRUCTURES_H
|
||||
#define MT32EMU_STRUCTURES_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// MT32EMU_MEMADDR() converts from sysex-padded, MT32EMU_SYSEXMEMADDR converts to it
|
||||
|
@ -102,8 +105,8 @@ struct TimbreParam {
|
|||
Bit8u envTime[5]; // 0-100
|
||||
Bit8u envLevel[4]; // 0-100 // [3]: SUSTAIN LEVEL
|
||||
} MT32EMU_ALIGN_PACKED tva;
|
||||
} MT32EMU_ALIGN_PACKED partial[4];
|
||||
} MT32EMU_ALIGN_PACKED;
|
||||
} MT32EMU_ALIGN_PACKED partial[4]; // struct PartialParam
|
||||
} MT32EMU_ALIGN_PACKED; // struct TimbreParam
|
||||
|
||||
struct PatchParam {
|
||||
Bit8u timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm)
|
||||
|
@ -163,7 +166,16 @@ struct MemParams {
|
|||
Bit8u chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
|
||||
Bit8u masterVol; // MASTER VOLUME 0-100
|
||||
} MT32EMU_ALIGN_PACKED system;
|
||||
};
|
||||
}; // struct MemParams
|
||||
|
||||
struct SoundGroup {
|
||||
Bit8u timbreNumberTableAddrLow;
|
||||
Bit8u timbreNumberTableAddrHigh;
|
||||
Bit8u displayPosition;
|
||||
Bit8u name[9];
|
||||
Bit8u timbreCount;
|
||||
Bit8u pad;
|
||||
} MT32EMU_ALIGN_PACKED;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#pragma pack(pop)
|
||||
|
@ -171,10 +183,17 @@ struct MemParams {
|
|||
#pragma pack()
|
||||
#endif
|
||||
|
||||
struct ControlROMFeatureSet {
|
||||
unsigned int quirkPitchEnvelopeOverflow : 1;
|
||||
|
||||
// Features below don't actually depend on control ROM version, which is used to identify hardware model
|
||||
unsigned int defaultReverbMT32Compatible : 1;
|
||||
unsigned int oldMT32AnalogLPF : 1;
|
||||
};
|
||||
|
||||
struct ControlROMMap {
|
||||
Bit16u idPos;
|
||||
Bit16u idLen;
|
||||
const char *idBytes;
|
||||
const char *shortName;
|
||||
const ControlROMFeatureSet &featureSet;
|
||||
Bit16u pcmTable; // 4 * pcmCount bytes
|
||||
Bit16u pcmCount;
|
||||
Bit16u timbreAMap; // 128 bytes
|
||||
|
@ -194,6 +213,8 @@ struct ControlROMMap {
|
|||
Bit16u patchMaxTable; // 16 bytes
|
||||
Bit16u systemMaxTable; // 23 bytes
|
||||
Bit16u timbreMaxTable; // 72 bytes
|
||||
Bit16u soundGroupsTable; // 14 bytes each entry
|
||||
Bit16u soundGroupsCount;
|
||||
};
|
||||
|
||||
struct ControlROMPCMStruct {
|
||||
|
@ -215,7 +236,7 @@ struct PatchCache {
|
|||
bool playPartial;
|
||||
bool PCMPartial;
|
||||
int pcm;
|
||||
char waveform;
|
||||
Bit8u waveform;
|
||||
|
||||
Bit32u structureMix;
|
||||
int structurePosition;
|
||||
|
@ -233,6 +254,6 @@ struct PatchCache {
|
|||
const TimbreParam::PartialParam *partialParam;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_STRUCTURES_H
|
||||
|
|
741
audio/softsynth/mt32/Synth.cpp
Normal file → Executable file
741
audio/softsynth/mt32/Synth.cpp
Normal file → Executable file
File diff suppressed because it is too large
Load diff
384
audio/softsynth/mt32/Synth.h
Normal file → Executable file
384
audio/softsynth/mt32/Synth.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,8 +18,13 @@
|
|||
#ifndef MT32EMU_SYNTH_H
|
||||
#define MT32EMU_SYNTH_H
|
||||
|
||||
//#include <cstdarg>
|
||||
//#include <cstring>
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
#include "Enumerations.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -31,6 +36,8 @@ class Part;
|
|||
class Poly;
|
||||
class Partial;
|
||||
class PartialManager;
|
||||
class Renderer;
|
||||
class ROMImage;
|
||||
|
||||
class PatchTempMemoryRegion;
|
||||
class RhythmTempMemoryRegion;
|
||||
|
@ -41,82 +48,11 @@ class SystemMemoryRegion;
|
|||
class DisplayMemoryRegion;
|
||||
class ResetMemoryRegion;
|
||||
|
||||
struct ControlROMFeatureSet;
|
||||
struct ControlROMMap;
|
||||
struct PCMWaveEntry;
|
||||
struct MemParams;
|
||||
|
||||
/**
|
||||
* Methods for emulating the connection between the LA32 and the DAC, which involves
|
||||
* some hacks in the real devices for doubling the volume.
|
||||
* See also http://en.wikipedia.org/wiki/Roland_MT-32#Digital_overflow
|
||||
*/
|
||||
enum DACInputMode {
|
||||
// Produces samples at double the volume, without tricks.
|
||||
// * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)
|
||||
// * Higher quality than the real devices
|
||||
DACInputMode_NICE,
|
||||
|
||||
// Produces samples that exactly match the bits output from the emulated LA32.
|
||||
// * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)
|
||||
// * Much less likely to overdrive than any other mode.
|
||||
// * Half the volume of any of the other modes.
|
||||
// * Output gain is ignored for both LA32 and reverb output.
|
||||
// * Perfect for developers while debugging :)
|
||||
DACInputMode_PURE,
|
||||
|
||||
// Re-orders the LA32 output bits as in early generation MT-32s (according to Wikipedia).
|
||||
// Bit order at DAC (where each number represents the original LA32 output bit number, and XX means the bit is always low):
|
||||
// 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX
|
||||
DACInputMode_GENERATION1,
|
||||
|
||||
// Re-orders the LA32 output bits as in later generations (personally confirmed on my CM-32L - KG).
|
||||
// Bit order at DAC (where each number represents the original LA32 output bit number):
|
||||
// 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14
|
||||
DACInputMode_GENERATION2
|
||||
};
|
||||
|
||||
// Methods for emulating the effective delay of incoming MIDI messages introduced by a MIDI interface.
|
||||
enum MIDIDelayMode {
|
||||
// Process incoming MIDI events immediately.
|
||||
MIDIDelayMode_IMMEDIATE,
|
||||
|
||||
// Delay incoming short MIDI messages as if they where transferred via a MIDI cable to a real hardware unit and immediate sysex processing.
|
||||
// This ensures more accurate timing of simultaneous NoteOn messages.
|
||||
MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY,
|
||||
|
||||
// Delay all incoming MIDI events as if they where transferred via a MIDI cable to a real hardware unit.
|
||||
MIDIDelayMode_DELAY_ALL
|
||||
};
|
||||
|
||||
// Methods for emulating the effects of analogue circuits of real hardware units on the output signal.
|
||||
enum AnalogOutputMode {
|
||||
// Only digital path is emulated. The output samples correspond to the digital signal at the DAC entrance.
|
||||
AnalogOutputMode_DIGITAL_ONLY,
|
||||
// Coarse emulation of LPF circuit. High frequencies are boosted, sample rate remains unchanged.
|
||||
AnalogOutputMode_COARSE,
|
||||
// Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz to allow emulation of audible mirror spectra above 16 kHz,
|
||||
// which is passed through the LPF circuit without significant attenuation.
|
||||
AnalogOutputMode_ACCURATE,
|
||||
// Same as AnalogOutputMode_ACCURATE mode but the output signal is 2x oversampled, i.e. the output sample rate is 96 kHz.
|
||||
// This makes subsequent resampling easier. Besides, due to nonlinear passband of the LPF emulated, it takes fewer number of MACs
|
||||
// compared to a regular LPF FIR implementations.
|
||||
AnalogOutputMode_OVERSAMPLED
|
||||
};
|
||||
|
||||
enum ReverbMode {
|
||||
REVERB_MODE_ROOM,
|
||||
REVERB_MODE_HALL,
|
||||
REVERB_MODE_PLATE,
|
||||
REVERB_MODE_TAP_DELAY
|
||||
};
|
||||
|
||||
enum PartialState {
|
||||
PartialState_INACTIVE,
|
||||
PartialState_ATTACK,
|
||||
PartialState_SUSTAIN,
|
||||
PartialState_RELEASE
|
||||
};
|
||||
|
||||
const Bit8u SYSEX_MANUFACTURER_ROLAND = 0x41;
|
||||
|
||||
const Bit8u SYSEX_MDL_MT32 = 0x16;
|
||||
|
@ -132,47 +68,64 @@ const Bit8u SYSEX_CMD_EOD = 0x45; // End of data
|
|||
const Bit8u SYSEX_CMD_ERR = 0x4E; // Communications error
|
||||
const Bit8u SYSEX_CMD_RJC = 0x4F; // Rejection
|
||||
|
||||
const int MAX_SYSEX_SIZE = 512; // FIXME: Does this correspond to a real MIDI buffer used in h/w devices?
|
||||
const Bit32u CONTROL_ROM_SIZE = 64 * 1024;
|
||||
|
||||
const unsigned int CONTROL_ROM_SIZE = 64 * 1024;
|
||||
|
||||
class ReportHandler {
|
||||
friend class Synth;
|
||||
// Set of multiplexed output streams appeared at the DAC entrance.
|
||||
template <class T>
|
||||
struct DACOutputStreams {
|
||||
T *nonReverbLeft;
|
||||
T *nonReverbRight;
|
||||
T *reverbDryLeft;
|
||||
T *reverbDryRight;
|
||||
T *reverbWetLeft;
|
||||
T *reverbWetRight;
|
||||
};
|
||||
|
||||
// Class for the client to supply callbacks for reporting various errors and information
|
||||
class MT32EMU_EXPORT ReportHandler {
|
||||
public:
|
||||
virtual ~ReportHandler() {}
|
||||
|
||||
protected:
|
||||
|
||||
// Callback for debug messages, in vprintf() format
|
||||
virtual void printDebug(const char *fmt, va_list list);
|
||||
|
||||
// Callbacks for reporting various errors and information
|
||||
// Callbacks for reporting errors
|
||||
virtual void onErrorControlROM() {}
|
||||
virtual void onErrorPCMROM() {}
|
||||
// Callback for reporting about displaying a new custom message on LCD
|
||||
virtual void showLCDMessage(const char *message);
|
||||
// Callback for reporting actual processing of a MIDI message
|
||||
virtual void onMIDIMessagePlayed() {}
|
||||
// Callback for reporting an overflow of the input MIDI queue.
|
||||
// Returns true if a recovery action was taken and yet another attempt to enqueue the MIDI event is desired.
|
||||
virtual bool onMIDIQueueOverflow() { return false; }
|
||||
// Callback invoked when a System Realtime MIDI message is detected at the input.
|
||||
virtual void onMIDISystemRealtime(Bit8u /* systemRealtime */) {}
|
||||
// Callbacks for reporting system events
|
||||
virtual void onDeviceReset() {}
|
||||
virtual void onDeviceReconfig() {}
|
||||
// Callbacks for reporting changes of reverb settings
|
||||
virtual void onNewReverbMode(Bit8u /* mode */) {}
|
||||
virtual void onNewReverbTime(Bit8u /* time */) {}
|
||||
virtual void onNewReverbLevel(Bit8u /* level */) {}
|
||||
virtual void onPolyStateChanged(int /* partNum */) {}
|
||||
virtual void onProgramChanged(int /* partNum */, int /* bankNum */, const char * /* patchName */) {}
|
||||
// Callbacks for reporting various information
|
||||
virtual void onPolyStateChanged(Bit8u /* partNum */) {}
|
||||
virtual void onProgramChanged(Bit8u /* partNum */, const char * /* soundGroupName */, const char * /* patchName */) {}
|
||||
};
|
||||
|
||||
class Synth {
|
||||
friend class DefaultMidiStreamParser;
|
||||
friend class Part;
|
||||
friend class RhythmPart;
|
||||
friend class Poly;
|
||||
friend class Partial;
|
||||
friend class PartialManager;
|
||||
friend class Tables;
|
||||
friend class MemoryRegion;
|
||||
friend class Poly;
|
||||
friend class Renderer;
|
||||
friend class RhythmPart;
|
||||
friend class TVA;
|
||||
friend class TVF;
|
||||
friend class TVP;
|
||||
|
||||
private:
|
||||
// **************************** Implementation fields **************************
|
||||
|
||||
PatchTempMemoryRegion *patchTempMemoryRegion;
|
||||
RhythmTempMemoryRegion *rhythmTempMemoryRegion;
|
||||
TimbreTempMemoryRegion *timbreTempMemoryRegion;
|
||||
|
@ -184,8 +137,6 @@ private:
|
|||
|
||||
Bit8u *paddedTimbreMaxTable;
|
||||
|
||||
bool isEnabled;
|
||||
|
||||
PCMWaveEntry *pcmWaves; // Array
|
||||
|
||||
const ControlROMFeatureSet *controlROMFeatures;
|
||||
|
@ -194,8 +145,11 @@ private:
|
|||
Bit16s *pcmROMData;
|
||||
size_t pcmROMSize; // This is in 16-bit samples, therefore half the number of bytes in the ROM
|
||||
|
||||
unsigned int partialCount;
|
||||
Bit8s chantable[32]; // FIXME: Need explanation why 32 is set, obviously it should be 16
|
||||
Bit8u soundGroupIx[128]; // For each standard timbre
|
||||
const char (*soundGroupNames)[9]; // Array
|
||||
|
||||
Bit32u partialCount;
|
||||
Bit8u chantable[16]; // NOTE: value above 8 means that the channel is not assigned
|
||||
|
||||
MidiEventQueue *midiQueue;
|
||||
volatile Bit32u lastReceivedMIDIEventTimestamp;
|
||||
|
@ -215,7 +169,8 @@ private:
|
|||
|
||||
bool reversedStereoEnabled;
|
||||
|
||||
bool isOpen;
|
||||
bool opened;
|
||||
bool activated;
|
||||
|
||||
bool isDefaultReportHandler;
|
||||
ReportHandler *reportHandler;
|
||||
|
@ -229,15 +184,17 @@ private:
|
|||
Poly *abortingPoly;
|
||||
|
||||
Analog *analog;
|
||||
Renderer &renderer;
|
||||
|
||||
// Binary compatibility helper.
|
||||
void *reserved;
|
||||
|
||||
// **************************** Implementation methods **************************
|
||||
|
||||
Bit32u addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp);
|
||||
bool isAbortingPoly() const { return abortingPoly != NULL; }
|
||||
|
||||
void produceLA32Output(Sample *buffer, Bit32u len);
|
||||
void convertSamplesToOutput(Sample *buffer, Bit32u len);
|
||||
bool isAbortingPoly() const;
|
||||
void doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len);
|
||||
|
||||
void readSysex(unsigned char channel, const Bit8u *sysex, Bit32u len) const;
|
||||
void readSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) const;
|
||||
void initMemoryRegions();
|
||||
void deleteMemoryRegions();
|
||||
MemoryRegion *findMemoryRegion(Bit32u addr);
|
||||
|
@ -248,79 +205,97 @@ private:
|
|||
bool loadPCMROM(const ROMImage &pcmROMImage);
|
||||
|
||||
bool initPCMList(Bit16u mapAddress, Bit16u count);
|
||||
bool initTimbres(Bit16u mapAddress, Bit16u offset, int timbreCount, int startTimbre, bool compressed);
|
||||
bool initCompressedTimbre(int drumNum, const Bit8u *mem, unsigned int memLen);
|
||||
bool initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u timbreCount, Bit16u startTimbre, bool compressed);
|
||||
bool initCompressedTimbre(Bit16u drumNum, const Bit8u *mem, Bit32u memLen);
|
||||
void initReverbModels(bool mt32CompatibleMode);
|
||||
void initSoundGroups(char newSoundGroupNames[][9]);
|
||||
|
||||
void refreshSystemMasterTune();
|
||||
void refreshSystemReverbParameters();
|
||||
void refreshSystemReserveSettings();
|
||||
void refreshSystemChanAssign(unsigned int firstPart, unsigned int lastPart);
|
||||
void refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart);
|
||||
void refreshSystemMasterVol();
|
||||
void refreshSystem();
|
||||
void reset();
|
||||
void dispose();
|
||||
|
||||
void printPartialUsage(unsigned long sampleOffset = 0);
|
||||
void printPartialUsage(Bit32u sampleOffset = 0);
|
||||
|
||||
void polyStateChanged(int partNum);
|
||||
void newTimbreSet(int partNum, Bit8u timbreGroup, const char patchName[]);
|
||||
void newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]);
|
||||
void printDebug(const char *fmt, ...);
|
||||
|
||||
// partNum should be 0..7 for Part 1..8, or 8 for Rhythm
|
||||
const Part *getPart(unsigned int partNum) const;
|
||||
const Part *getPart(Bit8u partNum) const;
|
||||
|
||||
public:
|
||||
static inline Sample clipSampleEx(SampleEx sampleEx) {
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
return sampleEx;
|
||||
#else
|
||||
static inline Bit16s clipSampleEx(Bit32s sampleEx) {
|
||||
// Clamp values above 32767 to 32767, and values below -32768 to -32768
|
||||
// FIXME: Do we really need this stuff? I think these branches are very well predicted. Instead, this introduces a chain.
|
||||
// The version below is actually a bit faster on my system...
|
||||
//return ((sampleEx + 0x8000) & ~0xFFFF) ? (sampleEx >> 31) ^ 0x7FFF : (Sample)sampleEx;
|
||||
return ((-0x8000 <= sampleEx) && (sampleEx <= 0x7FFF)) ? (Sample)sampleEx : (sampleEx >> 31) ^ 0x7FFF;
|
||||
#endif
|
||||
//return ((sampleEx + 0x8000) & ~0xFFFF) ? Bit16s((sampleEx >> 31) ^ 0x7FFF) : (Bit16s)sampleEx;
|
||||
return ((-0x8000 <= sampleEx) && (sampleEx <= 0x7FFF)) ? Bit16s(sampleEx) : Bit16s((sampleEx >> 31) ^ 0x7FFF);
|
||||
}
|
||||
|
||||
static inline void muteSampleBuffer(Sample *buffer, Bit32u len) {
|
||||
if (buffer == NULL) return;
|
||||
static inline float clipSampleEx(float sampleEx) {
|
||||
return sampleEx;
|
||||
}
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
template <class S>
|
||||
static inline void muteSampleBuffer(S *buffer, Bit32u len) {
|
||||
if (buffer == NULL) return;
|
||||
memset(buffer, 0, len * sizeof(S));
|
||||
}
|
||||
|
||||
static inline void muteSampleBuffer(float *buffer, Bit32u len) {
|
||||
if (buffer == NULL) return;
|
||||
// FIXME: Use memset() where compatibility is guaranteed (if this turns out to be a win)
|
||||
while (len--) {
|
||||
*(buffer++) = 0.0f;
|
||||
}
|
||||
#else
|
||||
memset(buffer, 0, len * sizeof(Sample));
|
||||
#endif
|
||||
}
|
||||
|
||||
static Bit32u getShortMessageLength(Bit32u msg);
|
||||
static Bit8u calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum = 0);
|
||||
// Returns library version as an integer in format: 0x00MMmmpp, where:
|
||||
// MM - major version number
|
||||
// mm - minor version number
|
||||
// pp - patch number
|
||||
MT32EMU_EXPORT static Bit32u getLibraryVersionInt();
|
||||
// Returns library version as a C-string in format: "MAJOR.MINOR.PATCH"
|
||||
MT32EMU_EXPORT static const char *getLibraryVersionString();
|
||||
|
||||
MT32EMU_EXPORT static Bit32u getShortMessageLength(Bit32u msg);
|
||||
MT32EMU_EXPORT static Bit8u calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum = 0);
|
||||
|
||||
// Returns output sample rate used in emulation of stereo analog circuitry of hardware units.
|
||||
// See comment for AnalogOutputMode.
|
||||
MT32EMU_EXPORT static Bit32u getStereoOutputSampleRate(AnalogOutputMode analogOutputMode);
|
||||
|
||||
// Optionally sets callbacks for reporting various errors, information and debug messages
|
||||
Synth(ReportHandler *useReportHandler = NULL);
|
||||
~Synth();
|
||||
MT32EMU_EXPORT explicit Synth(ReportHandler *useReportHandler = NULL);
|
||||
MT32EMU_EXPORT ~Synth();
|
||||
|
||||
// Used to initialise the MT-32. Must be called before any other function.
|
||||
// Returns true if initialization was sucessful, otherwise returns false.
|
||||
// controlROMImage and pcmROMImage represent Control and PCM ROM images for use by synth.
|
||||
// usePartialCount sets the maximum number of partials playing simultaneously for this session (optional).
|
||||
// analogOutputMode sets the mode for emulation of analogue circuitry of the hardware units (optional).
|
||||
bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount = DEFAULT_MAX_PARTIALS, AnalogOutputMode analogOutputMode = AnalogOutputMode_COARSE);
|
||||
MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, Bit32u usePartialCount = DEFAULT_MAX_PARTIALS, AnalogOutputMode analogOutputMode = AnalogOutputMode_COARSE);
|
||||
|
||||
// Overloaded method which opens the synth with default partial count.
|
||||
bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode);
|
||||
MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode);
|
||||
|
||||
// Closes the MT-32 and deallocates any memory used by the synthesizer
|
||||
void close(bool forced = false);
|
||||
MT32EMU_EXPORT void close();
|
||||
|
||||
// Returns true if the synth is in completely initialized state, otherwise returns false.
|
||||
MT32EMU_EXPORT bool isOpen() const;
|
||||
|
||||
// All the enqueued events are processed by the synth immediately.
|
||||
void flushMIDIQueue();
|
||||
MT32EMU_EXPORT void flushMIDIQueue();
|
||||
|
||||
// Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified.
|
||||
// The queue is flushed before reallocation.
|
||||
// Returns the actual queue size being used.
|
||||
Bit32u setMIDIEventQueueSize(Bit32u);
|
||||
MT32EMU_EXPORT Bit32u setMIDIEventQueueSize(Bit32u);
|
||||
|
||||
// Enqueues a MIDI event for subsequent playback.
|
||||
// The MIDI event will be processed not before the specified timestamp.
|
||||
|
@ -330,14 +305,15 @@ public:
|
|||
// Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread.
|
||||
// The methods return false if the MIDI event queue is full and the message cannot be enqueued.
|
||||
|
||||
// Enqueues a single short MIDI message. The message must contain a status byte.
|
||||
bool playMsg(Bit32u msg, Bit32u timestamp);
|
||||
// Enqueues a single well formed System Exclusive MIDI message.
|
||||
bool playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp);
|
||||
// Enqueues a single short MIDI message to play at specified time. The message must contain a status byte.
|
||||
MT32EMU_EXPORT bool playMsg(Bit32u msg, Bit32u timestamp);
|
||||
// Enqueues a single well formed System Exclusive MIDI message to play at specified time.
|
||||
MT32EMU_EXPORT bool playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp);
|
||||
|
||||
// Overloaded methods for the MIDI events to be processed ASAP.
|
||||
bool playMsg(Bit32u msg);
|
||||
bool playSysex(const Bit8u *sysex, Bit32u len);
|
||||
// Enqueues a single short MIDI message to be processed ASAP. The message must contain a status byte.
|
||||
MT32EMU_EXPORT bool playMsg(Bit32u msg);
|
||||
// Enqueues a single well formed System Exclusive MIDI message to be processed ASAP.
|
||||
MT32EMU_EXPORT bool playSysex(const Bit8u *sysex, Bit32u len);
|
||||
|
||||
// WARNING:
|
||||
// The methods below don't ensure minimum 1-sample delay between sequential MIDI events,
|
||||
|
@ -345,40 +321,60 @@ public:
|
|||
// A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering.
|
||||
|
||||
// Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte.
|
||||
void playMsgNow(Bit32u msg);
|
||||
void playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity);
|
||||
// See the WARNING above.
|
||||
MT32EMU_EXPORT void playMsgNow(Bit32u msg);
|
||||
// Sends unpacked short MIDI message to the synth for immediate playback. The message must contain a status byte.
|
||||
// See the WARNING above.
|
||||
MT32EMU_EXPORT void playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity);
|
||||
|
||||
// Sends a string of Sysex commands to the MT-32 for immediate interpretation
|
||||
// The length is in bytes
|
||||
void playSysexNow(const Bit8u *sysex, Bit32u len);
|
||||
void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len);
|
||||
void playSysexWithoutHeader(unsigned char device, unsigned char command, const Bit8u *sysex, Bit32u len);
|
||||
void writeSysex(unsigned char channel, const Bit8u *sysex, Bit32u len);
|
||||
// Sends a single well formed System Exclusive MIDI message for immediate processing. The length is in bytes.
|
||||
// See the WARNING above.
|
||||
MT32EMU_EXPORT void playSysexNow(const Bit8u *sysex, Bit32u len);
|
||||
// Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes.
|
||||
// See the WARNING above.
|
||||
MT32EMU_EXPORT void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len);
|
||||
// Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes.
|
||||
// See the WARNING above.
|
||||
MT32EMU_EXPORT void playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sysex, Bit32u len);
|
||||
// Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes.
|
||||
// See the WARNING above.
|
||||
MT32EMU_EXPORT void writeSysex(Bit8u channel, const Bit8u *sysex, Bit32u len);
|
||||
|
||||
void setReverbEnabled(bool reverbEnabled);
|
||||
bool isReverbEnabled() const;
|
||||
// Allows to disable wet reverb output altogether.
|
||||
MT32EMU_EXPORT void setReverbEnabled(bool reverbEnabled);
|
||||
// Returns whether wet reverb output is enabled.
|
||||
MT32EMU_EXPORT bool isReverbEnabled() const;
|
||||
// Sets override reverb mode. In this mode, emulation ignores sysexes (or the related part of them) which control the reverb parameters.
|
||||
// This mode is in effect until it is turned off. When the synth is re-opened, the override mode is unchanged but the state
|
||||
// of the reverb model is reset to default.
|
||||
void setReverbOverridden(bool reverbOverridden);
|
||||
bool isReverbOverridden() const;
|
||||
MT32EMU_EXPORT void setReverbOverridden(bool reverbOverridden);
|
||||
// Returns whether reverb settings are overridden.
|
||||
MT32EMU_EXPORT bool isReverbOverridden() const;
|
||||
// Forces reverb model compatibility mode. By default, the compatibility mode corresponds to the used control ROM version.
|
||||
// Invoking this method with the argument set to true forces emulation of old MT-32 reverb circuit.
|
||||
// When the argument is false, emulation of the reverb circuit used in new generation of MT-32 compatible modules is enforced
|
||||
// (these include CM-32L and LAPC-I).
|
||||
void setReverbCompatibilityMode(bool mt32CompatibleMode);
|
||||
bool isMT32ReverbCompatibilityMode() const;
|
||||
void setDACInputMode(DACInputMode mode);
|
||||
DACInputMode getDACInputMode() const;
|
||||
void setMIDIDelayMode(MIDIDelayMode mode);
|
||||
MIDIDelayMode getMIDIDelayMode() const;
|
||||
MT32EMU_EXPORT void setReverbCompatibilityMode(bool mt32CompatibleMode);
|
||||
// Returns whether reverb is in old MT-32 compatibility mode.
|
||||
MT32EMU_EXPORT bool isMT32ReverbCompatibilityMode() const;
|
||||
// Returns whether default reverb compatibility mode is the old MT-32 compatibility mode.
|
||||
MT32EMU_EXPORT bool isDefaultReverbMT32Compatible() const;
|
||||
// Sets new DAC input mode. See DACInputMode for details.
|
||||
MT32EMU_EXPORT void setDACInputMode(DACInputMode mode);
|
||||
// Returns current DAC input mode. See DACInputMode for details.
|
||||
MT32EMU_EXPORT DACInputMode getDACInputMode() const;
|
||||
// Sets new MIDI delay mode. See MIDIDelayMode for details.
|
||||
MT32EMU_EXPORT void setMIDIDelayMode(MIDIDelayMode mode);
|
||||
// Returns current MIDI delay mode. See MIDIDelayMode for details.
|
||||
MT32EMU_EXPORT MIDIDelayMode getMIDIDelayMode() const;
|
||||
|
||||
// Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume,
|
||||
// it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with setReverbOutputGain()
|
||||
// it offers to the user a capability to control the gain of reverb and non-reverb output channels independently.
|
||||
// Ignored in DACInputMode_PURE
|
||||
void setOutputGain(float);
|
||||
float getOutputGain() const;
|
||||
MT32EMU_EXPORT void setOutputGain(float gain);
|
||||
// Returns current output gain factor for synth output channels.
|
||||
MT32EMU_EXPORT float getOutputGain() const;
|
||||
|
||||
// Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output
|
||||
// analog circuitry of the hardware units. However, together with setOutputGain() it offers to the user a capability
|
||||
|
@ -389,59 +385,85 @@ public:
|
|||
// there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68
|
||||
// of that for LA32 analogue output. This factor is applied to the reverb output gain.
|
||||
// Ignored in DACInputMode_PURE
|
||||
void setReverbOutputGain(float);
|
||||
float getReverbOutputGain() const;
|
||||
MT32EMU_EXPORT void setReverbOutputGain(float gain);
|
||||
// Returns current output gain factor for reverb wet output channels.
|
||||
MT32EMU_EXPORT float getReverbOutputGain() const;
|
||||
|
||||
void setReversedStereoEnabled(bool enabled);
|
||||
bool isReversedStereoEnabled();
|
||||
// Swaps left and right output channels.
|
||||
MT32EMU_EXPORT void setReversedStereoEnabled(bool enabled);
|
||||
// Returns whether left and right output channels are swapped.
|
||||
MT32EMU_EXPORT bool isReversedStereoEnabled() const;
|
||||
|
||||
// Returns actual sample rate used in emulation of stereo analog circuitry of hardware units.
|
||||
// See comment for render() below.
|
||||
unsigned int getStereoOutputSampleRate() const;
|
||||
MT32EMU_EXPORT Bit32u getStereoOutputSampleRate() const;
|
||||
|
||||
// Renders samples to the specified output stream as if they were sampled at the analog stereo output.
|
||||
// When AnalogOutputMode is set to ACCURATE, the output signal is upsampled to 48 kHz in order
|
||||
// When AnalogOutputMode is set to ACCURATE (OVERSAMPLED), the output signal is upsampled to 48 (96) kHz in order
|
||||
// to retain emulation accuracy in whole audible frequency spectra. Otherwise, native digital signal sample rate is retained.
|
||||
// getStereoOutputSampleRate() can be used to query actual sample rate of the output signal.
|
||||
// The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes).
|
||||
void render(Sample *stream, Bit32u len);
|
||||
// The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes). Uses NATIVE byte ordering.
|
||||
MT32EMU_EXPORT void render(Bit16s *stream, Bit32u len);
|
||||
// Same as above but outputs to a float stereo stream.
|
||||
MT32EMU_EXPORT void render(float *stream, Bit32u len);
|
||||
|
||||
// Renders samples to the specified output streams as if they appeared at the DAC entrance.
|
||||
// No further processing performed in analog circuitry emulation is applied to the signal.
|
||||
// NULL may be specified in place of any or all of the stream buffers.
|
||||
// The length is in samples, not bytes.
|
||||
void renderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len);
|
||||
// NULL may be specified in place of any or all of the stream buffers to skip it.
|
||||
// The length is in samples, not bytes. Uses NATIVE byte ordering.
|
||||
MT32EMU_EXPORT void renderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len);
|
||||
void renderStreams(const DACOutputStreams<Bit16s> &streams, Bit32u len) {
|
||||
renderStreams(streams.nonReverbLeft, streams.nonReverbRight, streams.reverbDryLeft, streams.reverbDryRight, streams.reverbWetLeft, streams.reverbWetRight, len);
|
||||
}
|
||||
// Same as above but outputs to float streams.
|
||||
MT32EMU_EXPORT void renderStreams(float *nonReverbLeft, float *nonReverbRight, float *reverbDryLeft, float *reverbDryRight, float *reverbWetLeft, float *reverbWetRight, Bit32u len);
|
||||
void renderStreams(const DACOutputStreams<float> &streams, Bit32u len) {
|
||||
renderStreams(streams.nonReverbLeft, streams.nonReverbRight, streams.reverbDryLeft, streams.reverbDryRight, streams.reverbWetLeft, streams.reverbWetRight, len);
|
||||
}
|
||||
|
||||
// Returns true when there is at least one active partial, otherwise false.
|
||||
bool hasActivePartials() const;
|
||||
MT32EMU_EXPORT bool hasActivePartials() const;
|
||||
|
||||
// Returns true if hasActivePartials() returns true, or reverb is (somewhat unreliably) detected as being active.
|
||||
bool isActive() const;
|
||||
// Returns true if the synth is active and subsequent calls to render() may result in non-trivial output (i.e. silence).
|
||||
// The synth is considered active when either there are pending MIDI events in the queue, there is at least one active partial,
|
||||
// or the reverb is (somewhat unreliably) detected as being active.
|
||||
MT32EMU_EXPORT bool isActive();
|
||||
|
||||
// Returns the maximum number of partials playing simultaneously.
|
||||
unsigned int getPartialCount() const;
|
||||
MT32EMU_EXPORT Bit32u getPartialCount() const;
|
||||
|
||||
// Fills in current states of all the parts into the array provided. The array must have at least 9 entries to fit values for all the parts.
|
||||
// If the value returned for a part is true, there is at least one active non-releasing partial playing on this part.
|
||||
// This info is useful in emulating behaviour of LCD display of the hardware units.
|
||||
void getPartStates(bool *partStates) const;
|
||||
MT32EMU_EXPORT void getPartStates(bool *partStates) const;
|
||||
|
||||
// Returns current states of all the parts as a bit set. The least significant bit corresponds to the state of part 1,
|
||||
// total of 9 bits hold the states of all the parts. If the returned bit for a part is set, there is at least one active
|
||||
// non-releasing partial playing on this part. This info is useful in emulating behaviour of LCD display of the hardware units.
|
||||
MT32EMU_EXPORT Bit32u getPartStates() const;
|
||||
|
||||
// Fills in current states of all the partials into the array provided. The array must be large enough to accommodate states of all the partials.
|
||||
void getPartialStates(PartialState *partialStates) const;
|
||||
MT32EMU_EXPORT void getPartialStates(PartialState *partialStates) const;
|
||||
|
||||
// Fills in current states of all the partials into the array provided. Each byte in the array holds states of 4 partials
|
||||
// starting from the least significant bits. The state of each partial is packed in a pair of bits.
|
||||
// The array must be large enough to accommodate states of all the partials (see getPartialCount()).
|
||||
MT32EMU_EXPORT void getPartialStates(Bit8u *partialStates) const;
|
||||
|
||||
// Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough
|
||||
// to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials.
|
||||
// Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
|
||||
// Returns the number of currently playing notes on the specified part.
|
||||
unsigned int getPlayingNotes(unsigned int partNumber, Bit8u *keys, Bit8u *velocities) const;
|
||||
MT32EMU_EXPORT Bit32u getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) const;
|
||||
|
||||
// Returns name of the patch set on the specified part.
|
||||
// Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
|
||||
const char *getPatchName(unsigned int partNumber) const;
|
||||
MT32EMU_EXPORT const char *getPatchName(Bit8u partNumber) const;
|
||||
|
||||
void readMemory(Bit32u addr, Bit32u len, Bit8u *data);
|
||||
};
|
||||
// Stores internal state of emulated synth into an array provided (as it would be acquired from hardware).
|
||||
MT32EMU_EXPORT void readMemory(Bit32u addr, Bit32u len, Bit8u *data);
|
||||
}; // class Synth
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_SYNTH_H
|
||||
|
|
44
audio/softsynth/mt32/TVA.cpp
Normal file → Executable file
44
audio/softsynth/mt32/TVA.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -19,19 +19,23 @@
|
|||
* This class emulates the calculations performed by the 8095 microcontroller in order to configure the LA-32's amplitude ramp for a single partial at each stage of its TVA envelope.
|
||||
* Unless we introduced bugs, it should be pretty much 100% accurate according to Mok's specifications.
|
||||
*/
|
||||
//#include <cmath>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "TVA.h"
|
||||
#include "Part.h"
|
||||
#include "Partial.h"
|
||||
#include "Poly.h"
|
||||
#include "Synth.h"
|
||||
#include "Tables.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// CONFIRMED: Matches a table in ROM - haven't got around to coming up with a formula for it yet.
|
||||
static Bit8u biasLevelToAmpSubtractionCoeff[13] = {255, 187, 137, 100, 74, 54, 40, 29, 21, 15, 10, 5, 0};
|
||||
|
||||
TVA::TVA(const Partial *usePartial, LA32Ramp *useAmpRamp) :
|
||||
partial(usePartial), ampRamp(useAmpRamp), system_(&usePartial->getSynth()->mt32ram.system), phase(TVA_PHASE_DEAD) {
|
||||
partial(usePartial), ampRamp(useAmpRamp), system(&usePartial->getSynth()->mt32ram.system), phase(TVA_PHASE_DEAD) {
|
||||
}
|
||||
|
||||
void TVA::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) {
|
||||
|
@ -91,15 +95,15 @@ static int calcVeloAmpSubtraction(Bit8u veloSensitivity, unsigned int velocity)
|
|||
// FIXME:KG: Better variable names
|
||||
int velocityMult = veloSensitivity - 50;
|
||||
int absVelocityMult = velocityMult < 0 ? -velocityMult : velocityMult;
|
||||
velocityMult = (signed)((unsigned)(velocityMult * ((signed)velocity - 64)) << 2);
|
||||
velocityMult = signed(unsigned(velocityMult * (signed(velocity) - 64)) << 2);
|
||||
return absVelocityMult - (velocityMult >> 8); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
}
|
||||
|
||||
static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemParams::System *system_, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, const MemParams::RhythmTemp *rhythmTemp, int biasAmpSubtraction, int veloAmpSubtraction, Bit8u expression) {
|
||||
static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemParams::System *system, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, const MemParams::RhythmTemp *rhythmTemp, int biasAmpSubtraction, int veloAmpSubtraction, Bit8u expression) {
|
||||
int amp = 155;
|
||||
|
||||
if (!partial->isRingModulatingSlave()) {
|
||||
amp -= tables->masterVolToAmpSubtraction[system_->masterVol];
|
||||
amp -= tables->masterVolToAmpSubtraction[system->masterVol];
|
||||
if (amp < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -140,7 +144,7 @@ static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemP
|
|||
return amp;
|
||||
}
|
||||
|
||||
int calcKeyTimeSubtraction(Bit8u envTimeKeyfollow, int key) {
|
||||
static int calcKeyTimeSubtraction(Bit8u envTimeKeyfollow, int key) {
|
||||
if (envTimeKeyfollow == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -165,7 +169,7 @@ void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartial
|
|||
biasAmpSubtraction = calcBiasAmpSubtractions(partialParam, key);
|
||||
veloAmpSubtraction = calcVeloAmpSubtraction(partialParam->tva.veloSensitivity, velocity);
|
||||
|
||||
int newTarget = calcBasicAmp(tables, partial, system_, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
int newPhase;
|
||||
if (partialParam->tva.envTime[0] == 0) {
|
||||
// Initially go to the TVA_PHASE_ATTACK target amp, and spend the next phase going from there to the TVA_PHASE_2 target amp
|
||||
|
@ -182,7 +186,7 @@ void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartial
|
|||
// "Go downward as quickly as possible".
|
||||
// Since the current value is 0, the LA32Ramp will notice that we're already at or below the target and trying to go downward,
|
||||
// and therefore jump to the target immediately and raise an interrupt.
|
||||
startRamp((Bit8u)newTarget, 0x80 | 127, newPhase);
|
||||
startRamp(Bit8u(newTarget), 0x80 | 127, newPhase);
|
||||
}
|
||||
|
||||
void TVA::startAbort() {
|
||||
|
@ -217,7 +221,7 @@ void TVA::recalcSustain() {
|
|||
}
|
||||
// We're sustaining. Recalculate all the values
|
||||
const Tables *tables = &Tables::getInstance();
|
||||
int newTarget = calcBasicAmp(tables, partial, system_, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
newTarget += partialParam->tva.envLevel[3];
|
||||
// Since we're in TVA_PHASE_SUSTAIN at this point, we know that target has been reached and an interrupt fired, so we can rely on it being the current amp.
|
||||
int targetDelta = newTarget - target;
|
||||
|
@ -225,9 +229,9 @@ void TVA::recalcSustain() {
|
|||
// Calculate an increment to get to the new amp value in a short, more or less consistent amount of time
|
||||
Bit8u newIncrement;
|
||||
if (targetDelta >= 0) {
|
||||
newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - 2;
|
||||
newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - 2;
|
||||
} else {
|
||||
newIncrement = (tables->envLogarithmicTime[(Bit8u)-targetDelta] - 2) | 0x80;
|
||||
newIncrement = (tables->envLogarithmicTime[Bit8u(-targetDelta)] - 2) | 0x80;
|
||||
}
|
||||
// Configure so that once the transition's complete and nextPhase() is called, we'll just re-enter sustain phase (or decay phase, depending on parameters at the time).
|
||||
startRamp(newTarget, newIncrement, TVA_PHASE_SUSTAIN - 1);
|
||||
|
@ -279,7 +283,7 @@ void TVA::nextPhase() {
|
|||
int envPointIndex = phase;
|
||||
|
||||
if (!allLevelsZeroFromNowOn) {
|
||||
newTarget = calcBasicAmp(tables, partial, system_, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
|
||||
|
||||
if (newPhase == TVA_PHASE_SUSTAIN || newPhase == TVA_PHASE_RELEASE) {
|
||||
if (partialParam->tva.envLevel[3] == 0) {
|
||||
|
@ -311,7 +315,7 @@ void TVA::nextPhase() {
|
|||
int envTimeSetting = partialParam->tva.envTime[envPointIndex];
|
||||
|
||||
if (newPhase == TVA_PHASE_ATTACK) {
|
||||
envTimeSetting -= ((signed)partial->getPoly()->getVelocity() - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
envTimeSetting -= (signed(partial->getPoly()->getVelocity()) - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
|
||||
if (envTimeSetting <= 0 && partialParam->tva.envTime[envPointIndex] != 0) {
|
||||
envTimeSetting = 1;
|
||||
|
@ -338,14 +342,14 @@ void TVA::nextPhase() {
|
|||
}
|
||||
}
|
||||
targetDelta = -targetDelta;
|
||||
newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - envTimeSetting;
|
||||
newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - envTimeSetting;
|
||||
if (newIncrement <= 0) {
|
||||
newIncrement = 1;
|
||||
}
|
||||
newIncrement = newIncrement | 0x80;
|
||||
} else {
|
||||
// FIXME: The last 22 or so entries in this table are 128 - surely that fucks things up, since that ends up being -128 signed?
|
||||
newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - envTimeSetting;
|
||||
newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - envTimeSetting;
|
||||
if (newIncrement <= 0) {
|
||||
newIncrement = 1;
|
||||
}
|
||||
|
@ -360,7 +364,7 @@ void TVA::nextPhase() {
|
|||
}
|
||||
}
|
||||
|
||||
startRamp((Bit8u)newTarget, (Bit8u)newIncrement, newPhase);
|
||||
startRamp(Bit8u(newTarget), Bit8u(newIncrement), newPhase);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
16
audio/softsynth/mt32/TVA.h
Normal file → Executable file
16
audio/softsynth/mt32/TVA.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,9 +18,15 @@
|
|||
#ifndef MT32EMU_TVA_H
|
||||
#define MT32EMU_TVA_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
#include "Structures.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class LA32Ramp;
|
||||
class Part;
|
||||
class Partial;
|
||||
|
||||
// Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to
|
||||
// newPhase's value.
|
||||
|
@ -57,7 +63,7 @@ class TVA {
|
|||
private:
|
||||
const Partial * const partial;
|
||||
LA32Ramp *ampRamp;
|
||||
const MemParams::System * const system_;
|
||||
const MemParams::System * const system;
|
||||
|
||||
const Part *part;
|
||||
const TimbreParam::PartialParam *partialParam;
|
||||
|
@ -87,8 +93,8 @@ public:
|
|||
|
||||
bool isPlaying() const;
|
||||
int getPhase() const;
|
||||
};
|
||||
}; // class TVA
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif /* TVA_H_ */
|
||||
#endif // #ifndef MT32EMU_TVA_H
|
||||
|
|
24
audio/softsynth/mt32/TVF.cpp
Normal file → Executable file
24
audio/softsynth/mt32/TVF.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,12 +15,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cmath>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "TVF.h"
|
||||
#include "LA32Ramp.h"
|
||||
#include "Partial.h"
|
||||
#include "Poly.h"
|
||||
#include "Tables.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to
|
||||
|
@ -60,7 +62,7 @@ static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u
|
|||
static const Bit8s keyfollowMult21[] = {-21, -10, -5, 0, 2, 5, 8, 10, 13, 16, 18, 21, 26, 32, 42, 21, 21};
|
||||
int baseCutoff = keyfollowMult21[partialParam->tvf.keyfollow] - keyfollowMult21[partialParam->wg.pitchKeyfollow];
|
||||
// baseCutoff range now: -63 to 63
|
||||
baseCutoff *= (int)key - 60;
|
||||
baseCutoff *= int(key) - 60;
|
||||
// baseCutoff range now: -3024 to 3024
|
||||
int biasPoint = partialParam->tvf.biasPoint;
|
||||
if ((biasPoint & 0x40) == 0) {
|
||||
|
@ -75,7 +77,7 @@ static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u
|
|||
// biasPoint range here: 64 to 127
|
||||
int bias = biasPoint - 31 - key; // bias range here: -75 to 84
|
||||
if (bias < 0) {
|
||||
baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: −6375 to 6375
|
||||
baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -6375 to 6375
|
||||
// baseCutoff range now: -9399 to 9399
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +98,7 @@ static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u
|
|||
if (baseCutoff > 255) {
|
||||
baseCutoff = 255;
|
||||
}
|
||||
return (Bit8u)baseCutoff;
|
||||
return Bit8u(baseCutoff);
|
||||
}
|
||||
|
||||
TVF::TVF(const Partial *usePartial, LA32Ramp *useCutoffModifierRamp) :
|
||||
|
@ -128,7 +130,7 @@ void TVF::reset(const TimbreParam::PartialParam *newPartialParam, unsigned int b
|
|||
int newLevelMult = velocity * newPartialParam->tvf.envVeloSensitivity;
|
||||
newLevelMult >>= 6;
|
||||
newLevelMult += 109 - newPartialParam->tvf.envVeloSensitivity;
|
||||
newLevelMult += ((signed)key - 60) >> (4 - newPartialParam->tvf.envDepthKeyfollow);
|
||||
newLevelMult += (signed(key) - 60) >> (4 - newPartialParam->tvf.envDepthKeyfollow);
|
||||
if (newLevelMult < 0) {
|
||||
newLevelMult = 0;
|
||||
}
|
||||
|
@ -140,7 +142,7 @@ void TVF::reset(const TimbreParam::PartialParam *newPartialParam, unsigned int b
|
|||
levelMult = newLevelMult;
|
||||
|
||||
if (newPartialParam->tvf.envTimeKeyfollow != 0) {
|
||||
keyTimeSubtraction = ((signed)key - 60) >> (5 - newPartialParam->tvf.envTimeKeyfollow);
|
||||
keyTimeSubtraction = (signed(key) - 60) >> (5 - newPartialParam->tvf.envTimeKeyfollow);
|
||||
} else {
|
||||
keyTimeSubtraction = 0;
|
||||
}
|
||||
|
@ -228,4 +230,4 @@ void TVF::nextPhase() {
|
|||
startRamp(newTarget, newIncrement, newPhase);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
15
audio/softsynth/mt32/TVF.h
Normal file → Executable file
15
audio/softsynth/mt32/TVF.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,8 +18,15 @@
|
|||
#ifndef MT32EMU_TVF_H
|
||||
#define MT32EMU_TVF_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
#include "Structures.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class LA32Ramp;
|
||||
class Partial;
|
||||
|
||||
class TVF {
|
||||
private:
|
||||
const Partial * const partial;
|
||||
|
@ -47,8 +54,8 @@ public:
|
|||
Bit8u getBaseCutoff() const;
|
||||
void handleInterrupt();
|
||||
void startDecay();
|
||||
};
|
||||
}; // class TVF
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_TVF_H
|
||||
|
|
44
audio/softsynth/mt32/TVP.cpp
Normal file → Executable file
44
audio/softsynth/mt32/TVP.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,12 +15,17 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cmath>
|
||||
//#include <cstdlib>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include "TVP.h"
|
||||
#include "Part.h"
|
||||
#include "Partial.h"
|
||||
#include "Poly.h"
|
||||
#include "Synth.h"
|
||||
#include "TVA.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
// FIXME: Add Explanation
|
||||
|
@ -47,7 +52,7 @@ static Bit16u keyToPitchTable[] = {
|
|||
};
|
||||
|
||||
TVP::TVP(const Partial *usePartial) :
|
||||
partial(usePartial), system_(&usePartial->getSynth()->mt32ram.system) {
|
||||
partial(usePartial), system(&usePartial->getSynth()->mt32ram.system) {
|
||||
// We want to do processing 4000 times per second. FIXME: This is pretty arbitrary.
|
||||
maxCounter = SAMPLE_RATE / 4000;
|
||||
// The timer runs at 500kHz. We only need to bother updating it every maxCounter samples, before we do processing.
|
||||
|
@ -58,7 +63,7 @@ TVP::TVP(const Partial *usePartial) :
|
|||
static Bit16s keyToPitch(unsigned int key) {
|
||||
// We're using a table to do: return round_to_nearest_or_even((key - 60) * (4096.0 / 12.0))
|
||||
// Banker's rounding is just slightly annoying to do in C++
|
||||
int k = (int)key;
|
||||
int k = int(key);
|
||||
Bit16s pitch = keyToPitchTable[abs(k - 60)];
|
||||
return key < 60 ? -pitch : pitch;
|
||||
}
|
||||
|
@ -82,7 +87,7 @@ static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialPa
|
|||
|
||||
const ControlROMPCMStruct *controlROMPCMStruct = partial->getControlROMPCMStruct();
|
||||
if (controlROMPCMStruct != NULL) {
|
||||
basePitch += (Bit32s)((((Bit32s)controlROMPCMStruct->pitchMSB) << 8) | (Bit32s)controlROMPCMStruct->pitchLSB);
|
||||
basePitch += (Bit32s(controlROMPCMStruct->pitchMSB) << 8) | Bit32s(controlROMPCMStruct->pitchLSB);
|
||||
} else {
|
||||
if ((partialParam->wg.waveform & 1) == 0) {
|
||||
basePitch += 37133; // This puts Middle C at around 261.64Hz (assuming no other modifications, masterTune of 64, etc.)
|
||||
|
@ -98,7 +103,7 @@ static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialPa
|
|||
if (basePitch > 59392) {
|
||||
basePitch = 59392;
|
||||
}
|
||||
return (Bit32u)basePitch;
|
||||
return Bit32u(basePitch);
|
||||
}
|
||||
|
||||
static Bit32u calcVeloMult(Bit8u veloSensitivity, unsigned int velocity) {
|
||||
|
@ -119,7 +124,7 @@ static Bit32u calcVeloMult(Bit8u veloSensitivity, unsigned int velocity) {
|
|||
static Bit32s calcTargetPitchOffsetWithoutLFO(const TimbreParam::PartialParam *partialParam, int levelIndex, unsigned int velocity) {
|
||||
int veloMult = calcVeloMult(partialParam->pitchEnv.veloSensitivity, velocity);
|
||||
int targetPitchOffsetWithoutLFO = partialParam->pitchEnv.level[levelIndex] - 50;
|
||||
targetPitchOffsetWithoutLFO = (Bit32s)(targetPitchOffsetWithoutLFO * veloMult) >> (16 - partialParam->pitchEnv.depth); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
targetPitchOffsetWithoutLFO = (targetPitchOffsetWithoutLFO * veloMult) >> (16 - partialParam->pitchEnv.depth); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
return targetPitchOffsetWithoutLFO;
|
||||
}
|
||||
|
||||
|
@ -140,7 +145,7 @@ void TVP::reset(const Part *usePart, const TimbreParam::PartialParam *usePartial
|
|||
phase = 0;
|
||||
|
||||
if (partialParam->pitchEnv.timeKeyfollow) {
|
||||
timeKeyfollowSubtraction = (key - 60) >> (5 - partialParam->pitchEnv.timeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
timeKeyfollowSubtraction = Bit32s(key - 60) >> (5 - partialParam->pitchEnv.timeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
} else {
|
||||
timeKeyfollowSubtraction = 0;
|
||||
}
|
||||
|
@ -163,7 +168,7 @@ void TVP::updatePitch() {
|
|||
if (!partial->isPCM() || (partial->getControlROMPCMStruct()->len & 0x01) == 0) { // FIXME: Use !partial->pcmWaveEntry->unaffectedByMasterTune instead
|
||||
// FIXME: masterTune recalculation doesn't really happen here, and there are various bugs not yet emulated
|
||||
// 171 is ~half a semitone.
|
||||
newPitch += ((system_->masterTune - 64) * 171) >> 6; // PORTABILITY NOTE: Assumes arithmetic shift.
|
||||
newPitch += ((system->masterTune - 64) * 171) >> 6; // PORTABILITY NOTE: Assumes arithmetic shift.
|
||||
}
|
||||
if ((partialParam->wg.pitchBenderEnabled & 1) != 0) {
|
||||
newPitch += part->getPitchBend();
|
||||
|
@ -172,14 +177,13 @@ void TVP::updatePitch() {
|
|||
newPitch = 0;
|
||||
}
|
||||
|
||||
// Note: Temporary #ifdef until we have proper "quirk" configuration
|
||||
// This is about right emulation of MT-32 GEN0 quirk exploited in Colonel's Bequest timbre "Lightning"
|
||||
#ifndef MT32EMU_QUIRK_PITCH_ENVELOPE_OVERFLOW_MT32
|
||||
if (newPitch > 59392) {
|
||||
newPitch = 59392;
|
||||
// Skipping this check seems about right emulation of MT-32 GEN0 quirk exploited in Colonel's Bequest timbre "Lightning"
|
||||
if (partial->getSynth()->controlROMFeatures->quirkPitchEnvelopeOverflow == 0) {
|
||||
if (newPitch > 59392) {
|
||||
newPitch = 59392;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pitch = (Bit16u)newPitch;
|
||||
pitch = Bit16u(newPitch);
|
||||
|
||||
// FIXME: We're doing this here because that's what the CM-32L does - we should probably move this somewhere more appropriate in future.
|
||||
partial->getTVA()->recalcSustain();
|
||||
|
@ -317,10 +321,10 @@ void TVP::process() {
|
|||
negativeBigTicksRemaining = negativeBigTicksRemaining >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
rightShifts = 13;
|
||||
}
|
||||
int newResult = ((Bit32s)(negativeBigTicksRemaining * pitchOffsetChangePerBigTick)) >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
int newResult = (negativeBigTicksRemaining * pitchOffsetChangePerBigTick) >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
|
||||
newResult += targetPitchOffsetWithoutLFO + lfoPitchOffset;
|
||||
currentPitchOffset = newResult;
|
||||
updatePitch();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
17
audio/softsynth/mt32/TVP.h
Normal file → Executable file
17
audio/softsynth/mt32/TVP.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,12 +18,19 @@
|
|||
#ifndef MT32EMU_TVP_H
|
||||
#define MT32EMU_TVP_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
#include "Structures.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class Part;
|
||||
class Partial;
|
||||
|
||||
class TVP {
|
||||
private:
|
||||
const Partial * const partial;
|
||||
const MemParams::System * const system_; // FIXME: Only necessary because masterTune calculation is done in the wrong place atm.
|
||||
const MemParams::System * const system; // FIXME: Only necessary because masterTune calculation is done in the wrong place atm.
|
||||
|
||||
const Part *part;
|
||||
const TimbreParam::PartialParam *partialParam;
|
||||
|
@ -60,8 +67,8 @@ public:
|
|||
Bit32u getBasePitch() const;
|
||||
Bit16u nextPitch();
|
||||
void startDecay();
|
||||
};
|
||||
}; // class TVP
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_TVP_H
|
||||
|
|
30
audio/softsynth/mt32/Tables.cpp
Normal file → Executable file
30
audio/softsynth/mt32/Tables.cpp
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -15,11 +15,10 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include <cmath>
|
||||
#include "internals.h"
|
||||
|
||||
#include "mt32emu.h"
|
||||
#include "mmath.h"
|
||||
#include "Tables.h"
|
||||
#include "mmath.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -31,24 +30,25 @@ const Tables &Tables::getInstance() {
|
|||
}
|
||||
|
||||
Tables::Tables() {
|
||||
int lf;
|
||||
for (lf = 0; lf <= 100; lf++) {
|
||||
for (int lf = 0; lf <= 100; lf++) {
|
||||
// CONFIRMED:KG: This matches a ROM table found by Mok
|
||||
float fVal = (2.0f - LOG10F((float)lf + 1.0f)) * 128.0f;
|
||||
int val = (int)(fVal + 1.0);
|
||||
float fVal = (2.0f - LOG10F(float(lf) + 1.0f)) * 128.0f;
|
||||
int val = int(fVal + 1.0);
|
||||
if (val > 255) {
|
||||
val = 255;
|
||||
}
|
||||
levelToAmpSubtraction[lf] = (Bit8u)val;
|
||||
levelToAmpSubtraction[lf] = Bit8u(val);
|
||||
}
|
||||
|
||||
envLogarithmicTime[0] = 64;
|
||||
for (lf = 1; lf <= 255; lf++) {
|
||||
for (int lf = 1; lf <= 255; lf++) {
|
||||
// CONFIRMED:KG: This matches a ROM table found by Mok
|
||||
envLogarithmicTime[lf] = (Bit8u)ceil(64.0f + LOG2F((float)lf) * 8.0f);
|
||||
envLogarithmicTime[lf] = Bit8u(ceil(64.0f + LOG2F(float(lf)) * 8.0f));
|
||||
}
|
||||
|
||||
#ifdef EMULATE_LAPC_I // Dummy #ifdef - we'll have runtime emulation mode selection in future.
|
||||
#if 0
|
||||
// The table below is to be used in conjunction with emulation of VCA of newer generation units which is currently missing.
|
||||
// These relatively small values are rather intended to fine-tune the overall amplification of the VCA.
|
||||
// CONFIRMED: Based on a table found by Mok in the LAPC-I control ROM
|
||||
// Note that this matches the MT-32 table, but with the values clamped to a maximum of 8.
|
||||
memset(masterVolToAmpSubtraction, 8, 71);
|
||||
|
@ -64,12 +64,12 @@ Tables::Tables() {
|
|||
// CONFIRMED: Based on a table found by Mok in the MT-32 control ROM
|
||||
masterVolToAmpSubtraction[0] = 255;
|
||||
for (int masterVol = 1; masterVol <= 100; masterVol++) {
|
||||
masterVolToAmpSubtraction[masterVol] = (int)(106.31 - 16.0f * LOG2F((float)masterVol));
|
||||
masterVolToAmpSubtraction[masterVol] = Bit8u(106.31 - 16.0f * LOG2F(float(masterVol)));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i <= 100; i++) {
|
||||
pulseWidth100To255[i] = (int)(i * 255 / 100.0f + 0.5f);
|
||||
pulseWidth100To255[i] = Bit8u(i * 255 / 100.0f + 0.5f);
|
||||
//synth->printDebug("%d: %d", i, pulseWidth100To255[i]);
|
||||
}
|
||||
|
||||
|
@ -94,4 +94,4 @@ Tables::Tables() {
|
|||
resAmpDecayFactor = resAmpDecayFactorTable;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
|
11
audio/softsynth/mt32/Tables.h
Normal file → Executable file
11
audio/softsynth/mt32/Tables.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,6 +18,9 @@
|
|||
#ifndef MT32EMU_TABLES_H
|
||||
#define MT32EMU_TABLES_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class Tables {
|
||||
|
@ -52,8 +55,8 @@ public:
|
|||
Bit16u logsin9[512];
|
||||
|
||||
const Bit8u *resAmpDecayFactor;
|
||||
};
|
||||
}; // class Tables
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_TABLES_H
|
||||
|
|
10
audio/softsynth/mt32/Types.h
Normal file → Executable file
10
audio/softsynth/mt32/Types.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -27,14 +27,6 @@ typedef signed short int Bit16s;
|
|||
typedef unsigned char Bit8u;
|
||||
typedef signed char Bit8s;
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
typedef float Sample;
|
||||
typedef float SampleEx;
|
||||
#else
|
||||
typedef Bit16s Sample;
|
||||
typedef Bit32s SampleEx;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
624
audio/softsynth/mt32/c_interface/c_interface.cpp
Executable file
624
audio/softsynth/mt32/c_interface/c_interface.cpp
Executable file
|
@ -0,0 +1,624 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Types.h"
|
||||
#include "../File.h"
|
||||
#include "../FileStream.h"
|
||||
#include "../ROMInfo.h"
|
||||
#include "../Synth.h"
|
||||
#include "../MidiStreamParser.h"
|
||||
|
||||
#include "c_types.h"
|
||||
#include "c_interface.h"
|
||||
|
||||
using namespace MT32Emu;
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
static mt32emu_service_version getSynthVersionID(mt32emu_service_i) {
|
||||
return MT32EMU_SERVICE_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
static const mt32emu_service_i_v0 SERVICE_VTABLE = {
|
||||
getSynthVersionID,
|
||||
mt32emu_get_supported_report_handler_version,
|
||||
mt32emu_get_supported_midi_receiver_version,
|
||||
mt32emu_get_library_version_int,
|
||||
mt32emu_get_library_version_string,
|
||||
mt32emu_get_stereo_output_samplerate,
|
||||
mt32emu_create_context,
|
||||
mt32emu_free_context,
|
||||
mt32emu_add_rom_data,
|
||||
mt32emu_add_rom_file,
|
||||
mt32emu_get_rom_info,
|
||||
mt32emu_set_partial_count,
|
||||
mt32emu_set_analog_output_mode,
|
||||
mt32emu_open_synth,
|
||||
mt32emu_close_synth,
|
||||
mt32emu_is_open,
|
||||
mt32emu_get_actual_stereo_output_samplerate,
|
||||
mt32emu_flush_midi_queue,
|
||||
mt32emu_set_midi_event_queue_size,
|
||||
mt32emu_set_midi_receiver,
|
||||
mt32emu_parse_stream,
|
||||
mt32emu_parse_stream_at,
|
||||
mt32emu_play_short_message,
|
||||
mt32emu_play_short_message_at,
|
||||
mt32emu_play_msg,
|
||||
mt32emu_play_sysex,
|
||||
mt32emu_play_msg_at,
|
||||
mt32emu_play_sysex_at,
|
||||
mt32emu_play_msg_now,
|
||||
mt32emu_play_msg_on_part,
|
||||
mt32emu_play_sysex_now,
|
||||
mt32emu_write_sysex,
|
||||
mt32emu_set_reverb_enabled,
|
||||
mt32emu_is_reverb_enabled,
|
||||
mt32emu_set_reverb_overridden,
|
||||
mt32emu_is_reverb_overridden,
|
||||
mt32emu_set_reverb_compatibility_mode,
|
||||
mt32emu_is_mt32_reverb_compatibility_mode,
|
||||
mt32emu_is_default_reverb_mt32_compatible,
|
||||
mt32emu_set_dac_input_mode,
|
||||
mt32emu_get_dac_input_mode,
|
||||
mt32emu_set_midi_delay_mode,
|
||||
mt32emu_get_midi_delay_mode,
|
||||
mt32emu_set_output_gain,
|
||||
mt32emu_get_output_gain,
|
||||
mt32emu_set_reverb_output_gain,
|
||||
mt32emu_get_reverb_output_gain,
|
||||
mt32emu_set_reversed_stereo_enabled,
|
||||
mt32emu_is_reversed_stereo_enabled,
|
||||
mt32emu_render_bit16s,
|
||||
mt32emu_render_float,
|
||||
mt32emu_render_bit16s_streams,
|
||||
mt32emu_render_float_streams,
|
||||
mt32emu_has_active_partials,
|
||||
mt32emu_is_active,
|
||||
mt32emu_get_partial_count,
|
||||
mt32emu_get_part_states,
|
||||
mt32emu_get_partial_states,
|
||||
mt32emu_get_playing_notes,
|
||||
mt32emu_get_patch_name,
|
||||
mt32emu_read_memory
|
||||
};
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
struct mt32emu_data {
|
||||
ReportHandler *reportHandler;
|
||||
Synth *synth;
|
||||
const ROMImage *controlROMImage;
|
||||
const ROMImage *pcmROMImage;
|
||||
DefaultMidiStreamParser *midiParser;
|
||||
Bit32u partialCount;
|
||||
AnalogOutputMode analogOutputMode;
|
||||
};
|
||||
|
||||
// Internal C++ utility stuff
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
class DelegatingReportHandlerAdapter : public ReportHandler {
|
||||
public:
|
||||
DelegatingReportHandlerAdapter(mt32emu_report_handler_i useReportHandler, void *useInstanceData) :
|
||||
delegate(useReportHandler), instanceData(useInstanceData) {}
|
||||
|
||||
protected:
|
||||
const mt32emu_report_handler_i delegate;
|
||||
void * const instanceData;
|
||||
|
||||
private:
|
||||
void printDebug(const char *fmt, va_list list) {
|
||||
if (delegate.v0->printDebug == NULL) {
|
||||
ReportHandler::printDebug(fmt, list);
|
||||
} else {
|
||||
delegate.v0->printDebug(instanceData, fmt, list);
|
||||
}
|
||||
}
|
||||
|
||||
void onErrorControlROM() {
|
||||
if (delegate.v0->onErrorControlROM == NULL) {
|
||||
ReportHandler::onErrorControlROM();
|
||||
} else {
|
||||
delegate.v0->onErrorControlROM(instanceData);
|
||||
}
|
||||
}
|
||||
|
||||
void onErrorPCMROM() {
|
||||
if (delegate.v0->onErrorPCMROM == NULL) {
|
||||
ReportHandler::onErrorPCMROM();
|
||||
} else {
|
||||
delegate.v0->onErrorPCMROM(instanceData);
|
||||
}
|
||||
}
|
||||
|
||||
void showLCDMessage(const char *message) {
|
||||
if (delegate.v0->showLCDMessage == NULL) {
|
||||
ReportHandler::showLCDMessage(message);
|
||||
} else {
|
||||
delegate.v0->showLCDMessage(instanceData, message);
|
||||
}
|
||||
}
|
||||
|
||||
void onMIDIMessagePlayed() {
|
||||
if (delegate.v0->onMIDIMessagePlayed == NULL) {
|
||||
ReportHandler::onMIDIMessagePlayed();
|
||||
} else {
|
||||
delegate.v0->onMIDIMessagePlayed(instanceData);
|
||||
}
|
||||
}
|
||||
|
||||
bool onMIDIQueueOverflow() {
|
||||
if (delegate.v0->onMIDIQueueOverflow == NULL) {
|
||||
return ReportHandler::onMIDIQueueOverflow();
|
||||
}
|
||||
return delegate.v0->onMIDIQueueOverflow(instanceData) != MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
void onMIDISystemRealtime(Bit8u systemRealtime) {
|
||||
if (delegate.v0->onMIDISystemRealtime == NULL) {
|
||||
ReportHandler::onMIDISystemRealtime(systemRealtime);
|
||||
} else {
|
||||
delegate.v0->onMIDISystemRealtime(instanceData, systemRealtime);
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceReset() {
|
||||
if (delegate.v0->onDeviceReset == NULL) {
|
||||
ReportHandler::onDeviceReset();
|
||||
} else {
|
||||
delegate.v0->onDeviceReset(instanceData);
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceReconfig() {
|
||||
if (delegate.v0->onDeviceReconfig == NULL) {
|
||||
ReportHandler::onDeviceReconfig();
|
||||
} else {
|
||||
delegate.v0->onDeviceReconfig(instanceData);
|
||||
}
|
||||
}
|
||||
|
||||
void onNewReverbMode(Bit8u mode) {
|
||||
if (delegate.v0->onNewReverbMode == NULL) {
|
||||
ReportHandler::onNewReverbMode(mode);
|
||||
} else {
|
||||
delegate.v0->onNewReverbMode(instanceData, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void onNewReverbTime(Bit8u time) {
|
||||
if (delegate.v0->onNewReverbTime == NULL) {
|
||||
ReportHandler::onNewReverbTime(time);
|
||||
} else {
|
||||
delegate.v0->onNewReverbTime(instanceData, time);
|
||||
}
|
||||
}
|
||||
|
||||
void onNewReverbLevel(Bit8u level) {
|
||||
if (delegate.v0->onNewReverbLevel == NULL) {
|
||||
ReportHandler::onNewReverbLevel(level);
|
||||
} else {
|
||||
delegate.v0->onNewReverbLevel(instanceData, level);
|
||||
}
|
||||
}
|
||||
|
||||
void onPolyStateChanged(Bit8u partNum) {
|
||||
if (delegate.v0->onPolyStateChanged == NULL) {
|
||||
ReportHandler::onPolyStateChanged(partNum);
|
||||
} else {
|
||||
delegate.v0->onPolyStateChanged(instanceData, partNum);
|
||||
}
|
||||
}
|
||||
|
||||
void onProgramChanged(Bit8u partNum, const char *soundGroupName, const char *patchName) {
|
||||
if (delegate.v0->onProgramChanged == NULL) {
|
||||
ReportHandler::onProgramChanged(partNum, soundGroupName, patchName);
|
||||
} else {
|
||||
delegate.v0->onProgramChanged(instanceData, partNum, soundGroupName, patchName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DelegatingMidiStreamParser : public DefaultMidiStreamParser {
|
||||
public:
|
||||
DelegatingMidiStreamParser(const mt32emu_data *useData, mt32emu_midi_receiver_i useMIDIReceiver, void *useInstanceData) :
|
||||
DefaultMidiStreamParser(*useData->synth), delegate(useMIDIReceiver), instanceData(useInstanceData) {}
|
||||
|
||||
protected:
|
||||
mt32emu_midi_receiver_i delegate;
|
||||
void *instanceData;
|
||||
|
||||
private:
|
||||
void handleShortMessage(const Bit32u message) {
|
||||
if (delegate.v0->handleShortMessage == NULL) {
|
||||
DefaultMidiStreamParser::handleShortMessage(message);
|
||||
} else {
|
||||
delegate.v0->handleShortMessage(instanceData, message);
|
||||
}
|
||||
}
|
||||
|
||||
void handleSysex(const Bit8u *stream, const Bit32u length) {
|
||||
if (delegate.v0->handleSysex == NULL) {
|
||||
DefaultMidiStreamParser::handleSysex(stream, length);
|
||||
} else {
|
||||
delegate.v0->handleSysex(instanceData, stream, length);
|
||||
}
|
||||
}
|
||||
|
||||
void handleSystemRealtimeMessage(const Bit8u realtime) {
|
||||
if (delegate.v0->handleSystemRealtimeMessage == NULL) {
|
||||
DefaultMidiStreamParser::handleSystemRealtimeMessage(realtime);
|
||||
} else {
|
||||
delegate.v0->handleSystemRealtimeMessage(instanceData, realtime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static mt32emu_return_code addROMFile(mt32emu_data *data, File *file) {
|
||||
const ROMImage *image = ROMImage::makeROMImage(file);
|
||||
const ROMInfo *info = image->getROMInfo();
|
||||
if (info == NULL) {
|
||||
ROMImage::freeROMImage(image);
|
||||
return MT32EMU_RC_ROM_NOT_IDENTIFIED;
|
||||
}
|
||||
if (info->type == ROMInfo::Control) {
|
||||
if (data->controlROMImage != NULL) {
|
||||
delete data->controlROMImage->getFile();
|
||||
ROMImage::freeROMImage(data->controlROMImage);
|
||||
}
|
||||
data->controlROMImage = image;
|
||||
return MT32EMU_RC_ADDED_CONTROL_ROM;
|
||||
} else if (info->type == ROMInfo::PCM) {
|
||||
if (data->pcmROMImage != NULL) {
|
||||
delete data->pcmROMImage->getFile();
|
||||
ROMImage::freeROMImage(data->pcmROMImage);
|
||||
}
|
||||
data->pcmROMImage = image;
|
||||
return MT32EMU_RC_ADDED_PCM_ROM;
|
||||
}
|
||||
ROMImage::freeROMImage(image);
|
||||
return MT32EMU_RC_OK; // No support for reverb ROM yet.
|
||||
}
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
// C-visible implementation
|
||||
|
||||
extern "C" {
|
||||
|
||||
const mt32emu_service_i mt32emu_get_service_i() {
|
||||
mt32emu_service_i i = { &SERVICE_VTABLE };
|
||||
return i;
|
||||
}
|
||||
|
||||
mt32emu_report_handler_version mt32emu_get_supported_report_handler_version() {
|
||||
return MT32EMU_REPORT_HANDLER_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version() {
|
||||
return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_get_library_version_int() {
|
||||
return Synth::getLibraryVersionInt();
|
||||
}
|
||||
|
||||
const char *mt32emu_get_library_version_string() {
|
||||
return Synth::getLibraryVersionString();
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode) {
|
||||
return Synth::getStereoOutputSampleRate(static_cast<AnalogOutputMode>(analog_output_mode));
|
||||
}
|
||||
|
||||
mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data) {
|
||||
mt32emu_data *data = new mt32emu_data;
|
||||
data->reportHandler = (report_handler.v0 != NULL) ? new DelegatingReportHandlerAdapter(report_handler, instance_data) : new ReportHandler;
|
||||
data->synth = new Synth(data->reportHandler);
|
||||
data->midiParser = new DefaultMidiStreamParser(*data->synth);
|
||||
data->controlROMImage = NULL;
|
||||
data->pcmROMImage = NULL;
|
||||
data->partialCount = DEFAULT_MAX_PARTIALS;
|
||||
data->analogOutputMode = AnalogOutputMode_COARSE;
|
||||
return data;
|
||||
}
|
||||
|
||||
void mt32emu_free_context(mt32emu_context data) {
|
||||
if (data == NULL) return;
|
||||
if (data->controlROMImage != NULL) {
|
||||
delete data->controlROMImage->getFile();
|
||||
ROMImage::freeROMImage(data->controlROMImage);
|
||||
data->controlROMImage = NULL;
|
||||
}
|
||||
if (data->pcmROMImage != NULL) {
|
||||
delete data->pcmROMImage->getFile();
|
||||
ROMImage::freeROMImage(data->pcmROMImage);
|
||||
data->pcmROMImage = NULL;
|
||||
}
|
||||
delete data->midiParser;
|
||||
data->midiParser = NULL;
|
||||
delete data->synth;
|
||||
data->synth = NULL;
|
||||
delete data->reportHandler;
|
||||
data->reportHandler = NULL;
|
||||
delete data;
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest) {
|
||||
if (sha1_digest == NULL) return addROMFile(context, new ArrayFile(data, data_size));
|
||||
return addROMFile(context, new ArrayFile(data, data_size, *sha1_digest));
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename) {
|
||||
mt32emu_return_code rc = MT32EMU_RC_OK;
|
||||
FileStream *fs = new FileStream;
|
||||
if (fs->open(filename)) {
|
||||
if (fs->getData() != NULL) {
|
||||
rc = addROMFile(context, fs);
|
||||
if (rc > 0) return rc;
|
||||
} else {
|
||||
rc = MT32EMU_RC_FILE_NOT_LOADED;
|
||||
}
|
||||
} else {
|
||||
rc = MT32EMU_RC_FILE_NOT_FOUND;
|
||||
}
|
||||
delete fs;
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info) {
|
||||
const ROMInfo *romInfo = context->controlROMImage == NULL ? NULL : context->controlROMImage->getROMInfo();
|
||||
if (romInfo != NULL) {
|
||||
rom_info->control_rom_id = romInfo->shortName;
|
||||
rom_info->control_rom_description = romInfo->description;
|
||||
rom_info->control_rom_sha1_digest = romInfo->sha1Digest;
|
||||
} else {
|
||||
rom_info->control_rom_id = NULL;
|
||||
rom_info->control_rom_description = NULL;
|
||||
rom_info->control_rom_sha1_digest = NULL;
|
||||
}
|
||||
romInfo = context->pcmROMImage == NULL ? NULL : context->pcmROMImage->getROMInfo();
|
||||
if (romInfo != NULL) {
|
||||
rom_info->pcm_rom_id = romInfo->shortName;
|
||||
rom_info->pcm_rom_description = romInfo->description;
|
||||
rom_info->pcm_rom_sha1_digest = romInfo->sha1Digest;
|
||||
} else {
|
||||
rom_info->pcm_rom_id = NULL;
|
||||
rom_info->pcm_rom_description = NULL;
|
||||
rom_info->pcm_rom_sha1_digest = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count) {
|
||||
context->partialCount = partial_count;
|
||||
}
|
||||
|
||||
void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode) {
|
||||
context->analogOutputMode = static_cast<AnalogOutputMode>(analog_output_mode);
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context) {
|
||||
if ((context->controlROMImage == NULL) || (context->pcmROMImage == NULL)) {
|
||||
return MT32EMU_RC_MISSING_ROMS;
|
||||
}
|
||||
if (context->synth->open(*context->controlROMImage, *context->pcmROMImage, context->partialCount, context->analogOutputMode)) {
|
||||
return MT32EMU_RC_OK;
|
||||
}
|
||||
return MT32EMU_RC_FAILED;
|
||||
}
|
||||
|
||||
void mt32emu_close_synth(mt32emu_const_context context) {
|
||||
context->synth->close();
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_open(mt32emu_const_context context) {
|
||||
return context->synth->isOpen() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context) {
|
||||
return context->synth->getStereoOutputSampleRate();
|
||||
}
|
||||
|
||||
void mt32emu_flush_midi_queue(mt32emu_const_context context) {
|
||||
context->synth->flushMIDIQueue();
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size) {
|
||||
return context->synth->setMIDIEventQueueSize(queue_size);
|
||||
}
|
||||
|
||||
void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data) {
|
||||
delete context->midiParser;
|
||||
context->midiParser = (midi_receiver.v0 != NULL) ? new DelegatingMidiStreamParser(context, midi_receiver, instance_data) : new DefaultMidiStreamParser(*context->synth);
|
||||
}
|
||||
|
||||
void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length) {
|
||||
context->midiParser->resetTimestamp();
|
||||
context->midiParser->parseStream(stream, length);
|
||||
}
|
||||
|
||||
void mt32emu_parse_stream_at(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp) {
|
||||
context->midiParser->setTimestamp(timestamp);
|
||||
context->midiParser->parseStream(stream, length);
|
||||
}
|
||||
|
||||
void mt32emu_play_short_message(mt32emu_const_context context, mt32emu_bit32u message) {
|
||||
context->midiParser->resetTimestamp();
|
||||
context->midiParser->processShortMessage(message);
|
||||
}
|
||||
|
||||
void mt32emu_play_short_message_at(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp) {
|
||||
context->midiParser->setTimestamp(timestamp);
|
||||
context->midiParser->processShortMessage(message);
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_play_msg(mt32emu_const_context context, mt32emu_bit32u msg) {
|
||||
if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED;
|
||||
return (context->synth->playMsg(msg)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL;
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_play_sysex(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len) {
|
||||
if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED;
|
||||
return (context->synth->playSysex(sysex, len)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL;
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_play_msg_at(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp) {
|
||||
if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED;
|
||||
return (context->synth->playMsg(msg, timestamp)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL;
|
||||
}
|
||||
|
||||
mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp) {
|
||||
if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED;
|
||||
return (context->synth->playSysex(sysex, len, timestamp)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL;
|
||||
}
|
||||
|
||||
void mt32emu_play_msg_now(mt32emu_const_context context, mt32emu_bit32u msg) {
|
||||
context->synth->playMsgNow(msg);
|
||||
}
|
||||
|
||||
void mt32emu_play_msg_on_part(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity) {
|
||||
context->synth->playMsgOnPart(part, code, note, velocity);
|
||||
}
|
||||
|
||||
void mt32emu_play_sysex_now(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len) {
|
||||
context->synth->playSysexNow(sysex, len);
|
||||
}
|
||||
|
||||
void mt32emu_write_sysex(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len) {
|
||||
context->synth->writeSysex(channel, sysex, len);
|
||||
}
|
||||
|
||||
void mt32emu_set_reverb_enabled(mt32emu_const_context context, const mt32emu_boolean reverb_enabled) {
|
||||
context->synth->setReverbEnabled(reverb_enabled != MT32EMU_BOOL_FALSE);
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_reverb_enabled(mt32emu_const_context context) {
|
||||
return context->synth->isReverbEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
void mt32emu_set_reverb_overridden(mt32emu_const_context context, const mt32emu_boolean reverb_overridden) {
|
||||
context->synth->setReverbOverridden(reverb_overridden != MT32EMU_BOOL_FALSE);
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_reverb_overridden(mt32emu_const_context context) {
|
||||
return context->synth->isReverbOverridden() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
void mt32emu_set_reverb_compatibility_mode(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode) {
|
||||
context->synth->setReverbCompatibilityMode(mt32_compatible_mode != MT32EMU_BOOL_FALSE);
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu_const_context context) {
|
||||
return context->synth->isMT32ReverbCompatibilityMode() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context) {
|
||||
return context->synth->isDefaultReverbMT32Compatible() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode) {
|
||||
context->synth->setDACInputMode(static_cast<DACInputMode>(mode));
|
||||
}
|
||||
|
||||
mt32emu_dac_input_mode mt32emu_get_dac_input_mode(mt32emu_const_context context) {
|
||||
return static_cast<mt32emu_dac_input_mode>(context->synth->getDACInputMode());
|
||||
}
|
||||
|
||||
void mt32emu_set_midi_delay_mode(mt32emu_const_context context, const mt32emu_midi_delay_mode mode) {
|
||||
context->synth->setMIDIDelayMode(static_cast<MIDIDelayMode>(mode));
|
||||
}
|
||||
|
||||
mt32emu_midi_delay_mode mt32emu_get_midi_delay_mode(mt32emu_const_context context) {
|
||||
return static_cast<mt32emu_midi_delay_mode>(context->synth->getMIDIDelayMode());
|
||||
}
|
||||
|
||||
void mt32emu_set_output_gain(mt32emu_const_context context, float gain) {
|
||||
context->synth->setOutputGain(gain);
|
||||
}
|
||||
|
||||
float mt32emu_get_output_gain(mt32emu_const_context context) {
|
||||
return context->synth->getOutputGain();
|
||||
}
|
||||
|
||||
void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain) {
|
||||
context->synth->setReverbOutputGain(gain);
|
||||
}
|
||||
|
||||
float mt32emu_get_reverb_output_gain(mt32emu_const_context context) {
|
||||
return context->synth->getReverbOutputGain();
|
||||
}
|
||||
|
||||
void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
|
||||
context->synth->setReversedStereoEnabled(enabled != MT32EMU_BOOL_FALSE);
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context) {
|
||||
return context->synth->isReversedStereoEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len) {
|
||||
context->synth->render(stream, len);
|
||||
}
|
||||
|
||||
void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len) {
|
||||
context->synth->render(stream, len);
|
||||
}
|
||||
|
||||
void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len) {
|
||||
context->synth->renderStreams(*reinterpret_cast<const DACOutputStreams<Bit16s> *>(streams), len);
|
||||
}
|
||||
|
||||
void mt32emu_render_float_streams(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len) {
|
||||
context->synth->renderStreams(*reinterpret_cast<const DACOutputStreams<float> *>(streams), len);
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_has_active_partials(mt32emu_const_context context) {
|
||||
return context->synth->hasActivePartials() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
mt32emu_boolean mt32emu_is_active(mt32emu_const_context context) {
|
||||
return context->synth->isActive() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_get_partial_count(mt32emu_const_context context) {
|
||||
return context->synth->getPartialCount();
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context) {
|
||||
return context->synth->getPartStates();
|
||||
}
|
||||
|
||||
void mt32emu_get_partial_states(mt32emu_const_context context, mt32emu_bit8u *partial_states) {
|
||||
context->synth->getPartialStates(partial_states);
|
||||
}
|
||||
|
||||
mt32emu_bit32u mt32emu_get_playing_notes(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities) {
|
||||
return context->synth->getPlayingNotes(part_number, keys, velocities);
|
||||
}
|
||||
|
||||
const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number) {
|
||||
return context->synth->getPatchName(part_number);
|
||||
}
|
||||
|
||||
void mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data) {
|
||||
context->synth->readMemory(addr, len, data);
|
||||
}
|
||||
|
||||
} // extern "C"
|
362
audio/softsynth/mt32/c_interface/c_interface.h
Executable file
362
audio/softsynth/mt32/c_interface/c_interface.h
Executable file
|
@ -0,0 +1,362 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_C_INTERFACE_H
|
||||
#define MT32EMU_C_INTERFACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "c_types.h"
|
||||
|
||||
#undef MT32EMU_EXPORT
|
||||
#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* == Context-independent functions == */
|
||||
|
||||
/* === Interface handling === */
|
||||
|
||||
/** Returns mt32emu_service_i interface. */
|
||||
MT32EMU_EXPORT const mt32emu_service_i mt32emu_get_service_i();
|
||||
|
||||
#if MT32EMU_EXPORTS_TYPE == 2
|
||||
#undef MT32EMU_EXPORT
|
||||
#define MT32EMU_EXPORT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the version ID of mt32emu_report_handler_i interface the library has been compiled with.
|
||||
* This allows a client to fall-back gracefully instead of silently not receiving expected event reports.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_report_handler_version mt32emu_get_supported_report_handler_version();
|
||||
|
||||
/**
|
||||
* Returns the version ID of mt32emu_midi_receiver_version_i interface the library has been compiled with.
|
||||
* This allows a client to fall-back gracefully instead of silently not receiving expected MIDI messages.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version();
|
||||
|
||||
/**
|
||||
* Returns library version as an integer in format: 0x00MMmmpp, where:
|
||||
* MM - major version number
|
||||
* mm - minor version number
|
||||
* pp - patch number
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_library_version_int();
|
||||
|
||||
/**
|
||||
* Returns library version as a C-string in format: "MAJOR.MINOR.PATCH".
|
||||
*/
|
||||
MT32EMU_EXPORT const char *mt32emu_get_library_version_string();
|
||||
|
||||
/**
|
||||
* Returns output sample rate used in emulation of stereo analog circuitry of hardware units for particular analog_output_mode.
|
||||
* See comment for mt32emu_analog_output_mode.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode);
|
||||
|
||||
/* == Context-dependent functions == */
|
||||
|
||||
/** Initialises a new emulation context and installs custom report handler if non-NULL. */
|
||||
MT32EMU_EXPORT mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data);
|
||||
|
||||
/** Closes and destroys emulation context. */
|
||||
MT32EMU_EXPORT void mt32emu_free_context(mt32emu_context context);
|
||||
|
||||
/**
|
||||
* Adds new ROM identified by its SHA1 digest to the emulation context replacing previously added ROM of the same type if any.
|
||||
* Argument sha1_digest can be NULL, in this case the digest will be computed using the actual ROM data.
|
||||
* If sha1_digest is set to non-NULL, it is assumed being correct and will not be recomputed.
|
||||
* This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth().
|
||||
* Returns positive value upon success.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest);
|
||||
|
||||
/**
|
||||
* Loads a ROM file, identify it by SHA1 digest, and adds it to the emulation context replacing previously added ROM of the same type if any.
|
||||
* This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth().
|
||||
* Returns positive value upon success.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename);
|
||||
|
||||
/**
|
||||
* Fills in mt32emu_rom_info structure with identifiers and descriptions of control and PCM ROM files identified and added to the synth context.
|
||||
* If one of the ROM files is not loaded and identified yet, NULL is returned in the corresponding fields of the mt32emu_rom_info structure.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info);
|
||||
|
||||
/**
|
||||
* Allows to override the default maximum number of partials playing simultaneously within the emulation session.
|
||||
* This function doesn't immediately change the state of already opened synth. Newly set vale will take effect upon next call of mt32emu_open_synth().
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count);
|
||||
|
||||
/**
|
||||
* Allows to override the default mode for emulation of analogue circuitry of the hardware units within the emulation session.
|
||||
* This function doesn't immediately change the state of already opened synth. Newly set vale will take effect upon next call of mt32emu_open_synth().
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode);
|
||||
|
||||
/**
|
||||
* Prepares the emulation context to receive MIDI messages and produce output audio data using aforehand added set of ROMs,
|
||||
* and optionally set the maximum partial count and the analog output mode.
|
||||
* Returns MT32EMU_RC_OK upon success.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context);
|
||||
|
||||
/** Closes the emulation context freeing allocated resources. Added ROMs remain unaffected and ready for reuse. */
|
||||
MT32EMU_EXPORT void mt32emu_close_synth(mt32emu_const_context context);
|
||||
|
||||
/** Returns true if the synth is in completely initialized state, otherwise returns false. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_open(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Returns actual output sample rate used in emulation of stereo analog circuitry of hardware units.
|
||||
* See comment for mt32emu_analog_output_mode.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context);
|
||||
|
||||
/** All the enqueued events are processed by the synth immediately. */
|
||||
MT32EMU_EXPORT void mt32emu_flush_midi_queue(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified.
|
||||
* The queue is flushed before reallocation.
|
||||
* Returns the actual queue size being used.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size);
|
||||
|
||||
/**
|
||||
* Installs custom MIDI receiver object intended for receiving MIDI messages generated by MIDI stream parser.
|
||||
* MIDI stream parser is involved when functions mt32emu_parse_stream() and mt32emu_play_short_message() or the likes are called.
|
||||
* By default, parsed short MIDI messages and System Exclusive messages are sent to the synth input MIDI queue.
|
||||
* This function allows to override default behaviour. If midi_receiver argument is set to NULL, the default behaviour is restored.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data);
|
||||
|
||||
/* Enqueues a MIDI event for subsequent playback.
|
||||
* The MIDI event will be processed not before the specified timestamp.
|
||||
* The timestamp is measured as the global rendered sample count since the synth was created (at the native sample rate 32000 Hz).
|
||||
* The minimum delay involves emulation of the delay introduced while the event is transferred via MIDI interface
|
||||
* and emulation of the MCU busy-loop while it frees partials for use by a new Poly.
|
||||
* Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread.
|
||||
* onMIDIQueueOverflow callback is invoked when the MIDI event queue is full and the message cannot be enqueued.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses a block of raw MIDI bytes and enqueues parsed MIDI messages for further processing ASAP.
|
||||
* SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages.
|
||||
* When a System Realtime MIDI message is parsed, onMIDISystemRealtime callback is invoked.
|
||||
* NOTE: the total length of a SysEx message being fragmented shall not exceed MT32EMU_MAX_STREAM_BUFFER_SIZE (32768 bytes).
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length);
|
||||
|
||||
/**
|
||||
* Parses a block of raw MIDI bytes and enqueues parsed MIDI messages to play at specified time.
|
||||
* SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages.
|
||||
* When a System Realtime MIDI message is parsed, onMIDISystemRealtime callback is invoked.
|
||||
* NOTE: the total length of a SysEx message being fragmented shall not exceed MT32EMU_MAX_STREAM_BUFFER_SIZE (32768 bytes).
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_parse_stream_at(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp);
|
||||
|
||||
/**
|
||||
* Enqueues a single mt32emu_bit32u-encoded short MIDI message with full processing ASAP.
|
||||
* The short MIDI message may contain no status byte, the running status is used in this case.
|
||||
* When the argument is a System Realtime MIDI message, onMIDISystemRealtime callback is invoked.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_play_short_message(mt32emu_const_context context, mt32emu_bit32u message);
|
||||
|
||||
/**
|
||||
* Enqueues a single mt32emu_bit32u-encoded short MIDI message to play at specified time with full processing.
|
||||
* The short MIDI message may contain no status byte, the running status is used in this case.
|
||||
* When the argument is a System Realtime MIDI message, onMIDISystemRealtime callback is invoked.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_play_short_message_at(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp);
|
||||
|
||||
/** Enqueues a single short MIDI message to be processed ASAP. The message must contain a status byte. */
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_play_msg(mt32emu_const_context context, mt32emu_bit32u msg);
|
||||
/** Enqueues a single well formed System Exclusive MIDI message to be processed ASAP. */
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len);
|
||||
|
||||
/** Enqueues a single short MIDI message to play at specified time. The message must contain a status byte. */
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_play_msg_at(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp);
|
||||
/** Enqueues a single well formed System Exclusive MIDI message to play at specified time. */
|
||||
MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp);
|
||||
|
||||
/* WARNING:
|
||||
* The methods below don't ensure minimum 1-sample delay between sequential MIDI events,
|
||||
* and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent.
|
||||
* A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte.
|
||||
* See the WARNING above.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_play_msg_now(mt32emu_const_context context, mt32emu_bit32u msg);
|
||||
/**
|
||||
* Sends unpacked short MIDI message to the synth for immediate playback. The message must contain a status byte.
|
||||
* See the WARNING above.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_play_msg_on_part(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity);
|
||||
|
||||
/**
|
||||
* Sends a single well formed System Exclusive MIDI message for immediate processing. The length is in bytes.
|
||||
* See the WARNING above.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_play_sysex_now(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len);
|
||||
/**
|
||||
* Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes.
|
||||
* See the WARNING above.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_write_sysex(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len);
|
||||
|
||||
/** Allows to disable wet reverb output altogether. */
|
||||
MT32EMU_EXPORT void mt32emu_set_reverb_enabled(mt32emu_const_context context, const mt32emu_boolean reverb_enabled);
|
||||
/** Returns whether wet reverb output is enabled. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reverb_enabled(mt32emu_const_context context);
|
||||
/**
|
||||
* Sets override reverb mode. In this mode, emulation ignores sysexes (or the related part of them) which control the reverb parameters.
|
||||
* This mode is in effect until it is turned off. When the synth is re-opened, the override mode is unchanged but the state
|
||||
* of the reverb model is reset to default.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_reverb_overridden(mt32emu_const_context context, const mt32emu_boolean reverb_overridden);
|
||||
/** Returns whether reverb settings are overridden. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reverb_overridden(mt32emu_const_context context);
|
||||
/**
|
||||
* Forces reverb model compatibility mode. By default, the compatibility mode corresponds to the used control ROM version.
|
||||
* Invoking this method with the argument set to true forces emulation of old MT-32 reverb circuit.
|
||||
* When the argument is false, emulation of the reverb circuit used in new generation of MT-32 compatible modules is enforced
|
||||
* (these include CM-32L and LAPC-I).
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_reverb_compatibility_mode(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode);
|
||||
/** Returns whether reverb is in old MT-32 compatibility mode. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu_const_context context);
|
||||
/** Returns whether default reverb compatibility mode is the old MT-32 compatibility mode. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context);
|
||||
|
||||
/** Sets new DAC input mode. See mt32emu_dac_input_mode for details. */
|
||||
MT32EMU_EXPORT void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode);
|
||||
/** Returns current DAC input mode. See mt32emu_dac_input_mode for details. */
|
||||
MT32EMU_EXPORT mt32emu_dac_input_mode mt32emu_get_dac_input_mode(mt32emu_const_context context);
|
||||
|
||||
/** Sets new MIDI delay mode. See mt32emu_midi_delay_mode for details. */
|
||||
MT32EMU_EXPORT void mt32emu_set_midi_delay_mode(mt32emu_const_context context, const mt32emu_midi_delay_mode mode);
|
||||
/** Returns current MIDI delay mode. See mt32emu_midi_delay_mode for details. */
|
||||
MT32EMU_EXPORT mt32emu_midi_delay_mode mt32emu_get_midi_delay_mode(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume,
|
||||
* it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with mt32emu_set_reverb_output_gain()
|
||||
* it offers to the user a capability to control the gain of reverb and non-reverb output channels independently.
|
||||
* Ignored in MT32EMU_DAC_PURE mode.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_output_gain(mt32emu_const_context context, float gain);
|
||||
/** Returns current output gain factor for synth output channels. */
|
||||
MT32EMU_EXPORT float mt32emu_get_output_gain(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output
|
||||
* analog circuitry of the hardware units. However, together with mt32emu_set_output_gain() it offers to the user a capability
|
||||
* to control the gain of reverb and non-reverb output channels independently.
|
||||
*
|
||||
* Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely
|
||||
* corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic,
|
||||
* there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68
|
||||
* of that for LA32 analogue output. This factor is applied to the reverb output gain.
|
||||
* Ignored in MT32EMU_DAC_PURE mode.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain);
|
||||
/** Returns current output gain factor for reverb wet output channels. */
|
||||
MT32EMU_EXPORT float mt32emu_get_reverb_output_gain(mt32emu_const_context context);
|
||||
|
||||
/** Swaps left and right output channels. */
|
||||
MT32EMU_EXPORT void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
|
||||
/** Returns whether left and right output channels are swapped. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Renders samples to the specified output stream as if they were sampled at the analog stereo output.
|
||||
* When mt32emu_analog_output_mode is set to ACCURATE (OVERSAMPLED), the output signal is upsampled to 48 (96) kHz in order
|
||||
* to retain emulation accuracy in whole audible frequency spectra. Otherwise, native digital signal sample rate is retained.
|
||||
* mt32emu_get_actual_stereo_output_samplerate() can be used to query actual sample rate of the output signal.
|
||||
* The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes). Uses NATIVE byte ordering.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len);
|
||||
/** Same as above but outputs to a float stereo stream. */
|
||||
MT32EMU_EXPORT void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len);
|
||||
|
||||
/**
|
||||
* Renders samples to the specified output streams as if they appeared at the DAC entrance.
|
||||
* No further processing performed in analog circuitry emulation is applied to the signal.
|
||||
* NULL may be specified in place of any or all of the stream buffers to skip it.
|
||||
* The length is in samples, not bytes. Uses NATIVE byte ordering.
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len);
|
||||
/** Same as above but outputs to float streams. */
|
||||
MT32EMU_EXPORT void mt32emu_render_float_streams(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len);
|
||||
|
||||
/** Returns true when there is at least one active partial, otherwise false. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_has_active_partials(mt32emu_const_context context);
|
||||
|
||||
/** Returns true if mt32emu_has_active_partials() returns true, or reverb is (somewhat unreliably) detected as being active. */
|
||||
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_active(mt32emu_const_context context);
|
||||
|
||||
/** Returns the maximum number of partials playing simultaneously. */
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_partial_count(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Returns current states of all the parts as a bit set. The least significant bit corresponds to the state of part 1,
|
||||
* total of 9 bits hold the states of all the parts. If the returned bit for a part is set, there is at least one active
|
||||
* non-releasing partial playing on this part. This info is useful in emulating behaviour of LCD display of the hardware units.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context);
|
||||
|
||||
/**
|
||||
* Fills in current states of all the partials into the array provided. Each byte in the array holds states of 4 partials
|
||||
* starting from the least significant bits. The state of each partial is packed in a pair of bits.
|
||||
* The array must be large enough to accommodate states of all the partials.
|
||||
* @see getPartialCount()
|
||||
*/
|
||||
MT32EMU_EXPORT void mt32emu_get_partial_states(mt32emu_const_context context, mt32emu_bit8u *partial_states);
|
||||
|
||||
/**
|
||||
* Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough
|
||||
* to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials.
|
||||
* Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
|
||||
* Returns the number of currently playing notes on the specified part.
|
||||
*/
|
||||
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_playing_notes(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities);
|
||||
|
||||
/**
|
||||
* Returns name of the patch set on the specified part.
|
||||
* Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
|
||||
*/
|
||||
MT32EMU_EXPORT const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number);
|
||||
|
||||
/** Stores internal state of emulated synth into an array provided (as it would be acquired from hardware). */
|
||||
MT32EMU_EXPORT void mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef MT32EMU_C_INTERFACE_H */
|
298
audio/softsynth/mt32/c_interface/c_types.h
Executable file
298
audio/softsynth/mt32/c_interface/c_types.h
Executable file
|
@ -0,0 +1,298 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_C_TYPES_H
|
||||
#define MT32EMU_C_TYPES_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../globals.h"
|
||||
|
||||
#define MT32EMU_C_ENUMERATIONS
|
||||
#include "../Enumerations.h"
|
||||
#undef MT32EMU_C_ENUMERATIONS
|
||||
|
||||
typedef unsigned int mt32emu_bit32u;
|
||||
typedef signed int mt32emu_bit32s;
|
||||
typedef unsigned short int mt32emu_bit16u;
|
||||
typedef signed short int mt32emu_bit16s;
|
||||
typedef unsigned char mt32emu_bit8u;
|
||||
typedef signed char mt32emu_bit8s;
|
||||
|
||||
typedef char mt32emu_sha1_digest[41];
|
||||
|
||||
typedef enum {
|
||||
MT32EMU_BOOL_FALSE, MT32EMU_BOOL_TRUE
|
||||
} mt32emu_boolean;
|
||||
|
||||
typedef enum {
|
||||
/* Operation completed normally. */
|
||||
MT32EMU_RC_OK = 0,
|
||||
MT32EMU_RC_ADDED_CONTROL_ROM = 1,
|
||||
MT32EMU_RC_ADDED_PCM_ROM = 2,
|
||||
|
||||
/* Definite error occurred. */
|
||||
MT32EMU_RC_ROM_NOT_IDENTIFIED = -1,
|
||||
MT32EMU_RC_FILE_NOT_FOUND = -2,
|
||||
MT32EMU_RC_FILE_NOT_LOADED = -3,
|
||||
MT32EMU_RC_MISSING_ROMS = -4,
|
||||
MT32EMU_RC_NOT_OPENED = -5,
|
||||
MT32EMU_RC_QUEUE_FULL = -6,
|
||||
|
||||
/* Undefined error occurred. */
|
||||
MT32EMU_RC_FAILED = -100
|
||||
} mt32emu_return_code;
|
||||
|
||||
/** Emulation context */
|
||||
typedef struct mt32emu_data *mt32emu_context;
|
||||
typedef const struct mt32emu_data *mt32emu_const_context;
|
||||
|
||||
/* Convenience aliases */
|
||||
#ifndef __cplusplus
|
||||
typedef enum mt32emu_analog_output_mode mt32emu_analog_output_mode;
|
||||
typedef enum mt32emu_dac_input_mode mt32emu_dac_input_mode;
|
||||
typedef enum mt32emu_midi_delay_mode mt32emu_midi_delay_mode;
|
||||
typedef enum mt32emu_partial_state mt32emu_partial_state;
|
||||
#endif
|
||||
|
||||
/** Contains identifiers and descriptions of ROM files being used. */
|
||||
typedef struct {
|
||||
const char *control_rom_id;
|
||||
const char *control_rom_description;
|
||||
const char *control_rom_sha1_digest;
|
||||
const char *pcm_rom_id;
|
||||
const char *pcm_rom_description;
|
||||
const char *pcm_rom_sha1_digest;
|
||||
} mt32emu_rom_info;
|
||||
|
||||
/** Set of multiplexed output bit16s streams appeared at the DAC entrance. */
|
||||
typedef struct {
|
||||
mt32emu_bit16s *nonReverbLeft;
|
||||
mt32emu_bit16s *nonReverbRight;
|
||||
mt32emu_bit16s *reverbDryLeft;
|
||||
mt32emu_bit16s *reverbDryRight;
|
||||
mt32emu_bit16s *reverbWetLeft;
|
||||
mt32emu_bit16s *reverbWetRight;
|
||||
} mt32emu_dac_output_bit16s_streams;
|
||||
|
||||
/** Set of multiplexed output float streams appeared at the DAC entrance. */
|
||||
typedef struct {
|
||||
float *nonReverbLeft;
|
||||
float *nonReverbRight;
|
||||
float *reverbDryLeft;
|
||||
float *reverbDryRight;
|
||||
float *reverbWetLeft;
|
||||
float *reverbWetRight;
|
||||
} mt32emu_dac_output_float_streams;
|
||||
|
||||
/* === Interface handling === */
|
||||
|
||||
/** Report handler interface versions */
|
||||
typedef enum {
|
||||
MT32EMU_REPORT_HANDLER_VERSION_0 = 0,
|
||||
MT32EMU_REPORT_HANDLER_VERSION_CURRENT = MT32EMU_REPORT_HANDLER_VERSION_0
|
||||
} mt32emu_report_handler_version;
|
||||
|
||||
/** MIDI receiver interface versions */
|
||||
typedef enum {
|
||||
MT32EMU_MIDI_RECEIVER_VERSION_0 = 0,
|
||||
MT32EMU_MIDI_RECEIVER_VERSION_CURRENT = MT32EMU_MIDI_RECEIVER_VERSION_0
|
||||
} mt32emu_midi_receiver_version;
|
||||
|
||||
/** Synth interface versions */
|
||||
typedef enum {
|
||||
MT32EMU_SERVICE_VERSION_0 = 0,
|
||||
MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_0
|
||||
} mt32emu_service_version;
|
||||
|
||||
/* === Report Handler Interface === */
|
||||
|
||||
typedef union mt32emu_report_handler_i mt32emu_report_handler_i;
|
||||
|
||||
/** Interface for handling reported events (initial version) */
|
||||
typedef struct {
|
||||
/** Returns the actual interface version ID */
|
||||
mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i);
|
||||
|
||||
/** Callback for debug messages, in vprintf() format */
|
||||
void (*printDebug)(void *instance_data, const char *fmt, va_list list);
|
||||
/** Callbacks for reporting errors */
|
||||
void (*onErrorControlROM)(void *instance_data);
|
||||
void (*onErrorPCMROM)(void *instance_data);
|
||||
/** Callback for reporting about displaying a new custom message on LCD */
|
||||
void (*showLCDMessage)(void *instance_data, const char *message);
|
||||
/** Callback for reporting actual processing of a MIDI message */
|
||||
void (*onMIDIMessagePlayed)(void *instance_data);
|
||||
/**
|
||||
* Callback for reporting an overflow of the input MIDI queue.
|
||||
* Returns MT32EMU_BOOL_TRUE if a recovery action was taken
|
||||
* and yet another attempt to enqueue the MIDI event is desired.
|
||||
*/
|
||||
mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data);
|
||||
/**
|
||||
* Callback invoked when a System Realtime MIDI message is detected in functions
|
||||
* mt32emu_parse_stream and mt32emu_play_short_message and the likes.
|
||||
*/
|
||||
void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime);
|
||||
/** Callbacks for reporting system events */
|
||||
void (*onDeviceReset)(void *instance_data);
|
||||
void (*onDeviceReconfig)(void *instance_data);
|
||||
/** Callbacks for reporting changes of reverb settings */
|
||||
void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode);
|
||||
void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time);
|
||||
void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level);
|
||||
/** Callbacks for reporting various information */
|
||||
void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num);
|
||||
void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name);
|
||||
} mt32emu_report_handler_i_v0;
|
||||
|
||||
/**
|
||||
* Extensible interface for handling reported events.
|
||||
* Union intended to view an interface of any subsequent version as any parent interface not requiring a cast.
|
||||
* Elements are to be addressed using the tag of the interface version when they were introduced.
|
||||
*/
|
||||
union mt32emu_report_handler_i {
|
||||
const mt32emu_report_handler_i_v0 *v0;
|
||||
};
|
||||
|
||||
/* === MIDI Receiver Interface === */
|
||||
|
||||
typedef union mt32emu_midi_receiver_i mt32emu_midi_receiver_i;
|
||||
|
||||
/** Interface for receiving MIDI messages generated by MIDI stream parser (initial version) */
|
||||
typedef struct {
|
||||
/** Returns the actual interface version ID */
|
||||
mt32emu_midi_receiver_version (*getVersionID)(mt32emu_midi_receiver_i i);
|
||||
|
||||
/** Invoked when a complete short MIDI message is parsed in the input MIDI stream. */
|
||||
void (*handleShortMessage)(void *instance_data, const mt32emu_bit32u message);
|
||||
|
||||
/** Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream. */
|
||||
void (*handleSysex)(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length);
|
||||
|
||||
/** Invoked when a System Realtime MIDI message is parsed in the input MIDI stream. */
|
||||
void (*handleSystemRealtimeMessage)(void *instance_data, const mt32emu_bit8u realtime);
|
||||
} mt32emu_midi_receiver_i_v0;
|
||||
|
||||
/**
|
||||
* Extensible interface for receiving MIDI messages.
|
||||
* Union intended to view an interface of any subsequent version as any parent interface not requiring a cast.
|
||||
* Elements are to be addressed using the tag of the interface version when they were introduced.
|
||||
*/
|
||||
union mt32emu_midi_receiver_i {
|
||||
const mt32emu_midi_receiver_i_v0 *v0;
|
||||
};
|
||||
|
||||
/* === Service Interface === */
|
||||
|
||||
typedef union mt32emu_service_i mt32emu_service_i;
|
||||
|
||||
/**
|
||||
* Basic interface that defines all the library services (initial version).
|
||||
* The members closely resemble C functions declared in c_interface.h, and the intention is to provide for easier
|
||||
* access when the library is dynamically loaded in run-time, e.g. as a plugin. This way the client only needs
|
||||
* to bind to mt32emu_get_service_i() function instead of binding to each function it needs to use.
|
||||
* See c_interface.h for parameter description.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Returns the actual interface version ID */
|
||||
mt32emu_service_version (*getVersionID)(mt32emu_service_i i);
|
||||
mt32emu_report_handler_version (*getSupportedReportHandlerVersionID)();
|
||||
mt32emu_midi_receiver_version (*getSupportedMIDIReceiverVersionID)();
|
||||
|
||||
mt32emu_bit32u (*getLibraryVersionInt)();
|
||||
const char *(*getLibraryVersionString)();
|
||||
|
||||
mt32emu_bit32u (*getStereoOutputSamplerate)(const mt32emu_analog_output_mode analog_output_mode);
|
||||
|
||||
mt32emu_context (*createContext)(mt32emu_report_handler_i report_handler, void *instance_data);
|
||||
void (*freeContext)(mt32emu_context context);
|
||||
mt32emu_return_code (*addROMData)(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest);
|
||||
mt32emu_return_code (*addROMFile)(mt32emu_context context, const char *filename);
|
||||
void (*getROMInfo)(mt32emu_const_context context, mt32emu_rom_info *rom_info);
|
||||
void (*setPartialCount)(mt32emu_context context, const mt32emu_bit32u partial_count);
|
||||
void (*setAnalogOutputMode)(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode);
|
||||
mt32emu_return_code (*openSynth)(mt32emu_const_context context);
|
||||
void (*closeSynth)(mt32emu_const_context context);
|
||||
mt32emu_boolean (*isOpen)(mt32emu_const_context context);
|
||||
mt32emu_bit32u (*getActualStereoOutputSamplerate)(mt32emu_const_context context);
|
||||
void (*flushMIDIQueue)(mt32emu_const_context context);
|
||||
mt32emu_bit32u (*setMIDIEventQueueSize)(mt32emu_const_context context, const mt32emu_bit32u queue_size);
|
||||
void (*setMIDIReceiver)(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data);
|
||||
|
||||
void (*parseStream)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length);
|
||||
void (*parseStream_At)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp);
|
||||
void (*playShortMessage)(mt32emu_const_context context, mt32emu_bit32u message);
|
||||
void (*playShortMessageAt)(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp);
|
||||
mt32emu_return_code (*playMsg)(mt32emu_const_context context, mt32emu_bit32u msg);
|
||||
mt32emu_return_code (*playSysex)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len);
|
||||
mt32emu_return_code (*playMsgAt)(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp);
|
||||
mt32emu_return_code (*playSysexAt)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp);
|
||||
|
||||
void (*playMsgNow)(mt32emu_const_context context, mt32emu_bit32u msg);
|
||||
void (*playMsgOnPart)(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity);
|
||||
void (*playSysexNow)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len);
|
||||
void (*writeSysex)(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len);
|
||||
|
||||
void (*setReverbEnabled)(mt32emu_const_context context, const mt32emu_boolean reverb_enabled);
|
||||
mt32emu_boolean (*isReverbEnabled)(mt32emu_const_context context);
|
||||
void (*setReverbOverridden)(mt32emu_const_context context, const mt32emu_boolean reverb_overridden);
|
||||
mt32emu_boolean (*isReverbOverridden)(mt32emu_const_context context);
|
||||
void (*setReverbCompatibilityMode)(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode);
|
||||
mt32emu_boolean (*isMT32ReverbCompatibilityMode)(mt32emu_const_context context);
|
||||
mt32emu_boolean (*isDefaultReverbMT32Compatible)(mt32emu_const_context context);
|
||||
|
||||
void (*setDACInputMode)(mt32emu_const_context context, const mt32emu_dac_input_mode mode);
|
||||
mt32emu_dac_input_mode (*getDACInputMode)(mt32emu_const_context context);
|
||||
|
||||
void (*setMIDIDelayMode)(mt32emu_const_context context, const mt32emu_midi_delay_mode mode);
|
||||
mt32emu_midi_delay_mode (*getMIDIDelayMode)(mt32emu_const_context context);
|
||||
|
||||
void (*setOutputGain)(mt32emu_const_context context, float gain);
|
||||
float (*getOutputGain)(mt32emu_const_context context);
|
||||
void (*setReverbOutputGain)(mt32emu_const_context context, float gain);
|
||||
float (*getReverbOutputGain)(mt32emu_const_context context);
|
||||
|
||||
void (*setReversedStereoEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled);
|
||||
mt32emu_boolean (*isReversedStereoEnabled)(mt32emu_const_context context);
|
||||
|
||||
void (*renderBit16s)(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len);
|
||||
void (*renderFloat)(mt32emu_const_context context, float *stream, mt32emu_bit32u len);
|
||||
void (*renderBit16sStreams)(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len);
|
||||
void (*renderFloatStreams)(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len);
|
||||
|
||||
mt32emu_boolean (*hasActivePartials)(mt32emu_const_context context);
|
||||
mt32emu_boolean (*isActive)(mt32emu_const_context context);
|
||||
mt32emu_bit32u (*getPartialCount)(mt32emu_const_context context);
|
||||
mt32emu_bit32u (*getPartStates)(mt32emu_const_context context);
|
||||
void (*getPartialStates)(mt32emu_const_context context, mt32emu_bit8u *partial_states);
|
||||
mt32emu_bit32u (*getPlayingNotes)(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities);
|
||||
const char *(*getPatchName)(mt32emu_const_context context, mt32emu_bit8u part_number);
|
||||
void (*readMemory)(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data);
|
||||
} mt32emu_service_i_v0;
|
||||
|
||||
/**
|
||||
* Extensible interface for all the library services.
|
||||
* Union intended to view an interface of any subsequent version as any parent interface not requiring a cast.
|
||||
* Elements are to be addressed using the tag of the interface version when they were introduced.
|
||||
*/
|
||||
union mt32emu_service_i {
|
||||
const mt32emu_service_i_v0 *v0;
|
||||
};
|
||||
|
||||
#endif /* #ifndef MT32EMU_C_TYPES_H */
|
436
audio/softsynth/mt32/c_interface/cpp_interface.h
Executable file
436
audio/softsynth/mt32/c_interface/cpp_interface.h
Executable file
|
@ -0,0 +1,436 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_CPP_INTERFACE_H
|
||||
#define MT32EMU_CPP_INTERFACE_H
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "c_types.h"
|
||||
|
||||
#include "../Types.h"
|
||||
#include "../Enumerations.h"
|
||||
|
||||
#if MT32EMU_API_TYPE == 2
|
||||
|
||||
#define mt32emu_get_supported_report_handler_version i.v0->getSupportedReportHandlerVersionID
|
||||
#define mt32emu_get_supported_midi_receiver_version i.v0->getSupportedMIDIReceiverVersionID
|
||||
#define mt32emu_get_library_version_int i.v0->getLibraryVersionInt
|
||||
#define mt32emu_get_library_version_string i.v0->getLibraryVersionString
|
||||
#define mt32emu_get_stereo_output_samplerate i.v0->getStereoOutputSamplerate
|
||||
#define mt32emu_create_context i.v0->createContext
|
||||
#define mt32emu_free_context i.v0->freeContext
|
||||
#define mt32emu_add_rom_data i.v0->addROMData
|
||||
#define mt32emu_add_rom_file i.v0->addROMFile
|
||||
#define mt32emu_get_rom_info i.v0->getROMInfo
|
||||
#define mt32emu_set_partial_count i.v0->setPartialCount
|
||||
#define mt32emu_set_analog_output_mode i.v0->setAnalogOutputMode
|
||||
#define mt32emu_open_synth i.v0->openSynth
|
||||
#define mt32emu_close_synth i.v0->closeSynth
|
||||
#define mt32emu_is_open i.v0->isOpen
|
||||
#define mt32emu_get_actual_stereo_output_samplerate i.v0->getActualStereoOutputSamplerate
|
||||
#define mt32emu_flush_midi_queue i.v0->flushMIDIQueue
|
||||
#define mt32emu_set_midi_event_queue_size i.v0->setMIDIEventQueueSize
|
||||
#define mt32emu_set_midi_receiver i.v0->setMIDIReceiver
|
||||
#define mt32emu_parse_stream i.v0->parseStream
|
||||
#define mt32emu_parse_stream_at i.v0->parseStream_At
|
||||
#define mt32emu_play_short_message i.v0->playShortMessage
|
||||
#define mt32emu_play_short_message_at i.v0->playShortMessageAt
|
||||
#define mt32emu_play_msg i.v0->playMsg
|
||||
#define mt32emu_play_sysex i.v0->playSysex
|
||||
#define mt32emu_play_msg_at i.v0->playMsgAt
|
||||
#define mt32emu_play_sysex_at i.v0->playSysexAt
|
||||
#define mt32emu_play_msg_now i.v0->playMsgNow
|
||||
#define mt32emu_play_msg_on_part i.v0->playMsgOnPart
|
||||
#define mt32emu_play_sysex_now i.v0->playSysexNow
|
||||
#define mt32emu_write_sysex i.v0->writeSysex
|
||||
#define mt32emu_set_reverb_enabled i.v0->setReverbEnabled
|
||||
#define mt32emu_is_reverb_enabled i.v0->isReverbEnabled
|
||||
#define mt32emu_set_reverb_overridden i.v0->setReverbOverridden
|
||||
#define mt32emu_is_reverb_overridden i.v0->isReverbOverridden
|
||||
#define mt32emu_set_reverb_compatibility_mode i.v0->setReverbCompatibilityMode
|
||||
#define mt32emu_is_mt32_reverb_compatibility_mode i.v0->isMT32ReverbCompatibilityMode
|
||||
#define mt32emu_is_default_reverb_mt32_compatible i.v0->isDefaultReverbMT32Compatible
|
||||
#define mt32emu_set_dac_input_mode i.v0->setDACInputMode
|
||||
#define mt32emu_get_dac_input_mode i.v0->getDACInputMode
|
||||
#define mt32emu_set_midi_delay_mode i.v0->setMIDIDelayMode
|
||||
#define mt32emu_get_midi_delay_mode i.v0->getMIDIDelayMode
|
||||
#define mt32emu_set_output_gain i.v0->setOutputGain
|
||||
#define mt32emu_get_output_gain i.v0->getOutputGain
|
||||
#define mt32emu_set_reverb_output_gain i.v0->setReverbOutputGain
|
||||
#define mt32emu_get_reverb_output_gain i.v0->getReverbOutputGain
|
||||
#define mt32emu_set_reversed_stereo_enabled i.v0->setReversedStereoEnabled
|
||||
#define mt32emu_is_reversed_stereo_enabled i.v0->isReversedStereoEnabled
|
||||
#define mt32emu_render_bit16s i.v0->renderBit16s
|
||||
#define mt32emu_render_float i.v0->renderFloat
|
||||
#define mt32emu_render_bit16s_streams i.v0->renderBit16sStreams
|
||||
#define mt32emu_render_float_streams i.v0->renderFloatStreams
|
||||
#define mt32emu_has_active_partials i.v0->hasActivePartials
|
||||
#define mt32emu_is_active i.v0->isActive
|
||||
#define mt32emu_get_partial_count i.v0->getPartialCount
|
||||
#define mt32emu_get_part_states i.v0->getPartStates
|
||||
#define mt32emu_get_partial_states i.v0->getPartialStates
|
||||
#define mt32emu_get_playing_notes i.v0->getPlayingNotes
|
||||
#define mt32emu_get_patch_name i.v0->getPatchName
|
||||
#define mt32emu_read_memory i.v0->readMemory
|
||||
|
||||
#else // #if MT32EMU_API_TYPE == 2
|
||||
|
||||
#include "c_interface.h"
|
||||
|
||||
#endif // #if MT32EMU_API_TYPE == 2
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
namespace CppInterfaceImpl {
|
||||
|
||||
static const mt32emu_report_handler_i NULL_REPORT_HANDLER = { NULL };
|
||||
static mt32emu_report_handler_i getReportHandlerThunk();
|
||||
static mt32emu_midi_receiver_i getMidiReceiverThunk();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The classes below correspond to the interfaces defined in c_types.h and provided for convenience when using C++.
|
||||
* The approach used makes no assumption of any internal class data memory layout, since the C++ standard does not
|
||||
* provide any detail in this area and leaves it up to the implementation. Therefore, this way portability is guaranteed,
|
||||
* despite the implementation may be a little inefficient.
|
||||
* See c_types.h and c_interface.h for description of the corresponding interface methods.
|
||||
*/
|
||||
|
||||
// Defines the interface for handling reported events.
|
||||
// Corresponds to the current version of mt32emu_report_handler_i interface.
|
||||
class IReportHandler {
|
||||
public:
|
||||
virtual void printDebug(const char *fmt, va_list list) = 0;
|
||||
virtual void onErrorControlROM() = 0;
|
||||
virtual void onErrorPCMROM() = 0;
|
||||
virtual void showLCDMessage(const char *message) = 0;
|
||||
virtual void onMIDIMessagePlayed() = 0;
|
||||
virtual bool onMIDIQueueOverflow() = 0;
|
||||
virtual void onMIDISystemRealtime(Bit8u system_realtime) = 0;
|
||||
virtual void onDeviceReset() = 0;
|
||||
virtual void onDeviceReconfig() = 0;
|
||||
virtual void onNewReverbMode(Bit8u mode) = 0;
|
||||
virtual void onNewReverbTime(Bit8u time) = 0;
|
||||
virtual void onNewReverbLevel(Bit8u level) = 0;
|
||||
virtual void onPolyStateChanged(Bit8u part_num) = 0;
|
||||
virtual void onProgramChanged(Bit8u part_num, const char *sound_group_name, const char *patch_name) = 0;
|
||||
|
||||
protected:
|
||||
~IReportHandler() {}
|
||||
};
|
||||
|
||||
// Defines the interface for receiving MIDI messages generated by MIDI stream parser.
|
||||
// Corresponds to the current version of mt32emu_midi_receiver_i interface.
|
||||
class IMidiReceiver {
|
||||
public:
|
||||
virtual void handleShortMessage(const Bit32u message) = 0;
|
||||
virtual void handleSysex(const Bit8u stream[], const Bit32u length) = 0;
|
||||
virtual void handleSystemRealtimeMessage(const Bit8u realtime) = 0;
|
||||
|
||||
protected:
|
||||
~IMidiReceiver() {}
|
||||
};
|
||||
|
||||
// Defines all the library services.
|
||||
// Corresponds to the current version of mt32emu_service_i interface.
|
||||
class Service {
|
||||
public:
|
||||
#if MT32EMU_API_TYPE == 2
|
||||
explicit Service(mt32emu_service_i interface, mt32emu_context context = NULL) : i(interface), c(context) {}
|
||||
#else
|
||||
explicit Service(mt32emu_context context = NULL) : c(context) {}
|
||||
#endif
|
||||
~Service() { if (c != NULL) mt32emu_free_context(c); }
|
||||
|
||||
// Context-independent methods
|
||||
|
||||
#if MT32EMU_API_TYPE == 2
|
||||
mt32emu_service_version getVersionID() { return i.v0->getVersionID(i); }
|
||||
#endif
|
||||
mt32emu_report_handler_version getSupportedReportHandlerVersionID() { return mt32emu_get_supported_report_handler_version(); }
|
||||
mt32emu_midi_receiver_version getSupportedMIDIReceiverVersionID() { return mt32emu_get_supported_midi_receiver_version(); }
|
||||
|
||||
Bit32u getLibraryVersionInt() { return mt32emu_get_library_version_int(); }
|
||||
const char *getLibraryVersionString() { return mt32emu_get_library_version_string(); }
|
||||
|
||||
Bit32u getStereoOutputSamplerate(const AnalogOutputMode analog_output_mode) { return mt32emu_get_stereo_output_samplerate(static_cast<mt32emu_analog_output_mode>(analog_output_mode)); }
|
||||
|
||||
// Context-dependent methods
|
||||
|
||||
mt32emu_context getContext() { return c; }
|
||||
void createContext(mt32emu_report_handler_i report_handler = CppInterfaceImpl::NULL_REPORT_HANDLER, void *instance_data = NULL) { freeContext(); c = mt32emu_create_context(report_handler, instance_data); }
|
||||
void createContext(IReportHandler &report_handler) { createContext(CppInterfaceImpl::getReportHandlerThunk(), &report_handler); }
|
||||
void freeContext() { if (c != NULL) { mt32emu_free_context(c); c = NULL; } }
|
||||
mt32emu_return_code addROMData(const Bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest = NULL) { return mt32emu_add_rom_data(c, data, data_size, sha1_digest); }
|
||||
mt32emu_return_code addROMFile(const char *filename) { return mt32emu_add_rom_file(c, filename); }
|
||||
void getROMInfo(mt32emu_rom_info *rom_info) { mt32emu_get_rom_info(c, rom_info); }
|
||||
void setPartialCount(const Bit32u partial_count) { mt32emu_set_partial_count(c, partial_count); }
|
||||
void setAnalogOutputMode(const AnalogOutputMode analog_output_mode) { mt32emu_set_analog_output_mode(c, static_cast<mt32emu_analog_output_mode>(analog_output_mode)); }
|
||||
mt32emu_return_code openSynth() { return mt32emu_open_synth(c); }
|
||||
void closeSynth() { mt32emu_close_synth(c); }
|
||||
bool isOpen() { return mt32emu_is_open(c) != MT32EMU_BOOL_FALSE; }
|
||||
Bit32u getActualStereoOutputSamplerate() { return mt32emu_get_actual_stereo_output_samplerate(c); }
|
||||
void flushMIDIQueue() { mt32emu_flush_midi_queue(c); }
|
||||
Bit32u setMIDIEventQueueSize(const Bit32u queue_size) { return mt32emu_set_midi_event_queue_size(c, queue_size); }
|
||||
void setMIDIReceiver(mt32emu_midi_receiver_i midi_receiver, void *instance_data) { mt32emu_set_midi_receiver(c, midi_receiver, instance_data); }
|
||||
void setMIDIReceiver(IMidiReceiver &midi_receiver) { setMIDIReceiver(CppInterfaceImpl::getMidiReceiverThunk(), &midi_receiver); }
|
||||
|
||||
void parseStream(const Bit8u *stream, Bit32u length) { mt32emu_parse_stream(c, stream, length); }
|
||||
void parseStream_At(const Bit8u *stream, Bit32u length, Bit32u timestamp) { mt32emu_parse_stream_at(c, stream, length, timestamp); }
|
||||
void playShortMessage(Bit32u message) { mt32emu_play_short_message(c, message); }
|
||||
void playShortMessageAt(Bit32u message, Bit32u timestamp) { mt32emu_play_short_message_at(c, message, timestamp); }
|
||||
mt32emu_return_code playMsg(Bit32u msg) { return mt32emu_play_msg(c, msg); }
|
||||
mt32emu_return_code playSysex(const Bit8u *sysex, Bit32u len) { return mt32emu_play_sysex(c, sysex, len); }
|
||||
mt32emu_return_code playMsgAt(Bit32u msg, Bit32u timestamp) { return mt32emu_play_msg_at(c, msg, timestamp); }
|
||||
mt32emu_return_code playSysexAt(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { return mt32emu_play_sysex_at(c, sysex, len, timestamp); }
|
||||
|
||||
void playMsgNow(Bit32u msg) { mt32emu_play_msg_now(c, msg); }
|
||||
void playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) { mt32emu_play_msg_on_part(c, part, code, note, velocity); }
|
||||
void playSysexNow(const Bit8u *sysex, Bit32u len) { mt32emu_play_sysex_now(c, sysex, len); }
|
||||
void writeSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) { mt32emu_write_sysex(c, channel, sysex, len); }
|
||||
|
||||
void setReverbEnabled(const bool reverb_enabled) { mt32emu_set_reverb_enabled(c, reverb_enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
|
||||
bool isReverbEnabled() { return mt32emu_is_reverb_enabled(c) != MT32EMU_BOOL_FALSE; }
|
||||
void setReverbOverridden(const bool reverb_overridden) { mt32emu_set_reverb_overridden(c, reverb_overridden ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
|
||||
bool isReverbOverridden() { return mt32emu_is_reverb_overridden(c) != MT32EMU_BOOL_FALSE; }
|
||||
void setReverbCompatibilityMode(const bool mt32_compatible_mode) { mt32emu_set_reverb_compatibility_mode(c, mt32_compatible_mode ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
|
||||
bool isMT32ReverbCompatibilityMode() { return mt32emu_is_mt32_reverb_compatibility_mode(c) != MT32EMU_BOOL_FALSE; }
|
||||
bool isDefaultReverbMT32Compatible() { return mt32emu_is_default_reverb_mt32_compatible(c) != MT32EMU_BOOL_FALSE; }
|
||||
|
||||
void setDACInputMode(const DACInputMode mode) { mt32emu_set_dac_input_mode(c, static_cast<mt32emu_dac_input_mode>(mode)); }
|
||||
DACInputMode getDACInputMode() { return static_cast<DACInputMode>(mt32emu_get_dac_input_mode(c)); }
|
||||
|
||||
void setMIDIDelayMode(const MIDIDelayMode mode) { mt32emu_set_midi_delay_mode(c, static_cast<mt32emu_midi_delay_mode>(mode)); }
|
||||
MIDIDelayMode getMIDIDelayMode() { return static_cast<MIDIDelayMode>(mt32emu_get_midi_delay_mode(c)); }
|
||||
|
||||
void setOutputGain(float gain) { mt32emu_set_output_gain(c, gain); }
|
||||
float getOutputGain() { return mt32emu_get_output_gain(c); }
|
||||
void setReverbOutputGain(float gain) { mt32emu_set_reverb_output_gain(c, gain); }
|
||||
float getReverbOutputGain() { return mt32emu_get_reverb_output_gain(c); }
|
||||
|
||||
void setReversedStereoEnabled(const bool enabled) { mt32emu_set_reversed_stereo_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
|
||||
bool isReversedStereoEnabled() { return mt32emu_is_reversed_stereo_enabled(c) != MT32EMU_BOOL_FALSE; }
|
||||
|
||||
void renderBit16s(Bit16s *stream, Bit32u len) { mt32emu_render_bit16s(c, stream, len); }
|
||||
void renderFloat(float *stream, Bit32u len) { mt32emu_render_float(c, stream, len); }
|
||||
void renderBit16sStreams(const mt32emu_dac_output_bit16s_streams *streams, Bit32u len) { mt32emu_render_bit16s_streams(c, streams, len); }
|
||||
void renderFloatStreams(const mt32emu_dac_output_float_streams *streams, Bit32u len) { mt32emu_render_float_streams(c, streams, len); }
|
||||
|
||||
bool hasActivePartials() { return mt32emu_has_active_partials(c) != MT32EMU_BOOL_FALSE; }
|
||||
bool isActive() { return mt32emu_is_active(c) != MT32EMU_BOOL_FALSE; }
|
||||
Bit32u getPartialCount() { return mt32emu_get_partial_count(c); }
|
||||
Bit32u getPartStates() { return mt32emu_get_part_states(c); }
|
||||
void getPartialStates(Bit8u *partial_states) { mt32emu_get_partial_states(c, partial_states); }
|
||||
Bit32u getPlayingNotes(Bit8u part_number, Bit8u *keys, Bit8u *velocities) { return mt32emu_get_playing_notes(c, part_number, keys, velocities); }
|
||||
const char *getPatchName(Bit8u part_number) { return mt32emu_get_patch_name(c, part_number); }
|
||||
void readMemory(Bit32u addr, Bit32u len, Bit8u *data) { mt32emu_read_memory(c, addr, len, data); }
|
||||
|
||||
private:
|
||||
#if MT32EMU_API_TYPE == 2
|
||||
const mt32emu_service_i i;
|
||||
#endif
|
||||
mt32emu_context c;
|
||||
};
|
||||
|
||||
namespace CppInterfaceImpl {
|
||||
|
||||
static mt32emu_report_handler_version getReportHandlerVersionID(mt32emu_report_handler_i) {
|
||||
return MT32EMU_REPORT_HANDLER_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
static void printDebug(void *instance_data, const char *fmt, va_list list) {
|
||||
((IReportHandler *)instance_data)->printDebug(fmt, list);
|
||||
}
|
||||
|
||||
static void onErrorControlROM(void *instance_data) {
|
||||
((IReportHandler *)instance_data)->onErrorControlROM();
|
||||
}
|
||||
|
||||
static void onErrorPCMROM(void *instance_data) {
|
||||
((IReportHandler *)instance_data)->onErrorPCMROM();
|
||||
}
|
||||
|
||||
static void showLCDMessage(void *instance_data, const char *message) {
|
||||
((IReportHandler *)instance_data)->showLCDMessage(message);
|
||||
}
|
||||
|
||||
static void onMIDIMessagePlayed(void *instance_data) {
|
||||
((IReportHandler *)instance_data)->onMIDIMessagePlayed();
|
||||
}
|
||||
|
||||
static mt32emu_boolean onMIDIQueueOverflow(void *instance_data) {
|
||||
return ((IReportHandler *)instance_data)->onMIDIQueueOverflow() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
|
||||
}
|
||||
|
||||
static void onMIDISystemRealtime(void *instance_data, mt32emu_bit8u system_realtime) {
|
||||
((IReportHandler *)instance_data)->onMIDISystemRealtime(system_realtime);
|
||||
}
|
||||
|
||||
static void onDeviceReset(void *instance_data) {
|
||||
((IReportHandler *)instance_data)->onDeviceReset();
|
||||
}
|
||||
|
||||
static void onDeviceReconfig(void *instance_data) {
|
||||
((IReportHandler *)instance_data)->onDeviceReconfig();
|
||||
}
|
||||
|
||||
static void onNewReverbMode(void *instance_data, mt32emu_bit8u mode) {
|
||||
((IReportHandler *)instance_data)->onNewReverbMode(mode);
|
||||
}
|
||||
|
||||
static void onNewReverbTime(void *instance_data, mt32emu_bit8u time) {
|
||||
((IReportHandler *)instance_data)->onNewReverbTime(time);
|
||||
}
|
||||
|
||||
static void onNewReverbLevel(void *instance_data, mt32emu_bit8u level) {
|
||||
((IReportHandler *)instance_data)->onNewReverbLevel(level);
|
||||
}
|
||||
|
||||
static void onPolyStateChanged(void *instance_data, mt32emu_bit8u part_num) {
|
||||
((IReportHandler *)instance_data)->onPolyStateChanged(part_num);
|
||||
}
|
||||
|
||||
static void onProgramChanged(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name) {
|
||||
((IReportHandler *)instance_data)->onProgramChanged(part_num, sound_group_name, patch_name);
|
||||
}
|
||||
|
||||
static mt32emu_report_handler_i getReportHandlerThunk() {
|
||||
static const mt32emu_report_handler_i_v0 REPORT_HANDLER_V0_THUNK = {
|
||||
getReportHandlerVersionID,
|
||||
printDebug,
|
||||
onErrorControlROM,
|
||||
onErrorPCMROM,
|
||||
showLCDMessage,
|
||||
onMIDIMessagePlayed,
|
||||
onMIDIQueueOverflow,
|
||||
onMIDISystemRealtime,
|
||||
onDeviceReset,
|
||||
onDeviceReconfig,
|
||||
onNewReverbMode,
|
||||
onNewReverbTime,
|
||||
onNewReverbLevel,
|
||||
onPolyStateChanged,
|
||||
onProgramChanged
|
||||
};
|
||||
|
||||
static const mt32emu_report_handler_i REPORT_HANDLER_THUNK = { &REPORT_HANDLER_V0_THUNK };
|
||||
|
||||
return REPORT_HANDLER_THUNK;
|
||||
}
|
||||
|
||||
static mt32emu_midi_receiver_version getMidiReceiverVersionID(mt32emu_midi_receiver_i) {
|
||||
return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
static void handleShortMessage(void *instance_data, const mt32emu_bit32u message) {
|
||||
((IMidiReceiver *)instance_data)->handleShortMessage(message);
|
||||
}
|
||||
|
||||
static void handleSysex(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length) {
|
||||
((IMidiReceiver *)instance_data)->handleSysex(stream, length);
|
||||
}
|
||||
|
||||
static void handleSystemRealtimeMessage(void *instance_data, const mt32emu_bit8u realtime) {
|
||||
((IMidiReceiver *)instance_data)->handleSystemRealtimeMessage(realtime);
|
||||
}
|
||||
|
||||
static mt32emu_midi_receiver_i getMidiReceiverThunk() {
|
||||
static const mt32emu_midi_receiver_i_v0 MIDI_RECEIVER_V0_THUNK = {
|
||||
getMidiReceiverVersionID,
|
||||
handleShortMessage,
|
||||
handleSysex,
|
||||
handleSystemRealtimeMessage
|
||||
};
|
||||
|
||||
static const mt32emu_midi_receiver_i MIDI_RECEIVER_THUNK = { &MIDI_RECEIVER_V0_THUNK };
|
||||
|
||||
return MIDI_RECEIVER_THUNK;
|
||||
}
|
||||
|
||||
} // namespace CppInterfaceImpl
|
||||
|
||||
} // namespace MT32Emu
|
||||
|
||||
#if MT32EMU_API_TYPE == 2
|
||||
|
||||
#undef mt32emu_get_supported_report_handler_version
|
||||
#undef mt32emu_get_supported_midi_receiver_version
|
||||
#undef mt32emu_get_library_version_int
|
||||
#undef mt32emu_get_library_version_string
|
||||
#undef mt32emu_get_stereo_output_samplerate
|
||||
#undef mt32emu_create_context
|
||||
#undef mt32emu_free_context
|
||||
#undef mt32emu_add_rom_data
|
||||
#undef mt32emu_add_rom_file
|
||||
#undef mt32emu_get_rom_info
|
||||
#undef mt32emu_set_partial_count
|
||||
#undef mt32emu_set_analog_output_mode
|
||||
#undef mt32emu_open_synth
|
||||
#undef mt32emu_close_synth
|
||||
#undef mt32emu_is_open
|
||||
#undef mt32emu_get_actual_stereo_output_samplerate
|
||||
#undef mt32emu_flush_midi_queue
|
||||
#undef mt32emu_set_midi_event_queue_size
|
||||
#undef mt32emu_set_midi_receiver
|
||||
#undef mt32emu_parse_stream
|
||||
#undef mt32emu_parse_stream_at
|
||||
#undef mt32emu_play_short_message
|
||||
#undef mt32emu_play_short_message_at
|
||||
#undef mt32emu_play_msg
|
||||
#undef mt32emu_play_sysex
|
||||
#undef mt32emu_play_msg_at
|
||||
#undef mt32emu_play_sysex_at
|
||||
#undef mt32emu_play_msg_now
|
||||
#undef mt32emu_play_msg_on_part
|
||||
#undef mt32emu_play_sysex_now
|
||||
#undef mt32emu_write_sysex
|
||||
#undef mt32emu_set_reverb_enabled
|
||||
#undef mt32emu_is_reverb_enabled
|
||||
#undef mt32emu_set_reverb_overridden
|
||||
#undef mt32emu_is_reverb_overridden
|
||||
#undef mt32emu_set_reverb_compatibility_mode
|
||||
#undef mt32emu_is_mt32_reverb_compatibility_mode
|
||||
#undef mt32emu_is_default_reverb_mt32_compatible
|
||||
#undef mt32emu_set_dac_input_mode
|
||||
#undef mt32emu_get_dac_input_mode
|
||||
#undef mt32emu_set_midi_delay_mode
|
||||
#undef mt32emu_get_midi_delay_mode
|
||||
#undef mt32emu_set_output_gain
|
||||
#undef mt32emu_get_output_gain
|
||||
#undef mt32emu_set_reverb_output_gain
|
||||
#undef mt32emu_get_reverb_output_gain
|
||||
#undef mt32emu_set_reversed_stereo_enabled
|
||||
#undef mt32emu_is_reversed_stereo_enabled
|
||||
#undef mt32emu_render_bit16s
|
||||
#undef mt32emu_render_float
|
||||
#undef mt32emu_render_bit16s_streams
|
||||
#undef mt32emu_render_float_streams
|
||||
#undef mt32emu_has_active_partials
|
||||
#undef mt32emu_is_active
|
||||
#undef mt32emu_get_partial_count
|
||||
#undef mt32emu_get_part_states
|
||||
#undef mt32emu_get_partial_states
|
||||
#undef mt32emu_get_playing_notes
|
||||
#undef mt32emu_get_patch_name
|
||||
#undef mt32emu_read_memory
|
||||
|
||||
#endif // #if MT32EMU_API_TYPE == 2
|
||||
|
||||
#endif /* #ifndef MT32EMU_CPP_INTERFACE_H */
|
28
audio/softsynth/mt32/config.h
Normal file
28
audio/softsynth/mt32/config.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_CONFIG_H
|
||||
#define MT32EMU_CONFIG_H
|
||||
|
||||
#define MT32EMU_VERSION "2.0.0"
|
||||
#define MT32EMU_VERSION_MAJOR 2
|
||||
#define MT32EMU_VERSION_MINOR 0
|
||||
#define MT32EMU_VERSION_PATCH 0
|
||||
|
||||
#define MT32EMU_EXPORTS_TYPE 3
|
||||
|
||||
#endif
|
119
audio/softsynth/mt32/globals.h
Executable file
119
audio/softsynth/mt32/globals.h
Executable file
|
@ -0,0 +1,119 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MT32EMU_GLOBALS_H
|
||||
#define MT32EMU_GLOBALS_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Support for compiling shared library. */
|
||||
#ifdef MT32EMU_SHARED
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#ifdef _MSC_VER
|
||||
#ifdef mt32emu_EXPORTS
|
||||
#define MT32EMU_EXPORT_ATTRIBUTE _declspec(dllexport)
|
||||
#else /* #ifdef mt32emu_EXPORTS */
|
||||
#define MT32EMU_EXPORT_ATTRIBUTE _declspec(dllimport)
|
||||
#endif /* #ifdef mt32emu_EXPORTS */
|
||||
#else /* #ifdef _MSC_VER */
|
||||
#ifdef mt32emu_EXPORTS
|
||||
#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((dllexport))
|
||||
#else /* #ifdef mt32emu_EXPORTS */
|
||||
#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((dllimport))
|
||||
#endif /* #ifdef mt32emu_EXPORTS */
|
||||
#endif /* #ifdef _MSC_VER */
|
||||
#else /* #if defined _WIN32 || defined __CYGWIN__ */
|
||||
#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((visibility("default")))
|
||||
#endif /* #if defined _WIN32 || defined __CYGWIN__ */
|
||||
#else /* #ifdef MT32EMU_SHARED */
|
||||
#define MT32EMU_EXPORT_ATTRIBUTE
|
||||
#endif /* #ifdef MT32EMU_SHARED */
|
||||
|
||||
#if MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2
|
||||
#define MT32EMU_EXPORT
|
||||
#else
|
||||
#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
/* Useful constants */
|
||||
|
||||
/* Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent.
|
||||
* In order to achieve further advance in emulation accuracy, sample rate made fixed throughout the emulator,
|
||||
* except the emulation of analogue path.
|
||||
* The output from the synth is supposed to be resampled externally in order to convert to the desired sample rate.
|
||||
*/
|
||||
#define MT32EMU_SAMPLE_RATE 32000
|
||||
|
||||
/* The default value for the maximum number of partials playing simultaneously. */
|
||||
#define MT32EMU_DEFAULT_MAX_PARTIALS 32
|
||||
|
||||
/* The higher this number, the more memory will be used, but the more samples can be processed in one run -
|
||||
* various parts of sample generation can be processed more efficiently in a single run.
|
||||
* A run's maximum length is that given to Synth::render(), so giving a value here higher than render() is ever
|
||||
* called with will give no gain (but simply waste the memory).
|
||||
* Note that this value does *not* in any way impose limitations on the length given to render(), and has no effect
|
||||
* on the generated audio.
|
||||
* This value must be >= 1.
|
||||
*/
|
||||
#define MT32EMU_MAX_SAMPLES_PER_RUN 4096
|
||||
|
||||
/* The default size of the internal MIDI event queue.
|
||||
* It holds the incoming MIDI events before the rendering engine actually processes them.
|
||||
* The main goal is to fairly emulate the real hardware behaviour which obviously
|
||||
* uses an internal MIDI event queue to gather incoming data as well as the delays
|
||||
* introduced by transferring data via the MIDI interface.
|
||||
* This also facilitates building of an external rendering loop
|
||||
* as the queue stores timestamped MIDI events.
|
||||
*/
|
||||
#define MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE 1024
|
||||
|
||||
/* Maximum allowed size of MIDI parser input stream buffer.
|
||||
* Should suffice for any reasonable bulk dump SysEx, as the h/w units have only 32K of RAM onboard.
|
||||
*/
|
||||
#define MT32EMU_MAX_STREAM_BUFFER_SIZE 32768
|
||||
|
||||
/* This should correspond to the MIDI buffer size used in real h/w devices.
|
||||
* CM-32L control ROM seems using 1000 bytes, old MT-32 isn't confirmed by now.
|
||||
*/
|
||||
#define MT32EMU_SYSEX_BUFFER_SIZE 1000
|
||||
|
||||
#if defined(__cplusplus) && MT32EMU_API_TYPE != 1
|
||||
|
||||
namespace MT32Emu
|
||||
{
|
||||
const unsigned int SAMPLE_RATE = MT32EMU_SAMPLE_RATE;
|
||||
#undef MT32EMU_SAMPLE_RATE
|
||||
|
||||
const unsigned int DEFAULT_MAX_PARTIALS = MT32EMU_DEFAULT_MAX_PARTIALS;
|
||||
#undef MT32EMU_DEFAULT_MAX_PARTIALS
|
||||
|
||||
const unsigned int MAX_SAMPLES_PER_RUN = MT32EMU_MAX_SAMPLES_PER_RUN;
|
||||
#undef MT32EMU_MAX_SAMPLES_PER_RUN
|
||||
|
||||
const unsigned int DEFAULT_MIDI_EVENT_QUEUE_SIZE = MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE;
|
||||
#undef MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE
|
||||
|
||||
const unsigned int MAX_STREAM_BUFFER_SIZE = MT32EMU_MAX_STREAM_BUFFER_SIZE;
|
||||
#undef MT32EMU_MAX_STREAM_BUFFER_SIZE
|
||||
|
||||
const unsigned int SYSEX_BUFFER_SIZE = MT32EMU_SYSEX_BUFFER_SIZE;
|
||||
#undef MT32EMU_SYSEX_BUFFER_SIZE
|
||||
}
|
||||
|
||||
#endif /* #if defined(__cplusplus) && MT32EMU_API_TYPE != 1 */
|
||||
|
||||
#endif /* #ifndef MT32EMU_GLOBALS_H */
|
71
audio/softsynth/mt32/internals.h
Normal file → Executable file
71
audio/softsynth/mt32/internals.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,66 +18,111 @@
|
|||
#ifndef MT32EMU_INTERNALS_H
|
||||
#define MT32EMU_INTERNALS_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
// Debugging
|
||||
|
||||
// 0: Standard debug output is not stamped with the rendered sample count
|
||||
// 1: Standard debug output is stamped with the rendered sample count
|
||||
// NOTE: The "samplestamp" corresponds to the end of the last completed rendering run.
|
||||
// This is important to bear in mind for debug output that occurs during a run.
|
||||
#ifndef MT32EMU_DEBUG_SAMPLESTAMPS
|
||||
#define MT32EMU_DEBUG_SAMPLESTAMPS 0
|
||||
#endif
|
||||
|
||||
// 0: No debug output for initialisation progress
|
||||
// 1: Debug output for initialisation progress
|
||||
#ifndef MT32EMU_MONITOR_INIT
|
||||
#define MT32EMU_MONITOR_INIT 0
|
||||
#endif
|
||||
|
||||
// 0: No debug output for MIDI events
|
||||
// 1: Debug output for weird MIDI events
|
||||
#ifndef MT32EMU_MONITOR_MIDI
|
||||
#define MT32EMU_MONITOR_MIDI 0
|
||||
#endif
|
||||
|
||||
// 0: No debug output for note on/off
|
||||
// 1: Basic debug output for note on/off
|
||||
// 2: Comprehensive debug output for note on/off
|
||||
#ifndef MT32EMU_MONITOR_INSTRUMENTS
|
||||
#define MT32EMU_MONITOR_INSTRUMENTS 0
|
||||
#endif
|
||||
|
||||
// 0: No debug output for partial allocations
|
||||
// 1: Show partial stats when an allocation fails
|
||||
// 2: Show partial stats with every new poly
|
||||
// 3: Show individual partial allocations/deactivations
|
||||
#ifndef MT32EMU_MONITOR_PARTIALS
|
||||
#define MT32EMU_MONITOR_PARTIALS 0
|
||||
#endif
|
||||
|
||||
// 0: No debug output for sysex
|
||||
// 1: Basic debug output for sysex
|
||||
#ifndef MT32EMU_MONITOR_SYSEX
|
||||
#define MT32EMU_MONITOR_SYSEX 0
|
||||
#endif
|
||||
|
||||
// 0: No debug output for sysex writes to the timbre areas
|
||||
// 1: Debug output with the name and location of newly-written timbres
|
||||
// 2: Complete dump of timbre parameters for newly-written timbres
|
||||
#ifndef MT32EMU_MONITOR_TIMBRES
|
||||
#define MT32EMU_MONITOR_TIMBRES 0
|
||||
#endif
|
||||
|
||||
// 0: No TVA/TVF-related debug output.
|
||||
// 1: Shows changes to TVA/TVF target, increment and phase.
|
||||
#ifndef MT32EMU_MONITOR_TVA
|
||||
#define MT32EMU_MONITOR_TVA 0
|
||||
#endif
|
||||
#ifndef MT32EMU_MONITOR_TVF
|
||||
#define MT32EMU_MONITOR_TVF 0
|
||||
#endif
|
||||
|
||||
// Configuration
|
||||
|
||||
// 0: Use 16-bit signed samples and refined wave generator based on logarithmic fixed-point computations and LUTs. Maximum emulation accuracy and speed.
|
||||
// 1: Use float samples in the wave generator and renderer. Maximum output quality and minimum noise.
|
||||
#ifndef MT32EMU_USE_FLOAT_SAMPLES
|
||||
#define MT32EMU_USE_FLOAT_SAMPLES 0
|
||||
#endif
|
||||
|
||||
// If non-zero, deletes reverb buffers that are not in use to save memory.
|
||||
// If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path.
|
||||
#ifndef MT32EMU_REDUCE_REVERB_MEMORY
|
||||
#define MT32EMU_REDUCE_REVERB_MEMORY 1
|
||||
#endif
|
||||
|
||||
// 0: Maximum speed at the cost of a bit lower emulation accuracy.
|
||||
// 1: Maximum achievable emulation accuracy.
|
||||
#ifndef MT32EMU_BOSS_REVERB_PRECISE_MODE
|
||||
#define MT32EMU_BOSS_REVERB_PRECISE_MODE 0
|
||||
|
||||
#include "Structures.h"
|
||||
#include "Tables.h"
|
||||
#include "Poly.h"
|
||||
#include "LA32Ramp.h"
|
||||
#include "LA32WaveGenerator.h"
|
||||
#include "TVA.h"
|
||||
#include "TVP.h"
|
||||
#include "TVF.h"
|
||||
#include "Partial.h"
|
||||
#include "Part.h"
|
||||
|
||||
#endif
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
enum PolyState {
|
||||
POLY_Playing,
|
||||
POLY_Held, // This marks keys that have been released on the keyboard, but are being held by the pedal
|
||||
POLY_Releasing,
|
||||
POLY_Inactive
|
||||
};
|
||||
|
||||
enum ReverbMode {
|
||||
REVERB_MODE_ROOM,
|
||||
REVERB_MODE_HALL,
|
||||
REVERB_MODE_PLATE,
|
||||
REVERB_MODE_TAP_DELAY
|
||||
};
|
||||
|
||||
#if MT32EMU_USE_FLOAT_SAMPLES
|
||||
typedef float Sample;
|
||||
typedef float SampleEx;
|
||||
#else
|
||||
typedef Bit16s Sample;
|
||||
typedef Bit32s SampleEx;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // #ifndef MT32EMU_INTERNALS_H
|
||||
|
|
15
audio/softsynth/mt32/mmath.h
Normal file → Executable file
15
audio/softsynth/mt32/mmath.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,12 +18,7 @@
|
|||
#ifndef MT32EMU_MMATH_H
|
||||
#define MT32EMU_MMATH_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))
|
||||
|
||||
#define FIXEDPOINT_MAKE(x, point) ((Bit32u)((1 << point) * x))
|
||||
#include <cmath>
|
||||
|
||||
namespace MT32Emu {
|
||||
|
||||
|
@ -46,7 +41,7 @@ static inline float EXPF(float x) {
|
|||
static inline float EXP2F(float x) {
|
||||
#ifdef __APPLE__
|
||||
// on OSX exp2f() is 1.59 times faster than "exp() and the multiplication with FLOAT_LN_2"
|
||||
return exp2(x);
|
||||
return exp2f(x);
|
||||
#else
|
||||
return exp(FLOAT_LN_2 * x);
|
||||
#endif
|
||||
|
@ -68,6 +63,6 @@ static inline float LOG10F(float x) {
|
|||
return log10(x);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace MT32Emu
|
||||
|
||||
#endif
|
||||
#endif // #ifndef MT32EMU_MMATH_H
|
||||
|
|
|
@ -3,8 +3,11 @@ MODULE := audio/softsynth/mt32
|
|||
MODULE_OBJS := \
|
||||
Analog.o \
|
||||
BReverbModel.o \
|
||||
File.o \
|
||||
FileStream.o \
|
||||
LA32Ramp.o \
|
||||
LA32WaveGenerator.o \
|
||||
MidiStreamParser.o \
|
||||
Part.o \
|
||||
Partial.o \
|
||||
PartialManager.o \
|
||||
|
@ -14,7 +17,9 @@ MODULE_OBJS := \
|
|||
Tables.o \
|
||||
TVA.o \
|
||||
TVF.o \
|
||||
TVP.o
|
||||
TVP.o \
|
||||
sha1/sha1.o \
|
||||
c_interface/c_interface.o
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
|
86
audio/softsynth/mt32/mt32emu.h
Normal file → Executable file
86
audio/softsynth/mt32/mt32emu.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
|
||||
* Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
* Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
|
@ -18,44 +18,66 @@
|
|||
#ifndef MT32EMU_MT32EMU_H
|
||||
#define MT32EMU_MT32EMU_H
|
||||
|
||||
// Configuration
|
||||
#include "config.h"
|
||||
|
||||
// 0: Use 16-bit signed samples and refined wave generator based on logarithmic fixed-point computations and LUTs. Maximum emulation accuracy and speed.
|
||||
// 1: Use float samples in the wave generator and renderer. Maximum output quality and minimum noise.
|
||||
#define MT32EMU_USE_FLOAT_SAMPLES 0
|
||||
/* API Configuration */
|
||||
|
||||
namespace MT32Emu
|
||||
{
|
||||
// Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent.
|
||||
// In order to achieve further advance in emulation accuracy, sample rate made fixed throughout the emulator,
|
||||
// except the emulation of analogue path.
|
||||
// The output from the synth is supposed to be resampled externally in order to convert to the desired sample rate.
|
||||
const unsigned int SAMPLE_RATE = 32000;
|
||||
/* 0: Use full-featured C++ API. Well suitable when the library is to be linked statically.
|
||||
* When the library is shared, ABI compatibility may be an issue. Therefore, it should
|
||||
* only be used within a project comprising of several modules to share the library code.
|
||||
* 1: Use C-compatible API. Make the library looks as a regular C library with well-defined ABI.
|
||||
* This is also crucial when the library is to be linked with modules in a different
|
||||
* language, either statically or dynamically.
|
||||
* 2: Use plugin-like API via C-interface wrapped in a C++ class. This is mainly intended
|
||||
* for a shared library being dynamically loaded in run-time. To get access to all the library
|
||||
* services, a client application only needs to bind with a single factory function.
|
||||
* 3: Use optimised C++ API compatible with the plugin API (type 2). The facade class also wraps
|
||||
* the C functions but they are invoked directly. This enables the compiler to generate better
|
||||
* code for the library when linked statically yet being consistent with the plugin-like API.
|
||||
*/
|
||||
|
||||
// The default value for the maximum number of partials playing simultaneously.
|
||||
const unsigned int DEFAULT_MAX_PARTIALS = 32;
|
||||
#ifdef MT32EMU_API_TYPE
|
||||
#if MT32EMU_API_TYPE == 0 && (MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2)
|
||||
#error Incompatible setting MT32EMU_API_TYPE=0
|
||||
#elif MT32EMU_API_TYPE == 1 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2)
|
||||
#error Incompatible setting MT32EMU_API_TYPE=1
|
||||
#elif MT32EMU_API_TYPE == 2 && (MT32EMU_EXPORTS_TYPE == 0)
|
||||
#error Incompatible setting MT32EMU_API_TYPE=2
|
||||
#elif MT32EMU_API_TYPE == 3 && (MT32EMU_EXPORTS_TYPE == 0)
|
||||
#error Incompatible setting MT32EMU_API_TYPE=3
|
||||
#endif
|
||||
#else /* #ifdef MT32EMU_API_TYPE */
|
||||
#if 0 < MT32EMU_EXPORTS_TYPE && MT32EMU_EXPORTS_TYPE < 3
|
||||
#define MT32EMU_API_TYPE MT32EMU_EXPORTS_TYPE
|
||||
#else
|
||||
#define MT32EMU_API_TYPE 0
|
||||
#endif
|
||||
#endif /* #ifdef MT32EMU_API_TYPE */
|
||||
|
||||
// The higher this number, the more memory will be used, but the more samples can be processed in one run -
|
||||
// various parts of sample generation can be processed more efficiently in a single run.
|
||||
// A run's maximum length is that given to Synth::render(), so giving a value here higher than render() is ever
|
||||
// called with will give no gain (but simply waste the memory).
|
||||
// Note that this value does *not* in any way impose limitations on the length given to render(), and has no effect
|
||||
// on the generated audio.
|
||||
// This value must be >= 1.
|
||||
const unsigned int MAX_SAMPLES_PER_RUN = 4096;
|
||||
/* MT32EMU_SHARED should be defined when building shared library, especially for Windows platforms. */
|
||||
/*
|
||||
#define MT32EMU_SHARED
|
||||
*/
|
||||
|
||||
// The default size of the internal MIDI event queue.
|
||||
// It holds the incoming MIDI events before the rendering engine actually processes them.
|
||||
// The main goal is to fairly emulate the real hardware behaviour which obviously
|
||||
// uses an internal MIDI event queue to gather incoming data as well as the delays
|
||||
// introduced by transferring data via the MIDI interface.
|
||||
// This also facilitates building of an external rendering loop
|
||||
// as the queue stores timestamped MIDI events.
|
||||
const unsigned int DEFAULT_MIDI_EVENT_QUEUE_SIZE = 1024;
|
||||
}
|
||||
#include "globals.h"
|
||||
|
||||
#if !defined(__cplusplus) || MT32EMU_API_TYPE == 1
|
||||
|
||||
#include "c_interface/c_interface.h"
|
||||
|
||||
#elif MT32EMU_API_TYPE == 2 || MT32EMU_API_TYPE == 3
|
||||
|
||||
#include "c_interface/cpp_interface.h"
|
||||
|
||||
#else /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */
|
||||
|
||||
#include "Types.h"
|
||||
#include "File.h"
|
||||
#include "FileStream.h"
|
||||
#include "ROMInfo.h"
|
||||
#include "Synth.h"
|
||||
#include "MidiStreamParser.h"
|
||||
|
||||
#endif
|
||||
#endif /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */
|
||||
|
||||
#endif /* #ifndef MT32EMU_MT32EMU_H */
|
||||
|
|
185
audio/softsynth/mt32/sha1/sha1.cpp
Executable file
185
audio/softsynth/mt32/sha1/sha1.cpp
Executable file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributors:
|
||||
Gustav
|
||||
Several members in the gamedev.se forum.
|
||||
Gregory Petrosyan
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
namespace // local
|
||||
{
|
||||
// Rotate an integer value to left.
|
||||
inline unsigned int rol(const unsigned int value,
|
||||
const unsigned int steps)
|
||||
{
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int* buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void innerHash(unsigned int* result, unsigned int* w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash)
|
||||
{
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
const unsigned char* sarray = static_cast<const unsigned char*>(src);
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
const int endOfFullBlocks = bytelength - 64;
|
||||
int endCurrentBlock;
|
||||
int currentBlock = 0;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks)
|
||||
{
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on little endian.
|
||||
w[roundPos++] = static_cast<unsigned int>(sarray[currentBlock + 3])
|
||||
| (static_cast<unsigned int>(sarray[currentBlock + 2]) << 8)
|
||||
| (static_cast<unsigned int>(sarray[currentBlock + 1]) << 16)
|
||||
| (static_cast<unsigned int>(sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
int lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
|
||||
{
|
||||
w[lastBlockBytes >> 2] |= static_cast<unsigned int>(sarray[lastBlockBytes + currentBlock]) << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56)
|
||||
{
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void toHexString(const unsigned char* hash, char* hexstring)
|
||||
{
|
||||
const char hexDigits[] = { "0123456789abcdef" };
|
||||
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
|
||||
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
|
||||
}
|
||||
hexstring[40] = 0;
|
||||
}
|
||||
} // namespace sha1
|
49
audio/softsynth/mt32/sha1/sha1.h
Executable file
49
audio/softsynth/mt32/sha1/sha1.h
Executable file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_DEFINED
|
||||
#define SHA1_DEFINED
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
|
||||
/**
|
||||
@param src points to any kind of data to be hashed.
|
||||
@param bytelength the number of bytes to hash from the src pointer.
|
||||
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
|
||||
*/
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash);
|
||||
|
||||
/**
|
||||
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
|
||||
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
|
||||
*/
|
||||
void toHexString(const unsigned char* hash, char* hexstring);
|
||||
|
||||
} // namespace sha1
|
||||
|
||||
#endif // SHA1_DEFINED
|
Loading…
Add table
Add a link
Reference in a new issue