[Scummvm-git-logs] scummvm master -> d94505d46e9226210ede4ec9e63f091270273b09
lotharsm
noreply at scummvm.org
Thu Sep 15 10:13:54 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
d94505d46e AUDIO: MT32: Update MT32 emulation code to mt32emu 2.7.0
Commit: d94505d46e9226210ede4ec9e63f091270273b09
https://github.com/scummvm/scummvm/commit/d94505d46e9226210ede4ec9e63f091270273b09
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-09-15T11:52:47+02:00
Commit Message:
AUDIO: MT32: Update MT32 emulation code to mt32emu 2.7.0
Changed paths:
A audio/softsynth/mt32/Display.cpp
A audio/softsynth/mt32/Display.h
NEWS.md
audio/softsynth/mt32/Analog.cpp
audio/softsynth/mt32/Analog.h
audio/softsynth/mt32/BReverbModel.cpp
audio/softsynth/mt32/BReverbModel.h
audio/softsynth/mt32/Enumerations.h
audio/softsynth/mt32/File.cpp
audio/softsynth/mt32/File.h
audio/softsynth/mt32/FileStream.cpp
audio/softsynth/mt32/FileStream.h
audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
audio/softsynth/mt32/LA32FloatWaveGenerator.h
audio/softsynth/mt32/LA32Ramp.cpp
audio/softsynth/mt32/LA32Ramp.h
audio/softsynth/mt32/LA32WaveGenerator.cpp
audio/softsynth/mt32/LA32WaveGenerator.h
audio/softsynth/mt32/MemoryRegion.h
audio/softsynth/mt32/MidiEventQueue.h
audio/softsynth/mt32/MidiStreamParser.cpp
audio/softsynth/mt32/MidiStreamParser.h
audio/softsynth/mt32/Part.cpp
audio/softsynth/mt32/Part.h
audio/softsynth/mt32/Partial.cpp
audio/softsynth/mt32/Partial.h
audio/softsynth/mt32/PartialManager.cpp
audio/softsynth/mt32/PartialManager.h
audio/softsynth/mt32/Poly.cpp
audio/softsynth/mt32/Poly.h
audio/softsynth/mt32/ROMInfo.cpp
audio/softsynth/mt32/ROMInfo.h
audio/softsynth/mt32/SampleRateConverter.cpp
audio/softsynth/mt32/SampleRateConverter.h
audio/softsynth/mt32/Structures.h
audio/softsynth/mt32/Synth.cpp
audio/softsynth/mt32/Synth.h
audio/softsynth/mt32/TVA.cpp
audio/softsynth/mt32/TVA.h
audio/softsynth/mt32/TVF.cpp
audio/softsynth/mt32/TVF.h
audio/softsynth/mt32/TVP.cpp
audio/softsynth/mt32/TVP.h
audio/softsynth/mt32/Tables.cpp
audio/softsynth/mt32/Tables.h
audio/softsynth/mt32/Types.h
audio/softsynth/mt32/VersionTagging.cpp
audio/softsynth/mt32/VersionTagging.h
audio/softsynth/mt32/c_interface/c_interface.cpp
audio/softsynth/mt32/c_interface/c_interface.h
audio/softsynth/mt32/c_interface/c_types.h
audio/softsynth/mt32/c_interface/cpp_interface.h
audio/softsynth/mt32/config.h
audio/softsynth/mt32/globals.h
audio/softsynth/mt32/internals.h
audio/softsynth/mt32/mmath.h
audio/softsynth/mt32/module.mk
audio/softsynth/mt32/mt32emu.h
audio/softsynth/mt32/mt32emu.pc.in
audio/softsynth/mt32/srchelper/InternalResampler.cpp
audio/softsynth/mt32/srchelper/InternalResampler.h
audio/softsynth/mt32/srchelper/SamplerateAdapter.cpp
audio/softsynth/mt32/srchelper/SamplerateAdapter.h
audio/softsynth/mt32/srchelper/SoxrAdapter.cpp
audio/softsynth/mt32/srchelper/SoxrAdapter.h
audio/softsynth/mt32/srchelper/srctools/include/FIRResampler.h
audio/softsynth/mt32/srchelper/srctools/include/FloatSampleProvider.h
audio/softsynth/mt32/srchelper/srctools/include/IIR2xResampler.h
audio/softsynth/mt32/srchelper/srctools/include/LinearResampler.h
audio/softsynth/mt32/srchelper/srctools/include/ResamplerModel.h
audio/softsynth/mt32/srchelper/srctools/include/ResamplerStage.h
audio/softsynth/mt32/srchelper/srctools/include/SincResampler.h
audio/softsynth/mt32/srchelper/srctools/src/FIRResampler.cpp
audio/softsynth/mt32/srchelper/srctools/src/IIR2xResampler.cpp
audio/softsynth/mt32/srchelper/srctools/src/LinearResampler.cpp
audio/softsynth/mt32/srchelper/srctools/src/ResamplerModel.cpp
audio/softsynth/mt32/srchelper/srctools/src/SincResampler.cpp
doc/de/NEUES.md
diff --git a/NEWS.md b/NEWS.md
index 1a056d2e66d..fbd38116c1e 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -12,6 +12,7 @@ For a more comprehensive changelog of the latest experimental code, see:
General:
- Reduced amount of false positives in Mass Add.
+ - Updated the Roland MT-32 emulation code to Munt mt32emu 2.7.0.
AGOS:
- Added option to disable the fade-out effects on room transition for
diff --git a/audio/softsynth/mt32/Analog.cpp b/audio/softsynth/mt32/Analog.cpp
index 291d527c141..41fb19b44b9 100644
--- a/audio/softsynth/mt32/Analog.cpp
+++ b/audio/softsynth/mt32/Analog.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -127,7 +127,7 @@ public:
template <class SampleEx>
class NullLowPassFilter : public AbstractLowPassFilter<SampleEx> {
public:
- SampleEx process(const SampleEx sample) override {
+ SampleEx process(const SampleEx sample) {
return sample;
}
};
@@ -150,7 +150,7 @@ public:
Synth::muteSampleBuffer(ringBuffer, COARSE_LPF_DELAY_LINE_LENGTH);
}
- SampleEx process(const SampleEx inSample) override {
+ SampleEx process(const SampleEx inSample) {
static const unsigned int DELAY_LINE_MASK = COARSE_LPF_DELAY_LINE_LENGTH - 1;
SampleEx sample = lpfTaps[COARSE_LPF_DELAY_LINE_LENGTH] * ringBuffer[ringBufferPosition];
@@ -179,12 +179,12 @@ private:
public:
AccurateLowPassFilter(const bool oldMT32AnalogLPF, const bool oversample);
- FloatSample process(const FloatSample sample) override;
- IntSampleEx process(const IntSampleEx sample) override;
- bool hasNextSample() const override;
- unsigned int getOutputSampleRate() const override;
- unsigned int estimateInSampleCount(const unsigned int outSamples) const override;
- void addPositionIncrement(const unsigned int positionIncrement) override;
+ FloatSample process(const FloatSample sample);
+ IntSampleEx process(const IntSampleEx sample);
+ bool hasNextSample() const;
+ unsigned int getOutputSampleRate() const;
+ unsigned int estimateInSampleCount(const unsigned int outSamples) const;
+ void addPositionIncrement(const unsigned int positionIncrement);
};
static inline IntSampleEx normaliseSample(const IntSampleEx sample) {
@@ -223,23 +223,23 @@ public:
delete &rightChannelLPF;
}
- unsigned int getOutputSampleRate() const override {
+ unsigned int getOutputSampleRate() const {
return leftChannelLPF.getOutputSampleRate();
}
- Bit32u getDACStreamsLength(const Bit32u outputLength) const override {
+ Bit32u getDACStreamsLength(const Bit32u outputLength) const {
return leftChannelLPF.estimateInSampleCount(outputLength);
}
- void setSynthOutputGain(const float synthGain) override;
- void setReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode) override;
+ void setSynthOutputGain(const float synthGain);
+ void setReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode);
- bool process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength) override;
- bool process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength) override;
+ bool process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength);
+ bool process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength);
template <class Sample>
void produceOutput(Sample *outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength) {
- if (outStream == nullptr) {
+ if (outStream == NULL) {
leftChannelLPF.addPositionIncrement(outLength);
rightChannelLPF.addPositionIncrement(outLength);
return;
@@ -276,7 +276,7 @@ Analog *Analog::createAnalog(const AnalogOutputMode mode, const bool oldMT32Anal
default:
break;
}
- return nullptr;
+ return NULL;
}
template<>
diff --git a/audio/softsynth/mt32/Analog.h b/audio/softsynth/mt32/Analog.h
index 307cfc34b32..62c092d9dcb 100644
--- a/audio/softsynth/mt32/Analog.h
+++ b/audio/softsynth/mt32/Analog.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/BReverbModel.cpp b/audio/softsynth/mt32/BReverbModel.cpp
index 0e109c9d493..05a2e4240c9 100644
--- a/audio/softsynth/mt32/BReverbModel.cpp
+++ b/audio/softsynth/mt32/BReverbModel.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -116,7 +116,7 @@ static const BReverbSettings &getCM32L_LAPCSettings(const ReverbMode mode) {
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};
static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP};
- static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, nullptr, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0};
+ static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0};
static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS};
@@ -185,7 +185,7 @@ static const BReverbSettings &getMT32Settings(const ReverbMode mode) {
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};
static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP};
- static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, nullptr, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0};
+ static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0};
static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS};
@@ -289,7 +289,7 @@ public:
virtual ~RingBuffer() {
delete[] buffer;
- buffer = nullptr;
+ buffer = NULL;
}
Sample next() {
@@ -300,7 +300,7 @@ public:
}
bool isEmpty() const {
- if (buffer == nullptr) return true;
+ if (buffer == NULL) return true;
Sample *buf = buffer;
for (Bit32u i = 0; i < size; i++) {
@@ -446,7 +446,7 @@ public:
Bit8u wetLevel;
BReverbModelImpl(const ReverbMode mode, const bool mt32CompatibleModel) :
- allpasses(nullptr), combs(nullptr),
+ allpasses(NULL), combs(NULL),
currentSettings(mt32CompatibleModel ? getMT32Settings(mode) : getCM32L_LAPCSettings(mode)),
tapDelayMode(mode == REVERB_MODE_TAP_DELAY)
{}
@@ -455,11 +455,11 @@ public:
close();
}
- bool isOpen() const override {
- return combs != nullptr;
+ bool isOpen() const {
+ return combs != NULL;
}
- void open() override {
+ void open() {
if (isOpen()) return;
if (currentSettings.numberOfAllpasses > 0) {
allpasses = new AllpassFilter<Sample>*[currentSettings.numberOfAllpasses];
@@ -479,43 +479,43 @@ public:
mute();
}
- void close() override {
- if (allpasses != nullptr) {
+ void close() {
+ if (allpasses != NULL) {
for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) {
- if (allpasses[i] != nullptr) {
+ if (allpasses[i] != NULL) {
delete allpasses[i];
- allpasses[i] = nullptr;
+ allpasses[i] = NULL;
}
}
delete[] allpasses;
- allpasses = nullptr;
+ allpasses = NULL;
}
- if (combs != nullptr) {
+ if (combs != NULL) {
for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) {
- if (combs[i] != nullptr) {
+ if (combs[i] != NULL) {
delete combs[i];
- combs[i] = nullptr;
+ combs[i] = NULL;
}
}
delete[] combs;
- combs = nullptr;
+ combs = NULL;
}
}
- void mute() override {
- if (allpasses != nullptr) {
+ void mute() {
+ if (allpasses != NULL) {
for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) {
allpasses[i]->mute();
}
}
- if (combs != nullptr) {
+ if (combs != NULL) {
for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) {
combs[i]->mute();
}
}
}
- void setParameters(Bit8u time, Bit8u level) override {
+ void setParameters(Bit8u time, Bit8u level) {
if (!isOpen()) return;
level &= 7;
time &= 7;
@@ -542,7 +542,7 @@ public:
}
}
- bool isActive() const override {
+ bool isActive() const {
if (!isOpen()) return false;
for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) {
if (!allpasses[i]->isEmpty()) return true;
@@ -553,7 +553,7 @@ public:
return false;
}
- bool isMT32Compatible(const ReverbMode mode) const override {
+ bool isMT32Compatible(const ReverbMode mode) const {
return ¤tSettings == &getMT32Settings(mode);
}
@@ -580,10 +580,10 @@ public:
if (tapDelayMode) {
TapDelayCombFilter<Sample> *comb = static_cast<TapDelayCombFilter<Sample> *>(*combs);
comb->process(dry);
- if (outLeft != nullptr) {
+ if (outLeft != NULL) {
*(outLeft++) = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF);
}
- if (outRight != nullptr) {
+ if (outRight != NULL) {
*(outRight++) = weirdMul(comb->getRightOutput(), wetLevel, 0xFF);
}
} else {
@@ -605,13 +605,13 @@ public:
combs[2]->process(link);
combs[3]->process(link);
- if (outLeft != nullptr) {
+ if (outLeft != NULL) {
Sample outL2 = combs[2]->getOutputAt(currentSettings.outLPositions[1]);
Sample outL3 = combs[3]->getOutputAt(currentSettings.outLPositions[2]);
Sample outSample = mixCombs(outL1, outL2, outL3);
*(outLeft++) = weirdMul(outSample, wetLevel, 0xFF);
}
- if (outRight != nullptr) {
+ if (outRight != NULL) {
Sample outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]);
Sample outR2 = combs[2]->getOutputAt(currentSettings.outRPositions[1]);
Sample outR3 = combs[3]->getOutputAt(currentSettings.outRPositions[2]);
@@ -622,8 +622,8 @@ public:
} // while ((numSamples--) > 0)
} // produceOutput
- bool process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples) override;
- bool process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples) override;
+ bool process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples);
+ bool process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples);
};
BReverbModel *BReverbModel::createBReverbModel(const ReverbMode mode, const bool mt32CompatibleModel, const RendererType rendererType) {
@@ -636,7 +636,7 @@ BReverbModel *BReverbModel::createBReverbModel(const ReverbMode mode, const bool
default:
break;
}
- return nullptr;
+ return NULL;
}
template <>
diff --git a/audio/softsynth/mt32/BReverbModel.h b/audio/softsynth/mt32/BReverbModel.h
index ea911d3bb29..ff34e9543cb 100644
--- a/audio/softsynth/mt32/BReverbModel.h
+++ b/audio/softsynth/mt32/BReverbModel.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/Display.cpp b/audio/softsynth/mt32/Display.cpp
new file mode 100644
index 00000000000..e04ea2cd171
--- /dev/null
+++ b/audio/softsynth/mt32/Display.cpp
@@ -0,0 +1,354 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011-2022 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 <cstdlib>
+#include <cstring>
+
+#include "internals.h"
+
+#include "Display.h"
+#include "Part.h"
+#include "Structures.h"
+#include "Synth.h"
+
+namespace MT32Emu {
+
+/* Details on the emulation model.
+ *
+ * There are four display modes emulated:
+ * - main (Master Volume), set upon startup after showing the welcoming banner;
+ * - program change notification;
+ * - custom display message received via a SysEx;
+ * - error banner (e.g. the MIDI message checksum error).
+ * Stuff like cursor blinking, patch selection mode, test mode, reaction to the front panel buttons, etc. is out of scope, as more
+ * convenient UI/UX solutions are likely desired in applications, if at all.
+ *
+ * Note, despite the LAPC and CM devices come without the LCD and the front panel buttons, the control ROM does support these,
+ * if connected to the main board. That's intended for running the test mode in a service centre, as documented.
+ *
+ * Within the aforementioned scope, the observable hardware behaviour differs noticeably, depending on the control ROM version.
+ * At least three milestones can be identified:
+ * - with MT-32 control ROM V1.06, custom messages are no longer shown unless the display is in the main (Master Volume) mode;
+ * - with MT-32 control ROM V2.04, new function introduced - Display Reset yet added many other changes (taking the full SysEx
+ * address into account when processing custom messages and special handling of the ASCII control characters are among them);
+ * all the second-gen devices, including LAPC-I and CM-32L, behave very similarly;
+ * - in the third-gen devices, the LCD support was partially cut down in the control ROM (basically, only the status
+ * of the test mode, the ROM version and the checksum warnings are shown) - it's not fun, so this is NOT emulated.
+ *
+ * Features of the old-gen units.
+ * - Any message with the first address byte 0x20 is processed and has some effect on the LCD. Messages with any other first
+ * address byte (e.g. starting with 0x21 or 0x1F7F7F with an overlap) are not considered display-relevant.
+ * - The second and the third address byte are largely irrelevant. Only presence of the second address byte makes an observable
+ * difference, not the data within.
+ * - Any string received in the custom message is normalised - all ASCII control characters are replaced with spaces, messages
+ * shorter than 20 bytes are filled up with spaces to the full supported length. However, should a timbre name contain an ASCII
+ * control character, it is displayed nevertheless, with zero meaning the end-of-string.
+ * - Special message 0x20 (of just 1 address byte) shows the contents of the custom message buffer with either the last received
+ * message or the empty buffer initially filled with spaces. See the note below about the priorities of the display modes.
+ * - Messages containing two or three bytes with just the address are considered empty and fill the custom message buffer with
+ * all spaces. The contents of the empty buffer is then shown, depending on the priority of the current display mode.
+ * - Timing: custom messages are shown until an external event occurs like pressing a front panel button, receiving a new custom
+ * message, program change, etc., and for indefinitely long otherwise. A program change notification is shown for about 1300
+ * milliseconds; when the timer expires, the display returns to the main mode (irrespective to the current display mode).
+ * When an error occurs, the warning is shown for a limited time only, similarly to the program change notifications.
+ * - The earlier old-gen devices treat all display modes with equal priority, except the main mode, which has a lower one. This
+ * makes it possible e.g. to replace the error banner with a custom message or a program change notification, and so on.
+ * A slightly improved behaviour is observed since the control ROM V1.06, when custom messages were de-prioritised. But still,
+ * a program change beats an error banner even in the later models.
+ *
+ * Features of the second-gen units.
+ * - All three bytes in SysEx address are now relevant.
+ * - It is possible to replace individual characters in the custom message buffer which are addressed individually within
+ * the range 0x200000-0x200013.
+ * - Writes to higher addresses up to 0x20007F simply make the custom message buffer shown, with either the last received message
+ * or the empty buffer initially filled with spaces.
+ * - Writes to address 0x200100 trigger the Display Reset function which resets the display to the main (Master Volume) mode.
+ * Similarly, showing an error banner is ended. If a program change notification is shown, this function does nothing, however.
+ * - Writes to other addresses are not considered display-relevant, albeit writing a long string to lower addresses
+ * (e.g. 0x1F7F7F) that overlaps the display range does result in updating and showing the custom display message.
+ * - Writing a long string that covers the custom message buffer and address 0x200100 does both things, i.e. updates the buffer
+ * and triggers the Display Reset function.
+ * - While the display is not in a user interaction mode, custom messages and error banners have the highest display priority.
+ * As long as these are shown, program change notifications are suppressed. The display only leaves this mode when the Display
+ * Reset function is triggered or a front panel button is pressed. Notably, when the user enters the menu, all custom messages
+ * are ignored, including the Display Reset command, but error banners are shown nevertheless.
+ * - Sending cut down messages with partially specified address rather leads to undefined behaviour, except for a two-byte message
+ * 0x20 0x00 which consistently shows the content of the custom message buffer (if priority permits). Otherwise, the behaviour
+ * depends on the previously submitted address, e.g. the two-byte version of Display Reset may fail depending on the third byte
+ * of the previous message. One-byte message 0x20 seemingly does Display Reset yet writes a zero character to a position derived
+ * from the third byte of the preceding message.
+ *
+ * Some notes on the behaviour that is common to all hardware models.
+ * - The display is DM2011 with LSI SED1200D-0A. This unit supports 4 user-programmable characters stored in CGRAM, all 4 get
+ * loaded at startup. Character #0 is empty (with the cursor underline), #1 is the full block (used to mark active parts),
+ * #2 is the pipe character (identical to #124 from the CGROM) and #3 is a variation on "down arrow". During normal operation,
+ * those duplicated characters #2 and #124 are both used in different places and character #3 can only be made visible by adding
+ * it either to a custom timbre name or a custom message. Character #0 is probably never shown as this code has special meaning
+ * in the processing routines. For simplicity, we only use characters #124 and #1 in this model.
+ * - When the main mode is active, the current state of the first 5 parts and the rhythm part is represented by replacing the part
+ * symbol with the full rectangle character (#1 from the CGRAM). For voice parts, the rectangle is shown as long as at least one
+ * partial is playing in a non-releasing phase on that part. For the rhythm part, the rectangle blinks briefly when a new NoteOn
+ * message is received on that part (sometimes even when that actually produces no sound).
+ */
+
+static const char MASTER_VOLUME_WITH_DELIMITER[] = "| 0";
+static const char MASTER_VOLUME_WITH_DELIMITER_AND_PREFIX[] = "|vol: 0";
+static const Bit8u RHYTHM_PART_CODE = 'R';
+static const Bit8u FIELD_DELIMITER = '|';
+static const Bit8u ACTIVE_PART_INDICATOR = 1;
+
+static const Bit32u DISPLAYED_VOICE_PARTS_COUNT = 5;
+static const Bit32u SOUND_GROUP_NAME_WITH_DELIMITER_SIZE = 8;
+static const Bit32u MASTER_VOLUME_WITH_DELIMITER_SIZE = sizeof(MASTER_VOLUME_WITH_DELIMITER) - 1;
+static const Bit32u MASTER_VOLUME_WITH_DELIMITER_AND_PREFIX_SIZE = sizeof(MASTER_VOLUME_WITH_DELIMITER_AND_PREFIX) - 1;
+
+// This is the period to show those short blinks of MIDI MESSAGE LED and the rhythm part state.
+// Two related countdowns are initialised to 8 and touched each 10 milliseconds by the software timer 0 interrupt handler.
+static const Bit32u BLINK_TIME_MILLIS = 80;
+static const Bit32u BLINK_TIME_FRAMES = BLINK_TIME_MILLIS * SAMPLE_RATE / 1000;
+
+// This is based on the (free-running) TIMER1 overflow interrupt. The timer is 16-bit and clocked at 500KHz.
+// The message is displayed until 10 overflow interrupts occur. At the standard sample rate, it counts
+// precisely as 41943.04 frame times.
+static const Bit32u SCHEDULED_DISPLAY_MODE_RESET_FRAMES = 41943;
+
+/**
+ * Copies up to lengthLimit characters from possibly null-terminated source to destination. The character of destination located
+ * at the position of the null terminator (if any) in source and the rest of destination are left untouched.
+ */
+static void copyNullTerminatedString(Bit8u *destination, const Bit8u *source, Bit32u lengthLimit) {
+ for (Bit32u i = 0; i < lengthLimit; i++) {
+ Bit8u c = source[i];
+ if (c == 0) break;
+ destination[i] = c;
+ }
+}
+
+Display::Display(Synth &useSynth) :
+ synth(useSynth),
+ lastLEDState(),
+ lcdDirty(),
+ lcdUpdateSignalled(),
+ lastRhythmPartState(),
+ mode(Mode_STARTUP_MESSAGE),
+ midiMessagePlayedSinceLastReset(),
+ rhythmNotePlayedSinceLastReset()
+{
+ scheduleDisplayReset();
+ const Bit8u *startupMessage = &synth.controlROMData[synth.controlROMMap->startupMessage];
+ memcpy(displayBuffer, startupMessage, LCD_TEXT_SIZE);
+ memset(customMessageBuffer, ' ', LCD_TEXT_SIZE);
+ memset(voicePartStates, 0, sizeof voicePartStates);
+}
+
+void Display::checkDisplayStateUpdated(bool &midiMessageLEDState, bool &midiMessageLEDUpdated, bool &lcdUpdated) {
+ midiMessageLEDState = midiMessagePlayedSinceLastReset;
+ maybeResetTimer(midiMessagePlayedSinceLastReset, midiMessageLEDResetTimestamp);
+ // Note, the LED represents activity of the voice parts only.
+ for (Bit32u partIndex = 0; !midiMessageLEDState && partIndex < 8; partIndex++) {
+ midiMessageLEDState = voicePartStates[partIndex];
+ }
+ midiMessageLEDUpdated = lastLEDState != midiMessageLEDState;
+ lastLEDState = midiMessageLEDState;
+
+ if (displayResetScheduled && shouldResetTimer(displayResetTimestamp)) setMainDisplayMode();
+
+ if (lastRhythmPartState != rhythmNotePlayedSinceLastReset && mode == Mode_MAIN) lcdDirty = true;
+ lastRhythmPartState = rhythmNotePlayedSinceLastReset;
+ maybeResetTimer(rhythmNotePlayedSinceLastReset, rhythmStateResetTimestamp);
+
+ lcdUpdated = lcdDirty && !lcdUpdateSignalled;
+ if (lcdUpdated) lcdUpdateSignalled = true;
+}
+
+bool Display::getDisplayState(char *targetBuffer, bool narrowLCD) {
+ if (lcdUpdateSignalled) {
+ lcdDirty = false;
+ lcdUpdateSignalled = false;
+
+ switch (mode) {
+ case Mode_CUSTOM_MESSAGE:
+ if (synth.isDisplayOldMT32Compatible()) {
+ memcpy(displayBuffer, customMessageBuffer, LCD_TEXT_SIZE);
+ } else {
+ copyNullTerminatedString(displayBuffer, customMessageBuffer, LCD_TEXT_SIZE);
+ }
+ break;
+ case Mode_ERROR_MESSAGE: {
+ const Bit8u *sysexErrorMessage = &synth.controlROMData[synth.controlROMMap->sysexErrorMessage];
+ memcpy(displayBuffer, sysexErrorMessage, LCD_TEXT_SIZE);
+ break;
+ }
+ case Mode_PROGRAM_CHANGE: {
+ Bit8u *writePosition = displayBuffer;
+ *writePosition++ = '1' + lastProgramChangePartIndex;
+ *writePosition++ = FIELD_DELIMITER;
+ if (narrowLCD) {
+ writePosition[TIMBRE_NAME_SIZE] = 0;
+ } else {
+ memcpy(writePosition, lastProgramChangeSoundGroupName, SOUND_GROUP_NAME_WITH_DELIMITER_SIZE);
+ writePosition += SOUND_GROUP_NAME_WITH_DELIMITER_SIZE;
+ }
+ copyNullTerminatedString(writePosition, lastProgramChangeTimbreName, TIMBRE_NAME_SIZE);
+ break;
+ }
+ case Mode_MAIN: {
+ Bit8u *writePosition = displayBuffer;
+ for (Bit32u partIndex = 0; partIndex < DISPLAYED_VOICE_PARTS_COUNT; partIndex++) {
+ *writePosition++ = voicePartStates[partIndex] ? ACTIVE_PART_INDICATOR : '1' + partIndex;
+ *writePosition++ = ' ';
+ }
+ *writePosition++ = lastRhythmPartState ? ACTIVE_PART_INDICATOR : RHYTHM_PART_CODE;
+ *writePosition++ = ' ';
+ if (narrowLCD) {
+ memcpy(writePosition, MASTER_VOLUME_WITH_DELIMITER, MASTER_VOLUME_WITH_DELIMITER_SIZE);
+ writePosition += MASTER_VOLUME_WITH_DELIMITER_SIZE;
+ *writePosition = 0;
+ } else {
+ memcpy(writePosition, MASTER_VOLUME_WITH_DELIMITER_AND_PREFIX, MASTER_VOLUME_WITH_DELIMITER_AND_PREFIX_SIZE);
+ writePosition += MASTER_VOLUME_WITH_DELIMITER_AND_PREFIX_SIZE;
+ }
+ Bit32u masterVol = synth.mt32ram.system.masterVol;
+ while (masterVol > 0) {
+ std::div_t result = std::div(masterVol, 10);
+ *--writePosition = '0' + result.rem;
+ masterVol = result.quot;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ memcpy(targetBuffer, displayBuffer, LCD_TEXT_SIZE);
+ targetBuffer[LCD_TEXT_SIZE] = 0;
+ return lastLEDState;
+}
+
+void Display::setMainDisplayMode() {
+ displayResetScheduled = false;
+ mode = Mode_MAIN;
+ lcdDirty = true;
+}
+
+void Display::midiMessagePlayed() {
+ midiMessagePlayedSinceLastReset = true;
+ midiMessageLEDResetTimestamp = synth.renderedSampleCount + BLINK_TIME_FRAMES;
+}
+
+void Display::rhythmNotePlayed() {
+ rhythmNotePlayedSinceLastReset = true;
+ rhythmStateResetTimestamp = synth.renderedSampleCount + BLINK_TIME_FRAMES;
+ midiMessagePlayed();
+ if (synth.isDisplayOldMT32Compatible() && mode == Mode_CUSTOM_MESSAGE) setMainDisplayMode();
+}
+
+void Display::voicePartStateChanged(Bit8u partIndex, bool activated) {
+ if (mode == Mode_MAIN) lcdDirty = true;
+ voicePartStates[partIndex] = activated;
+ if (synth.isDisplayOldMT32Compatible() && mode == Mode_CUSTOM_MESSAGE) setMainDisplayMode();
+}
+
+void Display::masterVolumeChanged() {
+ if (mode == Mode_MAIN) lcdDirty = true;
+}
+
+void Display::programChanged(Bit8u partIndex) {
+ if (!synth.isDisplayOldMT32Compatible() && (mode == Mode_CUSTOM_MESSAGE || mode == Mode_ERROR_MESSAGE)) return;
+ mode = Mode_PROGRAM_CHANGE;
+ lcdDirty = true;
+ scheduleDisplayReset();
+ lastProgramChangePartIndex = partIndex;
+ const Part *part = synth.getPart(partIndex);
+ lastProgramChangeSoundGroupName = synth.getSoundGroupName(part);
+ memcpy(lastProgramChangeTimbreName, part->getCurrentInstr(), TIMBRE_NAME_SIZE);
+}
+
+void Display::checksumErrorOccurred() {
+ if (mode != Mode_ERROR_MESSAGE) {
+ mode = Mode_ERROR_MESSAGE;
+ lcdDirty = true;
+ }
+ if (synth.isDisplayOldMT32Compatible()) {
+ scheduleDisplayReset();
+ } else {
+ displayResetScheduled = false;
+ }
+}
+
+bool Display::customDisplayMessageReceived(const Bit8u *message, Bit32u startIndex, Bit32u length) {
+ if (synth.isDisplayOldMT32Compatible()) {
+ for (Bit32u i = 0; i < LCD_TEXT_SIZE; i++) {
+ Bit8u c = i < length ? message[i] : ' ';
+ if (c < 32 || 127 < c) c = ' ';
+ customMessageBuffer[i] = c;
+ }
+ if (!synth.controlROMFeatures->quirkDisplayCustomMessagePriority
+ && (mode == Mode_PROGRAM_CHANGE || mode == Mode_ERROR_MESSAGE)) return false;
+ // Note, real devices keep the display reset timer running.
+ } else {
+ if (startIndex > 0x80) return false;
+ if (startIndex == 0x80) {
+ if (mode != Mode_PROGRAM_CHANGE) setMainDisplayMode();
+ return false;
+ }
+ displayResetScheduled = false;
+ if (startIndex < LCD_TEXT_SIZE) {
+ if (length > LCD_TEXT_SIZE - startIndex) length = LCD_TEXT_SIZE - startIndex;
+ memcpy(customMessageBuffer + startIndex, message, length);
+ }
+ }
+ mode = Mode_CUSTOM_MESSAGE;
+ lcdDirty = true;
+ return true;
+}
+
+void Display::displayControlMessageReceived(const Bit8u *messageBytes, Bit32u length) {
+ Bit8u emptyMessage[] = { 0 };
+ if (synth.isDisplayOldMT32Compatible()) {
+ if (length == 1) {
+ customDisplayMessageReceived(customMessageBuffer, 0, LCD_TEXT_SIZE);
+ } else {
+ customDisplayMessageReceived(emptyMessage, 0, 0);
+ }
+ } else {
+ // Always assume the third byte to be zero for simplicity.
+ if (length == 2) {
+ customDisplayMessageReceived(emptyMessage, messageBytes[1] << 7, 0);
+ } else if (length == 1) {
+ customMessageBuffer[0] = 0;
+ customDisplayMessageReceived(emptyMessage, 0x80, 0);
+ }
+ }
+}
+
+void Display::scheduleDisplayReset() {
+ displayResetTimestamp = synth.renderedSampleCount + SCHEDULED_DISPLAY_MODE_RESET_FRAMES;
+ displayResetScheduled = true;
+}
+
+bool Display::shouldResetTimer(Bit32u scheduledResetTimestamp) {
+ // Deals with wrapping of renderedSampleCount.
+ return Bit32s(scheduledResetTimestamp - synth.renderedSampleCount) < 0;
+}
+
+void Display::maybeResetTimer(bool &timerState, Bit32u scheduledResetTimestamp) {
+ if (timerState && shouldResetTimer(scheduledResetTimestamp)) timerState = false;
+}
+
+} // namespace MT32Emu
diff --git a/audio/softsynth/mt32/Display.h b/audio/softsynth/mt32/Display.h
new file mode 100644
index 00000000000..1802b0bd28c
--- /dev/null
+++ b/audio/softsynth/mt32/Display.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011-2022 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_DISPLAY_H
+#define MT32EMU_DISPLAY_H
+
+#include "globals.h"
+#include "Types.h"
+
+namespace MT32Emu {
+
+class Synth;
+
+/** Facilitates emulation of internal state of the MIDI MESSAGE LED and the MT-32 LCD. */
+class Display {
+public:
+ static const unsigned int LCD_TEXT_SIZE = 20;
+
+ enum Mode {
+ Mode_MAIN, // a.k.a. Master Volume
+ Mode_STARTUP_MESSAGE,
+ Mode_PROGRAM_CHANGE,
+ Mode_CUSTOM_MESSAGE,
+ Mode_ERROR_MESSAGE
+ };
+
+ Display(Synth &synth);
+ void checkDisplayStateUpdated(bool &midiMessageLEDState, bool &midiMessageLEDUpdated, bool &lcdUpdated);
+ /** Returns whether the MIDI MESSAGE LED is ON and fills the targetBuffer parameter. */
+ bool getDisplayState(char *targetBuffer, bool narrowLCD);
+ void setMainDisplayMode();
+
+ void midiMessagePlayed();
+ void rhythmNotePlayed();
+ void voicePartStateChanged(Bit8u partIndex, bool activated);
+ void masterVolumeChanged();
+ void programChanged(Bit8u partIndex);
+ void checksumErrorOccurred();
+ bool customDisplayMessageReceived(const Bit8u *message, Bit32u startIndex, Bit32u length);
+ void displayControlMessageReceived(const Bit8u *messageBytes, Bit32u length);
+
+private:
+ typedef Bit8u DisplayBuffer[LCD_TEXT_SIZE];
+
+ static const unsigned int TIMBRE_NAME_SIZE = 10;
+
+ Synth &synth;
+
+ bool lastLEDState;
+ bool lcdDirty;
+ bool lcdUpdateSignalled;
+ bool lastRhythmPartState;
+ bool voicePartStates[8];
+
+ Bit8u lastProgramChangePartIndex;
+ const char *lastProgramChangeSoundGroupName;
+ Bit8u lastProgramChangeTimbreName[TIMBRE_NAME_SIZE];
+
+ Mode mode;
+ Bit32u displayResetTimestamp;
+ bool displayResetScheduled;
+ Bit32u midiMessageLEDResetTimestamp;
+ bool midiMessagePlayedSinceLastReset;
+ Bit32u rhythmStateResetTimestamp;
+ bool rhythmNotePlayedSinceLastReset;
+
+ DisplayBuffer displayBuffer;
+ DisplayBuffer customMessageBuffer;
+
+ void scheduleDisplayReset();
+ bool shouldResetTimer(Bit32u scheduledResetTimestamp);
+ void maybeResetTimer(bool &timerState, Bit32u scheduledResetTimestamp);
+};
+
+} // namespace MT32Emu
+
+#endif // #ifndef MT32EMU_DISPLAY_H
diff --git a/audio/softsynth/mt32/Enumerations.h b/audio/softsynth/mt32/Enumerations.h
index fe05d210097..3cbfdd4c8f8 100644
--- a/audio/softsynth/mt32/Enumerations.h
+++ b/audio/softsynth/mt32/Enumerations.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/File.cpp b/audio/softsynth/mt32/File.cpp
index 0cc282921de..fb2febeb173 100644
--- a/audio/softsynth/mt32/File.cpp
+++ b/audio/softsynth/mt32/File.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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,14 @@ namespace MT32Emu {
AbstractFile::AbstractFile() : sha1DigestCalculated(false) {
sha1Digest[0] = 0;
- reserved = nullptr;
+ reserved = NULL;
}
AbstractFile::AbstractFile(const SHA1Digest &useSHA1Digest) : sha1DigestCalculated(true) {
memcpy(sha1Digest, useSHA1Digest, sizeof(SHA1Digest) - 1);
sha1Digest[sizeof(SHA1Digest) - 1] = 0; // Ensure terminator char.
- reserved = nullptr;
+ reserved = NULL;
}
const File::SHA1Digest &AbstractFile::getSHA1() {
@@ -49,7 +49,7 @@ const File::SHA1Digest &AbstractFile::getSHA1() {
}
const Bit8u *data = getData();
- if (data == nullptr) {
+ if (data == NULL) {
return sha1Digest;
}
diff --git a/audio/softsynth/mt32/File.h b/audio/softsynth/mt32/File.h
index 06ab33917d0..2aa34b4c774 100644
--- a/audio/softsynth/mt32/File.h
+++ b/audio/softsynth/mt32/File.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/FileStream.cpp b/audio/softsynth/mt32/FileStream.cpp
index 30f9d27cca5..4424c282ff0 100644
--- a/audio/softsynth/mt32/FileStream.cpp
+++ b/audio/softsynth/mt32/FileStream.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -21,6 +21,11 @@
#include "internals.h"
+// Disable MSVC STL exceptions
+#ifdef _MSC_VER
+#define _HAS_EXCEPTIONS 0
+#endif
+
#include "FileStream.h"
namespace MT32Emu {
@@ -42,7 +47,7 @@ static inline void configureSystemLocale() {
using std::ios_base;
-FileStream::FileStream() : ifsp(*new std::ifstream), data(nullptr), size(0)
+FileStream::FileStream() : ifsp(*new std::ifstream), data(NULL), size(0)
{}
FileStream::~FileStream() {
@@ -64,24 +69,24 @@ size_t FileStream::getSize() {
}
const Bit8u *FileStream::getData() {
- if (data != nullptr) {
+ if (data != NULL) {
return data;
}
if (!ifsp.is_open()) {
- return nullptr;
+ return NULL;
}
if (getSize() == 0) {
- return nullptr;
+ return NULL;
}
Bit8u *fileData = new Bit8u[size];
- if (fileData == nullptr) {
- return nullptr;
+ 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 nullptr;
+ return NULL;
}
data = fileData;
close();
diff --git a/audio/softsynth/mt32/FileStream.h b/audio/softsynth/mt32/FileStream.h
index c5c96973c68..3b397686962 100644
--- a/audio/softsynth/mt32/FileStream.h
+++ b/audio/softsynth/mt32/FileStream.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
index f02eca5fc67..7aea6c240af 100644
--- a/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
+++ b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -49,7 +49,7 @@ void LA32FloatWaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit
wavePos = 0.0f;
lastFreq = 0.0f;
- pcmWaveAddress = nullptr;
+ pcmWaveAddress = NULL;
active = true;
}
@@ -236,7 +236,7 @@ float LA32FloatWaveGenerator::generateNextSample(const Bit32u ampVal, const Bit1
relWavePos -= cosineLen + hLen;
}
- // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment
+ // To ensure the output wave has no breaks, two different windows are applied to the beginning and the ending of the resonance sine segment
if (relWavePos < 0.5f * cosineLen) {
float syncSine = sin(FLOAT_PI * relWavePos / cosineLen);
if (relWavePos < 0.0f) {
@@ -278,7 +278,7 @@ bool LA32FloatWaveGenerator::isActive() const {
}
bool LA32FloatWaveGenerator::isPCMWave() const {
- return pcmWaveAddress != nullptr;
+ return pcmWaveAddress != NULL;
}
void LA32FloatPartialPair::init(const bool useRingModulated, const bool useMixed) {
diff --git a/audio/softsynth/mt32/LA32FloatWaveGenerator.h b/audio/softsynth/mt32/LA32FloatWaveGenerator.h
index 5807b19484e..b34c1fa868e 100644
--- a/audio/softsynth/mt32/LA32FloatWaveGenerator.h
+++ b/audio/softsynth/mt32/LA32FloatWaveGenerator.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/LA32Ramp.cpp b/audio/softsynth/mt32/LA32Ramp.cpp
index d67744280c2..cc61d8357d7 100644
--- a/audio/softsynth/mt32/LA32Ramp.cpp
+++ b/audio/softsynth/mt32/LA32Ramp.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/LA32Ramp.h b/audio/softsynth/mt32/LA32Ramp.h
index 618aaaec1ad..178e16b604e 100644
--- a/audio/softsynth/mt32/LA32Ramp.h
+++ b/audio/softsynth/mt32/LA32Ramp.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/LA32WaveGenerator.cpp b/audio/softsynth/mt32/LA32WaveGenerator.cpp
index 62f66f2a960..cf1a34c9c2b 100644
--- a/audio/softsynth/mt32/LA32WaveGenerator.cpp
+++ b/audio/softsynth/mt32/LA32WaveGenerator.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -173,7 +173,7 @@ void LA32WaveGenerator::generateNextResonanceWaveLogSample() {
// Unsure about resonanceSinePosition here. It's possible that dedicated counter & decrement are used. Although, cutoff is finely ramped, so maybe not.
logSampleValue += resonanceAmpSubtraction + (((resonanceSinePosition >> 4) * decayFactor) >> 8);
- // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment
+ // To ensure the output wave has no breaks, two different windows are applied to the beginning and the ending of the resonance sine segment
if (phase == POSITIVE_RISING_SINE_SEGMENT || phase == NEGATIVE_FALLING_SINE_SEGMENT) {
// The window is synchronous sine here
logSampleValue += Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511] << 2;
@@ -183,7 +183,7 @@ void LA32WaveGenerator::generateNextResonanceWaveLogSample() {
}
if (cutoffVal < MIDDLE_CUTOFF_VALUE) {
- // For the cutoff values below the cutoff middle point, it seems the amp of the resonance wave is expotentially decayed
+ // For the cutoff values below the cutoff middle point, it seems the amp of the resonance wave is exponentially decayed
logSampleValue += 31743 + ((MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9);
} else if (cutoffVal < RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE) {
// For the cutoff values below this point, the amp of the resonance wave is sinusoidally decayed
@@ -269,7 +269,7 @@ void LA32WaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u us
resonanceAmpSubtraction = (32 - resonance) << 10;
resAmpDecayFactor = Tables::getInstance().resAmpDecayFactor[resonance >> 2] << 2;
- pcmWaveAddress = nullptr;
+ pcmWaveAddress = NULL;
active = true;
}
@@ -330,7 +330,7 @@ bool LA32WaveGenerator::isActive() const {
}
bool LA32WaveGenerator::isPCMWave() const {
- return pcmWaveAddress != nullptr;
+ return pcmWaveAddress != NULL;
}
Bit32u LA32WaveGenerator::getPCMInterpolationFactor() const {
diff --git a/audio/softsynth/mt32/LA32WaveGenerator.h b/audio/softsynth/mt32/LA32WaveGenerator.h
index 3de831ae079..71d909df885 100644
--- a/audio/softsynth/mt32/LA32WaveGenerator.h
+++ b/audio/softsynth/mt32/LA32WaveGenerator.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/MemoryRegion.h b/audio/softsynth/mt32/MemoryRegion.h
index af47edf47ed..1f224768ce9 100644
--- a/audio/softsynth/mt32/MemoryRegion.h
+++ b/audio/softsynth/mt32/MemoryRegion.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -120,7 +120,9 @@ public:
};
class DisplayMemoryRegion : public MemoryRegion {
public:
- DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), SYSEX_BUFFER_SIZE - 1, 1) {}
+ // Note, we set realMemory to NULL despite the real devices buffer inbound strings. However, it is impossible to retrieve them.
+ // This entrySize permits emulation of handling a 20-byte display message sent to an old-gen device at address 0x207F7F.
+ DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), 0x4013, 1) {}
};
class ResetMemoryRegion : public MemoryRegion {
public:
diff --git a/audio/softsynth/mt32/MidiEventQueue.h b/audio/softsynth/mt32/MidiEventQueue.h
index af67ca437cd..b458b81902b 100644
--- a/audio/softsynth/mt32/MidiEventQueue.h
+++ b/audio/softsynth/mt32/MidiEventQueue.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/MidiStreamParser.cpp b/audio/softsynth/mt32/MidiStreamParser.cpp
index 462474d9149..7b64f97f9f9 100644
--- a/audio/softsynth/mt32/MidiStreamParser.cpp
+++ b/audio/softsynth/mt32/MidiStreamParser.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -80,7 +80,7 @@ MidiStreamParserImpl::MidiStreamParserImpl(MidiReceiver &useReceiver, MidiReport
streamBufferSize = 0;
runningStatus = 0;
- reserved = nullptr;
+ reserved = NULL;
}
MidiStreamParserImpl::~MidiStreamParserImpl() {
diff --git a/audio/softsynth/mt32/MidiStreamParser.h b/audio/softsynth/mt32/MidiStreamParser.h
index 580b9dd30c5..d3a76c8a037 100644
--- a/audio/softsynth/mt32/MidiStreamParser.h
+++ b/audio/softsynth/mt32/MidiStreamParser.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/Part.cpp b/audio/softsynth/mt32/Part.cpp
index e0acb23329b..5888b97b2d5 100644
--- a/audio/softsynth/mt32/Part.cpp
+++ b/audio/softsynth/mt32/Part.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -52,17 +52,19 @@ Part::Part(Synth *useSynth, unsigned int usePartNum) {
patchTemp = &synth->mt32ram.patchTemp[partNum];
if (usePartNum == 8) {
// Nasty hack for rhythm
- timbreTemp = nullptr;
+ timbreTemp = NULL;
} else {
sprintf(name, "Part %d", partNum + 1);
timbreTemp = &synth->mt32ram.timbreTemp[partNum];
}
currentInstr[0] = 0;
currentInstr[10] = 0;
+ volumeOverride = 255;
modulation = 0;
expression = 100;
pitchBend = 0;
activePartialCount = 0;
+ activeNonReleasingPolyCount = 0;
memset(patchCache, 0, sizeof(patchCache));
}
@@ -166,7 +168,7 @@ void Part::refresh() {
patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0;
}
memcpy(currentInstr, timbreTemp->common.name, 10);
- synth->newTimbreSet(partNum, patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, currentInstr);
+ synth->newTimbreSet(partNum);
updatePitchBenderRange();
}
@@ -235,7 +237,7 @@ void Part::backupCacheToPartials(PatchCache cache[4]) {
// if so then duplicate the cached data from the part to the partial so that
// we can change the part's cache without affecting the partial.
// We delay this until now to avoid a copy operation with every note played
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
poly->backupCacheToPartials(cache);
}
}
@@ -317,7 +319,21 @@ void Part::setVolume(unsigned int midiVolume) {
}
Bit8u Part::getVolume() const {
- return patchTemp->outputLevel;
+ return volumeOverride <= 100 ? volumeOverride : patchTemp->outputLevel;
+}
+
+void Part::setVolumeOverride(Bit8u volume) {
+ volumeOverride = volume;
+ // When volume is 0, we want the part to stop producing any sound at all.
+ // For that to achieve, we have to actually stop processing NoteOn MIDI messages; merely
+ // returning 0 volume is not enough - the output may still be generated at a very low level.
+ // But first, we have to stop all the currently playing polys. This behaviour may also help
+ // with performance issues, because parts muted this way barely consume CPU resources.
+ if (volume == 0) allSoundOff();
+}
+
+Bit8u Part::getVolumeOverride() const {
+ return volumeOverride;
}
Bit8u Part::getExpression() const {
@@ -380,6 +396,7 @@ void RhythmPart::noteOn(unsigned int midiKey, unsigned int velocity) {
synth->printDebug("%s: Attempted to play invalid key %d (velocity %d)", name, midiKey, velocity);
return;
}
+ synth->rhythmNotePlayed();
unsigned int key = midiKey;
unsigned int drumNum = key - 24;
int drumTimbreNum = rhythmTemp[drumNum].timbre;
@@ -427,11 +444,11 @@ void Part::noteOn(unsigned int midiKey, unsigned int velocity) {
synth->printDebug(" PatchTemp: outputLevel %u, panpot %u", patchTemp->outputLevel, patchTemp->panpot);
#endif
#endif
- playPoly(patchCache, nullptr, midiKey, key, velocity);
+ playPoly(patchCache, NULL, midiKey, key, velocity);
}
bool Part::abortFirstPoly(unsigned int key) {
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
if (poly->getKey() == key) {
return poly->startAbort();
}
@@ -440,7 +457,7 @@ bool Part::abortFirstPoly(unsigned int key) {
}
bool Part::abortFirstPoly(PolyState polyState) {
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
if (poly->getState() == polyState) {
return poly->startAbort();
}
@@ -486,7 +503,7 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt
if (synth->isAbortingPoly()) return;
Poly *poly = synth->partialManager->assignPolyToPart(this);
- if (poly == nullptr) {
+ if (poly == NULL) {
synth->printDebug("%s (%s): No free poly to play key %d (velocity %d)", name, currentInstr, midiKey, velocity);
return;
}
@@ -503,13 +520,13 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt
partials[x] = synth->partialManager->allocPartial(partNum);
activePartialCount++;
} else {
- partials[x] = nullptr;
+ partials[x] = NULL;
}
}
poly->reset(key, velocity, cache[0].sustain, partials);
for (int x = 0; x < 4; x++) {
- if (partials[x] != nullptr) {
+ if (partials[x] != NULL) {
#if MT32EMU_MONITOR_PARTIALS > 2
synth->printDebug("%s (%s): Allocated partial %d", name, currentInstr, partials[x]->debugGetPartialNum());
#endif
@@ -525,7 +542,7 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt
void Part::allNotesOff() {
// The MIDI specification states - and Mok confirms - that all notes off (0x7B)
// should treat the hold pedal as usual.
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
// FIXME: This has special handling of key 0 in NoteOff that Mok has not yet confirmed applies to AllNotesOff.
// if (poly->canSustain() || poly->getKey() == 0) {
// FIXME: The real devices are found to be ignoring non-sustaining polys while processing AllNotesOff. Need to be confirmed.
@@ -539,13 +556,13 @@ void Part::allSoundOff() {
// MIDI "All sound off" (0x78) should release notes immediately regardless of the hold pedal.
// This controller is not actually implemented by the synths, though (according to the docs and Mok) -
// we're only using this method internally.
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
poly->startDecay();
}
}
void Part::stopPedalHold() {
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
poly->stopPedalHold();
}
}
@@ -563,7 +580,7 @@ void Part::stopNote(unsigned int key) {
synth->printDebug("%s (%s): stopping key %d", name, currentInstr, key);
#endif
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
// Generally, non-sustaining instruments ignore note off. They die away eventually anyway.
// Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held.
if (poly->getKey() == key && (poly->canSustain() || key == 0)) {
@@ -588,7 +605,7 @@ const Poly *Part::getFirstActivePoly() const {
unsigned int Part::getActiveNonReleasingPartialCount() const {
unsigned int activeNonReleasingPartialCount = 0;
- for (Poly *poly = activePolys.getFirst(); poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) {
if (poly->getState() != POLY_Releasing) {
activeNonReleasingPartialCount += poly->getActivePartialCount();
}
@@ -609,7 +626,28 @@ void Part::partialDeactivated(Poly *poly) {
}
}
-PolyList::PolyList() : firstPoly(nullptr), lastPoly(nullptr) {}
+void RhythmPart::polyStateChanged(PolyState, PolyState) {}
+
+void Part::polyStateChanged(PolyState oldState, PolyState newState) {
+ switch (newState) {
+ case POLY_Playing:
+ if (activeNonReleasingPolyCount++ == 0) synth->voicePartStateChanged(partNum, true);
+ break;
+ case POLY_Releasing:
+ case POLY_Inactive:
+ if (oldState == POLY_Playing || oldState == POLY_Held) {
+ if (--activeNonReleasingPolyCount == 0) synth->voicePartStateChanged(partNum, false);
+ }
+ break;
+ default:
+ break;
+ }
+#ifdef MT32EMU_TRACE_POLY_STATE_CHANGES
+ synth->printDebug("Part %d: Changed poly state %d->%d, activeNonReleasingPolyCount=%d", partNum, oldState, newState, activeNonReleasingPolyCount);
+#endif
+}
+
+PolyList::PolyList() : firstPoly(NULL), lastPoly(NULL) {}
bool PolyList::isEmpty() const {
#ifdef MT32EMU_POLY_LIST_DEBUG
@@ -617,7 +655,7 @@ bool PolyList::isEmpty() const {
printf("PolyList: desynchronised firstPoly & lastPoly pointers\n");
}
#endif
- return firstPoly == nullptr && lastPoly == nullptr;
+ return firstPoly == NULL && lastPoly == NULL;
}
Poly *PolyList::getFirst() const {
@@ -636,7 +674,7 @@ void PolyList::prepend(Poly *poly) {
#endif
poly->setNext(firstPoly);
firstPoly = poly;
- if (lastPoly == nullptr) {
+ if (lastPoly == NULL) {
lastPoly = poly;
}
}
@@ -647,8 +685,8 @@ void PolyList::append(Poly *poly) {
printf("PolyList: Non-NULL next field in a Poly being appended is ignored\n");
}
#endif
- poly->setNext(nullptr);
- if (lastPoly != nullptr) {
+ poly->setNext(NULL);
+ if (lastPoly != NULL) {
#ifdef MT32EMU_POLY_LIST_DEBUG
if (lastPoly->getNext() != NULL) {
printf("PolyList: Non-NULL next field in the lastPoly\n");
@@ -657,7 +695,7 @@ void PolyList::append(Poly *poly) {
lastPoly->setNext(poly);
}
lastPoly = poly;
- if (firstPoly == nullptr) {
+ if (firstPoly == NULL) {
firstPoly = poly;
}
}
@@ -665,15 +703,15 @@ void PolyList::append(Poly *poly) {
Poly *PolyList::takeFirst() {
Poly *oldFirst = firstPoly;
firstPoly = oldFirst->getNext();
- if (firstPoly == nullptr) {
+ if (firstPoly == NULL) {
#ifdef MT32EMU_POLY_LIST_DEBUG
if (lastPoly != oldFirst) {
printf("PolyList: firstPoly != lastPoly in a list with a single Poly\n");
}
#endif
- lastPoly = nullptr;
+ lastPoly = NULL;
}
- oldFirst->setNext(nullptr);
+ oldFirst->setNext(NULL);
return oldFirst;
}
@@ -682,7 +720,7 @@ void PolyList::remove(Poly * const polyToRemove) {
takeFirst();
return;
}
- for (Poly *poly = firstPoly; poly != nullptr; poly = poly->getNext()) {
+ for (Poly *poly = firstPoly; poly != NULL; poly = poly->getNext()) {
if (poly->getNext() == polyToRemove) {
if (polyToRemove == lastPoly) {
#ifdef MT32EMU_POLY_LIST_DEBUG
@@ -693,7 +731,7 @@ void PolyList::remove(Poly * const polyToRemove) {
lastPoly = poly;
}
poly->setNext(polyToRemove->getNext());
- polyToRemove->setNext(nullptr);
+ polyToRemove->setNext(NULL);
break;
}
}
diff --git a/audio/softsynth/mt32/Part.h b/audio/softsynth/mt32/Part.h
index f81a89bd0e5..d266efb7ea4 100644
--- a/audio/softsynth/mt32/Part.h
+++ b/audio/softsynth/mt32/Part.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -55,6 +55,7 @@ private:
bool holdpedal;
unsigned int activePartialCount;
+ unsigned int activeNonReleasingPolyCount;
PatchCache patchCache[4];
PolyList activePolys;
@@ -69,6 +70,8 @@ protected:
MemParams::PatchTemp *patchTemp;
char name[8]; // "Part 1".."Part 8", "Rhythm"
char currentInstr[11];
+ // Values outside the valid range 0..100 imply no override.
+ Bit8u volumeOverride;
Bit8u modulation;
Bit8u expression;
Bit32s pitchBend;
@@ -95,8 +98,10 @@ public:
virtual void noteOff(unsigned int midiKey);
void allNotesOff();
void allSoundOff();
- Bit8u getVolume() const; // Internal volume, 0-100, exposed for use by ExternalInterface
- void setVolume(unsigned int midiVolume);
+ Bit8u getVolume() const; // Effective output level, valid range 0..100.
+ void setVolume(unsigned int midiVolume); // Valid range 0..127, as defined for MIDI controller 7.
+ Bit8u getVolumeOverride() const;
+ void setVolumeOverride(Bit8u volumeOverride);
Bit8u getModulation() const;
void setModulation(unsigned int midiModulation);
Bit8u getExpression() const;
@@ -122,6 +127,7 @@ public:
// This should only be called by Poly
void partialDeactivated(Poly *poly);
+ virtual void polyStateChanged(PolyState oldState, PolyState newState);
// These are rather specialised, and should probably only be used by PartialManager
bool abortFirstPoly(PolyState polyState);
@@ -146,6 +152,7 @@ public:
unsigned int getAbsTimbreNum() const;
void setPan(unsigned int midiPan);
void setProgram(unsigned int patchNum);
+ void polyStateChanged(PolyState oldState, PolyState newState);
};
} // namespace MT32Emu
diff --git a/audio/softsynth/mt32/Partial.cpp b/audio/softsynth/mt32/Partial.cpp
index 364fea4aede..2a4b21d9f09 100644
--- a/audio/softsynth/mt32/Partial.cpp
+++ b/audio/softsynth/mt32/Partial.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -60,8 +60,8 @@ Partial::Partial(Synth *useSynth, int usePartialIndex) :
tvp = new TVP(this);
tvf = new TVF(this, &cutoffModifierRamp);
ownerPart = -1;
- poly = nullptr;
- pair = nullptr;
+ poly = NULL;
+ pair = NULL;
switch (synth->getSelectedRendererType()) {
case RendererType_BIT16S:
la32Pair = new LA32IntPartialPair;
@@ -70,7 +70,7 @@ Partial::Partial(Synth *useSynth, int usePartialIndex) :
la32Pair = new LA32FloatPartialPair;
break;
default:
- la32Pair = nullptr;
+ la32Pair = NULL;
}
}
@@ -114,7 +114,7 @@ void Partial::deactivate() {
}
ownerPart = -1;
synth->partialManager->partialDeactivated(partialIndex);
- if (poly != nullptr) {
+ if (poly != NULL) {
poly->partialDeactivated(this);
}
#if MT32EMU_MONITOR_PARTIALS > 2
@@ -127,17 +127,17 @@ void Partial::deactivate() {
la32Pair->deactivate(LA32PartialPair::MASTER);
if (hasRingModulatingSlave()) {
pair->deactivate();
- pair = nullptr;
+ pair = NULL;
}
}
- if (pair != nullptr) {
- pair->pair = nullptr;
+ if (pair != NULL) {
+ pair->pair = NULL;
}
}
void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *usePatchCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial) {
- if (usePoly == nullptr || usePatchCache == nullptr) {
- synth->printDebug("[Partial %d] *** Error: Starting partial for owner %d, usePoly=%s, usePatchCache=%s", partialIndex, ownerPart, usePoly == nullptr ? "*** NULL ***" : "OK", usePatchCache == nullptr ? "*** NULL ***" : "OK");
+ if (usePoly == NULL || usePatchCache == NULL) {
+ synth->printDebug("[Partial %d] *** Error: Starting partial for owner %d, usePoly=%s, usePatchCache=%s", partialIndex, ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", usePatchCache == NULL ? "*** NULL ***" : "OK");
return;
}
patchCache = usePatchCache;
@@ -145,7 +145,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
mixType = patchCache->structureMix;
structurePosition = patchCache->structurePosition;
- Bit8u panSetting = rhythmTemp != nullptr ? rhythmTemp->panpot : part->getPatchTemp()->panpot;
+ Bit8u panSetting = rhythmTemp != NULL ? rhythmTemp->panpot : part->getPatchTemp()->panpot;
if (mixType == 3) {
if (structurePosition == 0) {
panSetting = PAN_NUMERATOR_MASTER[panSetting] << 1;
@@ -154,7 +154,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
}
// Do a normal mix independent of any pair partial.
mixType = 0;
- pairPartial = nullptr;
+ pairPartial = NULL;
} else if (!synth->isNicePanningEnabled()) {
// Mok wanted an option for smoother panning, and we love Mok.
// CONFIRMED by Mok: exactly bytes like this (right shifted) are sent to the LA32.
@@ -197,7 +197,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
}
pcmWave = &synth->pcmWaves[pcmNum];
} else {
- pcmWave = nullptr;
+ pcmWave = NULL;
}
// CONFIRMED: pulseWidthVal calculation is based on information from Mok
@@ -264,26 +264,26 @@ Bit32u Partial::getCutoffValue() {
}
bool Partial::hasRingModulatingSlave() const {
- return pair != nullptr && structurePosition == 0 && (mixType == 1 || mixType == 2);
+ return pair != NULL && structurePosition == 0 && (mixType == 1 || mixType == 2);
}
bool Partial::isRingModulatingSlave() const {
- return pair != nullptr && structurePosition == 1 && (mixType == 1 || mixType == 2);
+ return pair != NULL && structurePosition == 1 && (mixType == 1 || mixType == 2);
}
bool Partial::isRingModulatingNoMix() const {
- return pair != nullptr && ((structurePosition == 1 && mixType == 1) || mixType == 2);
+ return pair != NULL && ((structurePosition == 1 && mixType == 1) || mixType == 2);
}
bool Partial::isPCM() const {
- return pcmWave != nullptr;
+ return pcmWave != NULL;
}
const ControlROMPCMStruct *Partial::getControlROMPCMStruct() const {
- if (pcmWave != nullptr) {
+ if (pcmWave != NULL) {
return pcmWave->controlROMPCMStruct;
}
- return nullptr;
+ return NULL;
}
Synth *Partial::getSynth() const {
@@ -305,7 +305,7 @@ bool Partial::canProduceOutput() {
if (!isActive() || alreadyOutputed || isRingModulatingSlave()) {
return false;
}
- if (poly == nullptr) {
+ if (poly == NULL) {
synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", partialIndex);
return false;
}
diff --git a/audio/softsynth/mt32/Partial.h b/audio/softsynth/mt32/Partial.h
index 3a147b7af53..bfc6f6dcade 100644
--- a/audio/softsynth/mt32/Partial.h
+++ b/audio/softsynth/mt32/Partial.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/PartialManager.cpp b/audio/softsynth/mt32/PartialManager.cpp
index 8ff3ca0cf3f..609adaa74ef 100644
--- a/audio/softsynth/mt32/PartialManager.cpp
+++ b/audio/softsynth/mt32/PartialManager.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -46,7 +46,7 @@ PartialManager::PartialManager(Synth *useSynth, Part **useParts) {
PartialManager::~PartialManager(void) {
for (unsigned int i = 0; i < synth->getPartialCount(); i++) {
delete partialTable[i];
- if (freePolys[i] != nullptr) delete freePolys[i];
+ if (freePolys[i] != NULL) delete freePolys[i];
}
delete[] partialTable;
delete[] inactivePartials;
@@ -97,7 +97,7 @@ Partial *PartialManager::allocPartial(int partNum) {
const Partial *partial = partialTable[i];
synth->printDebug("[Partial %d]: activation=%d, owner part=%d\n", i, partial->isActive(), partial->getOwnerPart());
}
- return nullptr;
+ return NULL;
}
unsigned int PartialManager::getFreePartialCount() {
@@ -257,7 +257,7 @@ bool PartialManager::freePartials(unsigned int needed, int partNum) {
const Partial *PartialManager::getPartial(unsigned int partialNum) const {
if (partialNum > synth->getPartialCount() - 1) {
- return nullptr;
+ return NULL;
}
return partialTable[partialNum];
}
@@ -265,12 +265,12 @@ const Partial *PartialManager::getPartial(unsigned int partialNum) const {
Poly *PartialManager::assignPolyToPart(Part *part) {
if (firstFreePolyIndex < synth->getPartialCount()) {
Poly *poly = freePolys[firstFreePolyIndex];
- freePolys[firstFreePolyIndex] = nullptr;
+ freePolys[firstFreePolyIndex] = NULL;
firstFreePolyIndex++;
poly->setPart(part);
return poly;
}
- return nullptr;
+ return NULL;
}
void PartialManager::polyFreed(Poly *poly) {
@@ -279,7 +279,7 @@ void PartialManager::polyFreed(Poly *poly) {
for (Bit32u partNum = 0; partNum < 9; partNum++) {
const Poly *activePoly = synth->getPart(partNum)->getFirstActivePoly();
Bit32u polyCount = 0;
- while (activePoly != nullptr) {
+ while (activePoly != NULL) {
activePoly = activePoly->getNext();
polyCount++;
}
@@ -289,7 +289,7 @@ void PartialManager::polyFreed(Poly *poly) {
firstFreePolyIndex--;
freePolys[firstFreePolyIndex] = poly;
}
- poly->setPart(nullptr);
+ poly->setPart(NULL);
}
void PartialManager::partialDeactivated(int partialIndex) {
diff --git a/audio/softsynth/mt32/PartialManager.h b/audio/softsynth/mt32/PartialManager.h
index bbb09adc42e..5c019effe02 100644
--- a/audio/softsynth/mt32/PartialManager.h
+++ b/audio/softsynth/mt32/PartialManager.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/Poly.cpp b/audio/softsynth/mt32/Poly.cpp
index 7d4876cd1cf..0306e51ffe8 100644
--- a/audio/softsynth/mt32/Poly.cpp
+++ b/audio/softsynth/mt32/Poly.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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,16 +27,16 @@
namespace MT32Emu {
Poly::Poly() {
- part = nullptr;
+ part = NULL;
key = 255;
velocity = 255;
sustain = false;
activePartialCount = 0;
for (int i = 0; i < 4; i++) {
- partials[i] = nullptr;
+ partials[i] = NULL;
}
state = POLY_Inactive;
- next = nullptr;
+ next = NULL;
}
void Poly::setPart(Part *usePart) {
@@ -48,12 +48,12 @@ void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain,
// This should never happen
part->getSynth()->printDebug("Resetting active poly. Active partial count: %i\n", activePartialCount);
for (int i = 0; i < 4; i++) {
- if (partials[i] != nullptr && partials[i]->isActive()) {
+ if (partials[i] != NULL && partials[i]->isActive()) {
partials[i]->deactivate();
activePartialCount--;
}
}
- state = POLY_Inactive;
+ setState(POLY_Inactive);
}
key = newKey;
@@ -63,9 +63,9 @@ void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain,
activePartialCount = 0;
for (int i = 0; i < 4; i++) {
partials[i] = newPartials[i];
- if (newPartials[i] != nullptr) {
+ if (newPartials[i] != NULL) {
activePartialCount++;
- state = POLY_Playing;
+ setState(POLY_Playing);
}
}
}
@@ -80,7 +80,7 @@ bool Poly::noteOff(bool pedalHeld) {
if (state == POLY_Held) {
return false;
}
- state = POLY_Held;
+ setState(POLY_Held);
} else {
startDecay();
}
@@ -98,11 +98,11 @@ bool Poly::startDecay() {
if (state == POLY_Inactive || state == POLY_Releasing) {
return false;
}
- state = POLY_Releasing;
+ setState(POLY_Releasing);
for (int t = 0; t < 4; t++) {
Partial *partial = partials[t];
- if (partial != nullptr) {
+ if (partial != NULL) {
partial->startDecayAll();
}
}
@@ -115,7 +115,7 @@ bool Poly::startAbort() {
}
for (int t = 0; t < 4; t++) {
Partial *partial = partials[t];
- if (partial != nullptr) {
+ if (partial != NULL) {
partial->startAbort();
part->getSynth()->abortingPoly = this;
}
@@ -123,10 +123,17 @@ bool Poly::startAbort() {
return true;
}
+void Poly::setState(PolyState newState) {
+ if (state == newState) return;
+ PolyState oldState = state;
+ state = newState;
+ part->polyStateChanged(oldState, newState);
+}
+
void Poly::backupCacheToPartials(PatchCache cache[4]) {
for (int partialNum = 0; partialNum < 4; partialNum++) {
Partial *partial = partials[partialNum];
- if (partial != nullptr) {
+ if (partial != NULL) {
partial->backupCache(cache[partialNum]);
}
}
@@ -166,14 +173,14 @@ bool Poly::isActive() const {
void Poly::partialDeactivated(Partial *partial) {
for (int i = 0; i < 4; i++) {
if (partials[i] == partial) {
- partials[i] = nullptr;
+ partials[i] = NULL;
activePartialCount--;
}
}
if (activePartialCount == 0) {
- state = POLY_Inactive;
+ setState(POLY_Inactive);
if (part->getSynth()->abortingPoly == this) {
- part->getSynth()->abortingPoly = nullptr;
+ part->getSynth()->abortingPoly = NULL;
}
}
part->partialDeactivated(this);
diff --git a/audio/softsynth/mt32/Poly.h b/audio/softsynth/mt32/Poly.h
index 6085820d8e9..dd6def0943c 100644
--- a/audio/softsynth/mt32/Poly.h
+++ b/audio/softsynth/mt32/Poly.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -41,6 +41,8 @@ private:
Poly *next;
+ void setState(PolyState state);
+
public:
Poly();
void setPart(Part *usePart);
diff --git a/audio/softsynth/mt32/ROMInfo.cpp b/audio/softsynth/mt32/ROMInfo.cpp
index 9a09dc9a1fd..0f58cd292cb 100644
--- a/audio/softsynth/mt32/ROMInfo.cpp
+++ b/audio/softsynth/mt32/ROMInfo.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -37,9 +37,13 @@ struct ROMInfoLists {
ROMInfoList mt32_1_06;
ROMInfoList mt32_1_07;
ROMInfoList mt32_bluer;
+ ROMInfoList mt32_2_03;
ROMInfoList mt32_2_04;
+ ROMInfoList mt32_2_06;
+ ROMInfoList mt32_2_07;
ROMInfoList cm32l_1_00;
ROMInfoList cm32l_1_02;
+ ROMInfoList cm32ln_1_00;
ROMInfoList fullROMInfos;
ROMInfoList partialROMInfos;
ROMInfoList allROMInfos;
@@ -50,33 +54,37 @@ struct ROMInfoLists {
#define _CALC_ARRAY_LENGTH(x) Bit32u(sizeof (x) / sizeof *(x) - 1)
static const ROMInfoLists &getROMInfoLists() {
- static ROMInfo CTRL_MT32_V1_04_A = {32768, "9cd4858014c4e8a9dff96053f784bfaac1092a2e", ROMInfo::Control, "ctrl_mt32_1_04_a", "MT-32 Control v1.04", ROMInfo::Mux0, nullptr};
+ static ROMInfo CTRL_MT32_V1_04_A = {32768, "9cd4858014c4e8a9dff96053f784bfaac1092a2e", ROMInfo::Control, "ctrl_mt32_1_04_a", "MT-32 Control v1.04", ROMInfo::Mux0, NULL};
static ROMInfo CTRL_MT32_V1_04_B = {32768, "fe8db469b5bfeb37edb269fd47e3ce6d91014652", ROMInfo::Control, "ctrl_mt32_1_04_b", "MT-32 Control v1.04", ROMInfo::Mux1, &CTRL_MT32_V1_04_A};
- static ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, nullptr};
- static ROMInfo CTRL_MT32_V1_05_A = {32768, "57a09d80d2f7ca5b9734edbe9645e6e700f83701", ROMInfo::Control, "ctrl_mt32_1_05_a", "MT-32 Control v1.05", ROMInfo::Mux0, nullptr};
+ static ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_V1_05_A = {32768, "57a09d80d2f7ca5b9734edbe9645e6e700f83701", ROMInfo::Control, "ctrl_mt32_1_05_a", "MT-32 Control v1.05", ROMInfo::Mux0, NULL};
static ROMInfo CTRL_MT32_V1_05_B = {32768, "52e3c6666db9ef962591a8ee99be0cde17f3a6b6", ROMInfo::Control, "ctrl_mt32_1_05_b", "MT-32 Control v1.05", ROMInfo::Mux1, &CTRL_MT32_V1_05_A};
- static ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, nullptr};
- static ROMInfo CTRL_MT32_V1_06_A = {32768, "cc83bf23cee533097fb4c7e2c116e43b50ebacc8", ROMInfo::Control, "ctrl_mt32_1_06_a", "MT-32 Control v1.06", ROMInfo::Mux0, nullptr};
+ static ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_V1_06_A = {32768, "cc83bf23cee533097fb4c7e2c116e43b50ebacc8", ROMInfo::Control, "ctrl_mt32_1_06_a", "MT-32 Control v1.06", ROMInfo::Mux0, NULL};
static ROMInfo CTRL_MT32_V1_06_B = {32768, "bf4f15666bc46679579498386704893b630c1171", ROMInfo::Control, "ctrl_mt32_1_06_b", "MT-32 Control v1.06", ROMInfo::Mux1, &CTRL_MT32_V1_06_A};
- static ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, nullptr};
- static ROMInfo CTRL_MT32_V1_07_A = {32768, "13f06b38f0d9e0fc050b6503ab777bb938603260", ROMInfo::Control, "ctrl_mt32_1_07_a", "MT-32 Control v1.07", ROMInfo::Mux0, nullptr};
+ static ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_V1_07_A = {32768, "13f06b38f0d9e0fc050b6503ab777bb938603260", ROMInfo::Control, "ctrl_mt32_1_07_a", "MT-32 Control v1.07", ROMInfo::Mux0, NULL};
static ROMInfo CTRL_MT32_V1_07_B = {32768, "c55e165487d71fa88bd8c5e9c083bc456c1a89aa", ROMInfo::Control, "ctrl_mt32_1_07_b", "MT-32 Control v1.07", ROMInfo::Mux1, &CTRL_MT32_V1_07_A};
- static ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, nullptr};
- static ROMInfo CTRL_MT32_BLUER_A = {32768, "11a6ae5d8b6ee328b371af7f1e40b82125aa6b4d", ROMInfo::Control, "ctrl_mt32_bluer_a", "MT-32 Control BlueRidge", ROMInfo::Mux0, nullptr};
+ static ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_BLUER_A = {32768, "11a6ae5d8b6ee328b371af7f1e40b82125aa6b4d", ROMInfo::Control, "ctrl_mt32_bluer_a", "MT-32 Control BlueRidge", ROMInfo::Mux0, NULL};
static ROMInfo CTRL_MT32_BLUER_B = {32768, "e0934320d7cbb5edfaa29e0d01ae835ef620085b", ROMInfo::Control, "ctrl_mt32_bluer_b", "MT-32 Control BlueRidge", ROMInfo::Mux1, &CTRL_MT32_BLUER_A};
- static ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, nullptr};
+ static ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL};
- static const ROMInfo CTRL_MT32_V2_04 = {131072, "2c16432b6c73dd2a3947cba950a0f4c19d6180eb", ROMInfo::Control, "ctrl_mt32_2_04", "MT-32 Control v2.04", ROMInfo::Full, nullptr};
- static const ROMInfo CTRL_CM32L_V1_00 = {65536, "73683d585cd6948cc19547942ca0e14a0319456d", ROMInfo::Control, "ctrl_cm32l_1_00", "CM-32L/LAPC-I Control v1.00", ROMInfo::Full, nullptr};
- static const ROMInfo CTRL_CM32L_V1_02 = {65536, "a439fbb390da38cada95a7cbb1d6ca199cd66ef8", ROMInfo::Control, "ctrl_cm32l_1_02", "CM-32L/LAPC-I Control v1.02", ROMInfo::Full, nullptr};
+ static const ROMInfo CTRL_MT32_V2_03 = {131072, "5837064c9df4741a55f7c4d8787ac158dff2d3ce", ROMInfo::Control, "ctrl_mt32_2_03", "MT-32 Control v2.03", ROMInfo::Full, NULL};
+ static const ROMInfo CTRL_MT32_V2_04 = {131072, "2c16432b6c73dd2a3947cba950a0f4c19d6180eb", ROMInfo::Control, "ctrl_mt32_2_04", "MT-32 Control v2.04", ROMInfo::Full, NULL};
+ static const ROMInfo CTRL_MT32_V2_06 = {131072, "2869cf4c235d671668cfcb62415e2ce8323ad4ed", ROMInfo::Control, "ctrl_mt32_2_06", "MT-32 Control v2.06", ROMInfo::Full, NULL};
+ static const ROMInfo CTRL_MT32_V2_07 = {131072, "47b52adefedaec475c925e54340e37673c11707c", ROMInfo::Control, "ctrl_mt32_2_07", "MT-32 Control v2.07", 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};
+ 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 CTRL_CM32LN_V1_00 = {65536, "dc1c5b1b90a4646d00f7daf3679733c7badc7077", ROMInfo::Control, "ctrl_cm32ln_1_00", "CM-32LN/CM-500/LAPC-N Control v1.00", ROMInfo::Full, NULL};
- static ROMInfo PCM_MT32_L = {262144, "3a1e19b0cd4036623fd1d1d11f5f25995585962b", ROMInfo::PCM, "pcm_mt32_l", "MT-32 PCM ROM", ROMInfo::FirstHalf, nullptr};
+ static ROMInfo PCM_MT32_L = {262144, "3a1e19b0cd4036623fd1d1d11f5f25995585962b", ROMInfo::PCM, "pcm_mt32_l", "MT-32 PCM ROM", ROMInfo::FirstHalf, NULL};
static ROMInfo PCM_MT32_H = {262144, "2cadb99d21a6a4a6f5b61b6218d16e9b43f61d01", ROMInfo::PCM, "pcm_mt32_h", "MT-32 PCM ROM", ROMInfo::SecondHalf, &PCM_MT32_L};
- static ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, nullptr};
+ static ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL};
// Alias of PCM_MT32 ROM, only useful for pairing with PCM_CM32L_H.
- static ROMInfo PCM_CM32L_L = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_cm32l_l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::FirstHalf, nullptr};
+ static ROMInfo PCM_CM32L_L = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_cm32l_l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::FirstHalf, NULL};
static ROMInfo PCM_CM32L_H = {524288, "3ad889fde5db5b6437cbc2eb6e305312fec3df93", ROMInfo::PCM, "pcm_cm32l_h", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::SecondHalf, &PCM_CM32L_L};
- static ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, nullptr};
+ static ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL};
static const ROMInfo * const FULL_ROM_INFOS[] = {
&CTRL_MT32_V1_04,
@@ -84,12 +92,16 @@ static const ROMInfoLists &getROMInfoLists() {
&CTRL_MT32_V1_06,
&CTRL_MT32_V1_07,
&CTRL_MT32_BLUER,
+ &CTRL_MT32_V2_03,
&CTRL_MT32_V2_04,
+ &CTRL_MT32_V2_06,
+ &CTRL_MT32_V2_07,
&CTRL_CM32L_V1_00,
&CTRL_CM32L_V1_02,
+ &CTRL_CM32LN_V1_00,
&PCM_MT32,
&PCM_CM32L,
- nullptr
+ NULL
};
static const ROMInfo * const PARTIAL_ROM_INFOS[] = {
&CTRL_MT32_V1_04_A, &CTRL_MT32_V1_04_B,
@@ -99,11 +111,11 @@ static const ROMInfoLists &getROMInfoLists() {
&CTRL_MT32_BLUER_A, &CTRL_MT32_BLUER_B,
&PCM_MT32_L, &PCM_MT32_H,
&PCM_CM32L_L, &PCM_CM32L_H,
- nullptr
+ NULL
};
static const ROMInfo *ALL_ROM_INFOS[_CALC_ARRAY_LENGTH(FULL_ROM_INFOS) + _CALC_ARRAY_LENGTH(PARTIAL_ROM_INFOS) + 1];
- if (CTRL_MT32_V1_04_A.pairROMInfo == nullptr) {
+ if (CTRL_MT32_V1_04_A.pairROMInfo == NULL) {
CTRL_MT32_V1_04_A.pairROMInfo = &CTRL_MT32_V1_04_B;
CTRL_MT32_V1_05_A.pairROMInfo = &CTRL_MT32_V1_05_B;
CTRL_MT32_V1_06_A.pairROMInfo = &CTRL_MT32_V1_06_B;
@@ -116,14 +128,18 @@ static const ROMInfoLists &getROMInfoLists() {
memcpy(&ALL_ROM_INFOS[_CALC_ARRAY_LENGTH(FULL_ROM_INFOS)], PARTIAL_ROM_INFOS, sizeof PARTIAL_ROM_INFOS); // Includes NULL terminator.
}
- static const ROMInfo * const MT32_V1_04_ROMS[] = {&CTRL_MT32_V1_04, &PCM_MT32, &CTRL_MT32_V1_04_A, &CTRL_MT32_V1_04_B, &PCM_MT32_L, &PCM_MT32_H, nullptr};
- static const ROMInfo * const MT32_V1_05_ROMS[] = {&CTRL_MT32_V1_05, &PCM_MT32, &CTRL_MT32_V1_05_A, &CTRL_MT32_V1_05_B, &PCM_MT32_L, &PCM_MT32_H, nullptr};
- static const ROMInfo * const MT32_V1_06_ROMS[] = {&CTRL_MT32_V1_06, &PCM_MT32, &CTRL_MT32_V1_06_A, &CTRL_MT32_V1_06_B, &PCM_MT32_L, &PCM_MT32_H, nullptr};
- static const ROMInfo * const MT32_V1_07_ROMS[] = {&CTRL_MT32_V1_07, &PCM_MT32, &CTRL_MT32_V1_07_A, &CTRL_MT32_V1_07_B, &PCM_MT32_L, &PCM_MT32_H, nullptr};
- static const ROMInfo * const MT32_BLUER_ROMS[] = {&CTRL_MT32_BLUER, &PCM_MT32, &CTRL_MT32_BLUER_A, &CTRL_MT32_BLUER_B, &PCM_MT32_L, &PCM_MT32_H, nullptr};
- static const ROMInfo * const MT32_V2_04_ROMS[] = {&CTRL_MT32_V2_04, &PCM_MT32, &PCM_MT32_L, &PCM_MT32_H, nullptr};
- static const ROMInfo * const CM32L_V1_00_ROMS[] = {&CTRL_CM32L_V1_00, &PCM_CM32L, &PCM_CM32L_L, &PCM_CM32L_H, nullptr};
- static const ROMInfo * const CM32L_V1_02_ROMS[] = {&CTRL_CM32L_V1_02, &PCM_CM32L, &PCM_CM32L_L, &PCM_CM32L_H, nullptr};
+ static const ROMInfo * const MT32_V1_04_ROMS[] = {&CTRL_MT32_V1_04, &PCM_MT32, &CTRL_MT32_V1_04_A, &CTRL_MT32_V1_04_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V1_05_ROMS[] = {&CTRL_MT32_V1_05, &PCM_MT32, &CTRL_MT32_V1_05_A, &CTRL_MT32_V1_05_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V1_06_ROMS[] = {&CTRL_MT32_V1_06, &PCM_MT32, &CTRL_MT32_V1_06_A, &CTRL_MT32_V1_06_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V1_07_ROMS[] = {&CTRL_MT32_V1_07, &PCM_MT32, &CTRL_MT32_V1_07_A, &CTRL_MT32_V1_07_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_BLUER_ROMS[] = {&CTRL_MT32_BLUER, &PCM_MT32, &CTRL_MT32_BLUER_A, &CTRL_MT32_BLUER_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V2_03_ROMS[] = {&CTRL_MT32_V2_03, &PCM_MT32, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V2_04_ROMS[] = {&CTRL_MT32_V2_04, &PCM_MT32, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V2_06_ROMS[] = {&CTRL_MT32_V2_06, &PCM_MT32, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V2_07_ROMS[] = {&CTRL_MT32_V2_07, &PCM_MT32, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const CM32L_V1_00_ROMS[] = {&CTRL_CM32L_V1_00, &PCM_CM32L, &PCM_CM32L_L, &PCM_CM32L_H, NULL};
+ static const ROMInfo * const CM32L_V1_02_ROMS[] = {&CTRL_CM32L_V1_02, &PCM_CM32L, &PCM_CM32L_L, &PCM_CM32L_H, NULL};
+ static const ROMInfo * const CM32LN_V1_00_ROMS[] = {&CTRL_CM32LN_V1_00, &PCM_CM32L, NULL};
static const ROMInfoLists romInfoLists = {
{MT32_V1_04_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_04_ROMS)},
@@ -131,9 +147,13 @@ static const ROMInfoLists &getROMInfoLists() {
{MT32_V1_06_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_06_ROMS)},
{MT32_V1_07_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_07_ROMS)},
{MT32_BLUER_ROMS, _CALC_ARRAY_LENGTH(MT32_BLUER_ROMS)},
+ {MT32_V2_03_ROMS, _CALC_ARRAY_LENGTH(MT32_V2_03_ROMS)},
{MT32_V2_04_ROMS, _CALC_ARRAY_LENGTH(MT32_V2_04_ROMS)},
+ {MT32_V2_06_ROMS, _CALC_ARRAY_LENGTH(MT32_V2_06_ROMS)},
+ {MT32_V2_07_ROMS, _CALC_ARRAY_LENGTH(MT32_V2_07_ROMS)},
{CM32L_V1_00_ROMS, _CALC_ARRAY_LENGTH(CM32L_V1_00_ROMS)},
{CM32L_V1_02_ROMS, _CALC_ARRAY_LENGTH(CM32L_V1_02_ROMS)},
+ {CM32LN_V1_00_ROMS, _CALC_ARRAY_LENGTH(CM32LN_V1_00_ROMS)},
{FULL_ROM_INFOS, _CALC_ARRAY_LENGTH(FULL_ROM_INFOS)},
{PARTIAL_ROM_INFOS, _CALC_ARRAY_LENGTH(PARTIAL_ROM_INFOS)},
{ALL_ROM_INFOS, _CALC_ARRAY_LENGTH(ALL_ROM_INFOS)}
@@ -155,13 +175,13 @@ const ROMInfo *ROMInfo::getROMInfo(File *file) {
const ROMInfo *ROMInfo::getROMInfo(File *file, const ROMInfo * const *romInfos) {
size_t fileSize = file->getSize();
- for (Bit32u i = 0; romInfos[i] != nullptr; i++) {
+ for (Bit32u i = 0; romInfos[i] != NULL; i++) {
const ROMInfo *romInfo = romInfos[i];
if (fileSize == romInfo->fileSize && !strcmp(file->getSHA1(), romInfo->sha1Digest)) {
return romInfo;
}
}
- return nullptr;
+ return NULL;
}
void ROMInfo::freeROMInfo(const ROMInfo *romInfo) {
@@ -178,7 +198,7 @@ const ROMInfo **ROMInfo::getROMInfoList(Bit32u types, Bit32u pairTypes) {
*currentROMInList++ = romInfo;
}
}
- *currentROMInList = nullptr;
+ *currentROMInList = NULL;
return romInfoList;
}
@@ -187,17 +207,17 @@ void ROMInfo::freeROMInfoList(const ROMInfo **romInfoList) {
}
const ROMInfo * const *ROMInfo::getAllROMInfos(Bit32u *itemCount) {
- if (itemCount != nullptr) *itemCount = getROMInfoLists().allROMInfos.itemCount;
+ if (itemCount != NULL) *itemCount = getROMInfoLists().allROMInfos.itemCount;
return getROMInfoLists().allROMInfos.romInfos;
}
const ROMInfo * const *ROMInfo::getFullROMInfos(Bit32u *itemCount) {
- if (itemCount != nullptr) *itemCount = getROMInfoLists().fullROMInfos.itemCount;
+ if (itemCount != NULL) *itemCount = getROMInfoLists().fullROMInfos.itemCount;
return getROMInfoLists().fullROMInfos.romInfos;
}
const ROMInfo * const *ROMInfo::getPartialROMInfos(Bit32u *itemCount) {
- if (itemCount != nullptr) *itemCount = getROMInfoLists().partialROMInfos.itemCount;
+ if (itemCount != NULL) *itemCount = getROMInfoLists().partialROMInfos.itemCount;
return getROMInfoLists().partialROMInfos.romInfos;
}
@@ -213,9 +233,9 @@ const ROMImage *ROMImage::appendImages(const ROMImage *romImageLow, const ROMIma
memcpy(data, romDataLow, partSize);
memcpy(data + partSize, romDataHigh, partSize);
const ROMImage *romImageFull = makeFullROMImage(data, 2 * partSize);
- if (romImageFull->getROMInfo() == nullptr) {
+ if (romImageFull->getROMInfo() == NULL) {
freeROMImage(romImageFull);
- return nullptr;
+ return NULL;
}
return romImageFull;
}
@@ -231,9 +251,9 @@ const ROMImage *ROMImage::interleaveImages(const ROMImage *romImageEven, const R
*(writePtr++) = romDataOdd[romDataIx];
}
const ROMImage *romImageFull = makeFullROMImage(data, 2 * partSize);
- if (romImageFull->getROMInfo() == nullptr) {
+ if (romImageFull->getROMInfo() == NULL) {
freeROMImage(romImageFull);
- return nullptr;
+ return NULL;
}
return romImageFull;
}
@@ -263,7 +283,7 @@ const ROMImage *ROMImage::makeROMImage(File *file1, File *file2) {
const ROMInfo * const *partialROMInfos = getROMInfoLists().partialROMInfos.romInfos;
const ROMImage *image1 = makeROMImage(file1, partialROMInfos);
const ROMImage *image2 = makeROMImage(file2, partialROMInfos);
- const ROMImage *fullImage = image1->getROMInfo() == nullptr || image2->getROMInfo() == nullptr ? nullptr : mergeROMImages(image1, image2);
+ const ROMImage *fullImage = image1->getROMInfo() == NULL || image2->getROMInfo() == NULL ? NULL : mergeROMImages(image1, image2);
freeROMImage(image1);
freeROMImage(image2);
return fullImage;
@@ -275,7 +295,7 @@ void ROMImage::freeROMImage(const ROMImage *romImage) {
const ROMImage *ROMImage::mergeROMImages(const ROMImage *romImage1, const ROMImage *romImage2) {
if (romImage1->romInfo->pairROMInfo != romImage2->romInfo) {
- return nullptr;
+ return NULL;
}
switch (romImage1->romInfo->pairType) {
case ROMInfo::FirstHalf:
@@ -289,7 +309,7 @@ const ROMImage *ROMImage::mergeROMImages(const ROMImage *romImage1, const ROMIma
default:
break;
}
- return nullptr;
+ return NULL;
}
File *ROMImage::getFile() const {
@@ -311,14 +331,18 @@ const MachineConfiguration * const *MachineConfiguration::getAllMachineConfigura
static const MachineConfiguration MT32_1_06 = MachineConfiguration("mt32_1_06", romInfoLists.mt32_1_06.romInfos, romInfoLists.mt32_1_06.itemCount);
static const MachineConfiguration MT32_1_07 = MachineConfiguration("mt32_1_07", romInfoLists.mt32_1_07.romInfos, romInfoLists.mt32_1_07.itemCount);
static const MachineConfiguration MT32_BLUER = MachineConfiguration("mt32_bluer", romInfoLists.mt32_bluer.romInfos, romInfoLists.mt32_bluer.itemCount);
+ static const MachineConfiguration MT32_2_03 = MachineConfiguration("mt32_2_03", romInfoLists.mt32_2_03.romInfos, romInfoLists.mt32_2_03.itemCount);
static const MachineConfiguration MT32_2_04 = MachineConfiguration("mt32_2_04", romInfoLists.mt32_2_04.romInfos, romInfoLists.mt32_2_04.itemCount);
+ static const MachineConfiguration MT32_2_06 = MachineConfiguration("mt32_2_06", romInfoLists.mt32_2_06.romInfos, romInfoLists.mt32_2_06.itemCount);
+ static const MachineConfiguration MT32_2_07 = MachineConfiguration("mt32_2_07", romInfoLists.mt32_2_07.romInfos, romInfoLists.mt32_2_07.itemCount);
static const MachineConfiguration CM32L_1_00 = MachineConfiguration("cm32l_1_00", romInfoLists.cm32l_1_00.romInfos, romInfoLists.cm32l_1_00.itemCount);
static const MachineConfiguration CM32L_1_02 = MachineConfiguration("cm32l_1_02", romInfoLists.cm32l_1_02.romInfos, romInfoLists.cm32l_1_02.itemCount);
+ static const MachineConfiguration CM32LN_1_00 = MachineConfiguration("cm32ln_1_00", romInfoLists.cm32ln_1_00.romInfos, romInfoLists.cm32ln_1_00.itemCount);
static const MachineConfiguration * const MACHINE_CONFIGURATIONS[] = {
- &MT32_1_04, &MT32_1_05, &MT32_1_06, &MT32_1_07, &MT32_BLUER, &MT32_2_04, &CM32L_1_00, &CM32L_1_02, nullptr
+ &MT32_1_04, &MT32_1_05, &MT32_1_06, &MT32_1_07, &MT32_BLUER, &MT32_2_03, &MT32_2_04, &MT32_2_06, &MT32_2_07, &CM32L_1_00, &CM32L_1_02, &CM32LN_1_00, NULL
};
- if (itemCount != nullptr) *itemCount = _CALC_ARRAY_LENGTH(MACHINE_CONFIGURATIONS);
+ if (itemCount != NULL) *itemCount = _CALC_ARRAY_LENGTH(MACHINE_CONFIGURATIONS);
return MACHINE_CONFIGURATIONS;
}
@@ -331,7 +355,7 @@ const char *MachineConfiguration::getMachineID() const {
}
const ROMInfo * const *MachineConfiguration::getCompatibleROMInfos(Bit32u *itemCount) const {
- if (itemCount != nullptr) *itemCount = romInfosCount;
+ if (itemCount != NULL) *itemCount = romInfosCount;
return romInfos;
}
diff --git a/audio/softsynth/mt32/ROMInfo.h b/audio/softsynth/mt32/ROMInfo.h
index 1e52ee78d3a..1580362f4e1 100644
--- a/audio/softsynth/mt32/ROMInfo.h
+++ b/audio/softsynth/mt32/ROMInfo.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/SampleRateConverter.cpp b/audio/softsynth/mt32/SampleRateConverter.cpp
index 7beac346b70..cce6f59fd65 100644
--- a/audio/softsynth/mt32/SampleRateConverter.cpp
+++ b/audio/softsynth/mt32/SampleRateConverter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
@@ -14,9 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define MT32EMU_WITH_LIBSOXR_RESAMPLER 0
-#define MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER 0
-#define MT32EMU_WITH_INTERNAL_RESAMPLER 1
+#include <cstddef>
#include "SampleRateConverter.h"
@@ -41,7 +39,7 @@ static inline void *createDelegate(Synth &synth, double targetSampleRate, Sample
return new InternalResampler(synth, targetSampleRate, quality);
#else
(void)synth, (void)targetSampleRate, (void)quality;
- return nullptr;
+ return NULL;
#endif
}
diff --git a/audio/softsynth/mt32/SampleRateConverter.h b/audio/softsynth/mt32/SampleRateConverter.h
index 4c501632a0a..6831ff2a0f3 100644
--- a/audio/softsynth/mt32/SampleRateConverter.h
+++ b/audio/softsynth/mt32/SampleRateConverter.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/Structures.h b/audio/softsynth/mt32/Structures.h
index 28dcb8514ce..29362020193 100644
--- a/audio/softsynth/mt32/Structures.h
+++ b/audio/softsynth/mt32/Structures.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -191,6 +191,9 @@ struct ControlROMFeatureSet {
unsigned int quirkPanMult : 1;
unsigned int quirkKeyShift : 1;
unsigned int quirkTVFBaseCutoffLimit : 1;
+ unsigned int quirkFastPitchChanges : 1;
+ unsigned int quirkDisplayCustomMessagePriority : 1;
+ unsigned int oldMT32DisplayFeatures : 1;
// Features below don't actually depend on control ROM version, which is used to identify hardware model
unsigned int defaultReverbMT32Compatible : 1;
@@ -221,6 +224,8 @@ struct ControlROMMap {
Bit16u timbreMaxTable; // 72 bytes
Bit16u soundGroupsTable; // 14 bytes each entry
Bit16u soundGroupsCount;
+ Bit16u startupMessage; // 20 characters + NULL terminator
+ Bit16u sysexErrorMessage; // 20 characters + NULL terminator
};
struct ControlROMPCMStruct {
diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp
index dee8b1a961b..0b81edb9341 100644
--- a/audio/softsynth/mt32/Synth.cpp
+++ b/audio/softsynth/mt32/Synth.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -22,6 +22,7 @@
#include "Synth.h"
#include "Analog.h"
#include "BReverbModel.h"
+#include "Display.h"
#include "File.h"
#include "MemoryRegion.h"
#include "MidiEventQueue.h"
@@ -41,19 +42,35 @@ namespace MT32Emu {
// MIDI interface data transfer rate in samples. Used to simulate the transfer delay.
static const double MIDI_DATA_TRANSFER_RATE = double(SAMPLE_RATE) / 31250.0 * 8.0;
-// FIXME: there should be more specific feature sets for various MT-32 control ROM versions
-static const ControlROMFeatureSet OLD_MT32_COMPATIBLE = {
- true, // quirkBasePitchOverflow
- true, // quirkPitchEnvelopeOverflow
- true, // quirkRingModulationNoMix
- true, // quirkTVAZeroEnvLevels
- true, // quirkPanMult
- true, // quirkKeyShift
- true, // quirkTVFBaseCutoffLimit
- true, // defaultReverbMT32Compatible
- true // oldMT32AnalogLPF
+static const ControlROMFeatureSet OLD_MT32_ELDER = {
+ true, // quirkBasePitchOverflow
+ true, // quirkPitchEnvelopeOverflow
+ true, // quirkRingModulationNoMix
+ true, // quirkTVAZeroEnvLevels
+ true, // quirkPanMult
+ true, // quirkKeyShift
+ true, // quirkTVFBaseCutoffLimit
+ false, // quirkFastPitchChanges
+ true, // quirkDisplayCustomMessagePriority
+ true, // oldMT32DisplayFeatures
+ true, // defaultReverbMT32Compatible
+ true // oldMT32AnalogLPF
};
-static const ControlROMFeatureSet CM32L_COMPATIBLE = {
+static const ControlROMFeatureSet OLD_MT32_LATER = {
+ true, // quirkBasePitchOverflow
+ true, // quirkPitchEnvelopeOverflow
+ true, // quirkRingModulationNoMix
+ true, // quirkTVAZeroEnvLevels
+ true, // quirkPanMult
+ true, // quirkKeyShift
+ true, // quirkTVFBaseCutoffLimit
+ false, // quirkFastPitchChanges
+ false, // quirkDisplayCustomMessagePriority
+ true, // oldMT32DisplayFeatures
+ true, // defaultReverbMT32Compatible
+ true // oldMT32AnalogLPF
+};
+static const ControlROMFeatureSet NEW_MT32_COMPATIBLE = {
false, // quirkBasePitchOverflow
false, // quirkPitchEnvelopeOverflow
false, // quirkRingModulationNoMix
@@ -61,20 +78,41 @@ static const ControlROMFeatureSet CM32L_COMPATIBLE = {
false, // quirkPanMult
false, // quirkKeyShift
false, // quirkTVFBaseCutoffLimit
+ false, // quirkFastPitchChanges
+ false, // quirkDisplayCustomMessagePriority
+ false, // oldMT32DisplayFeatures
false, // defaultReverbMT32Compatible
- false // oldMT32AnalogLPF
+ false // oldMT32AnalogLPF
+};
+static const ControlROMFeatureSet CM32LN_COMPATIBLE = {
+ false, // quirkBasePitchOverflow
+ false, // quirkPitchEnvelopeOverflow
+ false, // quirkRingModulationNoMix
+ false, // quirkTVAZeroEnvLevels
+ false, // quirkPanMult
+ false, // quirkKeyShift
+ false, // quirkTVFBaseCutoffLimit
+ true, // quirkFastPitchChanges
+ false, // quirkDisplayCustomMessagePriority
+ false, // oldMT32DisplayFeatures
+ false, // defaultReverbMT32Compatible
+ false // oldMT32AnalogLPF
};
-static const ControlROMMap ControlROMMaps[8] = {
- // ID Features PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax sndGrp sGC
- { "ctrl_mt32_1_04", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x7064, 19 },
- { "ctrl_mt32_1_05", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x70CA, 19 },
- { "ctrl_mt32_1_06", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C, 0x70CA, 19 },
- { "ctrl_mt32_1_07", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4, 0x70B0, 19 }, // MT-32 revision 1
- {"ctrl_mt32_bluer", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x741C, 85, 0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228, 0x70CE, 19 }, // MT-32 Blue Ridge mod
- {"ctrl_mt32_2_04", CM32L_COMPATIBLE, 0x8100, 128, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 30, 0x8580, 85, 0x4F5D, 0x4F78, 0x4F66, 0x4899, 0x489D, 0x48B6, 0x48CD, 0x5A58, 19 },
- {"ctrl_cm32l_1_00", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5, 0x5A6C, 19 },
- {"ctrl_cm32l_1_02", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF, 0x5A96, 19 } // CM-32L
+static const ControlROMMap ControlROMMaps[] = {
+ // ID Features PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax sndGrp sGC stMsg sErMsg
+ {"ctrl_mt32_1_04", OLD_MT32_ELDER, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x7064, 19, 0x217A, 0x4BB6},
+ {"ctrl_mt32_1_05", OLD_MT32_ELDER, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x70CA, 19, 0x217A, 0x4BB6},
+ {"ctrl_mt32_1_06", OLD_MT32_LATER, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C, 0x70CA, 19, 0x217A, 0x4BBA},
+ {"ctrl_mt32_1_07", OLD_MT32_LATER, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4, 0x70B0, 19, 0x217A, 0x4B92},
+ {"ctrl_mt32_bluer", OLD_MT32_LATER, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x741C, 85, 0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228, 0x70CE, 19, 0x217A, 0x4BC6},
+ {"ctrl_mt32_2_03", NEW_MT32_COMPATIBLE, 0x8100, 128, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F49, 0x4F64, 0x4F52, 0x4885, 0x4889, 0x48A2, 0x48B9, 0x5A44, 19, 0x1EF0, 0x4066},
+ {"ctrl_mt32_2_04", NEW_MT32_COMPATIBLE, 0x8100, 128, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F5D, 0x4F78, 0x4F66, 0x4899, 0x489D, 0x48B6, 0x48CD, 0x5A58, 19, 0x1EF0, 0x406D},
+ {"ctrl_mt32_2_06", NEW_MT32_COMPATIBLE, 0x8100, 128, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F69, 0x4F84, 0x4F72, 0x48A5, 0x48A9, 0x48C2, 0x48D9, 0x5A64, 19, 0x1EF0, 0x4021},
+ {"ctrl_mt32_2_07", NEW_MT32_COMPATIBLE, 0x8100, 128, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F81, 0x4F9C, 0x4F8A, 0x48B9, 0x48BD, 0x48D6, 0x48ED, 0x5A78, 19, 0x1EE7, 0x4035},
+ {"ctrl_cm32l_1_00", NEW_MT32_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5, 0x5A6C, 19, 0x1EF0, 0x401D},
+ {"ctrl_cm32l_1_02", NEW_MT32_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF, 0x5A96, 19, 0x1EE7, 0x4047},
+ {"ctrl_cm32ln_1_00", CM32LN_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4EC7, 0x4EE2, 0x4ED0, 0x47FF, 0x4803, 0x481C, 0x4833, 0x55A2, 19, 0x1F59, 0x3F7C}
// (Note that old MT-32 ROMs actually have 86 entries for rhythmTemp)
};
@@ -90,7 +128,7 @@ static inline PartialState getPartialState(PartialManager *partialManager, unsig
template <class I, class O>
static inline void convertSampleFormat(const I *inBuffer, O *outBuffer, const Bit32u len) {
- if (inBuffer == nullptr || outBuffer == nullptr) return;
+ if (inBuffer == NULL || outBuffer == NULL) return;
const I *inBufferEnd = inBuffer + len;
while (inBuffer < inBufferEnd) {
@@ -138,6 +176,8 @@ protected:
synth.renderedSampleCount += count;
}
+ void updateDisplayState();
+
public:
Renderer(Synth &useSynth) : synth(useSynth) {}
@@ -173,10 +213,10 @@ public:
tmpBuffers(createTmpBuffers())
{}
- void render(IntSample *stereoStream, Bit32u len) override;
- void render(FloatSample *stereoStream, Bit32u len) override;
- void renderStreams(const DACOutputStreams<IntSample> &streams, Bit32u len) override;
- void renderStreams(const DACOutputStreams<FloatSample> &streams, Bit32u len) override;
+ void render(IntSample *stereoStream, Bit32u len);
+ void render(FloatSample *stereoStream, Bit32u len);
+ void renderStreams(const DACOutputStreams<IntSample> &streams, Bit32u len);
+ void renderStreams(const DACOutputStreams<FloatSample> &streams, Bit32u len);
template <class O>
void doRenderAndConvert(O *stereoStream, Bit32u len);
@@ -209,10 +249,16 @@ public:
Bit32u midiEventQueueSize;
Bit32u midiEventQueueSysexStorageBufferSize;
+
+ Display *display;
+ bool oldMT32DisplayFeatures;
+
+ ReportHandler2 defaultReportHandler;
+ ReportHandler2 *reportHandler2;
};
Bit32u Synth::getLibraryVersionInt() {
- return (MT32EMU_VERSION_MAJOR << 16) | (MT32EMU_VERSION_MINOR << 8) | (MT32EMU_VERSION_PATCH);
+ return MT32EMU_CURRENT_VERSION_INT;
}
const char *Synth::getLibraryVersionString() {
@@ -241,24 +287,19 @@ Synth::Synth(ReportHandler *useReportHandler) :
opened = false;
reverbOverridden = false;
partialCount = DEFAULT_MAX_PARTIALS;
- controlROMMap = nullptr;
- controlROMFeatures = nullptr;
+ controlROMMap = NULL;
+ controlROMFeatures = NULL;
- if (useReportHandler == nullptr) {
- reportHandler = new ReportHandler;
- isDefaultReportHandler = true;
- } else {
- reportHandler = useReportHandler;
- isDefaultReportHandler = false;
- }
+ reportHandler = useReportHandler != NULL ? useReportHandler : &extensions.defaultReportHandler;
+ extensions.reportHandler2 = &extensions.defaultReportHandler;
extensions.preallocatedReverbMemory = false;
for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
- reverbModels[i] = nullptr;
+ reverbModels[i] = NULL;
}
- reverbModel = nullptr;
- analog = nullptr;
- renderer = nullptr;
+ reverbModel = NULL;
+ analog = NULL;
+ renderer = NULL;
setDACInputMode(DACInputMode_NICE);
setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY);
setOutputGain(1.0f);
@@ -269,38 +310,47 @@ Synth::Synth(ReportHandler *useReportHandler) :
setNicePartialMixingEnabled(false);
selectRendererType(RendererType_BIT16S);
- patchTempMemoryRegion = nullptr;
- rhythmTempMemoryRegion = nullptr;
- timbreTempMemoryRegion = nullptr;
- patchesMemoryRegion = nullptr;
- timbresMemoryRegion = nullptr;
- systemMemoryRegion = nullptr;
- displayMemoryRegion = nullptr;
- resetMemoryRegion = nullptr;
- paddedTimbreMaxTable = nullptr;
-
- partialManager = nullptr;
- pcmWaves = nullptr;
- pcmROMData = nullptr;
- soundGroupNames = nullptr;
- midiQueue = nullptr;
+ patchTempMemoryRegion = NULL;
+ rhythmTempMemoryRegion = NULL;
+ timbreTempMemoryRegion = NULL;
+ patchesMemoryRegion = NULL;
+ timbresMemoryRegion = NULL;
+ systemMemoryRegion = NULL;
+ displayMemoryRegion = NULL;
+ resetMemoryRegion = NULL;
+ paddedTimbreMaxTable = NULL;
+
+ partialManager = NULL;
+ pcmWaves = NULL;
+ pcmROMData = NULL;
+ soundGroupNames = NULL;
+ midiQueue = NULL;
extensions.midiEventQueueSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE;
extensions.midiEventQueueSysexStorageBufferSize = 0;
lastReceivedMIDIEventTimestamp = 0;
memset(parts, 0, sizeof(parts));
renderedSampleCount = 0;
+ extensions.display = NULL;
+ extensions.oldMT32DisplayFeatures = false;
}
Synth::~Synth() {
close(); // Make sure we're closed and everything is freed
- if (isDefaultReportHandler) {
- delete reportHandler;
- }
delete &mt32ram;
delete &mt32default;
delete &extensions;
}
+void Synth::setReportHandler2(ReportHandler2 *reportHandler2) {
+ if (reportHandler2 != NULL) {
+ reportHandler = reportHandler2;
+ extensions.reportHandler2 = reportHandler2;
+ } else {
+ reportHandler = &extensions.defaultReportHandler;
+ extensions.reportHandler2 = &extensions.defaultReportHandler;
+ }
+}
+
void ReportHandler::showLCDMessage(const char *data) {
printf("WRITE-LCD: %s\n", data);
}
@@ -310,26 +360,38 @@ void ReportHandler::printDebug(const char *fmt, va_list list) {
printf("\n");
}
-void Synth::newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]) {
- const char *soundGroupName;
+void Synth::rhythmNotePlayed() const {
+ extensions.display->rhythmNotePlayed();
+}
+
+void Synth::voicePartStateChanged(Bit8u partNum, bool partActivated) const {
+ extensions.display->voicePartStateChanged(partNum, partActivated);
+}
+
+void Synth::newTimbreSet(Bit8u partNum) const {
+ const Part *part = getPart(partNum);
+ reportHandler->onProgramChanged(partNum, getSoundGroupName(part), part->getCurrentInstr());
+}
+
+const char *Synth::getSoundGroupName(const Part *part) const {
+ const PatchParam &patch = part->getPatchTemp()->patch;
+ return getSoundGroupName(patch.timbreGroup, patch.timbreNum);
+}
+
+const char *Synth::getSoundGroupName(Bit8u timbreGroup, Bit8u timbreNumber) const {
switch (timbreGroup) {
case 1:
timbreNumber += 64;
// Fall-through
case 0:
- soundGroupName = soundGroupNames[soundGroupIx[timbreNumber]];
- break;
+ return soundGroupNames[soundGroupIx[timbreNumber]];
case 2:
- soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 2];
- break;
+ return soundGroupNames[controlROMMap->soundGroupsCount - 2];
case 3:
- soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 1];
- break;
+ return soundGroupNames[controlROMMap->soundGroupsCount - 1];
default:
- soundGroupName = nullptr;
- break;
+ return NULL;
}
- reportHandler->onProgramChanged(partNum, soundGroupName, patchName);
}
#define MT32EMU_PRINT_DEBUG \
@@ -365,12 +427,12 @@ void Synth::setReverbEnabled(bool newReverbEnabled) {
if (!extensions.preallocatedReverbMemory) {
reverbModel->close();
}
- reverbModel = nullptr;
+ reverbModel = NULL;
}
}
bool Synth::isReverbEnabled() const {
- return reverbModel != nullptr;
+ return reverbModel != NULL;
}
void Synth::setReverbOverridden(bool newReverbOverridden) {
@@ -433,7 +495,7 @@ MIDIDelayMode Synth::getMIDIDelayMode() const {
void Synth::setOutputGain(float newOutputGain) {
if (newOutputGain < 0.0f) newOutputGain = -newOutputGain;
outputGain = newOutputGain;
- if (analog != nullptr) analog->setSynthOutputGain(newOutputGain);
+ if (analog != NULL) analog->setSynthOutputGain(newOutputGain);
}
float Synth::getOutputGain() const {
@@ -443,13 +505,23 @@ float Synth::getOutputGain() const {
void Synth::setReverbOutputGain(float newReverbOutputGain) {
if (newReverbOutputGain < 0.0f) newReverbOutputGain = -newReverbOutputGain;
reverbOutputGain = newReverbOutputGain;
- if (analog != nullptr) analog->setReverbOutputGain(newReverbOutputGain, isMT32ReverbCompatibilityMode());
+ if (analog != NULL) analog->setReverbOutputGain(newReverbOutputGain, isMT32ReverbCompatibilityMode());
}
float Synth::getReverbOutputGain() const {
return reverbOutputGain;
}
+void Synth::setPartVolumeOverride(Bit8u partNumber, Bit8u volumeOverride) {
+ if (opened && partNumber < 9) {
+ parts[partNumber]->setVolumeOverride(volumeOverride);
+ }
+}
+
+Bit8u Synth::getPartVolumeOverride(Bit8u partNumber) const {
+ return (!opened || partNumber > 8) ? 255 : parts[partNumber]->getVolumeOverride();
+}
+
void Synth::setReversedStereoEnabled(bool enabled) {
reversedStereoEnabled = enabled;
}
@@ -485,7 +557,7 @@ bool Synth::isNicePartialMixingEnabled() const {
bool Synth::loadControlROM(const ROMImage &controlROMImage) {
File *file = controlROMImage.getFile();
const ROMInfo *controlROMInfo = controlROMImage.getROMInfo();
- if ((controlROMInfo == nullptr)
+ if ((controlROMInfo == NULL)
|| (controlROMInfo->type != ROMInfo::Control)
|| (controlROMInfo->pairType != ROMInfo::Full)) {
#if MT32EMU_MONITOR_INIT
@@ -501,8 +573,8 @@ bool Synth::loadControlROM(const ROMImage &controlROMImage) {
memcpy(controlROMData, fileData, CONTROL_ROM_SIZE);
// Control ROM successfully loaded, now check whether it's a known type
- controlROMMap = nullptr;
- controlROMFeatures = nullptr;
+ controlROMMap = NULL;
+ controlROMFeatures = NULL;
for (unsigned int i = 0; i < sizeof(ControlROMMaps) / sizeof(ControlROMMaps[0]); i++) {
if (strcmp(controlROMInfo->shortName, ControlROMMaps[i].shortName) == 0) {
controlROMMap = &ControlROMMaps[i];
@@ -519,7 +591,7 @@ bool Synth::loadControlROM(const ROMImage &controlROMImage) {
bool Synth::loadPCMROM(const ROMImage &pcmROMImage) {
File *file = pcmROMImage.getFile();
const ROMInfo *pcmROMInfo = pcmROMImage.getROMInfo();
- if ((pcmROMInfo == nullptr)
+ if ((pcmROMInfo == NULL)
|| (pcmROMInfo->type != ROMInfo::PCM)
|| (pcmROMInfo->pairType != ROMInfo::Full)) {
return false;
@@ -650,7 +722,7 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, B
return false;
}
partialCount = usePartialCount;
- abortingPoly = nullptr;
+ abortingPoly = NULL;
extensions.abortingPartIx = 0;
// This is to help detect bugs
@@ -717,6 +789,16 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, B
return false;
}
+ if (controlROMMap->timbreRCount == 30) {
+ // We must initialise all 64 rhythm timbres to avoid undefined behaviour.
+ // SEMI-CONFIRMED: Old-gen MT-32 units likely map timbres 30..59 to 0..29.
+ // Attempts to play rhythm timbres 60..63 exhibit undefined behaviour.
+ // We want to emulate the wrap around, so merely copy the entire set of standard
+ // timbres once more. The last 4 dangerous timbres are zeroed out.
+ memcpy(&mt32ram.timbres[222], &mt32ram.timbres[192], sizeof(*mt32ram.timbres) * 30);
+ memset(&mt32ram.timbres[252], 0, sizeof(*mt32ram.timbres) * 4);
+ }
+
#if MT32EMU_MONITOR_INIT
printDebug("Initialising Timbre Bank M");
#endif
@@ -838,6 +920,9 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, B
return false;
}
+ extensions.display = new Display(*this);
+ extensions.oldMT32DisplayFeatures = controlROMFeatures->oldMT32DisplayFeatures;
+
opened = true;
activated = false;
@@ -850,41 +935,44 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, B
void Synth::dispose() {
opened = false;
+ delete extensions.display;
+ extensions.display = NULL;
+
delete midiQueue;
- midiQueue = nullptr;
+ midiQueue = NULL;
delete renderer;
- renderer = nullptr;
+ renderer = NULL;
delete analog;
- analog = nullptr;
+ analog = NULL;
delete partialManager;
- partialManager = nullptr;
+ partialManager = NULL;
for (int i = 0; i < 9; i++) {
delete parts[i];
- parts[i] = nullptr;
+ parts[i] = NULL;
}
delete[] soundGroupNames;
- soundGroupNames = nullptr;
+ soundGroupNames = NULL;
delete[] pcmWaves;
- pcmWaves = nullptr;
+ pcmWaves = NULL;
delete[] pcmROMData;
- pcmROMData = nullptr;
+ pcmROMData = NULL;
deleteMemoryRegions();
for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
delete reverbModels[i];
- reverbModels[i] = nullptr;
+ reverbModels[i] = NULL;
}
- reverbModel = nullptr;
- controlROMFeatures = nullptr;
- controlROMMap = nullptr;
+ reverbModel = NULL;
+ controlROMFeatures = NULL;
+ controlROMMap = NULL;
}
void Synth::close() {
@@ -898,11 +986,11 @@ bool Synth::isOpen() const {
}
void Synth::flushMIDIQueue() {
- if (midiQueue == nullptr) return;
+ if (midiQueue == NULL) return;
for (;;) {
const volatile MidiEventQueue::MidiEvent *midiEvent = midiQueue->peekMidiEvent();
- if (midiEvent == nullptr) break;
- if (midiEvent->sysexData == nullptr) {
+ if (midiEvent == NULL) break;
+ if (midiEvent->sysexData == NULL) {
playMsgNow(midiEvent->shortMessageData);
} else {
playSysexNow(midiEvent->sysexData, midiEvent->sysexLength);
@@ -926,7 +1014,7 @@ Bit32u Synth::setMIDIEventQueueSize(Bit32u useSize) {
binarySize = MAX_QUEUE_SIZE;
}
extensions.midiEventQueueSize = binarySize;
- if (midiQueue != nullptr) {
+ if (midiQueue != NULL) {
flushMIDIQueue();
delete midiQueue;
midiQueue = new MidiEventQueue(binarySize, extensions.midiEventQueueSysexStorageBufferSize);
@@ -938,7 +1026,7 @@ void Synth::configureMIDIEventQueueSysexStorage(Bit32u storageBufferSize) {
if (extensions.midiEventQueueSysexStorageBufferSize == storageBufferSize) return;
extensions.midiEventQueueSysexStorageBufferSize = storageBufferSize;
- if (midiQueue != nullptr) {
+ if (midiQueue != NULL) {
flushMIDIQueue();
delete midiQueue;
midiQueue = new MidiEventQueue(extensions.midiEventQueueSize, storageBufferSize);
@@ -986,7 +1074,7 @@ bool Synth::playMsg(Bit32u msg, Bit32u timestamp) {
reportHandler->onMIDISystemRealtime(Bit8u(msg & 0xFF));
return true;
}
- if (midiQueue == nullptr) return false;
+ if (midiQueue == NULL) return false;
if (midiDelayMode != MIDIDelayMode_IMMEDIATE) {
timestamp = addMIDIInterfaceDelay(getShortMessageLength(msg), timestamp);
}
@@ -1002,7 +1090,7 @@ bool Synth::playSysex(const Bit8u *sysex, Bit32u len) {
}
bool Synth::playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp) {
- if (midiQueue == nullptr) return false;
+ if (midiQueue == NULL) return false;
if (midiDelayMode == MIDIDelayMode_DELAY_ALL) {
timestamp = addMIDIInterfaceDelay(len, timestamp);
}
@@ -1064,7 +1152,7 @@ void Synth::playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) {
if (velocity == 0) {
// MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40
parts[part]->noteOff(note);
- } else {
+ } else if (parts[part]->getVolumeOverride() > 0) {
parts[part]->noteOn(note, velocity);
}
break;
@@ -1130,16 +1218,21 @@ void Synth::playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) {
#endif
return;
}
-
+ extensions.display->midiMessagePlayed();
break;
case 0xC: // Program change
//printDebug("Program change %01x", note);
parts[part]->setProgram(note);
+ if (part < 8) {
+ extensions.display->midiMessagePlayed();
+ extensions.display->programChanged(part);
+ }
break;
case 0xE: // Pitch bender
bend = (velocity << 7) | (note);
//printDebug("Pitch bender %02x", bend);
parts[part]->setBend(bend);
+ extensions.display->midiMessagePlayed();
break;
default:
#if MT32EMU_MONITOR_MIDI > 0
@@ -1197,29 +1290,26 @@ void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sys
printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", int(device));
return;
}
- // This is checked early in the real devices (before any sysex length checks or further processing)
- // FIXME: Response to SYSEX_CMD_DAT reset with partials active (and in general) is untested.
- if ((command == SYSEX_CMD_DT1 || command == SYSEX_CMD_DAT) && sysex[0] == 0x7F) {
- reset();
- return;
- }
- if (command == SYSEX_CMD_EOD) {
-#if MT32EMU_MONITOR_SYSEX > 0
- printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command);
-#endif
- return;
- }
- if (len < 4) {
+ // All models process the checksum before anything else and ignore messages lacking the checksum, or containing the checksum only.
+ if (len < 2) {
printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len);
return;
}
Bit8u checksum = calcSysexChecksum(sysex, len - 1);
if (checksum != sysex[len - 1]) {
printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum);
+ if (opened) extensions.display->checksumErrorOccurred();
return;
}
len -= 1; // Exclude checksum
+
+ if (command == SYSEX_CMD_EOD) {
+#if MT32EMU_MONITOR_SYSEX > 0
+ printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command);
+#endif
+ return;
+ }
switch (command) {
case SYSEX_CMD_WSD:
#if MT32EMU_MONITOR_SYSEX > 0
@@ -1259,12 +1349,34 @@ void Synth::readSysex(Bit8u /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/)
}
void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) {
- if (!opened) return;
+ if (!opened || len < 1) return;
+
+ // This is checked early in the real devices (before any sysex length checks or further processing)
+ if (sysex[0] == 0x7F) {
+ if (!isDisplayOldMT32Compatible()) extensions.display->midiMessagePlayed();
+ reset();
+ return;
+ }
+
+ extensions.display->midiMessagePlayed();
reportHandler->onMIDIMessagePlayed();
+
+ if (len < 3) {
+ // A short message of just 1 or 2 bytes may be written to the display area yet it may cause a user-visible effect,
+ // similarly to the reset area.
+ if (sysex[0] == 0x20) {
+ extensions.display->displayControlMessageReceived(sysex, len);
+ return;
+ }
+ printDebug("writeSysex: Message is too short (%d bytes)!", len);
+ return;
+ }
+
Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]);
addr = MT32EMU_MEMADDR(addr);
sysex += 3;
len -= 3;
+
//printDebug("Sysex addr: 0x%06x", MT32EMU_SYSEXMEMADDR(addr));
// NOTE: Please keep both lower and upper bounds in each check, for ease of reading
@@ -1343,8 +1455,9 @@ void Synth::writeSysexGlobal(Bit32u addr, const Bit8u *sysex, Bit32u len) {
// Find the appropriate memory region
const MemoryRegion *region = findMemoryRegion(addr);
- if (region == nullptr) {
+ if (region == NULL) {
printDebug("Sysex write to unrecognised address %06x, len %d", MT32EMU_SYSEXMEMADDR(addr), len);
+ // FIXME: Real devices may respond differently to a long SysEx that covers adjacent regions.
break;
}
writeMemoryRegion(region, addr, region->getClampedLen(addr, len), sysex);
@@ -1362,7 +1475,7 @@ void Synth::writeSysexGlobal(Bit32u addr, const Bit8u *sysex, Bit32u len) {
void Synth::readMemory(Bit32u addr, Bit32u len, Bit8u *data) {
if (!opened) return;
const MemoryRegion *region = findMemoryRegion(addr);
- if (region != nullptr) {
+ if (region != NULL) {
readMemoryRegion(region, addr, len, data);
}
}
@@ -1391,24 +1504,24 @@ void Synth::initMemoryRegions() {
void Synth::deleteMemoryRegions() {
delete patchTempMemoryRegion;
- patchTempMemoryRegion = nullptr;
+ patchTempMemoryRegion = NULL;
delete rhythmTempMemoryRegion;
- rhythmTempMemoryRegion = nullptr;
+ rhythmTempMemoryRegion = NULL;
delete timbreTempMemoryRegion;
- timbreTempMemoryRegion = nullptr;
+ timbreTempMemoryRegion = NULL;
delete patchesMemoryRegion;
- patchesMemoryRegion = nullptr;
+ patchesMemoryRegion = NULL;
delete timbresMemoryRegion;
- timbresMemoryRegion = nullptr;
+ timbresMemoryRegion = NULL;
delete systemMemoryRegion;
- systemMemoryRegion = nullptr;
+ systemMemoryRegion = NULL;
delete displayMemoryRegion;
- displayMemoryRegion = nullptr;
+ displayMemoryRegion = NULL;
delete resetMemoryRegion;
- resetMemoryRegion = nullptr;
+ resetMemoryRegion = NULL;
delete[] paddedTimbreMaxTable;
- paddedTimbreMaxTable = nullptr;
+ paddedTimbreMaxTable = NULL;
}
MemoryRegion *Synth::findMemoryRegion(Bit32u addr) {
@@ -1421,14 +1534,14 @@ MemoryRegion *Synth::findMemoryRegion(Bit32u addr) {
systemMemoryRegion,
displayMemoryRegion,
resetMemoryRegion,
- nullptr
+ NULL
};
- for (int pos = 0; regions[pos] != nullptr; pos++) {
+ for (int pos = 0; regions[pos] != NULL; pos++) {
if (regions[pos]->contains(addr)) {
return regions[pos];
}
}
- return nullptr;
+ return NULL;
}
void Synth::readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data) {
@@ -1469,7 +1582,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
#if MT32EMU_MONITOR_SYSEX > 0
printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s), outlevel=%d", first, last, off, off + len, i, absTimbreNum, timbreName, mt32ram.patchTemp[i].outputLevel);
#endif
- if (parts[i] != nullptr) {
+ if (parts[i] != NULL) {
if (i != 8) {
// Note: Confirmed on CM-64 that we definitely *should* update the timbre here,
// but only in the case that the sysex actually writes to those values
@@ -1500,7 +1613,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", first, last, off, off + len, i, mt32ram.rhythmTemp[i].outputLevel, mt32ram.rhythmTemp[i].panpot, mt32ram.rhythmTemp[i].reverbSwitch, mt32ram.rhythmTemp[i].timbre, timbreName);
#endif
}
- if (parts[8] != nullptr) {
+ if (parts[8] != NULL) {
parts[8]->refresh();
}
break;
@@ -1513,7 +1626,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
#if MT32EMU_MONITOR_SYSEX > 0
printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", first, last, off, off + len, i, instrumentName);
#endif
- if (parts[i] != nullptr) {
+ if (parts[i] != NULL) {
parts[i]->refresh();
}
}
@@ -1622,7 +1735,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
// FIXME:KG: Not sure if the stuff below should be done (for rhythm and/or parts)...
// Does the real MT-32 automatically do this?
for (unsigned int part = 0; part < 9; part++) {
- if (parts[part] != nullptr) {
+ if (parts[part] != NULL) {
parts[part]->refreshTimbre(i);
}
}
@@ -1663,7 +1776,10 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
}
break;
case MR_Display:
- char buf[SYSEX_BUFFER_SIZE];
+ if (len > Display::LCD_TEXT_SIZE) len = Display::LCD_TEXT_SIZE;
+ if (!extensions.display->customDisplayMessageReceived(data, off, len)) break;
+ // Holds zero-terminated string of the maximum length.
+ char buf[Display::LCD_TEXT_SIZE + 1];
memcpy(&buf, &data[0], len);
buf[len] = 0;
#if MT32EMU_MONITOR_SYSEX > 0
@@ -1709,7 +1825,7 @@ void Synth::refreshSystemReverbParameters() {
if (mt32ram.system.reverbTime == 0 && mt32ram.system.reverbLevel == 0) {
// Setting both time and level to 0 effectively disables wet reverb output on real devices.
// Take a shortcut in this case to reduce CPU load.
- reverbModel = nullptr;
+ reverbModel = NULL;
} else {
reverbModel = reverbModels[mt32ram.system.reverbMode];
}
@@ -1719,7 +1835,7 @@ void Synth::refreshSystemReverbParameters() {
reverbModel->mute();
}
} else {
- if (oldReverbModel != nullptr) {
+ if (oldReverbModel != NULL) {
oldReverbModel->close();
}
if (isReverbEnabled()) {
@@ -1746,7 +1862,7 @@ void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) {
// CONFIRMED: In the case of assigning a MIDI channel to multiple parts,
// the messages received on that MIDI channel are handled by all the parts.
for (Bit32u i = 0; i <= 8; i++) {
- if (parts[i] != nullptr && i >= firstPart && i <= lastPart) {
+ if (parts[i] != NULL && i >= firstPart && i <= lastPart) {
// CONFIRMED: Decay is started for all polys, and all controllers are reset, for every part whose assignment was touched by the sysex write.
parts[i]->allSoundOff();
parts[i]->resetAllControllers();
@@ -1769,6 +1885,10 @@ void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) {
}
void Synth::refreshSystemMasterVol() {
+ // Note, this should only occur when the user turns the volume knob. When the master volume is set via a SysEx, display
+ // doesn't actually update on all real devices. However, we anyway update the display, as we don't foresee a dedicated
+ // API for setting the master volume yet it's rather dubious that one really needs this quirk to be fairly emulated.
+ if (opened) extensions.display->masterVolumeChanged();
#if MT32EMU_MONITOR_SYSEX > 0
printDebug(" Master volume: %d", mt32ram.system.masterVol);
#endif
@@ -1818,6 +1938,32 @@ Bit32s Synth::getMasterTunePitchDelta() const {
return extensions.masterTunePitchDelta;
}
+bool Synth::getDisplayState(char *targetBuffer, bool narrowLCD) const {
+ if (!opened) {
+ memset(targetBuffer, ' ', Display::LCD_TEXT_SIZE);
+ targetBuffer[Display::LCD_TEXT_SIZE] = 0;
+ return false;
+ }
+ return extensions.display->getDisplayState(targetBuffer, narrowLCD);
+}
+
+void Synth::setMainDisplayMode() {
+ if (opened) extensions.display->setMainDisplayMode();
+}
+
+
+void Synth::setDisplayCompatibility(bool oldMT32CompatibilityEnabled) {
+ extensions.oldMT32DisplayFeatures = oldMT32CompatibilityEnabled;
+}
+
+bool Synth::isDisplayOldMT32Compatible() const {
+ return extensions.oldMT32DisplayFeatures;
+}
+
+bool Synth::isDefaultDisplayOldMT32Compatible() const {
+ return opened && controlROMFeatures->oldMT32DisplayFeatures;
+}
+
/** Defines an interface of a class that maintains storage of variable-sized data of SysEx messages. */
class MidiEventQueue::SysexDataStorage {
public:
@@ -1832,13 +1978,13 @@ public:
/** Storage space for SysEx data is allocated dynamically on demand and is disposed lazily. */
class DynamicSysexDataStorage : public MidiEventQueue::SysexDataStorage {
public:
- Bit8u *allocate(Bit32u sysexLength) override {
+ Bit8u *allocate(Bit32u sysexLength) {
return new Bit8u[sysexLength];
}
- void reclaimUnused(const Bit8u *, Bit32u) override {}
+ void reclaimUnused(const Bit8u *, Bit32u) {}
- void dispose(const Bit8u *sysexData, Bit32u) override {
+ void dispose(const Bit8u *sysexData, Bit32u) {
delete[] sysexData;
}
};
@@ -1861,34 +2007,34 @@ public:
delete[] storageBuffer;
}
- Bit8u *allocate(Bit32u sysexLength) override {
+ Bit8u *allocate(Bit32u sysexLength) {
Bit32u myStartPosition = startPosition;
Bit32u myEndPosition = endPosition;
// When the free space isn't contiguous, the data is allocated either right after the end position
// or at the buffer beginning, wherever it fits.
if (myStartPosition > myEndPosition) {
- if (myStartPosition - myEndPosition <= sysexLength) return nullptr;
+ if (myStartPosition - myEndPosition <= sysexLength) return NULL;
} else if (storageBufferSize - myEndPosition < sysexLength) {
// There's not enough free space at the end to place the data block.
if (myStartPosition == myEndPosition) {
// The buffer is empty -> reset positions to the buffer beginning.
- if (storageBufferSize <= sysexLength) return nullptr;
+ if (storageBufferSize <= sysexLength) return NULL;
if (myStartPosition != 0) {
myStartPosition = 0;
// It's OK to write startPosition here non-atomically. We don't expect any
// concurrent reads, as there must be no SysEx messages in the queue.
startPosition = myStartPosition;
}
- } else if (myStartPosition <= sysexLength) return nullptr;
+ } else if (myStartPosition <= sysexLength) return NULL;
myEndPosition = 0;
}
endPosition = myEndPosition + sysexLength;
return storageBuffer + myEndPosition;
}
- void reclaimUnused(const Bit8u *sysexData, Bit32u sysexLength) override {
- if (sysexData == nullptr) return;
+ void reclaimUnused(const Bit8u *sysexData, Bit32u sysexLength) {
+ if (sysexData == NULL) return;
Bit32u allocatedPosition = startPosition;
if (storageBuffer + allocatedPosition == sysexData) {
startPosition = allocatedPosition + sysexLength;
@@ -1898,7 +2044,7 @@ public:
}
}
- void dispose(const Bit8u *, Bit32u) override {}
+ void dispose(const Bit8u *, Bit32u) {}
private:
Bit8u * const storageBuffer;
@@ -1921,7 +2067,7 @@ MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize, Bit32u storageBufferSiz
ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1)
{
for (Bit32u i = 0; i <= ringBufferMask; i++) {
- ringBuffer[i].sysexData = nullptr;
+ ringBuffer[i].sysexData = NULL;
}
reset();
}
@@ -1946,7 +2092,7 @@ bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp)
if (startPosition == newEndPosition) return false;
volatile MidiEvent &newEvent = ringBuffer[endPosition];
sysexDataStorage.dispose(newEvent.sysexData, newEvent.sysexLength);
- newEvent.sysexData = nullptr;
+ newEvent.sysexData = NULL;
newEvent.shortMessageData = shortMessageData;
newEvent.timestamp = timestamp;
endPosition = newEndPosition;
@@ -1960,7 +2106,7 @@ bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32
volatile MidiEvent &newEvent = ringBuffer[endPosition];
sysexDataStorage.dispose(newEvent.sysexData, newEvent.sysexLength);
Bit8u *dstSysexData = sysexDataStorage.allocate(sysexLength);
- if (dstSysexData == nullptr) return false;
+ if (dstSysexData == NULL) return false;
memcpy(dstSysexData, sysexData, sysexLength);
newEvent.sysexData = dstSysexData;
newEvent.sysexLength = sysexLength;
@@ -1970,7 +2116,7 @@ bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32
}
const volatile MidiEventQueue::MidiEvent *MidiEventQueue::peekMidiEvent() {
- return isEmpty() ? nullptr : &ringBuffer[startPosition];
+ return isEmpty() ? NULL : &ringBuffer[startPosition];
}
void MidiEventQueue::dropMidiEvent() {
@@ -1993,17 +2139,27 @@ RendererType Synth::getSelectedRendererType() const {
}
Bit32u Synth::getStereoOutputSampleRate() const {
- return (analog == nullptr) ? SAMPLE_RATE : analog->getOutputSampleRate();
+ return (analog == NULL) ? SAMPLE_RATE : analog->getOutputSampleRate();
+}
+
+void Renderer::updateDisplayState() {
+ bool midiMessageLEDState;
+ bool midiMessageLEDStateUpdated;
+ bool lcdUpdated;
+ synth.extensions.display->checkDisplayStateUpdated(midiMessageLEDState, midiMessageLEDStateUpdated, lcdUpdated);
+ if (midiMessageLEDStateUpdated) synth.extensions.reportHandler2->onMidiMessageLEDStateUpdated(midiMessageLEDState);
+ if (lcdUpdated) synth.extensions.reportHandler2->onLCDStateUpdated();
}
template <class Sample>
void RendererImpl<Sample>::doRender(Sample *stereoStream, Bit32u len) {
if (!isActivated()) {
incRenderedSampleCount(getAnalog().getDACStreamsLength(len));
- if (!getAnalog().process(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, stereoStream, len)) {
+ if (!getAnalog().process(NULL, NULL, NULL, NULL, NULL, NULL, stereoStream, len)) {
printDebug("RendererImpl: Invalid call to Analog::process()!\n");
}
Synth::muteSampleBuffer(stereoStream, len << 1);
+ updateDisplayState();
return;
}
@@ -2073,7 +2229,7 @@ void Synth::render(float *stream, Bit32u len) {
template <class Sample>
static inline void advanceStream(Sample *&stream, Bit32u len) {
- if (stream != nullptr) {
+ if (stream != NULL) {
stream += len;
}
}
@@ -2117,14 +2273,14 @@ void RendererImpl<Sample>::doRenderStreams(const DACOutputStreams<Sample> &strea
Bit32u thisLen = 1;
if (!isAbortingPoly()) {
const volatile MidiEventQueue::MidiEvent *nextEvent = getMidiQueue().peekMidiEvent();
- Bit32s samplesToNextEvent = (nextEvent != nullptr) ? Bit32s(nextEvent->timestamp - getRenderedSampleCount()) : MAX_SAMPLES_PER_RUN;
+ Bit32s samplesToNextEvent = (nextEvent != NULL) ? Bit32s(nextEvent->timestamp - getRenderedSampleCount()) : MAX_SAMPLES_PER_RUN;
if (samplesToNextEvent > 0) {
thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len;
if (thisLen > Bit32u(samplesToNextEvent)) {
thisLen = samplesToNextEvent;
}
} else {
- if (nextEvent->sysexData == nullptr) {
+ if (nextEvent->sysexData == NULL) {
synth.playMsgNow(nextEvent->shortMessageData);
// If a poly is aborting we don't drop the event from the queue.
// Instead, we'll return to it again when the abortion is done.
@@ -2311,10 +2467,10 @@ template <class Sample>
void RendererImpl<Sample>::produceStreams(const DACOutputStreams<Sample> &streams, Bit32u len) {
if (isActivated()) {
// Even if LA32 output isn't desired, we proceed anyway with temp buffers
- Sample *nonReverbLeft = streams.nonReverbLeft == nullptr ? tmpNonReverbLeft : streams.nonReverbLeft;
- Sample *nonReverbRight = streams.nonReverbRight == nullptr ? tmpNonReverbRight : streams.nonReverbRight;
- Sample *reverbDryLeft = streams.reverbDryLeft == nullptr ? tmpReverbDryLeft : streams.reverbDryLeft;
- Sample *reverbDryRight = streams.reverbDryRight == nullptr ? tmpReverbDryRight : streams.reverbDryRight;
+ Sample *nonReverbLeft = streams.nonReverbLeft == NULL ? tmpNonReverbLeft : streams.nonReverbLeft;
+ Sample *nonReverbRight = streams.nonReverbRight == NULL ? tmpNonReverbRight : streams.nonReverbRight;
+ Sample *reverbDryLeft = streams.reverbDryLeft == NULL ? tmpReverbDryLeft : streams.reverbDryLeft;
+ Sample *reverbDryRight = streams.reverbDryRight == NULL ? tmpReverbDryRight : streams.reverbDryRight;
Synth::muteSampleBuffer(nonReverbLeft, len);
Synth::muteSampleBuffer(nonReverbRight, len);
@@ -2336,30 +2492,31 @@ void RendererImpl<Sample>::produceStreams(const DACOutputStreams<Sample> &stream
if (!getReverbModel().process(reverbDryLeft, reverbDryRight, streams.reverbWetLeft, streams.reverbWetRight, len)) {
printDebug("RendererImpl: Invalid call to BReverbModel::process()!\n");
}
- if (streams.reverbWetLeft != nullptr) convertSamplesToOutput(streams.reverbWetLeft, len);
- if (streams.reverbWetRight != nullptr) convertSamplesToOutput(streams.reverbWetRight, len);
+ if (streams.reverbWetLeft != NULL) convertSamplesToOutput(streams.reverbWetLeft, len);
+ if (streams.reverbWetRight != NULL) convertSamplesToOutput(streams.reverbWetRight, len);
} else {
Synth::muteSampleBuffer(streams.reverbWetLeft, len);
Synth::muteSampleBuffer(streams.reverbWetRight, len);
}
// Don't bother with conversion if the output is going to be unused
- if (streams.nonReverbLeft != nullptr) {
+ if (streams.nonReverbLeft != NULL) {
produceLA32Output(nonReverbLeft, len);
convertSamplesToOutput(nonReverbLeft, len);
}
- if (streams.nonReverbRight != nullptr) {
+ if (streams.nonReverbRight != NULL) {
produceLA32Output(nonReverbRight, len);
convertSamplesToOutput(nonReverbRight, len);
}
- if (streams.reverbDryLeft != nullptr) convertSamplesToOutput(reverbDryLeft, len);
- if (streams.reverbDryRight != nullptr) convertSamplesToOutput(reverbDryRight, len);
+ if (streams.reverbDryLeft != NULL) convertSamplesToOutput(reverbDryLeft, len);
+ if (streams.reverbDryRight != NULL) convertSamplesToOutput(reverbDryRight, len);
} else {
muteStreams(streams, len);
}
getPartialManager().clearAlreadyOutputed();
incRenderedSampleCount(len);
+ updateDisplayState();
}
void Synth::printPartialUsage(Bit32u sampleOffset) {
@@ -2456,7 +2613,7 @@ Bit32u Synth::getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities)
if (opened && (partNumber < 9)) {
const Part *part = parts[partNumber];
const Poly *poly = part->getFirstActivePoly();
- while (poly != nullptr) {
+ while (poly != NULL) {
keys[playingNotes] = Bit8u(poly->getKey());
velocities[playingNotes] = Bit8u(poly->getVelocity());
playingNotes++;
@@ -2467,12 +2624,32 @@ Bit32u Synth::getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities)
}
const char *Synth::getPatchName(Bit8u partNumber) const {
- return (!opened || partNumber > 8) ? nullptr : parts[partNumber]->getCurrentInstr();
+ return (!opened || partNumber > 8) ? NULL : parts[partNumber]->getCurrentInstr();
+}
+
+bool Synth::getSoundGroupName(char *soundGroupName, Bit8u timbreGroup, Bit8u timbreNumber) const {
+ if (!opened || 63 < timbreNumber) return false;
+ const char *foundGroupName = getSoundGroupName(timbreGroup, timbreNumber);
+ if (foundGroupName == NULL) return false;
+ memcpy(soundGroupName, foundGroupName, 7);
+ soundGroupName[7] = 0;
+ return true;
+}
+
+bool Synth::getSoundName(char *soundName, Bit8u timbreGroup, Bit8u timbreNumber) const {
+ if (!opened || 3 < timbreGroup) return false;
+ Bit8u timbresInGroup = 3 == timbreGroup ? controlROMMap->timbreRCount : 64;
+ if (timbresInGroup <= timbreNumber) return false;
+ TimbreParam::CommonParam &timbreCommon = mt32ram.timbres[timbreGroup * 64 + timbreNumber].timbre.common;
+ if (timbreCommon.partialMute == 0) return false;
+ memcpy(soundName, timbreCommon.name, sizeof timbreCommon.name);
+ soundName[sizeof timbreCommon.name] = 0;
+ return true;
}
const Part *Synth::getPart(Bit8u partNum) const {
if (partNum > 8) {
- return nullptr;
+ return NULL;
}
return parts[partNum];
}
@@ -2494,7 +2671,7 @@ void MemoryRegion::read(unsigned int entry, unsigned int off, Bit8u *dst, unsign
len = entrySize * entries - off;
}
Bit8u *src = getRealMemory();
- if (src == nullptr) {
+ if (src == NULL) {
#if MT32EMU_MONITOR_SYSEX > 0
synth->printDebug("read[%d]: unreadable region: entry=%d, off=%d, len=%d", type, entry, off, len);
#endif
@@ -2520,7 +2697,7 @@ void MemoryRegion::write(unsigned int entry, unsigned int off, const Bit8u *src,
len = entrySize * entries - off;
}
Bit8u *dest = getRealMemory();
- if (dest == nullptr) {
+ if (dest == NULL) {
#if MT32EMU_MONITOR_SYSEX > 0
synth->printDebug("write[%d]: unwritable region: entry=%d, off=%d, len=%d", type, entry, off, len);
#endif
diff --git a/audio/softsynth/mt32/Synth.h b/audio/softsynth/mt32/Synth.h
index 6b9e0c58717..0f88eb9f050 100644
--- a/audio/softsynth/mt32/Synth.h
+++ b/audio/softsynth/mt32/Synth.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -69,6 +69,9 @@ const Bit8u SYSEX_CMD_EOD = 0x45; // End of data
const Bit8u SYSEX_CMD_ERR = 0x4E; // Communications error
const Bit8u SYSEX_CMD_RJC = 0x4F; // Rejection
+// This value isn't quite correct: the new-gen MT-32 control ROMs (ver. 2.XX) are twice as big.
+// Nevertheless, this is still relevant for library internal usage because the higher half
+// of those ROMs only contains the demo songs in all cases.
const Bit32u CONTROL_ROM_SIZE = 64 * 1024;
// Set of multiplexed output streams appeared at the DAC entrance.
@@ -113,8 +116,21 @@ public:
virtual void onProgramChanged(Bit8u /* partNum */, const char * /* soundGroupName */, const char * /* patchName */) {}
};
+// Extends ReportHandler, so that the client may supply callbacks for reporting signals about updated display state.
+class MT32EMU_EXPORT_V(2.6) ReportHandler2 : public ReportHandler {
+public:
+ virtual ~ReportHandler2() {}
+
+ // Invoked to signal about a change of the emulated LCD state. Use method Synth::getDisplayState to retrieve the actual data.
+ // This callback will not be invoked on further changes, until the client retrieves the LCD state.
+ virtual void onLCDStateUpdated() {}
+ // Invoked when the emulated MIDI MESSAGE LED changes state. The ledState parameter represents whether the LED is ON.
+ virtual void onMidiMessageLEDStateUpdated(bool /* ledState */) {}
+};
+
class Synth {
friend class DefaultMidiStreamParser;
+friend class Display;
friend class MemoryRegion;
friend class Part;
friend class Partial;
@@ -177,7 +193,7 @@ private:
bool opened;
bool activated;
- bool isDefaultReportHandler;
+ bool isDefaultReportHandler; // No longer used, retained for binary compatibility only.
ReportHandler *reportHandler;
PartialManager *partialManager;
@@ -227,7 +243,11 @@ private:
void printPartialUsage(Bit32u sampleOffset = 0);
- void newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]);
+ void rhythmNotePlayed() const;
+ void voicePartStateChanged(Bit8u partNum, bool activated) const;
+ void newTimbreSet(Bit8u partNum) const;
+ const char *getSoundGroupName(const Part *part) const;
+ const char *getSoundGroupName(Bit8u timbreGroup, Bit8u timbreNumber) const;
void printDebug(const char *fmt, ...);
// partNum should be 0..7 for Part 1..8, or 8 for Rhythm
@@ -290,6 +310,10 @@ public:
MT32EMU_EXPORT explicit Synth(ReportHandler *useReportHandler = NULL);
MT32EMU_EXPORT ~Synth();
+ // Sets an implementation of ReportHandler2 interface for reporting various errors, information and debug messages.
+ // If the argument is NULL, the default implementation is installed as a fallback.
+ MT32EMU_EXPORT_V(2.6) void setReportHandler2(ReportHandler2 *reportHandler2);
+
// Used to initialise the MT-32. Must be called before any other function.
// Returns true if initialization was successful, otherwise returns false.
// controlROMImage and pcmROMImage represent full Control and PCM ROM images for use by synth.
@@ -423,6 +447,22 @@ public:
// Returns current output gain factor for reverb wet output channels.
MT32EMU_EXPORT float getReverbOutputGain() const;
+ // Sets (or removes) an override for the current volume (output level) on a specific part.
+ // When the part volume is overridden, the MIDI controller Volume (7) on the MIDI channel this part is assigned to
+ // has no effect on the output level of this part. Similarly, the output level value set on this part via a SysEx that
+ // modifies the Patch temp structure is disregarded.
+ // To enable the override mode, argument volumeOverride should be in range 0..100, setting a value outside this range
+ // disables the previously set override, if any.
+ // Note: Setting volumeOverride to 0 mutes the part completely, meaning no sound is generated at all.
+ // This is unlike the behaviour of real devices - setting 0 volume on a part may leave it still producing
+ // sound at a very low level.
+ // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ MT32EMU_EXPORT_V(2.6) void setPartVolumeOverride(Bit8u partNumber, Bit8u volumeOverride);
+ // Returns the overridden volume previously set on a specific part; a value outside the range 0..100 means no override
+ // is currently in effect.
+ // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ MT32EMU_EXPORT_V(2.6) Bit8u getPartVolumeOverride(Bit8u partNumber) const;
+
// Swaps left and right output channels.
MT32EMU_EXPORT void setReversedStereoEnabled(bool enabled);
// Returns whether left and right output channels are swapped.
@@ -529,10 +569,53 @@ public:
// Returns name of the patch set on the specified part.
// Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ // The returned value is a null-terminated string which is guaranteed to remain valid until the next call to one of render methods.
MT32EMU_EXPORT const char *getPatchName(Bit8u partNumber) const;
+ // Retrieves the name of the sound group the timbre identified by arguments timbreGroup and timbreNumber is associated with.
+ // Values 0-3 of timbreGroup correspond to the timbre banks GROUP A, GROUP B, MEMORY and RHYTHM.
+ // For all but the RHYTHM timbre bank, allowed values of timbreNumber are in range 0-63. The number of timbres
+ // contained in the RHYTHM bank depends on the used control ROM version.
+ // The argument soundGroupName must point to an array of at least 8 characters. The result is a null-terminated string.
+ // Returns whether the specified timbre has been found and the result written in soundGroupName.
+ MT32EMU_EXPORT_V(2.7) bool getSoundGroupName(char *soundGroupName, Bit8u timbreGroup, Bit8u timbreNumber) const;
+ // Retrieves the name of the timbre identified by arguments timbreGroup and timbreNumber.
+ // Values 0-3 of timbreGroup correspond to the timbre banks GROUP A, GROUP B, MEMORY and RHYTHM.
+ // For all but the RHYTHM timbre bank, allowed values of timbreNumber are in range 0-63. The number of timbres
+ // contained in the RHYTHM bank depends on the used control ROM version.
+ // The argument soundName must point to an array of at least 11 characters. The result is a null-terminated string.
+ // Returns whether the specified timbre has been found and the result written in soundName.
+ MT32EMU_EXPORT_V(2.7) bool getSoundName(char *soundName, Bit8u timbreGroup, Bit8u timbreNumber) const;
+
// 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);
+
+ // Retrieves the current state of the emulated MT-32 display facilities.
+ // Typically, the state is updated during the rendering. When that happens, a related callback from ReportHandler2 is invoked.
+ // However, there might be no need to invoke this method after each update, e.g. when the render buffer is just a few milliseconds
+ // long.
+ // The argument targetBuffer must point to an array of at least 21 characters. The result is a null-terminated string.
+ // The optional argument narrowLCD enables a condensed representation of the displayed information in some cases. This is mainly
+ // intended to route the result to a hardware LCD that is only 16 characters wide. Automatic scrolling of longer strings
+ // is not supported.
+ // Returns whether the MIDI MESSAGE LED is ON and fills the targetBuffer parameter.
+ MT32EMU_EXPORT_V(2.6) bool getDisplayState(char *targetBuffer, bool narrowLCD = false) const;
+
+ // Resets the emulated LCD to the main mode (Master Volume). This has the same effect as pressing the Master Volume button
+ // while the display shows some other message. Useful for the new-gen devices as those require a special Display Reset SysEx
+ // to return to the main mode e.g. from showing a custom display message or a checksum error.
+ MT32EMU_EXPORT_V(2.6) void setMainDisplayMode();
+
+ // Permits to select an arbitrary display emulation model that does not necessarily match the actual behaviour implemented
+ // in the control ROM version being used.
+ // Invoking this method with the argument set to true forces emulation of the old-gen MT-32 display features.
+ // Otherwise, emulation of the new-gen devices is enforced (these include CM-32L and LAPC-I as if these were connected to an LCD).
+ MT32EMU_EXPORT_V(2.6) void setDisplayCompatibility(bool oldMT32CompatibilityEnabled);
+ // Returns whether the currently configured features of the emulated display are compatible with the old-gen MT-32 devices.
+ MT32EMU_EXPORT_V(2.6) bool isDisplayOldMT32Compatible() const;
+ // Returns whether the emulated display features configured by default depending on the actual control ROM version
+ // are compatible with the old-gen MT-32 devices.
+ MT32EMU_EXPORT_V(2.6) bool isDefaultDisplayOldMT32Compatible() const;
}; // class Synth
} // namespace MT32Emu
diff --git a/audio/softsynth/mt32/TVA.cpp b/audio/softsynth/mt32/TVA.cpp
index 35cee3ef9e0..e3f76181f16 100644
--- a/audio/softsynth/mt32/TVA.cpp
+++ b/audio/softsynth/mt32/TVA.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -99,7 +99,7 @@ static int calcVeloAmpSubtraction(Bit8u veloSensitivity, unsigned int velocity)
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, bool hasRingModQuirk) {
+static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemParams::System *system, const TimbreParam::PartialParam *partialParam, Bit8u partVolume, const MemParams::RhythmTemp *rhythmTemp, int biasAmpSubtraction, int veloAmpSubtraction, Bit8u expression, bool hasRingModQuirk) {
int amp = 155;
if (!(hasRingModQuirk ? partial->isRingModulatingNoMix() : partial->isRingModulatingSlave())) {
@@ -107,7 +107,7 @@ static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemP
if (amp < 0) {
return 0;
}
- amp -= tables->levelToAmpSubtraction[patchTemp->outputLevel];
+ amp -= tables->levelToAmpSubtraction[partVolume];
if (amp < 0) {
return 0;
}
@@ -115,7 +115,7 @@ static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemP
if (amp < 0) {
return 0;
}
- if (rhythmTemp != nullptr) {
+ if (rhythmTemp != NULL) {
amp -= tables->levelToAmpSubtraction[rhythmTemp->outputLevel];
if (amp < 0) {
return 0;
@@ -154,7 +154,6 @@ static int calcKeyTimeSubtraction(Bit8u envTimeKeyfollow, int key) {
void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartialParam, const MemParams::RhythmTemp *newRhythmTemp) {
part = newPart;
partialParam = newPartialParam;
- patchTemp = newPart->getPatchTemp();
rhythmTemp = newRhythmTemp;
playing = true;
@@ -169,7 +168,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(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
+ int newTarget = calcBasicAmp(tables, partial, system, partialParam, part->getVolume(), newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
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
@@ -221,7 +220,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(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
+ int newTarget = calcBasicAmp(tables, partial, system, partialParam, part->getVolume(), rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
newTarget += partialParam->tva.envLevel[3];
// Although we're in TVA_PHASE_SUSTAIN at this point, we cannot be sure that there is no active ramp at the moment.
@@ -229,7 +228,7 @@ void TVA::recalcSustain() {
// Real hardware units ignore this possibility and rely on the assumption that the target is the current amp.
// This is OK in most situations but when the ramp that is currently in progress needs to change direction
// due to a volume/expression update, this leads to a jump in the amp that is audible as an unpleasant click.
- // To avoid that, we compare the newTarget with the actual current ramp value and correct the direction if necessary.
+ // To avoid that, we compare the newTarget with the the actual current ramp value and correct the direction if necessary.
int targetDelta = newTarget - target;
// Calculate an increment to get to the new amp value in a short, more or less consistent amount of time
@@ -271,10 +270,10 @@ void TVA::nextPhase() {
}
bool allLevelsZeroFromNowOn = false;
- if (!partial->getSynth()->controlROMFeatures->quirkTVAZeroEnvLevels && partialParam->tva.envLevel[3] == 0) {
+ if (partialParam->tva.envLevel[3] == 0) {
if (newPhase == TVA_PHASE_4) {
allLevelsZeroFromNowOn = true;
- } else if (partialParam->tva.envLevel[2] == 0) {
+ } else if (!partial->getSynth()->controlROMFeatures->quirkTVAZeroEnvLevels && partialParam->tva.envLevel[2] == 0) {
if (newPhase == TVA_PHASE_3) {
allLevelsZeroFromNowOn = true;
} else if (partialParam->tva.envLevel[1] == 0) {
@@ -294,7 +293,7 @@ void TVA::nextPhase() {
int envPointIndex = phase;
if (!allLevelsZeroFromNowOn) {
- newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
+ newTarget = calcBasicAmp(tables, partial, system, partialParam, part->getVolume(), rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
if (newPhase == TVA_PHASE_SUSTAIN || newPhase == TVA_PHASE_RELEASE) {
if (partialParam->tva.envLevel[3] == 0) {
diff --git a/audio/softsynth/mt32/TVA.h b/audio/softsynth/mt32/TVA.h
index bf2f0078539..415909be826 100644
--- a/audio/softsynth/mt32/TVA.h
+++ b/audio/softsynth/mt32/TVA.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -67,7 +67,6 @@ private:
const Part *part;
const TimbreParam::PartialParam *partialParam;
- const MemParams::PatchTemp *patchTemp;
const MemParams::RhythmTemp *rhythmTemp;
bool playing;
diff --git a/audio/softsynth/mt32/TVF.cpp b/audio/softsynth/mt32/TVF.cpp
index 921ba1a1a7e..47ce0a93655 100644
--- a/audio/softsynth/mt32/TVF.cpp
+++ b/audio/softsynth/mt32/TVF.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/TVF.h b/audio/softsynth/mt32/TVF.h
index 796e4d7414a..1b766e8ed63 100644
--- a/audio/softsynth/mt32/TVF.h
+++ b/audio/softsynth/mt32/TVF.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/TVP.cpp b/audio/softsynth/mt32/TVP.cpp
index 98d7bbad64e..9921f3a4d99 100644
--- a/audio/softsynth/mt32/TVP.cpp
+++ b/audio/softsynth/mt32/TVP.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -54,13 +54,32 @@ static Bit16u keyToPitchTable[] = {
// We want to do processing 4000 times per second. FIXME: This is pretty arbitrary.
static const int NOMINAL_PROCESS_TIMER_PERIOD_SAMPLES = SAMPLE_RATE / 4000;
-// The timer runs at 500kHz. This is how much to increment it after 8 samples passes.
-// We multiply by 8 to get rid of the fraction and deal with just integers.
-static const int PROCESS_TIMER_INCREMENT_x8 = 8 * 500000 / SAMPLE_RATE;
+// In all hardware units we emulate, the main clock frequency of the MCU is 12MHz.
+// However, the MCU used in the 3rd-gen sound modules (like CM-500 and LAPC-N)
+// is significantly faster. Importantly, the software timer also works faster,
+// yet this fact has been seemingly missed. To be more specific, the software timer
+// ticks each 8 "state times", and 1 state time equals to 3 clock periods
+// for 8095 and 8098 but 2 clock periods for 80C198. That is, on MT-32 and CM-32L,
+// the software timer tick rate is 12,000,000 / 3 / 8 = 500kHz, but on the 3rd-gen
+// devices it's 12,000,000 / 2 / 8 = 750kHz instead.
+
+// For 1st- and 2nd-gen devices, the timer ticks at 500kHz. This is how much to increment
+// timeElapsed once 16 samples passes. We multiply by 16 to get rid of the fraction
+// and deal with just integers.
+static const int PROCESS_TIMER_TICKS_PER_SAMPLE_X16_1N2_GEN = (500000 << 4) / SAMPLE_RATE;
+// For 3rd-gen devices, the timer ticks at 750kHz. This is how much to increment
+// timeElapsed once 16 samples passes. We multiply by 16 to get rid of the fraction
+// and deal with just integers.
+static const int PROCESS_TIMER_TICKS_PER_SAMPLE_X16_3_GEN = (750000 << 4) / SAMPLE_RATE;
TVP::TVP(const Partial *usePartial) :
- partial(usePartial), system(&usePartial->getSynth()->mt32ram.system) {
-}
+ partial(usePartial),
+ system(&usePartial->getSynth()->mt32ram.system),
+ processTimerTicksPerSampleX16(
+ partial->getSynth()->controlROMFeatures->quirkFastPitchChanges
+ ? PROCESS_TIMER_TICKS_PER_SAMPLE_X16_3_GEN
+ : PROCESS_TIMER_TICKS_PER_SAMPLE_X16_1N2_GEN)
+{}
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))
@@ -90,7 +109,7 @@ static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialPa
basePitch += fineToPitch(patchTemp->patch.fineTune);
const ControlROMPCMStruct *controlROMPCMStruct = partial->getControlROMPCMStruct();
- if (controlROMPCMStruct != nullptr) {
+ if (controlROMPCMStruct != NULL) {
basePitch += (Bit32s(controlROMPCMStruct->pitchMSB) << 8) | Bit32s(controlROMPCMStruct->pitchLSB);
} else {
if ((partialParam->wg.waveform & 1) == 0) {
@@ -301,7 +320,7 @@ void TVP::startDecay() {
Bit16u TVP::nextPitch() {
// We emulate MCU software timer using these counter and processTimerIncrement variables.
- // The value of nominalProcessTimerPeriod approximates the period in samples
+ // The value of NOMINAL_PROCESS_TIMER_PERIOD_SAMPLES approximates the period in samples
// between subsequent firings of the timer that normally occur.
// However, accurate emulation is quite complicated because the timer is not guaranteed to fire in time.
// This makes pitch variations on real unit non-deterministic and dependent on various factors.
@@ -309,7 +328,7 @@ Bit16u TVP::nextPitch() {
timeElapsed = (timeElapsed + processTimerIncrement) & 0x00FFFFFF;
// This roughly emulates pitch deviations observed on real units when playing a single partial that uses TVP/LFO.
counter = NOMINAL_PROCESS_TIMER_PERIOD_SAMPLES + (rand() & 3);
- processTimerIncrement = (PROCESS_TIMER_INCREMENT_x8 * counter) >> 3;
+ processTimerIncrement = (processTimerTicksPerSampleX16 * counter) >> 4;
process();
}
counter--;
diff --git a/audio/softsynth/mt32/TVP.h b/audio/softsynth/mt32/TVP.h
index f5ef5474347..61bd2033e64 100644
--- a/audio/softsynth/mt32/TVP.h
+++ b/audio/softsynth/mt32/TVP.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -36,6 +36,7 @@ private:
const TimbreParam::PartialParam *partialParam;
const MemParams::PatchTemp *patchTemp;
+ const int processTimerTicksPerSampleX16;
int processTimerIncrement;
int counter;
Bit32u timeElapsed;
diff --git a/audio/softsynth/mt32/Tables.cpp b/audio/softsynth/mt32/Tables.cpp
index 143cd4c6d2a..dff042d2066 100644
--- a/audio/softsynth/mt32/Tables.cpp
+++ b/audio/softsynth/mt32/Tables.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/Tables.h b/audio/softsynth/mt32/Tables.h
index dd75f751b8f..2f90532153c 100644
--- a/audio/softsynth/mt32/Tables.h
+++ b/audio/softsynth/mt32/Tables.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/Types.h b/audio/softsynth/mt32/Types.h
index f9590d6a85e..12e4547500c 100644
--- a/audio/softsynth/mt32/Types.h
+++ b/audio/softsynth/mt32/Types.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/VersionTagging.cpp b/audio/softsynth/mt32/VersionTagging.cpp
index a621d544c45..0a3388f3bf9 100644
--- a/audio/softsynth/mt32/VersionTagging.cpp
+++ b/audio/softsynth/mt32/VersionTagging.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -23,8 +23,10 @@ extern "C" {
// while for an application linked with a newer library version there will be no match.
MT32EMU_EXPORT_V(2.5) extern const volatile char mt32emu_2_5 = 0;
+MT32EMU_EXPORT_V(2.6) extern const volatile char mt32emu_2_6 = 0;
+MT32EMU_EXPORT_V(2.7) extern const volatile char mt32emu_2_7 = 0;
-#if MT32EMU_VERSION_MAJOR > 2 || MT32EMU_VERSION_MINOR > 5
+#if MT32EMU_VERSION_MAJOR > 2 || MT32EMU_VERSION_MINOR > 7
#error "Missing version tag definition for current library version"
#endif
}
diff --git a/audio/softsynth/mt32/VersionTagging.h b/audio/softsynth/mt32/VersionTagging.h
index ec63206a286..df211f3c065 100644
--- a/audio/softsynth/mt32/VersionTagging.h
+++ b/audio/softsynth/mt32/VersionTagging.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -20,25 +20,39 @@
#include "globals.h"
-// This is intended to implement a simple check of a shared library version in runtime. Sadly, per-symbol versioning
-// is unavailable on many platforms, and even where it is, it's still not too easy to maintain for a C++ library.
-// Therefore, the goal here is just to ensure that the client application quickly bails out when attempted to run
-// with an older version of shared library, as well as to produce a more readable error message indicating a version mismatch
-// rather than a report about some missing symbols with unreadable mangled names.
-// This is an optional feature, since it adds some minor burden to both the library and client applications code,
-// albeit it is ought to work on platforms that do not implement symbol versioning.
+/* This is intended to implement a simple check of a shared library version in runtime. Sadly, per-symbol versioning
+ * is unavailable on many platforms, and even where it is, it's still not too easy to maintain for a C++ library.
+ * Therefore, the goal here is just to ensure that the client application quickly bails out when attempted to run
+ * with an older version of shared library, as well as to produce a more readable error message indicating a version mismatch
+ * rather than a report about some missing symbols with unreadable mangled names.
+ * This is an optional feature, since it adds some minor burden to both the library and client applications code,
+ * albeit it is ought to work on platforms that do not implement symbol versioning.
+ */
#define MT32EMU_REALLY_BUILD_VERSION_TAG(major, minor) mt32emu_ ## major ## _ ## minor
-// This macro expansion step permits resolution the actual version numbers.
+/* This macro expansion step permits resolution the actual version numbers. */
#define MT32EMU_BUILD_VERSION_TAG(major, minor) MT32EMU_REALLY_BUILD_VERSION_TAG(major, minor)
#define MT32EMU_VERSION_TAG MT32EMU_BUILD_VERSION_TAG(MT32EMU_VERSION_MAJOR, MT32EMU_VERSION_MINOR)
+#if defined(__cplusplus)
+
extern "C" {
MT32EMU_EXPORT extern const volatile char MT32EMU_VERSION_TAG;
}
// This pulls the external reference in yet prevents it from being optimised out.
static const volatile char mt32emu_version_tag = MT32EMU_VERSION_TAG;
+#else
+
+static void mt32emu_refer_version_tag(void) {
+ MT32EMU_EXPORT extern const volatile char MT32EMU_VERSION_TAG;
+ (void)MT32EMU_VERSION_TAG;
+}
+
+static void (*const volatile mt32emu_refer_version_tag_ref)(void) = mt32emu_refer_version_tag;
+
+#endif
+
#undef MT32EMU_REALLY_BUILD_VERSION_TAG
#undef MT32EMU_BUILD_VERSION_TAG
#undef MT32EMU_VERSION_TAG
diff --git a/audio/softsynth/mt32/c_interface/c_interface.cpp b/audio/softsynth/mt32/c_interface/c_interface.cpp
index ae301616002..4c7706be8a6 100644
--- a/audio/softsynth/mt32/c_interface/c_interface.cpp
+++ b/audio/softsynth/mt32/c_interface/c_interface.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -39,11 +39,11 @@ struct SamplerateConversionState {
SampleRateConverter *src;
};
-static mt32emu_service_version getSynthVersionID(mt32emu_service_i) {
+static mt32emu_service_version MT32EMU_C_CALL getSynthVersionID(mt32emu_service_i) {
return MT32EMU_SERVICE_VERSION_CURRENT;
}
-static const mt32emu_service_i_v4 SERVICE_VTABLE = {
+static const mt32emu_service_i_v6 SERVICE_VTABLE = {
getSynthVersionID,
mt32emu_get_supported_report_handler_version,
mt32emu_get_supported_midi_receiver_version,
@@ -127,13 +127,22 @@ static const mt32emu_service_i_v4 SERVICE_VTABLE = {
mt32emu_identify_rom_file,
mt32emu_merge_and_add_rom_data,
mt32emu_merge_and_add_rom_files,
- mt32emu_add_machine_rom_file
+ mt32emu_add_machine_rom_file,
+ mt32emu_get_display_state,
+ mt32emu_set_main_display_mode,
+ mt32emu_set_display_compatibility,
+ mt32emu_is_display_old_mt32_compatible,
+ mt32emu_is_default_display_old_mt32_compatible,
+ mt32emu_set_part_volume_override,
+ mt32emu_get_part_volume_override,
+ mt32emu_get_sound_group_name,
+ mt32emu_get_sound_name
};
} // namespace MT32Emu
struct mt32emu_data {
- ReportHandler *reportHandler;
+ ReportHandler2 *reportHandler;
Synth *synth;
const ROMImage *controlROMImage;
const ROMImage *pcmROMImage;
@@ -147,126 +156,145 @@ struct mt32emu_data {
namespace MT32Emu {
-class DelegatingReportHandlerAdapter : public ReportHandler {
+class DelegatingReportHandlerAdapter : public ReportHandler2 {
public:
DelegatingReportHandlerAdapter(mt32emu_report_handler_i useReportHandler, void *useInstanceData) :
delegate(useReportHandler), instanceData(useInstanceData) {}
-protected:
+private:
const mt32emu_report_handler_i delegate;
void * const instanceData;
-private:
- void printDebug(const char *fmt, va_list list) override {
- if (delegate.v0->printDebug == nullptr) {
+ bool isVersionLess(mt32emu_report_handler_version versionID) {
+ return delegate.v0->getVersionID(delegate) < versionID;
+ }
+
+ 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() override {
- if (delegate.v0->onErrorControlROM == nullptr) {
+ void onErrorControlROM() {
+ if (delegate.v0->onErrorControlROM == NULL) {
ReportHandler::onErrorControlROM();
} else {
delegate.v0->onErrorControlROM(instanceData);
}
}
- void onErrorPCMROM() override {
- if (delegate.v0->onErrorPCMROM == nullptr) {
+ void onErrorPCMROM() {
+ if (delegate.v0->onErrorPCMROM == NULL) {
ReportHandler::onErrorPCMROM();
} else {
delegate.v0->onErrorPCMROM(instanceData);
}
}
- void showLCDMessage(const char *message) override {
- if (delegate.v0->showLCDMessage == nullptr) {
+ void showLCDMessage(const char *message) {
+ if (delegate.v0->showLCDMessage == NULL) {
ReportHandler::showLCDMessage(message);
} else {
delegate.v0->showLCDMessage(instanceData, message);
}
}
- void onMIDIMessagePlayed() override {
- if (delegate.v0->onMIDIMessagePlayed == nullptr) {
+ void onMIDIMessagePlayed() {
+ if (delegate.v0->onMIDIMessagePlayed == NULL) {
ReportHandler::onMIDIMessagePlayed();
} else {
delegate.v0->onMIDIMessagePlayed(instanceData);
}
}
- bool onMIDIQueueOverflow() override {
- if (delegate.v0->onMIDIQueueOverflow == nullptr) {
+ bool onMIDIQueueOverflow() {
+ if (delegate.v0->onMIDIQueueOverflow == NULL) {
return ReportHandler::onMIDIQueueOverflow();
}
return delegate.v0->onMIDIQueueOverflow(instanceData) != MT32EMU_BOOL_FALSE;
}
- void onMIDISystemRealtime(Bit8u systemRealtime) override {
- if (delegate.v0->onMIDISystemRealtime == nullptr) {
+ void onMIDISystemRealtime(Bit8u systemRealtime) {
+ if (delegate.v0->onMIDISystemRealtime == NULL) {
ReportHandler::onMIDISystemRealtime(systemRealtime);
} else {
delegate.v0->onMIDISystemRealtime(instanceData, systemRealtime);
}
}
- void onDeviceReset() override {
- if (delegate.v0->onDeviceReset == nullptr) {
+ void onDeviceReset() {
+ if (delegate.v0->onDeviceReset == NULL) {
ReportHandler::onDeviceReset();
} else {
delegate.v0->onDeviceReset(instanceData);
}
}
- void onDeviceReconfig() override {
- if (delegate.v0->onDeviceReconfig == nullptr) {
+ void onDeviceReconfig() {
+ if (delegate.v0->onDeviceReconfig == NULL) {
ReportHandler::onDeviceReconfig();
} else {
delegate.v0->onDeviceReconfig(instanceData);
}
}
- void onNewReverbMode(Bit8u mode) override {
- if (delegate.v0->onNewReverbMode == nullptr) {
+ void onNewReverbMode(Bit8u mode) {
+ if (delegate.v0->onNewReverbMode == NULL) {
ReportHandler::onNewReverbMode(mode);
} else {
delegate.v0->onNewReverbMode(instanceData, mode);
}
}
- void onNewReverbTime(Bit8u time) override {
- if (delegate.v0->onNewReverbTime == nullptr) {
+ void onNewReverbTime(Bit8u time) {
+ if (delegate.v0->onNewReverbTime == NULL) {
ReportHandler::onNewReverbTime(time);
} else {
delegate.v0->onNewReverbTime(instanceData, time);
}
}
- void onNewReverbLevel(Bit8u level) override {
- if (delegate.v0->onNewReverbLevel == nullptr) {
+ void onNewReverbLevel(Bit8u level) {
+ if (delegate.v0->onNewReverbLevel == NULL) {
ReportHandler::onNewReverbLevel(level);
} else {
delegate.v0->onNewReverbLevel(instanceData, level);
}
}
- void onPolyStateChanged(Bit8u partNum) override {
- if (delegate.v0->onPolyStateChanged == nullptr) {
+ 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) override {
- if (delegate.v0->onProgramChanged == nullptr) {
+ 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);
}
}
+
+ void onLCDStateUpdated() {
+ if (isVersionLess(MT32EMU_REPORT_HANDLER_VERSION_1) || delegate.v1->onLCDStateUpdated == NULL) {
+ ReportHandler2::onLCDStateUpdated();
+ } else {
+ delegate.v1->onLCDStateUpdated(instanceData);
+ }
+ }
+
+ void onMidiMessageLEDStateUpdated(bool ledState) {
+ if (isVersionLess(MT32EMU_REPORT_HANDLER_VERSION_1) || delegate.v1->onMidiMessageLEDStateUpdated == NULL) {
+ ReportHandler2::onMidiMessageLEDStateUpdated(ledState);
+ } else {
+ delegate.v1->onMidiMessageLEDStateUpdated(instanceData, ledState ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE);
+ }
+ }
};
class DelegatingMidiStreamParser : public DefaultMidiStreamParser {
@@ -279,24 +307,24 @@ protected:
void *instanceData;
private:
- void handleShortMessage(const Bit32u message) override {
- if (delegate.v0->handleShortMessage == nullptr) {
+ 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) override {
- if (delegate.v0->handleSysex == nullptr) {
+ 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) override {
- if (delegate.v0->handleSystemRealtimeMessage == nullptr) {
+ void handleSystemRealtimeMessage(const Bit8u realtime) {
+ if (delegate.v0->handleSystemRealtimeMessage == NULL) {
DefaultMidiStreamParser::handleSystemRealtimeMessage(realtime);
} else {
delegate.v0->handleSystemRealtimeMessage(instanceData, realtime);
@@ -305,23 +333,23 @@ private:
};
static void fillROMInfo(mt32emu_rom_info *rom_info, const ROMInfo *controlROMInfo, const ROMInfo *pcmROMInfo) {
- if (controlROMInfo != nullptr) {
+ if (controlROMInfo != NULL) {
rom_info->control_rom_id = controlROMInfo->shortName;
rom_info->control_rom_description = controlROMInfo->description;
rom_info->control_rom_sha1_digest = controlROMInfo->sha1Digest;
} else {
- rom_info->control_rom_id = nullptr;
- rom_info->control_rom_description = nullptr;
- rom_info->control_rom_sha1_digest = nullptr;
+ rom_info->control_rom_id = NULL;
+ rom_info->control_rom_description = NULL;
+ rom_info->control_rom_sha1_digest = NULL;
}
- if (pcmROMInfo != nullptr) {
+ if (pcmROMInfo != NULL) {
rom_info->pcm_rom_id = pcmROMInfo->shortName;
rom_info->pcm_rom_description = pcmROMInfo->description;
rom_info->pcm_rom_sha1_digest = pcmROMInfo->sha1Digest;
} else {
- rom_info->pcm_rom_id = nullptr;
- rom_info->pcm_rom_description = nullptr;
- rom_info->pcm_rom_sha1_digest = nullptr;
+ rom_info->pcm_rom_id = NULL;
+ rom_info->pcm_rom_description = NULL;
+ rom_info->pcm_rom_sha1_digest = NULL;
}
}
@@ -331,28 +359,28 @@ static const MachineConfiguration *findMachineConfiguration(const char *machine_
for (Bit32u i = 0; i < configurationCount; i++) {
if (!strcmp(configurations[i]->getMachineID(), machine_id)) return configurations[i];
}
- return nullptr;
+ return NULL;
}
static mt32emu_return_code identifyROM(mt32emu_rom_info *rom_info, File *romFile, const char *machineID) {
const ROMInfo *romInfo;
- if (machineID == nullptr) {
+ if (machineID == NULL) {
romInfo = ROMInfo::getROMInfo(romFile);
} else {
const MachineConfiguration *configuration = findMachineConfiguration(machineID);
- if (configuration == nullptr) {
- fillROMInfo(rom_info, nullptr, nullptr);
+ if (configuration == NULL) {
+ fillROMInfo(rom_info, NULL, NULL);
return MT32EMU_RC_MACHINE_NOT_IDENTIFIED;
}
romInfo = ROMInfo::getROMInfo(romFile, configuration->getCompatibleROMInfos());
}
- if (romInfo == nullptr) {
- fillROMInfo(rom_info, nullptr, nullptr);
+ if (romInfo == NULL) {
+ fillROMInfo(rom_info, NULL, NULL);
return MT32EMU_RC_ROM_NOT_IDENTIFIED;
}
- if (romInfo->type == ROMInfo::Control) fillROMInfo(rom_info, romInfo, nullptr);
- else if (romInfo->type == ROMInfo::PCM) fillROMInfo(rom_info, nullptr, romInfo);
- else fillROMInfo(rom_info, nullptr, nullptr);
+ if (romInfo->type == ROMInfo::Control) fillROMInfo(rom_info, romInfo, NULL);
+ else if (romInfo->type == ROMInfo::PCM) fillROMInfo(rom_info, NULL, romInfo);
+ else fillROMInfo(rom_info, NULL, NULL);
return MT32EMU_RC_OK;
}
@@ -366,10 +394,10 @@ static bool isROMInfoCompatible(const MachineConfiguration *machineConfiguration
}
static mt32emu_return_code replaceOrMergeROMImage(const ROMImage *&contextROMImage, const ROMImage *newROMImage, const MachineConfiguration *machineConfiguration, mt32emu_return_code addedFullROM, mt32emu_return_code addedPartialROM) {
- if (contextROMImage != nullptr) {
- if (machineConfiguration != nullptr) {
+ if (contextROMImage != NULL) {
+ if (machineConfiguration != NULL) {
const ROMImage *mergedROMImage = ROMImage::mergeROMImages(contextROMImage, newROMImage);
- if (mergedROMImage != nullptr) {
+ if (mergedROMImage != NULL) {
if (newROMImage->isFileUserProvided()) delete newROMImage->getFile();
ROMImage::freeROMImage(newROMImage);
if (contextROMImage->isFileUserProvided()) delete contextROMImage->getFile();
@@ -391,16 +419,16 @@ static mt32emu_return_code replaceOrMergeROMImage(const ROMImage *&contextROMIma
return newROMImage->getROMInfo()->pairType == ROMInfo::Full ? addedFullROM: addedPartialROM;
}
-static mt32emu_return_code addROMFiles(mt32emu_data *data, File *file1, File *file2 = nullptr, const MachineConfiguration *machineConfiguration = nullptr) {
+static mt32emu_return_code addROMFiles(mt32emu_data *data, File *file1, File *file2 = NULL, const MachineConfiguration *machineConfiguration = NULL) {
const ROMImage *romImage;
- if (machineConfiguration != nullptr) {
+ if (machineConfiguration != NULL) {
romImage = ROMImage::makeROMImage(file1, machineConfiguration->getCompatibleROMInfos());
} else {
- romImage = file2 == nullptr ? ROMImage::makeROMImage(file1, ROMInfo::getFullROMInfos()) : ROMImage::makeROMImage(file1, file2);
+ romImage = file2 == NULL ? ROMImage::makeROMImage(file1, ROMInfo::getFullROMInfos()) : ROMImage::makeROMImage(file1, file2);
}
- if (romImage == nullptr) return MT32EMU_RC_ROMS_NOT_PAIRABLE;
+ if (romImage == NULL) return MT32EMU_RC_ROMS_NOT_PAIRABLE;
const ROMInfo *info = romImage->getROMInfo();
- if (info == nullptr) {
+ if (info == NULL) {
ROMImage::freeROMImage(romImage);
return MT32EMU_RC_ROM_NOT_IDENTIFIED;
}
@@ -426,7 +454,7 @@ static mt32emu_return_code createFileStream(const char *filename, FileStream *&f
return MT32EMU_RC_OK;
}
delete fileStream;
- fileStream = nullptr;
+ fileStream = NULL;
return rc;
}
@@ -436,157 +464,162 @@ static mt32emu_return_code createFileStream(const char *filename, FileStream *&f
extern "C" {
-mt32emu_service_i mt32emu_get_service_i() {
+mt32emu_service_i MT32EMU_C_CALL mt32emu_get_service_i() {
mt32emu_service_i i;
- i.v4 = &SERVICE_VTABLE;
+ i.v6 = &SERVICE_VTABLE;
return i;
}
-mt32emu_report_handler_version mt32emu_get_supported_report_handler_version() {
+mt32emu_report_handler_version MT32EMU_C_CALL mt32emu_get_supported_report_handler_version() {
return MT32EMU_REPORT_HANDLER_VERSION_CURRENT;
}
-mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version() {
+mt32emu_midi_receiver_version MT32EMU_C_CALL mt32emu_get_supported_midi_receiver_version() {
return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT;
}
-mt32emu_bit32u mt32emu_get_library_version_int() {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_library_version_int() {
return Synth::getLibraryVersionInt();
}
-const char *mt32emu_get_library_version_string() {
+const char * MT32EMU_C_CALL mt32emu_get_library_version_string() {
return Synth::getLibraryVersionString();
}
-mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode) {
return Synth::getStereoOutputSampleRate(static_cast<AnalogOutputMode>(analog_output_mode));
}
-mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double target_samplerate) {
+mt32emu_analog_output_mode MT32EMU_C_CALL mt32emu_get_best_analog_output_mode(const double target_samplerate) {
return mt32emu_analog_output_mode(SampleRateConverter::getBestAnalogOutputMode(target_samplerate));
}
-size_t mt32emu_get_machine_ids(const char **machine_ids, size_t machine_ids_size) {
+size_t MT32EMU_C_CALL mt32emu_get_machine_ids(const char **machine_ids, size_t machine_ids_size) {
Bit32u configurationCount;
const MachineConfiguration * const *configurations = MachineConfiguration::getAllMachineConfigurations(&configurationCount);
- if (machine_ids != nullptr) {
+ if (machine_ids != NULL) {
for (Bit32u i = 0; i < machine_ids_size; i++) {
- machine_ids[i] = i < configurationCount ? configurations[i]->getMachineID() : nullptr;
+ machine_ids[i] = i < configurationCount ? configurations[i]->getMachineID() : NULL;
}
}
return configurationCount;
}
-size_t mt32emu_get_rom_ids(const char **rom_ids, size_t rom_ids_size, const char *machine_id) {
+size_t MT32EMU_C_CALL mt32emu_get_rom_ids(const char **rom_ids, size_t rom_ids_size, const char *machine_id) {
const ROMInfo * const *romInfos;
Bit32u romCount;
- if (machine_id != nullptr) {
+ if (machine_id != NULL) {
const MachineConfiguration *configuration = findMachineConfiguration(machine_id);
- if (configuration != nullptr) {
+ if (configuration != NULL) {
romInfos = configuration->getCompatibleROMInfos(&romCount);
} else {
- romInfos = nullptr;
+ romInfos = NULL;
romCount = 0U;
}
} else {
romInfos = ROMInfo::getAllROMInfos(&romCount);
}
- if (rom_ids != nullptr) {
+ if (rom_ids != NULL) {
for (size_t i = 0; i < rom_ids_size; i++) {
- rom_ids[i] = i < romCount ? romInfos[i]->shortName : nullptr;
+ rom_ids[i] = i < romCount ? romInfos[i]->shortName : NULL;
}
}
return romCount;
}
-mt32emu_return_code mt32emu_identify_rom_data(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id) {
+mt32emu_return_code MT32EMU_C_CALL mt32emu_identify_rom_data(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id) {
ArrayFile romFile = ArrayFile(data, data_size);
return identifyROM(rom_info, &romFile, machine_id);
}
-mt32emu_return_code mt32emu_identify_rom_file(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id) {
+mt32emu_return_code MT32EMU_C_CALL mt32emu_identify_rom_file(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id) {
FileStream *fs;
mt32emu_return_code rc = createFileStream(filename, fs);
- if (fs == nullptr) return rc;
+ if (fs == NULL) return rc;
rc = identifyROM(rom_info, fs, machine_id);
delete fs;
return rc;
}
-mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data) {
+mt32emu_context MT32EMU_C_CALL mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data) {
mt32emu_data *data = new mt32emu_data;
- data->reportHandler = (report_handler.v0 != nullptr) ? new DelegatingReportHandlerAdapter(report_handler, instance_data) : new ReportHandler;
- data->synth = new Synth(data->reportHandler);
+ data->synth = new Synth;
+ if (report_handler.v0 != NULL) {
+ data->reportHandler = new DelegatingReportHandlerAdapter(report_handler, instance_data);
+ data->synth->setReportHandler2(data->reportHandler);
+ } else {
+ data->reportHandler = NULL;
+ }
data->midiParser = new DefaultMidiStreamParser(*data->synth);
- data->controlROMImage = nullptr;
- data->pcmROMImage = nullptr;
+ data->controlROMImage = NULL;
+ data->pcmROMImage = NULL;
data->partialCount = DEFAULT_MAX_PARTIALS;
data->analogOutputMode = AnalogOutputMode_COARSE;
data->srcState = new SamplerateConversionState;
data->srcState->outputSampleRate = 0.0;
data->srcState->srcQuality = SamplerateConversionQuality_GOOD;
- data->srcState->src = nullptr;
+ data->srcState->src = NULL;
return data;
}
-void mt32emu_free_context(mt32emu_context data) {
- if (data == nullptr) return;
+void MT32EMU_C_CALL mt32emu_free_context(mt32emu_context data) {
+ if (data == NULL) return;
delete data->srcState->src;
- data->srcState->src = nullptr;
+ data->srcState->src = NULL;
delete data->srcState;
- data->srcState = nullptr;
+ data->srcState = NULL;
- if (data->controlROMImage != nullptr) {
+ if (data->controlROMImage != NULL) {
if (data->controlROMImage->isFileUserProvided()) delete data->controlROMImage->getFile();
ROMImage::freeROMImage(data->controlROMImage);
- data->controlROMImage = nullptr;
+ data->controlROMImage = NULL;
}
- if (data->pcmROMImage != nullptr) {
+ if (data->pcmROMImage != NULL) {
if (data->pcmROMImage->isFileUserProvided()) delete data->pcmROMImage->getFile();
ROMImage::freeROMImage(data->pcmROMImage);
- data->pcmROMImage = nullptr;
+ data->pcmROMImage = NULL;
}
delete data->midiParser;
- data->midiParser = nullptr;
+ data->midiParser = NULL;
delete data->synth;
- data->synth = nullptr;
+ data->synth = NULL;
delete data->reportHandler;
- data->reportHandler = nullptr;
+ 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 == nullptr) return addROMFiles(context, new ArrayFile(data, data_size));
+mt32emu_return_code MT32EMU_C_CALL 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 addROMFiles(context, new ArrayFile(data, data_size));
return addROMFiles(context, new ArrayFile(data, data_size, *sha1_digest));
}
-mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename) {
+mt32emu_return_code MT32EMU_C_CALL mt32emu_add_rom_file(mt32emu_context context, const char *filename) {
FileStream *fs;
mt32emu_return_code rc = createFileStream(filename, fs);
- if (fs != nullptr) rc = addROMFiles(context, fs);
+ if (fs != NULL) rc = addROMFiles(context, fs);
if (rc <= MT32EMU_RC_OK) delete fs;
return rc;
}
-mt32emu_return_code mt32emu_merge_and_add_rom_data(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest) {
- ArrayFile *file1 = part1_sha1_digest == nullptr ? new ArrayFile(part1_data, part1_data_size) : new ArrayFile(part1_data, part1_data_size, *part1_sha1_digest);
- ArrayFile *file2 = part2_sha1_digest == nullptr ? new ArrayFile(part2_data, part2_data_size) : new ArrayFile(part2_data, part2_data_size, *part2_sha1_digest);
+mt32emu_return_code MT32EMU_C_CALL mt32emu_merge_and_add_rom_data(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest) {
+ ArrayFile *file1 = part1_sha1_digest == NULL ? new ArrayFile(part1_data, part1_data_size) : new ArrayFile(part1_data, part1_data_size, *part1_sha1_digest);
+ ArrayFile *file2 = part2_sha1_digest == NULL ? new ArrayFile(part2_data, part2_data_size) : new ArrayFile(part2_data, part2_data_size, *part2_sha1_digest);
mt32emu_return_code rc = addROMFiles(context, file1, file2);
delete file1;
delete file2;
return rc;
}
-mt32emu_return_code mt32emu_merge_and_add_rom_files(mt32emu_context context, const char *part1_filename, const char *part2_filename) {
+mt32emu_return_code MT32EMU_C_CALL mt32emu_merge_and_add_rom_files(mt32emu_context context, const char *part1_filename, const char *part2_filename) {
FileStream *fs1;
mt32emu_return_code rc = createFileStream(part1_filename, fs1);
- if (fs1 != nullptr) {
+ if (fs1 != NULL) {
FileStream *fs2;
rc = createFileStream(part2_filename, fs2);
- if (fs2 != nullptr) {
+ if (fs2 != NULL) {
rc = addROMFiles(context, fs1, fs2);
delete fs2;
}
@@ -595,50 +628,50 @@ mt32emu_return_code mt32emu_merge_and_add_rom_files(mt32emu_context context, con
return rc;
}
-mt32emu_return_code mt32emu_add_machine_rom_file(mt32emu_context context, const char *machine_id, const char *filename) {
+mt32emu_return_code MT32EMU_C_CALL mt32emu_add_machine_rom_file(mt32emu_context context, const char *machine_id, const char *filename) {
const MachineConfiguration *machineConfiguration = findMachineConfiguration(machine_id);
- if (machineConfiguration == nullptr) return MT32EMU_RC_MACHINE_NOT_IDENTIFIED;
+ if (machineConfiguration == NULL) return MT32EMU_RC_MACHINE_NOT_IDENTIFIED;
FileStream *fs;
mt32emu_return_code rc = createFileStream(filename, fs);
- if (fs == nullptr) return rc;
- rc = addROMFiles(context, fs, nullptr, machineConfiguration);
+ if (fs == NULL) return rc;
+ rc = addROMFiles(context, fs, NULL, machineConfiguration);
if (rc <= MT32EMU_RC_OK) delete fs;
return rc;
}
-void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info) {
- const ROMInfo *controlROMInfo = context->controlROMImage == nullptr ? nullptr : context->controlROMImage->getROMInfo();
- const ROMInfo *pcmROMInfo = context->pcmROMImage == nullptr ? nullptr : context->pcmROMImage->getROMInfo();
+void MT32EMU_C_CALL mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info) {
+ const ROMInfo *controlROMInfo = context->controlROMImage == NULL ? NULL : context->controlROMImage->getROMInfo();
+ const ROMInfo *pcmROMInfo = context->pcmROMImage == NULL ? NULL : context->pcmROMImage->getROMInfo();
fillROMInfo(rom_info, controlROMInfo, pcmROMInfo);
}
-void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode) {
context->analogOutputMode = static_cast<AnalogOutputMode>(analog_output_mode);
}
-void mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate) {
+void MT32EMU_C_CALL mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate) {
context->srcState->outputSampleRate = SampleRateConverter::getSupportedOutputSampleRate(samplerate);
}
-void mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality) {
+void MT32EMU_C_CALL mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality) {
context->srcState->srcQuality = SamplerateConversionQuality(quality);
}
-void mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type) {
+void MT32EMU_C_CALL mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type) {
context->synth->selectRendererType(static_cast<RendererType>(renderer_type));
}
-mt32emu_renderer_type mt32emu_get_selected_renderer_type(mt32emu_context context) {
+mt32emu_renderer_type MT32EMU_C_CALL mt32emu_get_selected_renderer_type(mt32emu_context context) {
return static_cast<mt32emu_renderer_type>(context->synth->getSelectedRendererType());
}
-mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context) {
- if ((context->controlROMImage == nullptr) || (context->pcmROMImage == nullptr)) {
+mt32emu_return_code MT32EMU_C_CALL 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)) {
@@ -650,264 +683,300 @@ mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context) {
return MT32EMU_RC_OK;
}
-void mt32emu_close_synth(mt32emu_const_context context) {
+void MT32EMU_C_CALL mt32emu_close_synth(mt32emu_const_context context) {
context->synth->close();
delete context->srcState->src;
- context->srcState->src = nullptr;
+ context->srcState->src = NULL;
}
-mt32emu_boolean mt32emu_is_open(mt32emu_const_context context) {
+mt32emu_boolean MT32EMU_C_CALL 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) {
- if (context->srcState->src == nullptr) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context) {
+ if (context->srcState->src == NULL) {
return context->synth->getStereoOutputSampleRate();
}
return mt32emu_bit32u(0.5 + context->srcState->src->convertSynthToOutputTimestamp(SAMPLE_RATE));
}
-mt32emu_bit32u mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp) {
- if (context->srcState->src == nullptr) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp) {
+ if (context->srcState->src == NULL) {
return output_timestamp;
}
return mt32emu_bit32u(0.5 + context->srcState->src->convertOutputToSynthTimestamp(output_timestamp));
}
-mt32emu_bit32u mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp) {
- if (context->srcState->src == nullptr) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp) {
+ if (context->srcState->src == NULL) {
return synth_timestamp;
}
return mt32emu_bit32u(0.5 + context->srcState->src->convertSynthToOutputTimestamp(synth_timestamp));
}
-void mt32emu_flush_midi_queue(mt32emu_const_context context) {
+void MT32EMU_C_CALL 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) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size) {
return context->synth->setMIDIEventQueueSize(queue_size);
}
-void mt32emu_configure_midi_event_queue_sysex_storage(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size) {
- return context->synth->configureMIDIEventQueueSysexStorage(storage_buffer_size);
+void MT32EMU_C_CALL mt32emu_configure_midi_event_queue_sysex_storage(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size) {
+ context->synth->configureMIDIEventQueueSysexStorage(storage_buffer_size);
}
-void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data) {
+void MT32EMU_C_CALL mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data) {
delete context->midiParser;
- context->midiParser = (midi_receiver.v0 != nullptr) ? new DelegatingMidiStreamParser(context, midi_receiver, instance_data) : new DefaultMidiStreamParser(*context->synth);
+ context->midiParser = (midi_receiver.v0 != NULL) ? new DelegatingMidiStreamParser(context, midi_receiver, instance_data) : new DefaultMidiStreamParser(*context->synth);
}
-mt32emu_bit32u mt32emu_get_internal_rendered_sample_count(mt32emu_const_context context) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_internal_rendered_sample_count(mt32emu_const_context context) {
return context->synth->getInternalRenderedSampleCount();
}
-void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_return_code MT32EMU_C_CALL 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) {
+mt32emu_return_code MT32EMU_C_CALL 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) {
+mt32emu_return_code MT32EMU_C_CALL 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) {
+mt32emu_return_code MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context) {
return context->synth->isDefaultReverbMT32Compatible() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
}
-void mt32emu_preallocate_reverb_memory(mt32emu_const_context context, const mt32emu_boolean enabled) {
- return context->synth->preallocateReverbMemory(enabled != MT32EMU_BOOL_FALSE);
+void MT32EMU_C_CALL mt32emu_preallocate_reverb_memory(mt32emu_const_context context, const mt32emu_boolean enabled) {
+ context->synth->preallocateReverbMemory(enabled != MT32EMU_BOOL_FALSE);
}
-void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode) {
+void MT32EMU_C_CALL 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) {
+mt32emu_dac_input_mode MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_midi_delay_mode MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL mt32emu_set_output_gain(mt32emu_const_context context, float gain) {
context->synth->setOutputGain(gain);
}
-float mt32emu_get_output_gain(mt32emu_const_context context) {
+float MT32EMU_C_CALL mt32emu_get_output_gain(mt32emu_const_context context) {
return context->synth->getOutputGain();
}
-void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain) {
+void MT32EMU_C_CALL 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) {
+float MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL mt32emu_set_part_volume_override(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u volume_override) {
+ context->synth->setPartVolumeOverride(part_number, volume_override);
+}
+
+mt32emu_bit8u MT32EMU_C_CALL mt32emu_get_part_volume_override(mt32emu_const_context context, mt32emu_bit8u part_number) {
+ return context->synth->getPartVolumeOverride(part_number);
+}
+
+void MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context) {
return context->synth->isReversedStereoEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
}
-void mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
+void MT32EMU_C_CALL mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
context->synth->setNiceAmpRampEnabled(enabled != MT32EMU_BOOL_FALSE);
}
-mt32emu_boolean mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context) {
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context) {
return context->synth->isNiceAmpRampEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
}
-MT32EMU_EXPORT void mt32emu_set_nice_panning_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
+void MT32EMU_C_CALL mt32emu_set_nice_panning_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
context->synth->setNicePanningEnabled(enabled != MT32EMU_BOOL_FALSE);
}
-MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_panning_enabled(mt32emu_const_context context) {
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_nice_panning_enabled(mt32emu_const_context context) {
return context->synth->isNicePanningEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
}
-MT32EMU_EXPORT void mt32emu_set_nice_partial_mixing_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
+void MT32EMU_C_CALL mt32emu_set_nice_partial_mixing_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) {
context->synth->setNicePartialMixingEnabled(enabled != MT32EMU_BOOL_FALSE);
}
-MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_partial_mixing_enabled(mt32emu_const_context context) {
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_nice_partial_mixing_enabled(mt32emu_const_context context) {
return context->synth->isNicePartialMixingEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
}
-void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len) {
- if (context->srcState->src != nullptr) {
+void MT32EMU_C_CALL mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len) {
+ if (context->srcState->src != NULL) {
context->srcState->src->getOutputSamples(stream, len);
} else {
context->synth->render(stream, len);
}
}
-void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len) {
- if (context->srcState->src != nullptr) {
+void MT32EMU_C_CALL mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len) {
+ if (context->srcState->src != NULL) {
context->srcState->src->getOutputSamples(stream, len);
} else {
context->synth->render(stream, len);
}
}
-void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len) {
+void MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL 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) {
+mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_partial_count(mt32emu_const_context context) {
return context->synth->getPartialCount();
}
-mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context) {
+mt32emu_bit32u MT32EMU_C_CALL 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) {
+void MT32EMU_C_CALL 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) {
+mt32emu_bit32u MT32EMU_C_CALL 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) {
+const char * MT32EMU_C_CALL 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) {
+mt32emu_boolean MT32EMU_C_CALL mt32emu_get_sound_group_name(mt32emu_const_context context, char *sound_group_name, mt32emu_bit8u timbre_group, mt32emu_bit8u timbre_number) {
+ return context->synth->getSoundGroupName(sound_group_name, timbre_group, timbre_number) ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
+}
+
+mt32emu_boolean MT32EMU_C_CALL mt32emu_get_sound_name(mt32emu_const_context context, char *sound_name, mt32emu_bit8u timbre_group, mt32emu_bit8u timbre_number) {
+ return context->synth->getSoundName(sound_name, timbre_group, timbre_number) ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
+}
+
+void MT32EMU_C_CALL mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data) {
context->synth->readMemory(addr, len, data);
}
+mt32emu_boolean MT32EMU_C_CALL mt32emu_get_display_state(mt32emu_const_context context, char *target_buffer, const mt32emu_boolean narrow_lcd) {
+ return context->synth->getDisplayState(target_buffer, narrow_lcd != MT32EMU_BOOL_FALSE) ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
+}
+
+void MT32EMU_C_CALL mt32emu_set_main_display_mode(mt32emu_const_context context) {
+ context->synth->setMainDisplayMode();
+}
+
+void MT32EMU_C_CALL mt32emu_set_display_compatibility(mt32emu_const_context context, mt32emu_boolean old_mt32_compatibility_enabled) {
+ context->synth->setDisplayCompatibility(old_mt32_compatibility_enabled != MT32EMU_BOOL_FALSE);
+}
+
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_display_old_mt32_compatible(mt32emu_const_context context) {
+ return context->synth->isDisplayOldMT32Compatible() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
+}
+
+mt32emu_boolean MT32EMU_C_CALL mt32emu_is_default_display_old_mt32_compatible(mt32emu_const_context context) {
+ return context->synth->isDefaultDisplayOldMT32Compatible() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
+}
+
} // extern "C"
diff --git a/audio/softsynth/mt32/c_interface/c_interface.h b/audio/softsynth/mt32/c_interface/c_interface.h
index 14e7263b392..5653c905164 100644
--- a/audio/softsynth/mt32/c_interface/c_interface.h
+++ b/audio/softsynth/mt32/c_interface/c_interface.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -37,7 +37,7 @@ extern "C" {
/* === Interface handling === */
/** Returns mt32emu_service_i interface. */
-MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i(void);
+MT32EMU_EXPORT mt32emu_service_i MT32EMU_C_CALL mt32emu_get_service_i(void);
#if MT32EMU_EXPORTS_TYPE == 2
#undef MT32EMU_EXPORT
@@ -50,13 +50,13 @@ MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i(void);
* 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(void);
+MT32EMU_EXPORT mt32emu_report_handler_version MT32EMU_C_CALL mt32emu_get_supported_report_handler_version(void);
/**
* 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(void);
+MT32EMU_EXPORT mt32emu_midi_receiver_version MT32EMU_C_CALL mt32emu_get_supported_midi_receiver_version(void);
/* === Utility === */
@@ -66,25 +66,25 @@ MT32EMU_EXPORT mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver
* mm - minor version number
* pp - patch number
*/
-MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_library_version_int(void);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_library_version_int(void);
/**
* Returns library version as a C-string in format: "MAJOR.MINOR.PATCH".
*/
-MT32EMU_EXPORT const char *mt32emu_get_library_version_string(void);
+MT32EMU_EXPORT const char * MT32EMU_C_CALL mt32emu_get_library_version_string(void);
/**
* 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);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode);
/**
* Returns the value of analog_output_mode for which the output signal may retain its full frequency spectrum
* at the sample rate specified by the target_samplerate argument.
* See comment for mt32emu_analog_output_mode.
*/
-MT32EMU_EXPORT mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double target_samplerate);
+MT32EMU_EXPORT mt32emu_analog_output_mode MT32EMU_C_CALL mt32emu_get_best_analog_output_mode(const double target_samplerate);
/* === ROM handling === */
@@ -94,7 +94,7 @@ MT32EMU_EXPORT mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(co
* Returns the number of identifiers available for retrieval. The size of the target array to be allocated can be found
* by passing NULL in argument machine_ids; argument machine_ids_size is ignored in this case.
*/
-MT32EMU_EXPORT_V(2.5) size_t mt32emu_get_machine_ids(const char **machine_ids, size_t machine_ids_size);
+MT32EMU_EXPORT_V(2.5) size_t MT32EMU_C_CALL mt32emu_get_machine_ids(const char **machine_ids, size_t machine_ids_size);
/**
* Retrieves a list of identifiers (as C-strings) of supported ROM images. Argument rom_ids points to the array of size
* rom_ids_size to be filled. Optional argument machine_id can be used to indicate a specific machine to retrieve ROM identifiers
@@ -103,7 +103,7 @@ MT32EMU_EXPORT_V(2.5) size_t mt32emu_get_machine_ids(const char **machine_ids, s
* by passing NULL in argument rom_ids; argument rom_ids_size is ignored in this case. If argument machine_id contains
* an unrecognised value, 0 is returned.
*/
-MT32EMU_EXPORT_V(2.5) size_t mt32emu_get_rom_ids(const char **rom_ids, size_t rom_ids_size, const char *machine_id);
+MT32EMU_EXPORT_V(2.5) size_t MT32EMU_C_CALL mt32emu_get_rom_ids(const char **rom_ids, size_t rom_ids_size, const char *machine_id);
/**
* Identifies a ROM image the provided data array contains by its SHA1 digest. Optional argument machine_id can be used to indicate
@@ -113,7 +113,7 @@ MT32EMU_EXPORT_V(2.5) size_t mt32emu_get_rom_ids(const char **rom_ids, size_t ro
* with the specified machine), all fields of rom_info are filled with NULLs.
* Returns MT32EMU_RC_OK upon success or a negative error code otherwise.
*/
-MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_identify_rom_data(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id);
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code MT32EMU_C_CALL mt32emu_identify_rom_data(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id);
/**
* Loads the content of the file specified by argument filename and identifies a ROM image the file contains by its SHA1 digest.
* Optional argument machine_id can be used to indicate a specific machine to identify the ROM image for; if NULL, the ROM image
@@ -123,15 +123,15 @@ MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_identify_rom_data(mt32emu_rom_
* with the specified machine), all fields of rom_info are filled with NULLs.
* Returns MT32EMU_RC_OK upon success or a negative error code otherwise.
*/
-MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_identify_rom_file(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id);
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code MT32EMU_C_CALL mt32emu_identify_rom_file(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id);
/* == 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);
+MT32EMU_EXPORT mt32emu_context MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_free_context(mt32emu_context context);
/**
* Adds a new full ROM data image identified by its SHA1 digest to the emulation context replacing previously added ROM of the same
@@ -143,7 +143,7 @@ MT32EMU_EXPORT void mt32emu_free_context(mt32emu_context context);
* 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);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL 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 that contains a full ROM data image, identifies it by the SHA1 digest, and adds it to the emulation context
@@ -152,7 +152,7 @@ MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context,
* mt32emu_open_synth().
* Returns positive value upon success.
*/
-MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL mt32emu_add_rom_file(mt32emu_context context, const char *filename);
/**
* Merges a pair of compatible ROM data image parts into a full image and adds it to the emulation context replacing previously
@@ -163,7 +163,7 @@ MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context,
* mt32emu_open_synth().
* Returns positive value upon success.
*/
-MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_merge_and_add_rom_data(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest);
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code MT32EMU_C_CALL mt32emu_merge_and_add_rom_data(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest);
/**
* Loads a pair of files that contains compatible parts of a full ROM image, identifies them by the SHA1 digest, merges these
@@ -172,7 +172,7 @@ MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_merge_and_add_rom_data(mt32emu
* mt32emu_open_synth().
* Returns positive value upon success.
*/
-MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_merge_and_add_rom_files(mt32emu_context context, const char *part1_filename, const char *part2_filename);
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code MT32EMU_C_CALL mt32emu_merge_and_add_rom_files(mt32emu_context context, const char *part1_filename, const char *part2_filename);
/**
* Loads a file that contains a ROM image of a specific machine, identifies it by the SHA1 digest, and adds it to the emulation
@@ -190,25 +190,25 @@ MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_merge_and_add_rom_files(mt32em
* Returns a positive value in case changes have been made, MT32EMU_RC_OK if the file has been ignored or a negative error code
* upon failure.
*/
-MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_add_machine_rom_file(mt32emu_context context, const char *machine_id, const char *filename);
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code MT32EMU_C_CALL mt32emu_add_machine_rom_file(mt32emu_context context, const char *machine_id, 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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 value 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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 value 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode);
/**
* Allows to convert the synthesiser output to any desired sample rate. The samplerate conversion
@@ -219,7 +219,7 @@ MT32EMU_EXPORT void mt32emu_set_analog_output_mode(mt32emu_context context, cons
* This function doesn't immediately change the state of already opened synth.
* Newly set value will take effect upon next call of mt32emu_open_synth().
*/
-MT32EMU_EXPORT void mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate);
/**
* Several samplerate conversion quality options are provided which allow to trade-off the conversion speed vs.
@@ -228,33 +228,33 @@ MT32EMU_EXPORT void mt32emu_set_stereo_output_samplerate(mt32emu_context context
* This function doesn't immediately change the state of already opened synth.
* Newly set value will take effect upon next call of mt32emu_open_synth().
*/
-MT32EMU_EXPORT void mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality);
/**
* Selects new type of the wave generator and renderer to be used during subsequent calls to mt32emu_open_synth().
* By default, MT32EMU_RT_BIT16S is selected.
* See mt32emu_renderer_type for details.
*/
-MT32EMU_EXPORT void mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type);
/**
* Returns previously selected type of the wave generator and renderer.
* See mt32emu_renderer_type for details.
*/
-MT32EMU_EXPORT mt32emu_renderer_type mt32emu_get_selected_renderer_type(mt32emu_context context);
+MT32EMU_EXPORT mt32emu_renderer_type MT32EMU_C_CALL mt32emu_get_selected_renderer_type(mt32emu_context context);
/**
* 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);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL mt32emu_is_open(mt32emu_const_context context);
/**
* Returns actual sample rate of the fully processed output stereo signal.
@@ -263,31 +263,31 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_open(mt32emu_const_context context);
* Otherwise, the output samplerate is chosen depending on the emulation mode of stereo analog circuitry of hardware units.
* See comment for mt32emu_analog_output_mode for more info.
*/
-MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context);
/**
* Returns the number of samples produced at the internal synth sample rate (32000 Hz)
* that correspond to the given number of samples at the output sample rate.
* Intended to facilitate audio time synchronisation.
*/
-MT32EMU_EXPORT mt32emu_bit32u mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp);
/**
* Returns the number of samples produced at the output sample rate
* that correspond to the given number of samples at the internal synth sample rate (32000 Hz).
* Intended to facilitate audio time synchronisation.
*/
-MT32EMU_EXPORT mt32emu_bit32u mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp);
/** All the enqueued events are processed by the synth immediately. */
-MT32EMU_EXPORT void mt32emu_flush_midi_queue(mt32emu_const_context context);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size);
/**
* Configures the SysEx storage of the internal MIDI event queue.
@@ -300,7 +300,7 @@ MT32EMU_EXPORT mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_co
* by a SysEx event, that has been processed and thus is no longer necessary, is disposed instantly.
* Note, the queue is flushed and recreated in the process so that its size remains intact.
*/
-void mt32emu_configure_midi_event_queue_sysex_storage(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_configure_midi_event_queue_sysex_storage(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size);
/**
* Installs custom MIDI receiver object intended for receiving MIDI messages generated by MIDI stream parser.
@@ -308,13 +308,13 @@ void mt32emu_configure_midi_event_queue_sysex_storage(mt32emu_const_context cont
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data);
/**
* Returns current value of the global counter of samples rendered since the synth was created (at the native sample rate 32000 Hz).
* This method helps to compute accurate timestamp of a MIDI message to use with the methods below.
*/
-MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_internal_rendered_sample_count(mt32emu_const_context context);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL mt32emu_get_internal_rendered_sample_count(mt32emu_const_context context);
/* Enqueues a MIDI event for subsequent playback.
* The MIDI event will be processed not before the specified timestamp.
@@ -331,7 +331,7 @@ MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_internal_rendered_sample_count(mt32emu
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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.
@@ -339,31 +339,31 @@ MT32EMU_EXPORT void mt32emu_parse_stream(mt32emu_const_context context, const mt
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_return_code MT32EMU_C_CALL 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,
@@ -375,73 +375,73 @@ MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context c
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context);
/**
* If enabled, reverb buffers for all modes are kept around allocated all the time to avoid memory
* allocating/freeing in the rendering thread, which may be required for realtime operation.
* Otherwise, reverb buffers that are not in use are deleted to save memory (the default behaviour).
*/
-MT32EMU_EXPORT void mt32emu_preallocate_reverb_memory(mt32emu_const_context context, const mt32emu_boolean enabled);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_preallocate_reverb_memory(mt32emu_const_context context, const mt32emu_boolean enabled);
/** 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_dac_input_mode MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_midi_delay_mode MT32EMU_C_CALL 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.
*/
-MT32EMU_EXPORT void mt32emu_set_output_gain(mt32emu_const_context context, float gain);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT float MT32EMU_C_CALL 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
@@ -453,14 +453,34 @@ MT32EMU_EXPORT float mt32emu_get_output_gain(mt32emu_const_context context);
* 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.
*/
-MT32EMU_EXPORT void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT float MT32EMU_C_CALL mt32emu_get_reverb_output_gain(mt32emu_const_context context);
+
+/**
+ * Sets (or removes) an override for the current volume (output level) on a specific part.
+ * When the part volume is overridden, the MIDI controller Volume (7) on the MIDI channel this part is assigned to
+ * has no effect on the output level of this part. Similarly, the output level value set on this part via a SysEx that
+ * modifies the Patch temp structure is disregarded.
+ * To enable the override mode, argument volumeOverride should be in range 0..100, setting a value outside this range
+ * disables the previously set override, if any.
+ * Note: Setting volumeOverride to 0 mutes the part completely, meaning no sound is generated at all.
+ * This is unlike the behaviour of real devices - setting 0 volume on a part may leave it still producing
+ * sound at a very low level.
+ * Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ */
+MT32EMU_EXPORT_V(2.6) void MT32EMU_C_CALL mt32emu_set_part_volume_override(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u volume_override);
+/**
+ * Returns the overridden volume previously set on a specific part; a value outside the range 0..100 means no override
+ * is currently in effect.
+ * Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm.
+ */
+MT32EMU_EXPORT_V(2.6) mt32emu_bit8u MT32EMU_C_CALL mt32emu_get_part_volume_override(mt32emu_const_context context, mt32emu_bit8u part_number);
/** Swaps left and right output channels. */
-MT32EMU_EXPORT void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context);
/**
* Allows to toggle the NiceAmpRamp mode.
@@ -470,9 +490,9 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_
* We also prefer the quality improvement over the emulation accuracy,
* so this mode is enabled by default.
*/
-MT32EMU_EXPORT void mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
/** Returns whether NiceAmpRamp mode is enabled. */
-MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context);
/**
* Allows to toggle the NicePanning mode.
@@ -483,9 +503,9 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_co
* making it smoother thus sacrificing the emulation accuracy.
* This mode is disabled by default.
*/
-MT32EMU_EXPORT void mt32emu_set_nice_panning_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_nice_panning_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
/** Returns whether NicePanning mode is enabled. */
-MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_panning_enabled(mt32emu_const_context context);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL mt32emu_is_nice_panning_enabled(mt32emu_const_context context);
/**
* Allows to toggle the NicePartialMixing mode.
@@ -497,9 +517,9 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_panning_enabled(mt32emu_const_con
* thus making the behaviour more predictable.
* This mode is disabled by default.
*/
-MT32EMU_EXPORT void mt32emu_set_nice_partial_mixing_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_set_nice_partial_mixing_enabled(mt32emu_const_context context, const mt32emu_boolean enabled);
/** Returns whether NicePartialMixing mode is enabled. */
-MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_partial_mixing_enabled(mt32emu_const_context context);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL mt32emu_is_nice_partial_mixing_enabled(mt32emu_const_context context);
/**
* Renders samples to the specified output stream as if they were sampled at the analog stereo output at the desired sample rate.
@@ -507,9 +527,9 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_partial_mixing_enabled(mt32emu_co
* mode of analog circuitry emulation. See mt32emu_analog_output_mode.
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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.
@@ -517,25 +537,25 @@ MT32EMU_EXPORT void mt32emu_render_float(mt32emu_const_context context, float *s
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_boolean MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL 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);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL 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
@@ -543,7 +563,7 @@ MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context cont
* 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL 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
@@ -551,16 +571,71 @@ MT32EMU_EXPORT void mt32emu_get_partial_states(mt32emu_const_context context, mt
* 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);
+MT32EMU_EXPORT mt32emu_bit32u MT32EMU_C_CALL 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.
+ * The returned value is a null-terminated string which is guaranteed to remain valid until the next call to one of functions
+ * that perform sample rendering or immediate SysEx processing (e.g. mt32emu_play_sysex_now).
*/
-MT32EMU_EXPORT const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number);
+MT32EMU_EXPORT const char * MT32EMU_C_CALL mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number);
+
+/**
+ * Retrieves the name of the sound group the timbre identified by arguments timbre_group and timbre_number is associated with.
+ * Values 0-3 of timbre_group correspond to the timbre banks GROUP A, GROUP B, MEMORY and RHYTHM.
+ * For all but the RHYTHM timbre bank, allowed values of timbre_number are in range 0-63. The number of timbres
+ * contained in the RHYTHM bank depends on the used control ROM version.
+ * The argument sound_group_name must point to an array of at least 8 characters. The result is a null-terminated string.
+ * Returns whether the specified timbre has been found and the result written in sound_group_name.
+ */
+MT32EMU_EXPORT_V(2.7) mt32emu_boolean MT32EMU_C_CALL mt32emu_get_sound_group_name(mt32emu_const_context context, char *sound_group_name, mt32emu_bit8u timbre_group, mt32emu_bit8u timbre_number);
+/**
+ * Retrieves the name of the timbre identified by arguments timbre_group and timbre_number.
+ * Values 0-3 of timbre_group correspond to the timbre banks GROUP A, GROUP B, MEMORY and RHYTHM.
+ * For all but the RHYTHM timbre bank, allowed values of timbre_number are in range 0-63. The number of timbres
+ * contained in the RHYTHM bank depends on the used control ROM version.
+ * The argument sound_name must point to an array of at least 11 characters. The result is a null-terminated string.
+ * Returns whether the specified timbre has been found and the result written in sound_name.
+ */
+MT32EMU_EXPORT_V(2.7) mt32emu_boolean MT32EMU_C_CALL mt32emu_get_sound_name(mt32emu_const_context context, char *sound_name, mt32emu_bit8u timbreGroup, mt32emu_bit8u timbreNumber);
/** 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);
+MT32EMU_EXPORT void MT32EMU_C_CALL mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data);
+
+/**
+ * Retrieves the current state of the emulated MT-32 display facilities.
+ * Typically, the state is updated during the rendering. When that happens, a related callback from mt32emu_report_handler_i_v1
+ * is invoked. However, there might be no need to invoke this method after each update, e.g. when the render buffer is just
+ * a few milliseconds long.
+ * The argument target_buffer must point to an array of at least 21 characters. The result is a null-terminated string.
+ * The argument narrow_lcd enables a condensed representation of the displayed information in some cases. This is mainly intended
+ * to route the result to a hardware LCD that is only 16 characters wide. Automatic scrolling of longer strings is not supported.
+ * Returns whether the MIDI MESSAGE LED is ON and fills the target_buffer parameter.
+ */
+MT32EMU_EXPORT_V(2.6) mt32emu_boolean MT32EMU_C_CALL mt32emu_get_display_state(mt32emu_const_context context, char *target_buffer, const mt32emu_boolean narrow_lcd);
+
+/**
+ * Resets the emulated LCD to the main mode (Master Volume). This has the same effect as pressing the Master Volume button
+ * while the display shows some other message. Useful for the new-gen devices as those require a special Display Reset SysEx
+ * to return to the main mode e.g. from showing a custom display message or a checksum error.
+ */
+MT32EMU_EXPORT_V(2.6) void MT32EMU_C_CALL mt32emu_set_main_display_mode(mt32emu_const_context context);
+
+/**
+ * Permits to select an arbitrary display emulation model that does not necessarily match the actual behaviour implemented
+ * in the control ROM version being used.
+ * Invoking this method with the argument set to true forces emulation of the old-gen MT-32 display features.
+ * Otherwise, emulation of the new-gen devices is enforced (these include CM-32L and LAPC-I as if these were connected to an LCD).
+ */
+MT32EMU_EXPORT_V(2.6) void MT32EMU_C_CALL mt32emu_set_display_compatibility(mt32emu_const_context context, mt32emu_boolean old_mt32_compatibility_enabled);
+/** Returns whether the currently configured features of the emulated display are compatible with the old-gen MT-32 devices. */
+MT32EMU_EXPORT_V(2.6) mt32emu_boolean MT32EMU_C_CALL mt32emu_is_display_old_mt32_compatible(mt32emu_const_context context);
+/**
+ * Returns whether the emulated display features configured by default depending on the actual control ROM version
+ * are compatible with the old-gen MT-32 devices.
+ */
+MT32EMU_EXPORT_V(2.6) mt32emu_boolean MT32EMU_C_CALL mt32emu_is_default_display_old_mt32_compatible(mt32emu_const_context context);
#ifdef __cplusplus
} // extern "C"
diff --git a/audio/softsynth/mt32/c_interface/c_types.h b/audio/softsynth/mt32/c_interface/c_types.h
index 6bcf0775538..8928bfeae3b 100644
--- a/audio/softsynth/mt32/c_interface/c_types.h
+++ b/audio/softsynth/mt32/c_interface/c_types.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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,6 +27,12 @@
#include "../Enumerations.h"
#undef MT32EMU_C_ENUMERATIONS
+#ifdef _WIN32
+# define MT32EMU_C_CALL __cdecl
+#else
+# define MT32EMU_C_CALL
+#endif
+
typedef unsigned int mt32emu_bit32u;
typedef signed int mt32emu_bit32s;
typedef unsigned short int mt32emu_bit16u;
@@ -111,7 +117,8 @@ typedef struct {
/** 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_1 = 1,
+ MT32EMU_REPORT_HANDLER_VERSION_CURRENT = MT32EMU_REPORT_HANDLER_VERSION_1
} mt32emu_report_handler_version;
/** MIDI receiver interface versions */
@@ -127,7 +134,9 @@ typedef enum {
MT32EMU_SERVICE_VERSION_2 = 2,
MT32EMU_SERVICE_VERSION_3 = 3,
MT32EMU_SERVICE_VERSION_4 = 4,
- MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_4
+ MT32EMU_SERVICE_VERSION_5 = 5,
+ MT32EMU_SERVICE_VERSION_6 = 6,
+ MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_6
} mt32emu_service_version;
/* === Report Handler Interface === */
@@ -135,42 +144,59 @@ typedef enum {
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);
+#define MT32EMU_REPORT_HANDLER_I_V0 \
+ /** Returns the actual interface version ID */ \
+ mt32emu_report_handler_version (MT32EMU_C_CALL *getVersionID)(mt32emu_report_handler_i i); \
+\
+ /** Callback for debug messages, in vprintf() format */ \
+ void (MT32EMU_C_CALL *printDebug)(void *instance_data, const char *fmt, va_list list); \
+ /** Callbacks for reporting errors */ \
+ void (MT32EMU_C_CALL *onErrorControlROM)(void *instance_data); \
+ void (MT32EMU_C_CALL *onErrorPCMROM)(void *instance_data); \
+ /** Callback for reporting about displaying a new custom message on LCD */ \
+ void (MT32EMU_C_CALL *showLCDMessage)(void *instance_data, const char *message); \
+ /** Callback for reporting actual processing of a MIDI message */ \
+ void (MT32EMU_C_CALL *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);
+ */ \
+ mt32emu_boolean (MT32EMU_C_CALL *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);
+ */ \
+ void (MT32EMU_C_CALL *onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); \
+ /** Callbacks for reporting system events */ \
+ void (MT32EMU_C_CALL *onDeviceReset)(void *instance_data); \
+ void (MT32EMU_C_CALL *onDeviceReconfig)(void *instance_data); \
+ /** Callbacks for reporting changes of reverb settings */ \
+ void (MT32EMU_C_CALL *onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); \
+ void (MT32EMU_C_CALL *onNewReverbTime)(void *instance_data, mt32emu_bit8u time); \
+ void (MT32EMU_C_CALL *onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); \
+ /** Callbacks for reporting various information */ \
+ void (MT32EMU_C_CALL *onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); \
+ void (MT32EMU_C_CALL *onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name);
+
+#define MT32EMU_REPORT_HANDLER_I_V1 \
+ /**
+ * Invoked to signal about a change of the emulated LCD state. Use mt32emu_get_display_state to retrieve the actual data.
+ * This callback will not be invoked on further changes, until the client retrieves the LCD state.
+ */ \
+ void (MT32EMU_C_CALL *onLCDStateUpdated)(void *instance_data); \
+ /** Invoked when the emulated MIDI MESSAGE LED changes state. The led_state parameter represents whether the LED is ON. */ \
+ void (MT32EMU_C_CALL *onMidiMessageLEDStateUpdated)(void *instance_data, mt32emu_boolean led_state);
+
+typedef struct {
+ MT32EMU_REPORT_HANDLER_I_V0
} mt32emu_report_handler_i_v0;
+typedef struct {
+ MT32EMU_REPORT_HANDLER_I_V0
+ MT32EMU_REPORT_HANDLER_I_V1
+} mt32emu_report_handler_i_v1;
+
/**
* Extensible interface for handling reported events.
* Union intended to view an interface of any subsequent version as any parent interface not requiring a cast.
@@ -178,8 +204,12 @@ typedef struct {
*/
union mt32emu_report_handler_i {
const mt32emu_report_handler_i_v0 *v0;
+ const mt32emu_report_handler_i_v1 *v1;
};
+#undef MT32EMU_REPORT_HANDLER_I_V0
+#undef MT32EMU_REPORT_HANDLER_I_V1
+
/* === MIDI Receiver Interface === */
typedef union mt32emu_midi_receiver_i mt32emu_midi_receiver_i;
@@ -187,16 +217,16 @@ 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);
+ mt32emu_midi_receiver_version (MT32EMU_C_CALL *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);
+ void (MT32EMU_C_CALL *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);
+ void (MT32EMU_C_CALL *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);
+ void (MT32EMU_C_CALL *handleSystemRealtimeMessage)(void *instance_data, const mt32emu_bit8u realtime);
} mt32emu_midi_receiver_i_v0;
/**
@@ -221,111 +251,124 @@ typedef union mt32emu_service_i mt32emu_service_i;
*/
#define MT32EMU_SERVICE_I_V0 \
/** Returns the actual interface version ID */ \
- mt32emu_service_version (*getVersionID)(mt32emu_service_i i); \
- mt32emu_report_handler_version (*getSupportedReportHandlerVersionID)(void); \
- mt32emu_midi_receiver_version (*getSupportedMIDIReceiverVersionID)(void); \
+ mt32emu_service_version (MT32EMU_C_CALL *getVersionID)(mt32emu_service_i i); \
+ mt32emu_report_handler_version (MT32EMU_C_CALL *getSupportedReportHandlerVersionID)(void); \
+ mt32emu_midi_receiver_version (MT32EMU_C_CALL *getSupportedMIDIReceiverVersionID)(void); \
\
- mt32emu_bit32u (*getLibraryVersionInt)(void); \
- const char *(*getLibraryVersionString)(void); \
+ mt32emu_bit32u (MT32EMU_C_CALL *getLibraryVersionInt)(void); \
+ const char *(MT32EMU_C_CALL *getLibraryVersionString)(void); \
\
- mt32emu_bit32u (*getStereoOutputSamplerate)(const mt32emu_analog_output_mode analog_output_mode); \
+ mt32emu_bit32u (MT32EMU_C_CALL *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); \
+ mt32emu_context (MT32EMU_C_CALL *createContext)(mt32emu_report_handler_i report_handler, void *instance_data); \
+ void (MT32EMU_C_CALL *freeContext)(mt32emu_context context); \
+ mt32emu_return_code (MT32EMU_C_CALL *addROMData)(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest); \
+ mt32emu_return_code (MT32EMU_C_CALL *addROMFile)(mt32emu_context context, const char *filename); \
+ void (MT32EMU_C_CALL *getROMInfo)(mt32emu_const_context context, mt32emu_rom_info *rom_info); \
+ void (MT32EMU_C_CALL *setPartialCount)(mt32emu_context context, const mt32emu_bit32u partial_count); \
+ void (MT32EMU_C_CALL *setAnalogOutputMode)(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode); \
+ mt32emu_return_code (MT32EMU_C_CALL *openSynth)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *closeSynth)(mt32emu_const_context context); \
+ mt32emu_boolean (MT32EMU_C_CALL *isOpen)(mt32emu_const_context context); \
+ mt32emu_bit32u (MT32EMU_C_CALL *getActualStereoOutputSamplerate)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *flushMIDIQueue)(mt32emu_const_context context); \
+ mt32emu_bit32u (MT32EMU_C_CALL *setMIDIEventQueueSize)(mt32emu_const_context context, const mt32emu_bit32u queue_size); \
+ void (MT32EMU_C_CALL *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 (MT32EMU_C_CALL *parseStream)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length); \
+ void (MT32EMU_C_CALL *parseStream_At)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp); \
+ void (MT32EMU_C_CALL *playShortMessage)(mt32emu_const_context context, mt32emu_bit32u message); \
+ void (MT32EMU_C_CALL *playShortMessageAt)(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp); \
+ mt32emu_return_code (MT32EMU_C_CALL *playMsg)(mt32emu_const_context context, mt32emu_bit32u msg); \
+ mt32emu_return_code (MT32EMU_C_CALL *playSysex)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \
+ mt32emu_return_code (MT32EMU_C_CALL *playMsgAt)(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp); \
+ mt32emu_return_code (MT32EMU_C_CALL *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 (MT32EMU_C_CALL *playMsgNow)(mt32emu_const_context context, mt32emu_bit32u msg); \
+ void (MT32EMU_C_CALL *playMsgOnPart)(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity); \
+ void (MT32EMU_C_CALL *playSysexNow)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \
+ void (MT32EMU_C_CALL *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 (MT32EMU_C_CALL *setReverbEnabled)(mt32emu_const_context context, const mt32emu_boolean reverb_enabled); \
+ mt32emu_boolean (MT32EMU_C_CALL *isReverbEnabled)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setReverbOverridden)(mt32emu_const_context context, const mt32emu_boolean reverb_overridden); \
+ mt32emu_boolean (MT32EMU_C_CALL *isReverbOverridden)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setReverbCompatibilityMode)(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode); \
+ mt32emu_boolean (MT32EMU_C_CALL *isMT32ReverbCompatibilityMode)(mt32emu_const_context context); \
+ mt32emu_boolean (MT32EMU_C_CALL *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 (MT32EMU_C_CALL *setDACInputMode)(mt32emu_const_context context, const mt32emu_dac_input_mode mode); \
+ mt32emu_dac_input_mode (MT32EMU_C_CALL *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 (MT32EMU_C_CALL *setMIDIDelayMode)(mt32emu_const_context context, const mt32emu_midi_delay_mode mode); \
+ mt32emu_midi_delay_mode (MT32EMU_C_CALL *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 (MT32EMU_C_CALL *setOutputGain)(mt32emu_const_context context, float gain); \
+ float (MT32EMU_C_CALL *getOutputGain)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setReverbOutputGain)(mt32emu_const_context context, float gain); \
+ float (MT32EMU_C_CALL *getReverbOutputGain)(mt32emu_const_context context); \
\
- void (*setReversedStereoEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
- mt32emu_boolean (*isReversedStereoEnabled)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setReversedStereoEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
+ mt32emu_boolean (MT32EMU_C_CALL *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); \
+ void (MT32EMU_C_CALL *renderBit16s)(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len); \
+ void (MT32EMU_C_CALL *renderFloat)(mt32emu_const_context context, float *stream, mt32emu_bit32u len); \
+ void (MT32EMU_C_CALL *renderBit16sStreams)(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len); \
+ void (MT32EMU_C_CALL *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_boolean (MT32EMU_C_CALL *hasActivePartials)(mt32emu_const_context context); \
+ mt32emu_boolean (MT32EMU_C_CALL *isActive)(mt32emu_const_context context); \
+ mt32emu_bit32u (MT32EMU_C_CALL *getPartialCount)(mt32emu_const_context context); \
+ mt32emu_bit32u (MT32EMU_C_CALL *getPartStates)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *getPartialStates)(mt32emu_const_context context, mt32emu_bit8u *partial_states); \
+ mt32emu_bit32u (MT32EMU_C_CALL *getPlayingNotes)(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities); \
+ const char *(MT32EMU_C_CALL *getPatchName)(mt32emu_const_context context, mt32emu_bit8u part_number); \
+ void (MT32EMU_C_CALL *readMemory)(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data);
#define MT32EMU_SERVICE_I_V1 \
- mt32emu_analog_output_mode (*getBestAnalogOutputMode)(const double target_samplerate); \
- void (*setStereoOutputSampleRate)(mt32emu_context context, const double samplerate); \
- void (*setSamplerateConversionQuality)(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality); \
- void (*selectRendererType)(mt32emu_context context, mt32emu_renderer_type renderer_type); \
- mt32emu_renderer_type (*getSelectedRendererType)(mt32emu_context context); \
- mt32emu_bit32u (*convertOutputToSynthTimestamp)(mt32emu_const_context context, mt32emu_bit32u output_timestamp); \
- mt32emu_bit32u (*convertSynthToOutputTimestamp)(mt32emu_const_context context, mt32emu_bit32u synth_timestamp);
+ mt32emu_analog_output_mode (MT32EMU_C_CALL *getBestAnalogOutputMode)(const double target_samplerate); \
+ void (MT32EMU_C_CALL *setStereoOutputSampleRate)(mt32emu_context context, const double samplerate); \
+ void (MT32EMU_C_CALL *setSamplerateConversionQuality)(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality); \
+ void (MT32EMU_C_CALL *selectRendererType)(mt32emu_context context, mt32emu_renderer_type renderer_type); \
+ mt32emu_renderer_type (MT32EMU_C_CALL *getSelectedRendererType)(mt32emu_context context); \
+ mt32emu_bit32u (MT32EMU_C_CALL *convertOutputToSynthTimestamp)(mt32emu_const_context context, mt32emu_bit32u output_timestamp); \
+ mt32emu_bit32u (MT32EMU_C_CALL *convertSynthToOutputTimestamp)(mt32emu_const_context context, mt32emu_bit32u synth_timestamp);
#define MT32EMU_SERVICE_I_V2 \
- mt32emu_bit32u (*getInternalRenderedSampleCount)(mt32emu_const_context context); \
- void (*setNiceAmpRampEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
- mt32emu_boolean (*isNiceAmpRampEnabled)(mt32emu_const_context context);
+ mt32emu_bit32u (MT32EMU_C_CALL *getInternalRenderedSampleCount)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setNiceAmpRampEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
+ mt32emu_boolean (MT32EMU_C_CALL *isNiceAmpRampEnabled)(mt32emu_const_context context);
#define MT32EMU_SERVICE_I_V3 \
- void (*setNicePanningEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
- mt32emu_boolean (*isNicePanningEnabled)(mt32emu_const_context context); \
- void (*setNicePartialMixingEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
- mt32emu_boolean (*isNicePartialMixingEnabled)(mt32emu_const_context context); \
- void (*preallocateReverbMemory)(mt32emu_const_context context, const mt32emu_boolean enabled); \
- void (*configureMIDIEventQueueSysexStorage)(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size);
+ void (MT32EMU_C_CALL *setNicePanningEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
+ mt32emu_boolean (MT32EMU_C_CALL *isNicePanningEnabled)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setNicePartialMixingEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
+ mt32emu_boolean (MT32EMU_C_CALL *isNicePartialMixingEnabled)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *preallocateReverbMemory)(mt32emu_const_context context, const mt32emu_boolean enabled); \
+ void (MT32EMU_C_CALL *configureMIDIEventQueueSysexStorage)(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size);
#define MT32EMU_SERVICE_I_V4 \
- size_t (*getMachineIDs)(const char **machine_ids, size_t machine_ids_size); \
- size_t (*getROMIDs)(const char **rom_ids, size_t rom_ids_size, const char *machine_id); \
- mt32emu_return_code (*identifyROMData)(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id); \
- mt32emu_return_code (*identifyROMFile)(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id); \
+ size_t (MT32EMU_C_CALL *getMachineIDs)(const char **machine_ids, size_t machine_ids_size); \
+ size_t (MT32EMU_C_CALL *getROMIDs)(const char **rom_ids, size_t rom_ids_size, const char *machine_id); \
+ mt32emu_return_code (MT32EMU_C_CALL *identifyROMData)(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id); \
+ mt32emu_return_code (MT32EMU_C_CALL *identifyROMFile)(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id); \
\
- mt32emu_return_code (*mergeAndAddROMData)(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest); \
- mt32emu_return_code (*mergeAndAddROMFiles)(mt32emu_context context, const char *part1_filename, const char *part2_filename); \
- mt32emu_return_code (*addMachineROMFile)(mt32emu_context context, const char *machine_id, const char *filename);
+ mt32emu_return_code (MT32EMU_C_CALL *mergeAndAddROMData)(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest); \
+ mt32emu_return_code (MT32EMU_C_CALL *mergeAndAddROMFiles)(mt32emu_context context, const char *part1_filename, const char *part2_filename); \
+ mt32emu_return_code (MT32EMU_C_CALL *addMachineROMFile)(mt32emu_context context, const char *machine_id, const char *filename);
+
+#define MT32EMU_SERVICE_I_V5 \
+ mt32emu_boolean (MT32EMU_C_CALL *getDisplayState)(mt32emu_const_context context, char *target_buffer, const mt32emu_boolean narrow_lcd); \
+ void (MT32EMU_C_CALL *setMainDisplayMode)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setDisplayCompatibility)(mt32emu_const_context context, mt32emu_boolean old_mt32_compatibility_enabled); \
+ mt32emu_boolean (MT32EMU_C_CALL *isDisplayOldMT32Compatible)(mt32emu_const_context context); \
+ mt32emu_boolean (MT32EMU_C_CALL *isDefaultDisplayOldMT32Compatible)(mt32emu_const_context context); \
+ void (MT32EMU_C_CALL *setPartVolumeOverride)(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u volume_override); \
+ mt32emu_bit8u (MT32EMU_C_CALL *getPartVolumeOverride)(mt32emu_const_context context, mt32emu_bit8u part_number);
+
+#define MT32EMU_SERVICE_I_V6 \
+ mt32emu_boolean (MT32EMU_C_CALL *getSoundGroupName)(mt32emu_const_context context, char *sound_group_name, mt32emu_bit8u timbre_group, mt32emu_bit8u timbre_number); \
+ mt32emu_boolean (MT32EMU_C_CALL *getSoundName)(mt32emu_const_context context, char *sound_name, mt32emu_bit8u timbre_group, mt32emu_bit8u timbre_number);
typedef struct {
MT32EMU_SERVICE_I_V0
@@ -357,6 +400,25 @@ typedef struct {
MT32EMU_SERVICE_I_V4
} mt32emu_service_i_v4;
+typedef struct {
+ MT32EMU_SERVICE_I_V0
+ MT32EMU_SERVICE_I_V1
+ MT32EMU_SERVICE_I_V2
+ MT32EMU_SERVICE_I_V3
+ MT32EMU_SERVICE_I_V4
+ MT32EMU_SERVICE_I_V5
+} mt32emu_service_i_v5;
+
+typedef struct {
+ MT32EMU_SERVICE_I_V0
+ MT32EMU_SERVICE_I_V1
+ MT32EMU_SERVICE_I_V2
+ MT32EMU_SERVICE_I_V3
+ MT32EMU_SERVICE_I_V4
+ MT32EMU_SERVICE_I_V5
+ MT32EMU_SERVICE_I_V6
+} mt32emu_service_i_v6;
+
/**
* 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.
@@ -368,6 +430,8 @@ union mt32emu_service_i {
const mt32emu_service_i_v2 *v2;
const mt32emu_service_i_v3 *v3;
const mt32emu_service_i_v4 *v4;
+ const mt32emu_service_i_v5 *v5;
+ const mt32emu_service_i_v6 *v6;
};
#undef MT32EMU_SERVICE_I_V0
@@ -375,5 +439,7 @@ union mt32emu_service_i {
#undef MT32EMU_SERVICE_I_V2
#undef MT32EMU_SERVICE_I_V3
#undef MT32EMU_SERVICE_I_V4
+#undef MT32EMU_SERVICE_I_V5
+#undef MT32EMU_SERVICE_I_V6
#endif /* #ifndef MT32EMU_C_TYPES_H */
diff --git a/audio/softsynth/mt32/c_interface/cpp_interface.h b/audio/softsynth/mt32/c_interface/cpp_interface.h
index aa28327e87a..d22897b7426 100644
--- a/audio/softsynth/mt32/c_interface/cpp_interface.h
+++ b/audio/softsynth/mt32/c_interface/cpp_interface.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -98,6 +98,8 @@ mt32emu_service_i mt32emu_get_service_i();
#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_part_volume_override iV5()->setPartVolumeOverride
+#define mt32emu_get_part_volume_override iV5()->getPartVolumeOverride
#define mt32emu_set_reversed_stereo_enabled i.v0->setReversedStereoEnabled
#define mt32emu_is_reversed_stereo_enabled i.v0->isReversedStereoEnabled
#define mt32emu_set_nice_amp_ramp_enabled iV2()->setNiceAmpRampEnabled
@@ -117,7 +119,14 @@ mt32emu_service_i mt32emu_get_service_i();
#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_get_sound_group_name iV6()->getSoundGroupName
+#define mt32emu_get_sound_name iV6()->getSoundName
#define mt32emu_read_memory i.v0->readMemory
+#define mt32emu_get_display_state iV5()->getDisplayState
+#define mt32emu_set_main_display_mode iV5()->setMainDisplayMode
+#define mt32emu_set_display_compatibility iV5()->setDisplayCompatibility
+#define mt32emu_is_display_old_mt32_compatible iV5()->isDisplayOldMT32Compatible
+#define mt32emu_is_default_display_old_mt32_compatible iV5()->isDefaultDisplayOldMT32Compatible
#else // #if MT32EMU_API_TYPE == 2
@@ -130,7 +139,7 @@ namespace MT32Emu {
namespace CppInterfaceImpl {
static const mt32emu_report_handler_i NULL_REPORT_HANDLER = { NULL };
-static mt32emu_report_handler_i getReportHandlerThunk();
+static mt32emu_report_handler_i getReportHandlerThunk(mt32emu_report_handler_version);
static mt32emu_midi_receiver_i getMidiReceiverThunk();
}
@@ -143,8 +152,8 @@ static mt32emu_midi_receiver_i getMidiReceiverThunk();
* 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.
+// Defines the interface for handling reported events (initial version).
+// Corresponds to the mt32emu_report_handler_i_v0 interface.
class IReportHandler {
public:
virtual void printDebug(const char *fmt, va_list list) = 0;
@@ -166,6 +175,17 @@ protected:
~IReportHandler() {}
};
+// Extends IReportHandler, so that the client may supply callbacks for reporting signals about updated display state.
+// Corresponds to the mt32emu_report_handler_i_v1 interface.
+class IReportHandlerV1 : public IReportHandler {
+public:
+ virtual void onLCDStateUpdated() = 0;
+ virtual void onMidiMessageLEDStateUpdated(bool ledState) = 0;
+
+protected:
+ ~IReportHandlerV1() {}
+};
+
// 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 {
@@ -212,7 +232,8 @@ public:
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 createContext(IReportHandler &report_handler) { createContext(CppInterfaceImpl::getReportHandlerThunk(MT32EMU_REPORT_HANDLER_VERSION_0), &report_handler); }
+ void createContext(IReportHandlerV1 &report_handler) { createContext(CppInterfaceImpl::getReportHandlerThunk(MT32EMU_REPORT_HANDLER_VERSION_1), &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); }
@@ -274,6 +295,9 @@ public:
void setReverbOutputGain(float gain) { mt32emu_set_reverb_output_gain(c, gain); }
float getReverbOutputGain() { return mt32emu_get_reverb_output_gain(c); }
+ void setPartVolumeOverride(Bit8u part_number, Bit8u volume_override) { mt32emu_set_part_volume_override(c, part_number, volume_override); }
+ Bit8u getPartVolumeOverride(Bit8u part_number) { return mt32emu_get_part_volume_override(c, part_number); }
+
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; }
@@ -298,8 +322,17 @@ public:
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); }
+ bool getSoundGroupName(char *soundGroupName, Bit8u timbreGroup, Bit8u timbreNumber) { return mt32emu_get_sound_group_name(c, soundGroupName, timbreGroup, timbreNumber) != MT32EMU_BOOL_FALSE; }
+ bool getSoundName(char *soundName, Bit8u timbreGroup, Bit8u timbreNumber) { return mt32emu_get_sound_name(c, soundName, timbreGroup, timbreNumber) != MT32EMU_BOOL_FALSE; }
void readMemory(Bit32u addr, Bit32u len, Bit8u *data) { mt32emu_read_memory(c, addr, len, data); }
+ bool getDisplayState(char *target_buffer, const bool narrow_lcd) { return mt32emu_get_display_state(c, target_buffer, narrow_lcd ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE) != MT32EMU_BOOL_FALSE; }
+ void setMainDisplayMode() { mt32emu_set_main_display_mode(c); }
+
+ void setDisplayCompatibility(const bool oldMT32CompatibilityEnabled) { mt32emu_set_display_compatibility(c, oldMT32CompatibilityEnabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
+ bool isDisplayOldMT32Compatible() { return mt32emu_is_display_old_mt32_compatible(c) != MT32EMU_BOOL_FALSE; }
+ bool isDefaultDisplayOldMT32Compatible() { return mt32emu_is_default_display_old_mt32_compatible(c) != MT32EMU_BOOL_FALSE; }
+
private:
#if MT32EMU_API_TYPE == 2
const mt32emu_service_i i;
@@ -311,6 +344,8 @@ private:
const mt32emu_service_i_v2 *iV2() { return (getVersionID() < MT32EMU_SERVICE_VERSION_2) ? NULL : i.v2; }
const mt32emu_service_i_v3 *iV3() { return (getVersionID() < MT32EMU_SERVICE_VERSION_3) ? NULL : i.v3; }
const mt32emu_service_i_v4 *iV4() { return (getVersionID() < MT32EMU_SERVICE_VERSION_4) ? NULL : i.v4; }
+ const mt32emu_service_i_v5 *iV5() { return (getVersionID() < MT32EMU_SERVICE_VERSION_5) ? NULL : i.v5; }
+ const mt32emu_service_i_v6 *iV6() { return (getVersionID() < MT32EMU_SERVICE_VERSION_6) ? NULL : i.v6; }
#endif
Service(const Service &); // prevent copy-construction
@@ -319,103 +354,126 @@ private:
namespace CppInterfaceImpl {
-static mt32emu_report_handler_version getReportHandlerVersionID(mt32emu_report_handler_i) {
- return MT32EMU_REPORT_HANDLER_VERSION_CURRENT;
-}
+static mt32emu_report_handler_version MT32EMU_C_CALL getReportHandlerVersionID(mt32emu_report_handler_i);
-static void printDebug(void *instance_data, const char *fmt, va_list list) {
+static void MT32EMU_C_CALL printDebug(void *instance_data, const char *fmt, va_list list) {
static_cast<IReportHandler *>(instance_data)->printDebug(fmt, list);
}
-static void onErrorControlROM(void *instance_data) {
+static void MT32EMU_C_CALL onErrorControlROM(void *instance_data) {
static_cast<IReportHandler *>(instance_data)->onErrorControlROM();
}
-static void onErrorPCMROM(void *instance_data) {
+static void MT32EMU_C_CALL onErrorPCMROM(void *instance_data) {
static_cast<IReportHandler *>(instance_data)->onErrorPCMROM();
}
-static void showLCDMessage(void *instance_data, const char *message) {
+static void MT32EMU_C_CALL showLCDMessage(void *instance_data, const char *message) {
static_cast<IReportHandler *>(instance_data)->showLCDMessage(message);
}
-static void onMIDIMessagePlayed(void *instance_data) {
+static void MT32EMU_C_CALL onMIDIMessagePlayed(void *instance_data) {
static_cast<IReportHandler *>(instance_data)->onMIDIMessagePlayed();
}
-static mt32emu_boolean onMIDIQueueOverflow(void *instance_data) {
+static mt32emu_boolean MT32EMU_C_CALL onMIDIQueueOverflow(void *instance_data) {
return static_cast<IReportHandler *>(instance_data)->onMIDIQueueOverflow() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE;
}
-static void onMIDISystemRealtime(void *instance_data, mt32emu_bit8u system_realtime) {
+static void MT32EMU_C_CALL onMIDISystemRealtime(void *instance_data, mt32emu_bit8u system_realtime) {
static_cast<IReportHandler *>(instance_data)->onMIDISystemRealtime(system_realtime);
}
-static void onDeviceReset(void *instance_data) {
+static void MT32EMU_C_CALL onDeviceReset(void *instance_data) {
static_cast<IReportHandler *>(instance_data)->onDeviceReset();
}
-static void onDeviceReconfig(void *instance_data) {
+static void MT32EMU_C_CALL onDeviceReconfig(void *instance_data) {
static_cast<IReportHandler *>(instance_data)->onDeviceReconfig();
}
-static void onNewReverbMode(void *instance_data, mt32emu_bit8u mode) {
+static void MT32EMU_C_CALL onNewReverbMode(void *instance_data, mt32emu_bit8u mode) {
static_cast<IReportHandler *>(instance_data)->onNewReverbMode(mode);
}
-static void onNewReverbTime(void *instance_data, mt32emu_bit8u time) {
+static void MT32EMU_C_CALL onNewReverbTime(void *instance_data, mt32emu_bit8u time) {
static_cast<IReportHandler *>(instance_data)->onNewReverbTime(time);
}
-static void onNewReverbLevel(void *instance_data, mt32emu_bit8u level) {
+static void MT32EMU_C_CALL onNewReverbLevel(void *instance_data, mt32emu_bit8u level) {
static_cast<IReportHandler *>(instance_data)->onNewReverbLevel(level);
}
-static void onPolyStateChanged(void *instance_data, mt32emu_bit8u part_num) {
+static void MT32EMU_C_CALL onPolyStateChanged(void *instance_data, mt32emu_bit8u part_num) {
static_cast<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) {
+static void MT32EMU_C_CALL onProgramChanged(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name) {
static_cast<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 void MT32EMU_C_CALL onLCDStateUpdated(void *instance_data) {
+ static_cast<IReportHandlerV1 *>(instance_data)->onLCDStateUpdated();
+}
+
+static void MT32EMU_C_CALL onMidiMessageLEDStateUpdated(void *instance_data, mt32emu_boolean led_state) {
+ static_cast<IReportHandlerV1 *>(instance_data)->onMidiMessageLEDStateUpdated(led_state != MT32EMU_BOOL_FALSE);
+}
+
+#define MT32EMU_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_v0 REPORT_HANDLER_V0_THUNK = {
+ MT32EMU_REPORT_HANDLER_V0_THUNK
+};
- static const mt32emu_report_handler_i REPORT_HANDLER_THUNK = { &REPORT_HANDLER_V0_THUNK };
+static const mt32emu_report_handler_i_v1 REPORT_HANDLER_V1_THUNK = {
+ MT32EMU_REPORT_HANDLER_V0_THUNK,
+ onLCDStateUpdated,
+ onMidiMessageLEDStateUpdated
+};
+
+#undef MT32EMU_REPORT_HANDLER_THUNK_V0
+
+static mt32emu_report_handler_version MT32EMU_C_CALL getReportHandlerVersionID(mt32emu_report_handler_i thunk) {
+ if (thunk.v0 == &REPORT_HANDLER_V0_THUNK) return MT32EMU_REPORT_HANDLER_VERSION_0;
+ return MT32EMU_REPORT_HANDLER_VERSION_CURRENT;
+}
- return REPORT_HANDLER_THUNK;
+static mt32emu_report_handler_i getReportHandlerThunk(mt32emu_report_handler_version versionID) {
+ mt32emu_report_handler_i thunk;
+ if (versionID == MT32EMU_REPORT_HANDLER_VERSION_0) thunk.v0 = &REPORT_HANDLER_V0_THUNK;
+ else thunk.v1 = &REPORT_HANDLER_V1_THUNK;
+ return thunk;
}
-static mt32emu_midi_receiver_version getMidiReceiverVersionID(mt32emu_midi_receiver_i) {
+static mt32emu_midi_receiver_version MT32EMU_C_CALL getMidiReceiverVersionID(mt32emu_midi_receiver_i) {
return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT;
}
-static void handleShortMessage(void *instance_data, const mt32emu_bit32u message) {
+static void MT32EMU_C_CALL handleShortMessage(void *instance_data, const mt32emu_bit32u message) {
static_cast<IMidiReceiver *>(instance_data)->handleShortMessage(message);
}
-static void handleSysex(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length) {
+static void MT32EMU_C_CALL handleSysex(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length) {
static_cast<IMidiReceiver *>(instance_data)->handleSysex(stream, length);
}
-static void handleSystemRealtimeMessage(void *instance_data, const mt32emu_bit8u realtime) {
+static void MT32EMU_C_CALL handleSystemRealtimeMessage(void *instance_data, const mt32emu_bit8u realtime) {
static_cast<IMidiReceiver *>(instance_data)->handleSystemRealtimeMessage(realtime);
}
@@ -520,7 +578,14 @@ static mt32emu_midi_receiver_i getMidiReceiverThunk() {
#undef mt32emu_get_partial_states
#undef mt32emu_get_playing_notes
#undef mt32emu_get_patch_name
+#undef mt32emu_get_sound_group_name
+#undef mt32emu_get_sound_name
#undef mt32emu_read_memory
+#undef mt32emu_get_display_state
+#undef mt32emu_set_main_display_mode
+#undef mt32emu_set_display_compatibility
+#undef mt32emu_is_display_old_mt32_compatible
+#undef mt32emu_is_default_display_old_mt32_compatible
#endif // #if MT32EMU_API_TYPE == 2
diff --git a/audio/softsynth/mt32/config.h b/audio/softsynth/mt32/config.h
index d7c59d8d931..0509c1606e6 100644
--- a/audio/softsynth/mt32/config.h
+++ b/audio/softsynth/mt32/config.h
@@ -18,10 +18,10 @@
#ifndef MT32EMU_CONFIG_H
#define MT32EMU_CONFIG_H
-#define MT32EMU_VERSION "2.5.1"
+#define MT32EMU_VERSION "2.7.0"
#define MT32EMU_VERSION_MAJOR 2
-#define MT32EMU_VERSION_MINOR 5
-#define MT32EMU_VERSION_PATCH 1
+#define MT32EMU_VERSION_MINOR 7
+#define MT32EMU_VERSION_PATCH 0
/* Library Exports Configuration
*
diff --git a/audio/softsynth/mt32/globals.h b/audio/softsynth/mt32/globals.h
index 79b7ae5eb4b..86ac1ca5b15 100644
--- a/audio/softsynth/mt32/globals.h
+++ b/audio/softsynth/mt32/globals.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
@@ -63,6 +63,27 @@
*/
#define MT32EMU_EXPORT_V(symbol_version_tag) MT32EMU_EXPORT
+/* Helpers for compile-time version checks */
+
+/* Encodes the given version components to a single integer value to simplify further checks. */
+#define MT32EMU_VERSION_INT(major, minor, patch) ((major << 16) | (minor << 8) | patch)
+
+/* The version of this library build, as an integer. */
+#define MT32EMU_CURRENT_VERSION_INT MT32EMU_VERSION_INT(MT32EMU_VERSION_MAJOR, MT32EMU_VERSION_MINOR, MT32EMU_VERSION_PATCH)
+
+/* Compares the current library version with the given version components. Intended for feature checks. */
+#define MT32EMU_VERSION_ATLEAST(major, minor, patch) (MT32EMU_CURRENT_VERSION_INT >= MT32EMU_VERSION_INT(major, minor, patch))
+
+/* Implements a simple version check that ensures full API compatibility of this library build
+ * with the application requirements. The latter can be derived from the versions of used public symbols.
+ *
+ * Note: This macro is intended for a quick compile-time check. To ensure compatibility of an application
+ * linked with a shared library, an automatic version check can be engaged with help of the build option
+ * libmt32emu_WITH_VERSION_TAGGING. For a fine-grained feature checking in run-time, see functions
+ * mt32emu_get_library_version_int and Synth::getLibraryVersionInt.
+ */
+#define MT32EMU_IS_COMPATIBLE(major, minor) (MT32EMU_VERSION_MAJOR == major && MT32EMU_VERSION_MINOR >= minor)
+
/* Useful constants */
/* Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent.
diff --git a/audio/softsynth/mt32/internals.h b/audio/softsynth/mt32/internals.h
index 1876b08352a..1b3ad0de224 100644
--- a/audio/softsynth/mt32/internals.h
+++ b/audio/softsynth/mt32/internals.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/mmath.h b/audio/softsynth/mt32/mmath.h
index e0d233222cf..3164c7bfca2 100644
--- a/audio/softsynth/mt32/mmath.h
+++ b/audio/softsynth/mt32/mmath.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/module.mk b/audio/softsynth/mt32/module.mk
index 5b7a602bb65..3c17650f046 100644
--- a/audio/softsynth/mt32/module.mk
+++ b/audio/softsynth/mt32/module.mk
@@ -3,6 +3,7 @@ MODULE := audio/softsynth/mt32
MODULE_OBJS := \
Analog.o \
BReverbModel.o \
+ Display.o \
File.o \
FileStream.o \
LA32FloatWaveGenerator.o \
diff --git a/audio/softsynth/mt32/mt32emu.h b/audio/softsynth/mt32/mt32emu.h
index 399ddae069e..571b25571e6 100644
--- a/audio/softsynth/mt32/mt32emu.h
+++ b/audio/softsynth/mt32/mt32emu.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2022 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
diff --git a/audio/softsynth/mt32/mt32emu.pc.in b/audio/softsynth/mt32/mt32emu.pc.in
index 95ddf6fa1d8..24a3a8baa97 100644
--- a/audio/softsynth/mt32/mt32emu.pc.in
+++ b/audio/softsynth/mt32/mt32emu.pc.in
@@ -1,10 +1,10 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${exec_prefix}/@LIB_INSTALL_DIR@
-includedir=${prefix}/include
+libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: @PROJECT_NAME@
-Description: @libmt32emu_DESCRIPTION@
+Description: @libmt32emu_DESCRIPTION_SUMMARY@
URL: @libmt32emu_URL@
Version: @libmt32emu_VERSION@
Requires.private: @libmt32emu_PC_REQUIRES_PRIVATE@
diff --git a/audio/softsynth/mt32/srchelper/InternalResampler.cpp b/audio/softsynth/mt32/srchelper/InternalResampler.cpp
index 7babc4e7bf2..4e6a5a7489e 100644
--- a/audio/softsynth/mt32/srchelper/InternalResampler.cpp
+++ b/audio/softsynth/mt32/srchelper/InternalResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
@@ -32,7 +32,7 @@ public:
SynthWrapper(Synth &useSynth) : synth(useSynth)
{}
- void getOutputSamples(FloatSample *outBuffer, unsigned int size) override {
+ void getOutputSamples(FloatSample *outBuffer, unsigned int size) {
synth.render(outBuffer, size);
}
};
diff --git a/audio/softsynth/mt32/srchelper/InternalResampler.h b/audio/softsynth/mt32/srchelper/InternalResampler.h
index 9f094476ced..a80cc7dc433 100644
--- a/audio/softsynth/mt32/srchelper/InternalResampler.h
+++ b/audio/softsynth/mt32/srchelper/InternalResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/SamplerateAdapter.cpp b/audio/softsynth/mt32/srchelper/SamplerateAdapter.cpp
index dc95a5cd7e5..aeb695a2eef 100644
--- a/audio/softsynth/mt32/srchelper/SamplerateAdapter.cpp
+++ b/audio/softsynth/mt32/srchelper/SamplerateAdapter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/SamplerateAdapter.h b/audio/softsynth/mt32/srchelper/SamplerateAdapter.h
index 25209970140..6da9b64aaa8 100644
--- a/audio/softsynth/mt32/srchelper/SamplerateAdapter.h
+++ b/audio/softsynth/mt32/srchelper/SamplerateAdapter.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/SoxrAdapter.cpp b/audio/softsynth/mt32/srchelper/SoxrAdapter.cpp
index 07697d9381a..754f55d56cd 100644
--- a/audio/softsynth/mt32/srchelper/SoxrAdapter.cpp
+++ b/audio/softsynth/mt32/srchelper/SoxrAdapter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/SoxrAdapter.h b/audio/softsynth/mt32/srchelper/SoxrAdapter.h
index f116d2f9dd9..2abcbdd8abf 100644
--- a/audio/softsynth/mt32/srchelper/SoxrAdapter.h
+++ b/audio/softsynth/mt32/srchelper/SoxrAdapter.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/FIRResampler.h b/audio/softsynth/mt32/srchelper/srctools/include/FIRResampler.h
index 4d2a80247ae..b8e0be1bb7e 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/FIRResampler.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/FIRResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/FloatSampleProvider.h b/audio/softsynth/mt32/srchelper/srctools/include/FloatSampleProvider.h
index 6cfbdb0d314..9b88bced697 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/FloatSampleProvider.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/FloatSampleProvider.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/IIR2xResampler.h b/audio/softsynth/mt32/srchelper/srctools/include/IIR2xResampler.h
index bb50ca8cf26..247d575685f 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/IIR2xResampler.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/IIR2xResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/LinearResampler.h b/audio/softsynth/mt32/srchelper/srctools/include/LinearResampler.h
index 0b67503d619..a55f4ae67b3 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/LinearResampler.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/LinearResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/ResamplerModel.h b/audio/softsynth/mt32/srchelper/srctools/include/ResamplerModel.h
index 354d3767963..622ccbb1892 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/ResamplerModel.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/ResamplerModel.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/ResamplerStage.h b/audio/softsynth/mt32/srchelper/srctools/include/ResamplerStage.h
index bec447a0c66..2d8507037d8 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/ResamplerStage.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/ResamplerStage.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/include/SincResampler.h b/audio/softsynth/mt32/srchelper/srctools/include/SincResampler.h
index 5ab048a96d1..8db9f5bb9dd 100644
--- a/audio/softsynth/mt32/srchelper/srctools/include/SincResampler.h
+++ b/audio/softsynth/mt32/srchelper/srctools/include/SincResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/src/FIRResampler.cpp b/audio/softsynth/mt32/srchelper/srctools/src/FIRResampler.cpp
index 5737840ac46..0df8acd16df 100644
--- a/audio/softsynth/mt32/srchelper/srctools/src/FIRResampler.cpp
+++ b/audio/softsynth/mt32/srchelper/srctools/src/FIRResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/src/IIR2xResampler.cpp b/audio/softsynth/mt32/srchelper/srctools/src/IIR2xResampler.cpp
index b0bf0673f5a..a09b48d9ef5 100644
--- a/audio/softsynth/mt32/srchelper/srctools/src/IIR2xResampler.cpp
+++ b/audio/softsynth/mt32/srchelper/srctools/src/IIR2xResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
@@ -119,7 +119,7 @@ IIRResampler::Constants::Constants(const unsigned int useSectionsCount, const II
}
IIRResampler::IIRResampler(const Quality quality) :
- constants(0, 0.0f, nullptr, quality)
+ constants(0, 0.0f, NULL, quality)
{}
IIRResampler::IIRResampler(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) :
diff --git a/audio/softsynth/mt32/srchelper/srctools/src/LinearResampler.cpp b/audio/softsynth/mt32/srchelper/srctools/src/LinearResampler.cpp
index c46070b301f..18224833bd7 100644
--- a/audio/softsynth/mt32/srchelper/srctools/src/LinearResampler.cpp
+++ b/audio/softsynth/mt32/srchelper/srctools/src/LinearResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/audio/softsynth/mt32/srchelper/srctools/src/ResamplerModel.cpp b/audio/softsynth/mt32/srchelper/srctools/src/ResamplerModel.cpp
index 5e6b6ec2349..504024629e1 100644
--- a/audio/softsynth/mt32/srchelper/srctools/src/ResamplerModel.cpp
+++ b/audio/softsynth/mt32/srchelper/srctools/src/ResamplerModel.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
@@ -36,7 +36,7 @@ friend void freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &
public:
CascadeStage(FloatSampleProvider &source, ResamplerStage &resamplerStage);
- void getOutputSamples(FloatSample *outBuffer, unsigned int size) override;
+ void getOutputSamples(FloatSample *outBuffer, unsigned int size);
protected:
ResamplerStage &resamplerStage;
@@ -120,7 +120,7 @@ void ResamplerModel::freeResamplerModel(FloatSampleProvider &model, FloatSampleP
FloatSampleProvider *currentStage = &model;
while (currentStage != &source) {
CascadeStage *cascadeStage = dynamic_cast<CascadeStage *>(currentStage);
- if (cascadeStage == nullptr) return;
+ if (cascadeStage == NULL) return;
FloatSampleProvider &prevStage = cascadeStage->source;
delete currentStage;
currentStage = &prevStage;
diff --git a/audio/softsynth/mt32/srchelper/srctools/src/SincResampler.cpp b/audio/softsynth/mt32/srchelper/srctools/src/SincResampler.cpp
index 146a9a952c3..de904809392 100644
--- a/audio/softsynth/mt32/srchelper/srctools/src/SincResampler.cpp
+++ b/audio/softsynth/mt32/srchelper/srctools/src/SincResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2021 Sergey V. Mikayev
+/* Copyright (C) 2015-2022 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
diff --git a/doc/de/NEUES.md b/doc/de/NEUES.md
index d6c74b8fe3c..aa2795488e7 100644
--- a/doc/de/NEUES.md
+++ b/doc/de/NEUES.md
@@ -12,6 +12,7 @@ Umfangreichere Informationen über die Ãnderungen des aktuellen Codes findest D
Allgemein:
- Anzahl an falsch-positiven Einträgen reduziert, wenn das Gerät nach Spielen durchsucht wird.
+ - Code der Roland MT-32-Emulation auf Munt mt32emu 2.7.0 aktualisiert.
AGOS:
- Option hinzugefügt, mit der die Ausblende-Effekte bei einem Raum-Wechsel in Simon 1 und 2
More information about the Scummvm-git-logs
mailing list