diff --git a/src/sound/munt/Analog.cpp b/src/sound/munt/Analog.cpp
index 2901198f2..b14d824dd 100644
--- a/src/sound/munt/Analog.cpp
+++ b/src/sound/munt/Analog.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Analog.h b/src/sound/munt/Analog.h
index 3b6dcabfa..244e4118f 100644
--- a/src/sound/munt/Analog.h
+++ b/src/sound/munt/Analog.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/BReverbModel.cpp b/src/sound/munt/BReverbModel.cpp
index af559a92a..1eb6f7e56 100644
--- a/src/sound/munt/BReverbModel.cpp
+++ b/src/sound/munt/BReverbModel.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/BReverbModel.h b/src/sound/munt/BReverbModel.h
index 5b1d41198..ee2f838b2 100644
--- a/src/sound/munt/BReverbModel.h
+++ b/src/sound/munt/BReverbModel.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Enumerations.h b/src/sound/munt/Enumerations.h
index bb580ca5b..05a2b6f6d 100644
--- a/src/sound/munt/Enumerations.h
+++ b/src/sound/munt/Enumerations.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/File.cpp b/src/sound/munt/File.cpp
index a5967b4f3..dbe226648 100644
--- a/src/sound/munt/File.cpp
+++ b/src/sound/munt/File.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/File.h b/src/sound/munt/File.h
index 91a0a7fe6..a4b099fbb 100644
--- a/src/sound/munt/File.h
+++ b/src/sound/munt/File.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/FileStream.cpp b/src/sound/munt/FileStream.cpp
index 48ecc84b1..3fa1a3107 100644
--- a/src/sound/munt/FileStream.cpp
+++ b/src/sound/munt/FileStream.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -15,12 +15,26 @@
* along with this program. If not, see .
*/
+#ifdef MT32EMU_SHARED
+#include
+#endif
+
#include "internals.h"
#include "FileStream.h"
namespace MT32Emu {
+static inline void configureSystemLocale() {
+#ifdef MT32EMU_SHARED
+ static bool configured = false;
+
+ if (configured) return;
+ configured = true;
+ std::locale::global(std::locale(""));
+#endif
+}
+
using std::ios_base;
FileStream::FileStream() : ifsp(*new std::ifstream), data(NULL), size(0)
@@ -70,6 +84,7 @@ const Bit8u *FileStream::getData() {
}
bool FileStream::open(const char *filename) {
+ configureSystemLocale();
ifsp.clear();
ifsp.open(filename, ios_base::in | ios_base::binary);
return !ifsp.fail();
diff --git a/src/sound/munt/FileStream.h b/src/sound/munt/FileStream.h
index ea5de6952..2279890b4 100644
--- a/src/sound/munt/FileStream.h
+++ b/src/sound/munt/FileStream.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/LA32FloatWaveGenerator.cpp b/src/sound/munt/LA32FloatWaveGenerator.cpp
index 6ff4aa37b..34ea1fbf4 100644
--- a/src/sound/munt/LA32FloatWaveGenerator.cpp
+++ b/src/sound/munt/LA32FloatWaveGenerator.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/LA32FloatWaveGenerator.h b/src/sound/munt/LA32FloatWaveGenerator.h
index 7e92d0a67..a21d68e2b 100644
--- a/src/sound/munt/LA32FloatWaveGenerator.h
+++ b/src/sound/munt/LA32FloatWaveGenerator.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/LA32Ramp.cpp b/src/sound/munt/LA32Ramp.cpp
index 9dcf143fb..122ee05ac 100644
--- a/src/sound/munt/LA32Ramp.cpp
+++ b/src/sound/munt/LA32Ramp.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/LA32Ramp.h b/src/sound/munt/LA32Ramp.h
index 959a1ad37..802b34aa4 100644
--- a/src/sound/munt/LA32Ramp.h
+++ b/src/sound/munt/LA32Ramp.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/LA32WaveGenerator.cpp b/src/sound/munt/LA32WaveGenerator.cpp
index f6f692880..f4f7eeccb 100644
--- a/src/sound/munt/LA32WaveGenerator.cpp
+++ b/src/sound/munt/LA32WaveGenerator.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/LA32WaveGenerator.h b/src/sound/munt/LA32WaveGenerator.h
index c206daa63..d2d74f48d 100644
--- a/src/sound/munt/LA32WaveGenerator.h
+++ b/src/sound/munt/LA32WaveGenerator.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/MemoryRegion.h b/src/sound/munt/MemoryRegion.h
index 807f14782..c8e85c7fb 100644
--- a/src/sound/munt/MemoryRegion.h
+++ b/src/sound/munt/MemoryRegion.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/MidiEventQueue.h b/src/sound/munt/MidiEventQueue.h
index c5174d6cc..846f47c51 100644
--- a/src/sound/munt/MidiEventQueue.h
+++ b/src/sound/munt/MidiEventQueue.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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,20 +23,6 @@
namespace MT32Emu {
-/**
- * Used to safely store timestamped MIDI events in a local queue.
- */
-struct MidiEvent {
- Bit32u shortMessageData;
- const Bit8u *sysexData;
- Bit32u sysexLength;
- Bit32u timestamp;
-
- ~MidiEvent();
- void setShortMessage(Bit32u shortMessageData, Bit32u timestamp);
- void setSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp);
-};
-
/**
* Simple queue implementation using a ring buffer to store incoming MIDI event before the synth actually processes it.
* It is intended to:
@@ -48,22 +34,38 @@ struct MidiEvent {
* and one performs only writing. More complicated usage requires external synchronisation.
*/
class MidiEventQueue {
-private:
- MidiEvent * const ringBuffer;
- const Bit32u ringBufferMask;
- volatile Bit32u startPosition;
- volatile Bit32u endPosition;
-
public:
- MidiEventQueue(Bit32u ringBufferSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE); // Must be a power of 2
+ class SysexDataStorage;
+
+ struct MidiEvent {
+ const Bit8u *sysexData;
+ union {
+ Bit32u sysexLength;
+ Bit32u shortMessageData;
+ };
+ Bit32u timestamp;
+ };
+
+ explicit MidiEventQueue(
+ // Must be a power of 2
+ Bit32u ringBufferSize,
+ Bit32u storageBufferSize
+ );
~MidiEventQueue();
void reset();
bool pushShortMessage(Bit32u shortMessageData, Bit32u timestamp);
bool pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp);
- const MidiEvent *peekMidiEvent();
+ const volatile MidiEvent *peekMidiEvent();
void dropMidiEvent();
- bool isFull() const;
- bool inline isEmpty() const;
+ inline bool isEmpty() const;
+
+private:
+ SysexDataStorage &sysexDataStorage;
+
+ MidiEvent * const ringBuffer;
+ const Bit32u ringBufferMask;
+ volatile Bit32u startPosition;
+ volatile Bit32u endPosition;
};
} // namespace MT32Emu
diff --git a/src/sound/munt/MidiStreamParser.cpp b/src/sound/munt/MidiStreamParser.cpp
index a426a20cc..e9fbf7690 100644
--- a/src/sound/munt/MidiStreamParser.cpp
+++ b/src/sound/munt/MidiStreamParser.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/MidiStreamParser.h b/src/sound/munt/MidiStreamParser.h
index 881ec032f..f26fe11b7 100644
--- a/src/sound/munt/MidiStreamParser.h
+++ b/src/sound/munt/MidiStreamParser.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Part.cpp b/src/sound/munt/Part.cpp
index 9c85ce559..465903a72 100644
--- a/src/sound/munt/Part.cpp
+++ b/src/sound/munt/Part.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Part.h b/src/sound/munt/Part.h
index a4de1060b..bc2e11416 100644
--- a/src/sound/munt/Part.h
+++ b/src/sound/munt/Part.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Partial.cpp b/src/sound/munt/Partial.cpp
index 0b7231122..877d93b45 100644
--- a/src/sound/munt/Partial.cpp
+++ b/src/sound/munt/Partial.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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,7 @@
#include "Partial.h"
#include "Part.h"
+#include "PartialManager.h"
#include "Poly.h"
#include "Synth.h"
#include "Tables.h"
@@ -36,22 +37,22 @@ static const Bit8u PAN_NUMERATOR_SLAVE[] = {0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7,
// We assume the pan is applied using the same 13-bit multiplier circuit that is also used for ring modulation
// because of the observed sample overflow, so the panSetting values are likely mapped in a similar way via a LUT.
// FIXME: Sample analysis suggests that the use of panSetting is linear, but there are some quirks that still need to be resolved.
-static Bit32s getPANFactor(Bit32s panSetting) {
- static const Bit32s PAN_FACTORS_COUNT = 15;
+static Bit32s getPanFactor(Bit32s panSetting) {
+ static const Bit32u PAN_FACTORS_COUNT = 15;
static Bit32s PAN_FACTORS[PAN_FACTORS_COUNT];
static bool firstRun = true;
if (firstRun) {
firstRun = false;
- for (Bit32u i = 1; i < (Bit32u)PAN_FACTORS_COUNT; i++) {
+ for (Bit32u i = 1; i < PAN_FACTORS_COUNT; i++) {
PAN_FACTORS[i] = Bit32s(0.5 + i * 8192.0 / double(PAN_FACTORS_COUNT - 1));
}
}
return PAN_FACTORS[panSetting];
}
-Partial::Partial(Synth *useSynth, int useDebugPartialNum) :
- synth(useSynth), debugPartialNum(useDebugPartialNum), sampleNum(0),
+Partial::Partial(Synth *useSynth, int usePartialIndex) :
+ synth(useSynth), partialIndex(usePartialIndex), sampleNum(0),
floatMode(useSynth->getSelectedRendererType() == RendererType_FLOAT) {
// Initialisation of tva, tvp and tvf uses 'this' pointer
// and thus should not be in the initializer list to avoid a compiler warning
@@ -82,7 +83,7 @@ Partial::~Partial() {
// Only used for debugging purposes
int Partial::debugGetPartialNum() const {
- return debugPartialNum;
+ return partialIndex;
}
// Only used for debugging purposes
@@ -112,11 +113,12 @@ void Partial::deactivate() {
return;
}
ownerPart = -1;
+ synth->partialManager->partialDeactivated(partialIndex);
if (poly != NULL) {
poly->partialDeactivated(this);
}
#if MT32EMU_MONITOR_PARTIALS > 2
- synth->printDebug("[+%lu] [Partial %d] Deactivated", sampleNum, debugPartialNum);
+ synth->printDebug("[+%lu] [Partial %d] Deactivated", sampleNum, partialIndex);
synth->printPartialUsage(sampleNum);
#endif
if (isRingModulatingSlave()) {
@@ -135,7 +137,7 @@ void Partial::deactivate() {
void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *usePatchCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial) {
if (usePoly == NULL || usePatchCache == NULL) {
- synth->printDebug("[Partial %d] *** Error: Starting partial for owner %d, usePoly=%s, usePatchCache=%s", debugPartialNum, ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", usePatchCache == NULL ? "*** NULL ***" : "OK");
+ 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;
@@ -153,20 +155,18 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
// Do a normal mix independent of any pair partial.
mixType = 0;
pairPartial = NULL;
- } else {
+ } else if (!synth->isNicePanningEnabled()) {
// Mok wanted an option for smoother panning, and we love Mok.
-#ifndef INACCURATE_SMOOTH_PAN
- // CONFIRMED by Mok: exactly bytes like this (right shifted?) are sent to the LA32.
+ // CONFIRMED by Mok: exactly bytes like this (right shifted) are sent to the LA32.
panSetting &= 0x0E;
-#endif
}
leftPanValue = synth->reversedStereoEnabled ? 14 - panSetting : panSetting;
rightPanValue = 14 - leftPanValue;
if (!floatMode) {
- leftPanValue = getPANFactor(leftPanValue);
- rightPanValue = getPANFactor(rightPanValue);
+ leftPanValue = getPanFactor(leftPanValue);
+ rightPanValue = getPanFactor(rightPanValue);
}
// SEMI-CONFIRMED: From sample analysis:
@@ -174,7 +174,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
// Either partial pairs are added or subtracted, it depends on how the partial pairs are allocated.
// It seems that partials are grouped into quarters and if the partial pairs are allocated in different quarters the subtraction happens.
// Though, this matters little for the majority of timbres, it becomes crucial for timbres which contain several partials that sound very close.
- // In this case that timbre can sound totally different depending of the way it is mixed up.
+ // In this case that timbre can sound totally different depending on the way it is mixed up.
// Most easily this effect can be displayed with the help of a special timbre consisting of several identical square wave partials (3 or 4).
// Say, it is 3-partial timbre. Just play any two notes simultaneously and the polys very probably are mixed differently.
// Moreover, the partial allocator retains the last partial assignment it did and all the subsequent notes will sound the same as the last released one.
@@ -182,8 +182,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
// whole-quarter assignment or after some partials got aborted, even 4-partial timbres can be found sounding differently.
// This behaviour is also confirmed with two more special timbres: one with identical sawtooth partials, and one with PCM wave 02.
// For my personal taste, this behaviour rather enriches the sounding and should be emulated.
- // Also, the current partial allocator model probably needs to be refined.
- if (debugPartialNum & 8) {
+ if (!synth->isNicePartialMixingEnabled() && (partialIndex & 4)) {
leftPanValue = -leftPanValue;
rightPanValue = -rightPanValue;
}
@@ -307,7 +306,7 @@ bool Partial::canProduceOutput() {
return false;
}
if (poly == NULL) {
- synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum);
+ synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", partialIndex);
return false;
}
return true;
diff --git a/src/sound/munt/Partial.h b/src/sound/munt/Partial.h
index 95f4c3fc2..0c4355742 100644
--- a/src/sound/munt/Partial.h
+++ b/src/sound/munt/Partial.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -40,13 +40,14 @@ struct ControlROMPCMStruct;
class Partial {
private:
Synth *synth;
- const int debugPartialNum; // Only used for debugging
+ const int partialIndex; // Index of this Partial in the global partial table
// Number of the sample currently being rendered by produceOutput(), or 0 if no run is in progress
// This is only kept available for debugging purposes.
Bit32u sampleNum;
- // Actually, this is a 4-bit register but we abuse this to emulate inverted mixing.
- // Also we double the value to enable INACCURATE_SMOOTH_PAN, with respect to MoK.
+ // Actually, LA-32 receives only 3 bits as a pan setting, but we abuse these to emulate
+ // the inverted partial mixing as well. Also we double the values (making them correspond
+ // to the panpot range) to enable NicePanning mode, with respect to MoK.
Bit32s leftPanValue, rightPanValue;
int ownerPart; // -1 if unassigned
diff --git a/src/sound/munt/PartialManager.cpp b/src/sound/munt/PartialManager.cpp
index 6c622a9aa..508d5fa6c 100644
--- a/src/sound/munt/PartialManager.cpp
+++ b/src/sound/munt/PartialManager.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -31,11 +31,14 @@ namespace MT32Emu {
PartialManager::PartialManager(Synth *useSynth, Part **useParts) {
synth = useSynth;
parts = useParts;
- partialTable = new Partial *[synth->getPartialCount()];
+ inactivePartialCount = synth->getPartialCount();
+ partialTable = new Partial *[inactivePartialCount];
+ inactivePartials = new int[inactivePartialCount];
freePolys = new Poly *[synth->getPartialCount()];
firstFreePolyIndex = 0;
for (unsigned int i = 0; i < synth->getPartialCount(); i++) {
partialTable[i] = new Partial(synth, i);
+ inactivePartials[i] = inactivePartialCount - i - 1;
freePolys[i] = new Poly();
}
}
@@ -46,6 +49,7 @@ PartialManager::~PartialManager(void) {
if (freePolys[i] != NULL) delete freePolys[i];
}
delete[] partialTable;
+ delete[] inactivePartials;
delete[] freePolys;
}
@@ -83,29 +87,21 @@ unsigned int PartialManager::setReserve(Bit8u *rset) {
}
Partial *PartialManager::allocPartial(int partNum) {
- Partial *outPartial = NULL;
-
- // Get the first inactive partial
- for (unsigned int partialNum = 0; partialNum < synth->getPartialCount(); partialNum++) {
- if (!partialTable[partialNum]->isActive()) {
- outPartial = partialTable[partialNum];
- break;
- }
+ if (inactivePartialCount > 0) {
+ Partial *partial = partialTable[inactivePartials[--inactivePartialCount]];
+ partial->activate(partNum);
+ return partial;
}
- if (outPartial != NULL) {
- outPartial->activate(partNum);
+ synth->printDebug("PartialManager Error: No inactive partials to allocate for part %d, current partial state:\n", partNum);
+ for (Bit32u i = 0; i < synth->getPartialCount(); i++) {
+ const Partial *partial = partialTable[i];
+ synth->printDebug("[Partial %d]: activation=%d, owner part=%d\n", i, partial->isActive(), partial->getOwnerPart());
}
- return outPartial;
+ return NULL;
}
-unsigned int PartialManager::getFreePartialCount(void) {
- int count = 0;
- for (unsigned int i = 0; i < synth->getPartialCount(); i++) {
- if (!partialTable[i]->isActive()) {
- count++;
- }
- }
- return count;
+unsigned int PartialManager::getFreePartialCount() {
+ return inactivePartialCount;
}
// This function is solely used to gather data for debug output at the moment.
@@ -279,7 +275,7 @@ Poly *PartialManager::assignPolyToPart(Part *part) {
void PartialManager::polyFreed(Poly *poly) {
if (0 == firstFreePolyIndex) {
- synth->printDebug("Cannot return freed poly, currently active polys:\n");
+ synth->printDebug("PartialManager Error: Cannot return freed poly, currently active polys:\n");
for (Bit32u partNum = 0; partNum < 9; partNum++) {
const Poly *activePoly = synth->getPart(partNum)->getFirstActivePoly();
Bit32u polyCount = 0;
@@ -289,10 +285,23 @@ void PartialManager::polyFreed(Poly *poly) {
}
synth->printDebug("Part: %i, active poly count: %i\n", partNum, polyCount);
}
+ } else {
+ firstFreePolyIndex--;
+ freePolys[firstFreePolyIndex] = poly;
}
poly->setPart(NULL);
- firstFreePolyIndex--;
- freePolys[firstFreePolyIndex] = poly;
+}
+
+void PartialManager::partialDeactivated(int partialIndex) {
+ if (inactivePartialCount < synth->getPartialCount()) {
+ inactivePartials[inactivePartialCount++] = partialIndex;
+ return;
+ }
+ synth->printDebug("PartialManager Error: Cannot return deactivated partial %d, current partial state:\n", partialIndex);
+ for (Bit32u i = 0; i < synth->getPartialCount(); i++) {
+ const Partial *partial = partialTable[i];
+ synth->printDebug("[Partial %d]: activation=%d, owner part=%d\n", i, partial->isActive(), partial->getOwnerPart());
+ }
}
} // namespace MT32Emu
diff --git a/src/sound/munt/PartialManager.h b/src/sound/munt/PartialManager.h
index 46d8eeb98..6b59857cc 100644
--- a/src/sound/munt/PartialManager.h
+++ b/src/sound/munt/PartialManager.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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,6 +37,8 @@ private:
Partial **partialTable;
Bit8u numReservedPartialsForPart[9];
Bit32u firstFreePolyIndex;
+ int *inactivePartials; // Holds indices of inactive Partials in the Partial table
+ Bit32u inactivePartialCount;
bool abortFirstReleasingPolyWhereReserveExceeded(int minPart);
bool abortFirstPolyPreferHeldWhereReserveExceeded(int minPart);
@@ -45,7 +47,7 @@ public:
PartialManager(Synth *synth, Part **parts);
~PartialManager();
Partial *allocPartial(int partNum);
- unsigned int getFreePartialCount(void);
+ unsigned int getFreePartialCount();
void getPerPartPartialUsage(unsigned int perPartPartialUsage[9]);
bool freePartials(unsigned int needed, int partNum);
unsigned int setReserve(Bit8u *rset);
@@ -57,6 +59,7 @@ public:
const Partial *getPartial(unsigned int partialNum) const;
Poly *assignPolyToPart(Part *part);
void polyFreed(Poly *poly);
+ void partialDeactivated(int partialIndex);
}; // class PartialManager
} // namespace MT32Emu
diff --git a/src/sound/munt/Poly.cpp b/src/sound/munt/Poly.cpp
index 44b8d2446..f37e471d4 100644
--- a/src/sound/munt/Poly.cpp
+++ b/src/sound/munt/Poly.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Poly.h b/src/sound/munt/Poly.h
index b2d4eceaf..5b7cc30e4 100644
--- a/src/sound/munt/Poly.h
+++ b/src/sound/munt/Poly.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/ROMInfo.cpp b/src/sound/munt/ROMInfo.cpp
index 8c813a4e6..308d3eb1e 100644
--- a/src/sound/munt/ROMInfo.cpp
+++ b/src/sound/munt/ROMInfo.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/ROMInfo.h b/src/sound/munt/ROMInfo.h
index cd4a1c5ac..b695ba2a1 100644
--- a/src/sound/munt/ROMInfo.h
+++ b/src/sound/munt/ROMInfo.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/SampleRateConverter.cpp b/src/sound/munt/SampleRateConverter.cpp
index 2d7866ba6..9ae35e962 100644
--- a/src/sound/munt/SampleRateConverter.cpp
+++ b/src/sound/munt/SampleRateConverter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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,13 +14,15 @@
* along with this program. If not, see .
*/
+#include
+
#include "SampleRateConverter.h"
#if MT32EMU_WITH_LIBSOXR_RESAMPLER
#include "srchelper/SoxrAdapter.h"
#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER
#include "srchelper/SamplerateAdapter.h"
-#else
+#elif MT32EMU_WITH_INTERNAL_RESAMPLER
#include "srchelper/InternalResampler.h"
#endif
@@ -33,8 +35,11 @@ static inline void *createDelegate(Synth &synth, double targetSampleRate, Sample
return new SoxrAdapter(synth, targetSampleRate, quality);
#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER
return new SamplerateAdapter(synth, targetSampleRate, quality);
-#else
+#elif MT32EMU_WITH_INTERNAL_RESAMPLER
return new InternalResampler(synth, targetSampleRate, quality);
+#else
+ (void)synth, (void)targetSampleRate, (void)quality;
+ return NULL;
#endif
}
@@ -47,6 +52,15 @@ AnalogOutputMode SampleRateConverter::getBestAnalogOutputMode(double targetSampl
return AnalogOutputMode_COARSE;
}
+double SampleRateConverter::getSupportedOutputSampleRate(double desiredSampleRate) {
+#if MT32EMU_WITH_LIBSOXR_RESAMPLER || MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER || MT32EMU_WITH_INTERNAL_RESAMPLER
+ return desiredSampleRate > 0 ? desiredSampleRate : 0;
+#else
+ (void)desiredSampleRate;
+ return 0;
+#endif
+}
+
SampleRateConverter::SampleRateConverter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality useQuality) :
synthInternalToTargetSampleRateRatio(SAMPLE_RATE / targetSampleRate),
useSynthDelegate(useSynth.getStereoOutputSampleRate() == targetSampleRate),
@@ -59,7 +73,7 @@ SampleRateConverter::~SampleRateConverter() {
delete static_cast(srcDelegate);
#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER
delete static_cast(srcDelegate);
-#else
+#elif MT32EMU_WITH_INTERNAL_RESAMPLER
delete static_cast(srcDelegate);
#endif
}
@@ -75,8 +89,10 @@ void SampleRateConverter::getOutputSamples(float *buffer, unsigned int length) {
static_cast(srcDelegate)->getOutputSamples(buffer, length);
#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER
static_cast(srcDelegate)->getOutputSamples(buffer, length);
-#else
+#elif MT32EMU_WITH_INTERNAL_RESAMPLER
static_cast(srcDelegate)->getOutputSamples(buffer, length);
+#else
+ Synth::muteSampleBuffer(buffer, length);
#endif
}
diff --git a/src/sound/munt/SampleRateConverter.h b/src/sound/munt/SampleRateConverter.h
index 437f9b29f..96f3925e3 100644
--- a/src/sound/munt/SampleRateConverter.h
+++ b/src/sound/munt/SampleRateConverter.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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,6 +37,10 @@ public:
// at the sample rate specified by the targetSampleRate argument.
static AnalogOutputMode getBestAnalogOutputMode(double targetSampleRate);
+ // Returns the sample rate supported by the sample rate conversion implementation currently in effect
+ // that is closest to the one specified by the desiredSampleRate argument.
+ static double getSupportedOutputSampleRate(double desiredSampleRate);
+
// Creates a SampleRateConverter instance that converts output signal from the synth to the given sample rate
// with the specified conversion quality.
SampleRateConverter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality);
diff --git a/src/sound/munt/SampleRateConverter_dummy.cpp b/src/sound/munt/SampleRateConverter_dummy.cpp
index 09f491338..4d26b022d 100644
--- a/src/sound/munt/SampleRateConverter_dummy.cpp
+++ b/src/sound/munt/SampleRateConverter_dummy.cpp
@@ -16,7 +16,7 @@
#include
#include
-#include <86box/plat.h>
+#include "../../../plat.h"
#include "SampleRateConverter.h"
#include "Synth.h"
diff --git a/src/sound/munt/Structures.h b/src/sound/munt/Structures.h
index d116aaeb4..de7281b16 100644
--- a/src/sound/munt/Structures.h
+++ b/src/sound/munt/Structures.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Synth.cpp b/src/sound/munt/Synth.cpp
index f4eda5c79..d61ad44a6 100644
--- a/src/sound/munt/Synth.cpp
+++ b/src/sound/munt/Synth.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -195,6 +195,20 @@ public:
RendererType selectedRendererType;
Bit32s masterTunePitchDelta;
bool niceAmpRamp;
+ bool nicePanning;
+ bool nicePartialMixing;
+
+ // Here we keep the reverse mapping of assigned parts per MIDI channel.
+ // NOTE: value above 8 means that the channel is not assigned
+ Bit8u chantable[16][9];
+
+ // This stores the index of Part in chantable that failed to play and required partial abortion.
+ Bit32u abortingPartIx;
+
+ bool preallocatedReverbMemory;
+
+ Bit32u midiEventQueueSize;
+ Bit32u midiEventQueueSysexStorageBufferSize;
};
Bit32u Synth::getLibraryVersionInt() {
@@ -238,7 +252,8 @@ Synth::Synth(ReportHandler *useReportHandler) :
isDefaultReportHandler = false;
}
- for (int i = 0; i < 4; i++) {
+ extensions.preallocatedReverbMemory = false;
+ for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
reverbModels[i] = NULL;
}
reverbModel = NULL;
@@ -250,6 +265,8 @@ Synth::Synth(ReportHandler *useReportHandler) :
setReverbOutputGain(1.0f);
setReversedStereoEnabled(false);
setNiceAmpRampEnabled(true);
+ setNicePanningEnabled(false);
+ setNicePartialMixingEnabled(false);
selectRendererType(RendererType_BIT16S);
patchTempMemoryRegion = NULL;
@@ -267,6 +284,8 @@ Synth::Synth(ReportHandler *useReportHandler) :
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;
@@ -313,15 +332,26 @@ void Synth::newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, c
reportHandler->onProgramChanged(partNum, soundGroupName, patchName);
}
-void Synth::printDebug(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
-#if MT32EMU_DEBUG_SAMPLESTAMPS > 0
- reportHandler->printDebug("[%u]", (va_list)&renderedSampleCount);
-#endif
- reportHandler->printDebug(fmt, ap);
+#define MT32EMU_PRINT_DEBUG \
+ va_list ap; \
+ va_start(ap, fmt); \
+ reportHandler->printDebug(fmt, ap); \
va_end(ap);
+
+#if MT32EMU_DEBUG_SAMPLESTAMPS > 0
+static inline void printSamplestamp(ReportHandler *reportHandler, const char *fmt, ...) {
+ MT32EMU_PRINT_DEBUG
}
+#endif
+
+void Synth::printDebug(const char *fmt, ...) {
+#if MT32EMU_DEBUG_SAMPLESTAMPS > 0
+ printSamplestamp(reportHandler, "[%u]", renderedSampleCount);
+#endif
+ MT32EMU_PRINT_DEBUG
+}
+
+#undef MT32EMU_PRINT_DEBUG
void Synth::setReverbEnabled(bool newReverbEnabled) {
if (!opened) return;
@@ -332,9 +362,9 @@ void Synth::setReverbEnabled(bool newReverbEnabled) {
refreshSystemReverbParameters();
reverbOverridden = oldReverbOverridden;
} else {
-#if MT32EMU_REDUCE_REVERB_MEMORY
- reverbModel->close();
-#endif
+ if (!extensions.preallocatedReverbMemory) {
+ reverbModel->close();
+ }
reverbModel = NULL;
}
}
@@ -355,7 +385,7 @@ void Synth::setReverbCompatibilityMode(bool mt32CompatibleMode) {
if (!opened || (isMT32ReverbCompatibilityMode() == mt32CompatibleMode)) return;
bool oldReverbEnabled = isReverbEnabled();
setReverbEnabled(false);
- for (int i = 0; i < 4; i++) {
+ for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
delete reverbModels[i];
}
initReverbModels(mt32CompatibleMode);
@@ -371,6 +401,19 @@ bool Synth::isDefaultReverbMT32Compatible() const {
return opened && controlROMFeatures->defaultReverbMT32Compatible;
}
+void Synth::preallocateReverbMemory(bool enabled) {
+ if (extensions.preallocatedReverbMemory == enabled) return;
+ extensions.preallocatedReverbMemory = enabled;
+ if (!opened) return;
+ for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
+ if (enabled) {
+ reverbModels[i]->open();
+ } else if (reverbModel != reverbModels[i]) {
+ reverbModels[i]->close();
+ }
+ }
+}
+
void Synth::setDACInputMode(DACInputMode mode) {
dacInputMode = mode;
}
@@ -423,6 +466,22 @@ bool Synth::isNiceAmpRampEnabled() const {
return extensions.niceAmpRamp;
}
+void Synth::setNicePanningEnabled(bool enabled) {
+ extensions.nicePanning = enabled;
+}
+
+bool Synth::isNicePanningEnabled() const {
+ return extensions.nicePanning;
+}
+
+void Synth::setNicePartialMixingEnabled(bool enabled) {
+ extensions.nicePartialMixing = enabled;
+}
+
+bool Synth::isNicePartialMixingEnabled() const {
+ return extensions.nicePartialMixing;
+}
+
bool Synth::loadControlROM(const ROMImage &controlROMImage) {
File *file = controlROMImage.getFile();
const ROMInfo *controlROMInfo = controlROMImage.getROMInfo();
@@ -565,15 +624,13 @@ bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u count, Bit16u s
}
void Synth::initReverbModels(bool mt32CompatibleMode) {
- reverbModels[REVERB_MODE_ROOM] = BReverbModel::createBReverbModel(REVERB_MODE_ROOM, mt32CompatibleMode, getSelectedRendererType());
- reverbModels[REVERB_MODE_HALL] = BReverbModel::createBReverbModel(REVERB_MODE_HALL, mt32CompatibleMode, getSelectedRendererType());
- reverbModels[REVERB_MODE_PLATE] = BReverbModel::createBReverbModel(REVERB_MODE_PLATE, mt32CompatibleMode, getSelectedRendererType());
- reverbModels[REVERB_MODE_TAP_DELAY] = BReverbModel::createBReverbModel(REVERB_MODE_TAP_DELAY, mt32CompatibleMode, getSelectedRendererType());
-#if !MT32EMU_REDUCE_REVERB_MEMORY
- for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
- reverbModels[i]->open();
+ for (int mode = REVERB_MODE_ROOM; mode <= REVERB_MODE_TAP_DELAY; mode++) {
+ reverbModels[mode] = BReverbModel::createBReverbModel(ReverbMode(mode), mt32CompatibleMode, getSelectedRendererType());
+
+ if (extensions.preallocatedReverbMemory) {
+ reverbModels[mode]->open();
+ }
}
-#endif
}
void Synth::initSoundGroups(char newSoundGroupNames[][9]) {
@@ -594,6 +651,7 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, B
}
partialCount = usePartialCount;
abortingPoly = NULL;
+ extensions.abortingPartIx = 0;
// This is to help detect bugs
memset(&mt32ram, '?', sizeof(mt32ram));
@@ -751,7 +809,7 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, B
// For resetting mt32 mid-execution
mt32default = mt32ram;
- midiQueue = new MidiEventQueue();
+ midiQueue = new MidiEventQueue(extensions.midiEventQueueSize, extensions.midiEventQueueSysexStorageBufferSize);
analog = Analog::createAnalog(analogOutputMode, controlROMFeatures->oldMT32AnalogLPF, getSelectedRendererType());
#if MT32EMU_MONITOR_INIT
@@ -820,7 +878,7 @@ void Synth::dispose() {
deleteMemoryRegions();
- for (int i = 0; i < 4; i++) {
+ for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) {
delete reverbModels[i];
reverbModels[i] = NULL;
}
@@ -840,26 +898,24 @@ bool Synth::isOpen() const {
}
void Synth::flushMIDIQueue() {
- if (midiQueue != NULL) {
- for (;;) {
- const MidiEvent *midiEvent = midiQueue->peekMidiEvent();
- if (midiEvent == NULL) break;
- if (midiEvent->sysexData == NULL) {
- playMsgNow(midiEvent->shortMessageData);
- } else {
- playSysexNow(midiEvent->sysexData, midiEvent->sysexLength);
- }
- midiQueue->dropMidiEvent();
+ if (midiQueue == NULL) return;
+ for (;;) {
+ const volatile MidiEventQueue::MidiEvent *midiEvent = midiQueue->peekMidiEvent();
+ if (midiEvent == NULL) break;
+ if (midiEvent->sysexData == NULL) {
+ playMsgNow(midiEvent->shortMessageData);
+ } else {
+ playSysexNow(midiEvent->sysexData, midiEvent->sysexLength);
}
- lastReceivedMIDIEventTimestamp = renderedSampleCount;
+ midiQueue->dropMidiEvent();
}
+ lastReceivedMIDIEventTimestamp = renderedSampleCount;
}
Bit32u Synth::setMIDIEventQueueSize(Bit32u useSize) {
static const Bit32u MAX_QUEUE_SIZE = (1 << 24); // This results in about 256 Mb - much greater than any reasonable value
- if (midiQueue == NULL) return 0;
- flushMIDIQueue();
+ if (extensions.midiEventQueueSize == useSize) return useSize;
// Find a power of 2 that is >= useSize
Bit32u binarySize = 1;
@@ -869,11 +925,26 @@ Bit32u Synth::setMIDIEventQueueSize(Bit32u useSize) {
} else {
binarySize = MAX_QUEUE_SIZE;
}
- delete midiQueue;
- midiQueue = new MidiEventQueue(binarySize);
+ extensions.midiEventQueueSize = binarySize;
+ if (midiQueue != NULL) {
+ flushMIDIQueue();
+ delete midiQueue;
+ midiQueue = new MidiEventQueue(binarySize, extensions.midiEventQueueSysexStorageBufferSize);
+ }
return binarySize;
}
+void Synth::configureMIDIEventQueueSysexStorage(Bit32u storageBufferSize) {
+ if (extensions.midiEventQueueSysexStorageBufferSize == storageBufferSize) return;
+
+ extensions.midiEventQueueSysexStorageBufferSize = storageBufferSize;
+ if (midiQueue != NULL) {
+ flushMIDIQueue();
+ delete midiQueue;
+ midiQueue = new MidiEventQueue(extensions.midiEventQueueSize, storageBufferSize);
+ }
+}
+
Bit32u Synth::getShortMessageLength(Bit32u msg) {
if ((msg & 0xF0) == 0xF0) {
switch (msg & 0xFF) {
@@ -955,14 +1026,24 @@ void Synth::playMsgNow(Bit32u msg) {
//printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note);
- Bit8u part = chantable[chan];
- if (part > 8) {
+ Bit8u *chanParts = extensions.chantable[chan];
+ if (*chanParts > 8) {
#if MT32EMU_MONITOR_MIDI > 0
- printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity);
+ printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, *chanParts, code, velocity);
#endif
return;
}
- playMsgOnPart(part, code, note, velocity);
+ for (Bit32u i = extensions.abortingPartIx; i <= 8; i++) {
+ const Bit32u partNum = chanParts[i];
+ if (partNum > 8) break;
+ playMsgOnPart(partNum, code, note, velocity);
+ if (isAbortingPoly()) {
+ extensions.abortingPartIx = i;
+ break;
+ } else if (extensions.abortingPartIx) {
+ extensions.abortingPartIx = 0;
+ }
+ }
}
void Synth::playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) {
@@ -1153,7 +1234,7 @@ void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sys
break;
}
*/
- // Deliberate fall-through
+ // Fall-through
case SYSEX_CMD_DT1:
writeSysex(device, sysex, len);
break;
@@ -1163,7 +1244,7 @@ void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sys
// FIXME: We should send SYSEX_CMD_RJC in this case
break;
}
- // Deliberate fall-through
+ // Fall-through
case SYSEX_CMD_RQ1:
readSysex(device, sysex, len);
break;
@@ -1193,45 +1274,59 @@ void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) {
printDebug("WRITE-CHANNEL: Channel %d temp area 0x%06x", device, MT32EMU_SYSEXMEMADDR(addr));
#endif
if (/*addr >= MT32EMU_MEMADDR(0x000000) && */addr < MT32EMU_MEMADDR(0x010000)) {
- int offset;
- if (chantable[device] > 8) {
+ addr += MT32EMU_MEMADDR(0x030000);
+ Bit8u *chanParts = extensions.chantable[device];
+ if (*chanParts > 8) {
#if MT32EMU_MONITOR_SYSEX > 0
printDebug(" (Channel not mapped to a part... 0 offset)");
#endif
- offset = 0;
- } else if (chantable[device] == 8) {
-#if MT32EMU_MONITOR_SYSEX > 0
- printDebug(" (Channel mapped to rhythm... 0 offset)");
-#endif
- offset = 0;
} else {
- offset = chantable[device] * sizeof(MemParams::PatchTemp);
+ for (Bit32u partIx = 0; partIx <= 8; partIx++) {
+ if (chanParts[partIx] > 8) break;
+ int offset;
+ if (chanParts[partIx] == 8) {
#if MT32EMU_MONITOR_SYSEX > 0
- printDebug(" (Setting extra offset to %d)", offset);
+ printDebug(" (Channel mapped to rhythm... 0 offset)");
#endif
+ offset = 0;
+ } else {
+ offset = chanParts[partIx] * sizeof(MemParams::PatchTemp);
+#if MT32EMU_MONITOR_SYSEX > 0
+ printDebug(" (Setting extra offset to %d)", offset);
+#endif
+ }
+ writeSysexGlobal(addr + offset, sysex, len);
+ }
+ return;
}
- addr += MT32EMU_MEMADDR(0x030000) + offset;
} else if (/*addr >= MT32EMU_MEMADDR(0x010000) && */ addr < MT32EMU_MEMADDR(0x020000)) {
addr += MT32EMU_MEMADDR(0x030110) - MT32EMU_MEMADDR(0x010000);
} else if (/*addr >= MT32EMU_MEMADDR(0x020000) && */ addr < MT32EMU_MEMADDR(0x030000)) {
- int offset;
- if (chantable[device] > 8) {
+ addr += MT32EMU_MEMADDR(0x040000) - MT32EMU_MEMADDR(0x020000);
+ Bit8u *chanParts = extensions.chantable[device];
+ if (*chanParts > 8) {
#if MT32EMU_MONITOR_SYSEX > 0
printDebug(" (Channel not mapped to a part... 0 offset)");
#endif
- offset = 0;
- } else if (chantable[device] == 8) {
-#if MT32EMU_MONITOR_SYSEX > 0
- printDebug(" (Channel mapped to rhythm... 0 offset)");
-#endif
- offset = 0;
} else {
- offset = chantable[device] * sizeof(TimbreParam);
+ for (Bit32u partIx = 0; partIx <= 8; partIx++) {
+ if (chanParts[partIx] > 8) break;
+ int offset;
+ if (chanParts[partIx] == 8) {
#if MT32EMU_MONITOR_SYSEX > 0
- printDebug(" (Setting extra offset to %d)", offset);
+ printDebug(" (Channel mapped to rhythm... 0 offset)");
#endif
+ offset = 0;
+ } else {
+ offset = chanParts[partIx] * sizeof(TimbreParam);
+#if MT32EMU_MONITOR_SYSEX > 0
+ printDebug(" (Setting extra offset to %d)", offset);
+#endif
+ }
+ writeSysexGlobal(addr + offset, sysex, len);
+ }
+ return;
}
- addr += MT32EMU_MEMADDR(0x040000) - MT32EMU_MEMADDR(0x020000) + offset;
} else {
#if MT32EMU_MONITOR_SYSEX > 0
printDebug(" Invalid channel");
@@ -1239,8 +1334,11 @@ void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) {
return;
}
}
+ writeSysexGlobal(addr, sysex, len);
+}
- // Process device-global sysex (possibly converted from channel-specific sysex above)
+// Process device-global sysex (possibly converted from channel-specific sysex above)
+void Synth::writeSysexGlobal(Bit32u addr, const Bit8u *sysex, Bit32u len) {
for (;;) {
// Find the appropriate memory region
const MemoryRegion *region = findMemoryRegion(addr);
@@ -1429,7 +1527,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le
char instrumentName[11];
memcpy(instrumentName, mt32ram.timbres[patchAbsTimbreNum].timbre.common.name, 10);
instrumentName[10] = 0;
- Bit8u *n = (Bit8u *)patch;
+ Bit8u *n = reinterpret_cast(patch);
printDebug("WRITE-PATCH (%d-%d@%d..%d): %d; timbre=%d (%s) %02X%02X%02X%02X%02X%02X%02X%02X", first, last, off, off + len, i, patchAbsTimbreNum, instrumentName, n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]);
}
#endif
@@ -1614,18 +1712,18 @@ void Synth::refreshSystemReverbParameters() {
reverbModel = reverbModels[mt32ram.system.reverbMode];
}
if (reverbModel != oldReverbModel) {
-#if MT32EMU_REDUCE_REVERB_MEMORY
- if (oldReverbModel != NULL) {
- oldReverbModel->close();
+ if (extensions.preallocatedReverbMemory) {
+ if (isReverbEnabled()) {
+ reverbModel->mute();
+ }
+ } else {
+ if (oldReverbModel != NULL) {
+ oldReverbModel->close();
+ }
+ if (isReverbEnabled()) {
+ reverbModel->open();
+ }
}
- if (isReverbEnabled()) {
- reverbModel->open();
- }
-#else
- if (isReverbEnabled()) {
- reverbModel->mute();
- }
-#endif
}
if (isReverbEnabled()) {
reverbModel->setParameters(mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
@@ -1641,9 +1739,10 @@ void Synth::refreshSystemReserveSettings() {
}
void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) {
- memset(chantable, 0xFF, sizeof(chantable));
+ memset(extensions.chantable, 0xFF, sizeof(extensions.chantable));
- // CONFIRMED: In the case of assigning a channel to multiple parts, the lower part wins.
+ // 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] != 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.
@@ -1651,8 +1750,13 @@ void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) {
parts[i]->resetAllControllers();
}
Bit8u chan = mt32ram.system.chanAssign[i];
- if (chan < 16 && chantable[chan] > 8) {
- chantable[chan] = Bit8u(i);
+ if (chan > 15) continue;
+ Bit8u *chanParts = extensions.chantable[chan];
+ for (Bit32u j = 0; j <= 8; j++) {
+ if (chanParts[j] > 8) {
+ chanParts[j] = Bit8u(i);
+ break;
+ }
}
}
@@ -1712,40 +1816,120 @@ Bit32s Synth::getMasterTunePitchDelta() const {
return extensions.masterTunePitchDelta;
}
-MidiEvent::~MidiEvent() {
- if (sysexData != NULL) {
+/** Defines an interface of a class that maintains storage of variable-sized data of SysEx messages. */
+class MidiEventQueue::SysexDataStorage {
+public:
+ static MidiEventQueue::SysexDataStorage *create(Bit32u storageBufferSize);
+
+ virtual ~SysexDataStorage() {}
+ virtual Bit8u *allocate(Bit32u sysexLength) = 0;
+ virtual void reclaimUnused(const Bit8u *sysexData, Bit32u sysexLength) = 0;
+ virtual void dispose(const Bit8u *sysexData, Bit32u sysexLength) = 0;
+};
+
+/** Storage space for SysEx data is allocated dynamically on demand and is disposed lazily. */
+class DynamicSysexDataStorage : public MidiEventQueue::SysexDataStorage {
+public:
+ Bit8u *allocate(Bit32u sysexLength) {
+ return new Bit8u[sysexLength];
+ }
+
+ void reclaimUnused(const Bit8u *, Bit32u) {}
+
+ void dispose(const Bit8u *sysexData, Bit32u) {
delete[] sysexData;
}
+};
+
+/**
+ * SysEx data is stored in a preallocated buffer, that makes this kind of storage safe
+ * for use in a realtime thread. Additionally, the space retained by a SysEx event,
+ * that has been processed and thus is no longer necessary, is disposed instantly.
+ */
+class BufferedSysexDataStorage : public MidiEventQueue::SysexDataStorage {
+public:
+ explicit BufferedSysexDataStorage(Bit32u useStorageBufferSize) :
+ storageBuffer(new Bit8u[useStorageBufferSize]),
+ storageBufferSize(useStorageBufferSize),
+ startPosition(),
+ endPosition()
+ {}
+
+ ~BufferedSysexDataStorage() {
+ delete[] storageBuffer;
+ }
+
+ 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 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 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 NULL;
+ myEndPosition = 0;
+ }
+ endPosition = myEndPosition + sysexLength;
+ return storageBuffer + myEndPosition;
+ }
+
+ void reclaimUnused(const Bit8u *sysexData, Bit32u sysexLength) {
+ if (sysexData == NULL) return;
+ Bit32u allocatedPosition = startPosition;
+ if (storageBuffer + allocatedPosition == sysexData) {
+ startPosition = allocatedPosition + sysexLength;
+ } else if (storageBuffer == sysexData) {
+ // Buffer wrapped around.
+ startPosition = sysexLength;
+ }
+ }
+
+ void dispose(const Bit8u *, Bit32u) {}
+
+private:
+ Bit8u * const storageBuffer;
+ const Bit32u storageBufferSize;
+
+ volatile Bit32u startPosition;
+ volatile Bit32u endPosition;
+};
+
+MidiEventQueue::SysexDataStorage *MidiEventQueue::SysexDataStorage::create(Bit32u storageBufferSize) {
+ if (storageBufferSize > 0) {
+ return new BufferedSysexDataStorage(storageBufferSize);
+ } else {
+ return new DynamicSysexDataStorage;
+ }
}
-void MidiEvent::setShortMessage(Bit32u useShortMessageData, Bit32u useTimestamp) {
- if (sysexData != NULL) {
- delete[] sysexData;
+MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize, Bit32u storageBufferSize) :
+ sysexDataStorage(*SysexDataStorage::create(storageBufferSize)),
+ ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1)
+{
+ for (Bit32u i = 0; i <= ringBufferMask; i++) {
+ ringBuffer[i].sysexData = NULL;
}
- shortMessageData = useShortMessageData;
- timestamp = useTimestamp;
- sysexData = NULL;
- sysexLength = 0;
-}
-
-void MidiEvent::setSysex(const Bit8u *useSysexData, Bit32u useSysexLength, Bit32u useTimestamp) {
- if (sysexData != NULL) {
- delete[] sysexData;
- }
- shortMessageData = 0;
- timestamp = useTimestamp;
- sysexLength = useSysexLength;
- Bit8u *dstSysexData = new Bit8u[sysexLength];
- sysexData = dstSysexData;
- memcpy(dstSysexData, useSysexData, sysexLength);
-}
-
-MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1) {
- memset(ringBuffer, 0, useRingBufferSize * sizeof(MidiEvent));
reset();
}
MidiEventQueue::~MidiEventQueue() {
+ for (Bit32u i = 0; i <= ringBufferMask; i++) {
+ volatile MidiEvent ¤tEvent = ringBuffer[i];
+ sysexDataStorage.dispose(currentEvent.sysexData, currentEvent.sysexLength);
+ }
+ delete &sysexDataStorage;
delete[] ringBuffer;
}
@@ -1756,35 +1940,42 @@ void MidiEventQueue::reset() {
bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp) {
Bit32u newEndPosition = (endPosition + 1) & ringBufferMask;
- // Is ring buffer full?
+ // If ring buffer is full, bail out.
if (startPosition == newEndPosition) return false;
- ringBuffer[endPosition].setShortMessage(shortMessageData, timestamp);
+ volatile MidiEvent &newEvent = ringBuffer[endPosition];
+ sysexDataStorage.dispose(newEvent.sysexData, newEvent.sysexLength);
+ newEvent.sysexData = NULL;
+ newEvent.shortMessageData = shortMessageData;
+ newEvent.timestamp = timestamp;
endPosition = newEndPosition;
return true;
}
bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp) {
Bit32u newEndPosition = (endPosition + 1) & ringBufferMask;
- // Is ring buffer full?
+ // If ring buffer is full, bail out.
if (startPosition == newEndPosition) return false;
- ringBuffer[endPosition].setSysex(sysexData, sysexLength, timestamp);
+ volatile MidiEvent &newEvent = ringBuffer[endPosition];
+ sysexDataStorage.dispose(newEvent.sysexData, newEvent.sysexLength);
+ Bit8u *dstSysexData = sysexDataStorage.allocate(sysexLength);
+ if (dstSysexData == NULL) return false;
+ memcpy(dstSysexData, sysexData, sysexLength);
+ newEvent.sysexData = dstSysexData;
+ newEvent.sysexLength = sysexLength;
+ newEvent.timestamp = timestamp;
endPosition = newEndPosition;
return true;
}
-const MidiEvent *MidiEventQueue::peekMidiEvent() {
+const volatile MidiEventQueue::MidiEvent *MidiEventQueue::peekMidiEvent() {
return isEmpty() ? NULL : &ringBuffer[startPosition];
}
void MidiEventQueue::dropMidiEvent() {
- // Is ring buffer empty?
- if (startPosition != endPosition) {
- startPosition = (startPosition + 1) & ringBufferMask;
- }
-}
-
-bool MidiEventQueue::isFull() const {
- return startPosition == ((endPosition + 1) & ringBufferMask);
+ if (isEmpty()) return;
+ volatile MidiEvent &unusedEvent = ringBuffer[startPosition];
+ sysexDataStorage.reclaimUnused(unusedEvent.sysexData, unusedEvent.sysexLength);
+ startPosition = (startPosition + 1) & ringBufferMask;
}
bool MidiEventQueue::isEmpty() const {
@@ -1923,7 +2114,7 @@ void RendererImpl::doRenderStreams(const DACOutputStreams &strea
// We need to ensure zero-duration notes will play so add minimum 1-sample delay.
Bit32u thisLen = 1;
if (!isAbortingPoly()) {
- const MidiEvent *nextEvent = getMidiQueue().peekMidiEvent();
+ const volatile MidiEventQueue::MidiEvent *nextEvent = getMidiQueue().peekMidiEvent();
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;
diff --git a/src/sound/munt/Synth.h b/src/sound/munt/Synth.h
index cde080c9d..65f2656e6 100644
--- a/src/sound/munt/Synth.h
+++ b/src/sound/munt/Synth.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -115,6 +115,7 @@ public:
class Synth {
friend class DefaultMidiStreamParser;
+friend class MemoryRegion;
friend class Part;
friend class Partial;
friend class PartialManager;
@@ -153,7 +154,7 @@ private:
const char (*soundGroupNames)[9]; // Array
Bit32u partialCount;
- Bit8u chantable[16]; // NOTE: value above 8 means that the channel is not assigned
+ Bit8u nukeme[16]; // FIXME: Nuke it. For binary compatibility only.
MidiEventQueue *midiQueue;
volatile Bit32u lastReceivedMIDIEventTimestamp;
@@ -198,6 +199,7 @@ private:
Bit32u addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp);
bool isAbortingPoly() const { return abortingPoly != NULL; }
+ void writeSysexGlobal(Bit32u addr, const Bit8u *sysex, Bit32u len);
void readSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) const;
void initMemoryRegions();
void deleteMemoryRegions();
@@ -310,7 +312,18 @@ public:
// 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 Bit32u setMIDIEventQueueSize(Bit32u);
+ MT32EMU_EXPORT Bit32u setMIDIEventQueueSize(Bit32u requestedSize);
+
+ // Configures the SysEx storage of the internal MIDI event queue.
+ // Supplying 0 in the storageBufferSize argument makes the SysEx data stored
+ // in multiple dynamically allocated buffers per MIDI event. These buffers are only disposed
+ // when a new MIDI event replaces the SysEx event in the queue, thus never on the rendering thread.
+ // This is the default behaviour.
+ // In contrast, when a positive value is specified, SysEx data will be stored in a single preallocated buffer,
+ // which makes this kind of storage safe for use in a realtime thread. Additionally, the space retained
+ // 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.
+ MT32EMU_EXPORT void configureMIDIEventQueueSysexStorage(Bit32u storageBufferSize);
// 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.
@@ -378,6 +391,10 @@ public:
MT32EMU_EXPORT bool isMT32ReverbCompatibilityMode() const;
// Returns whether default reverb compatibility mode is the old MT-32 compatibility mode.
MT32EMU_EXPORT bool isDefaultReverbMT32Compatible() const;
+ // If enabled, reverb buffers for all modes are keept 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 preallocateReverbMemory(bool enabled);
// Sets new DAC input mode. See DACInputMode for details.
MT32EMU_EXPORT void setDACInputMode(DACInputMode mode);
// Returns current DAC input mode. See DACInputMode for details.
@@ -421,6 +438,29 @@ public:
// Returns whether NiceAmpRamp mode is enabled.
MT32EMU_EXPORT bool isNiceAmpRampEnabled() const;
+ // Allows to toggle the NicePanning mode.
+ // Despite the Roland's manual specifies allowed panpot values in range 0-14,
+ // the LA-32 only receives 3-bit pan setting in fact. In particular, this
+ // makes it impossible to set the "middle" panning for a single partial.
+ // In the NicePanning mode, we enlarge the pan setting accuracy to 4 bits
+ // making it smoother thus sacrificing the emulation accuracy.
+ // This mode is disabled by default.
+ MT32EMU_EXPORT void setNicePanningEnabled(bool enabled);
+ // Returns whether NicePanning mode is enabled.
+ MT32EMU_EXPORT bool isNicePanningEnabled() const;
+
+ // Allows to toggle the NicePartialMixing mode.
+ // LA-32 is known to mix partials either in-phase (so that they are added)
+ // or in counter-phase (so that they are subtracted instead).
+ // In some cases, this quirk isn't highly desired because a pair of closely
+ // sounding partials may occasionally cancel out.
+ // In the NicePartialMixing mode, the mixing is always performed in-phase,
+ // thus making the behaviour more predictable.
+ // This mode is disabled by default.
+ MT32EMU_EXPORT void setNicePartialMixingEnabled(bool enabled);
+ // Returns whether NicePartialMixing mode is enabled.
+ MT32EMU_EXPORT bool isNicePartialMixingEnabled() const;
+
// Selects new type of the wave generator and renderer to be used during subsequent calls to open().
// By default, RendererType_BIT16S is selected.
// See RendererType for details.
diff --git a/src/sound/munt/TVA.cpp b/src/sound/munt/TVA.cpp
index 3f7064f9a..a49ad0193 100644
--- a/src/sound/munt/TVA.cpp
+++ b/src/sound/munt/TVA.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/TVA.h b/src/sound/munt/TVA.h
index cf9296d48..de6e61017 100644
--- a/src/sound/munt/TVA.h
+++ b/src/sound/munt/TVA.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/TVF.cpp b/src/sound/munt/TVF.cpp
index 7ba9c7f2e..3d5f26049 100644
--- a/src/sound/munt/TVF.cpp
+++ b/src/sound/munt/TVF.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/TVF.h b/src/sound/munt/TVF.h
index e637aa5b4..149b1d09b 100644
--- a/src/sound/munt/TVF.h
+++ b/src/sound/munt/TVF.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/TVP.cpp b/src/sound/munt/TVP.cpp
index a3b364048..3d5f492fd 100644
--- a/src/sound/munt/TVP.cpp
+++ b/src/sound/munt/TVP.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -104,12 +104,12 @@ static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialPa
// MT-32 GEN0 does 16-bit calculations here, allowing an integer overflow.
// This quirk is observable playing the patch defined for timbre "HIT BOTTOM" in Larry 3.
+ // Note, the upper bound isn't checked either.
if (controlROMFeatures->quirkBasePitchOverflow) {
basePitch = basePitch & 0xffff;
} else if (basePitch < 0) {
basePitch = 0;
- }
- if (basePitch > 59392) {
+ } else if (basePitch > 59392) {
basePitch = 59392;
}
return Bit32u(basePitch);
@@ -151,6 +151,7 @@ void TVP::reset(const Part *usePart, const TimbreParam::PartialParam *usePartial
// FIXME: We're using a per-TVP timer instead of a system-wide one for convenience.
timeElapsed = 0;
+ processTimerIncrement = 0;
basePitch = calcBasePitch(partial, partialParam, patchTemp, key, partial->getSynth()->controlROMFeatures);
currentPitchOffset = calcTargetPitchOffsetWithoutLFO(partialParam, 0, velocity);
@@ -194,6 +195,7 @@ void TVP::updatePitch() {
} else if (newPitch < 0) {
newPitch = 0;
}
+ // This check is present in every unit.
if (newPitch > 59392) {
newPitch = 59392;
}
diff --git a/src/sound/munt/TVP.h b/src/sound/munt/TVP.h
index 896e8c11a..c3dc314b4 100644
--- a/src/sound/munt/TVP.h
+++ b/src/sound/munt/TVP.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Tables.cpp b/src/sound/munt/Tables.cpp
index f12caa6b6..7fee467e8 100644
--- a/src/sound/munt/Tables.cpp
+++ b/src/sound/munt/Tables.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Tables.h b/src/sound/munt/Tables.h
index 47465097e..790ee17b9 100644
--- a/src/sound/munt/Tables.h
+++ b/src/sound/munt/Tables.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/Types.h b/src/sound/munt/Types.h
index f70e4795c..17c33e568 100644
--- a/src/sound/munt/Types.h
+++ b/src/sound/munt/Types.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/c_interface/c_interface.cpp b/src/sound/munt/c_interface/c_interface.cpp
index 24bb1460e..48eb2824a 100644
--- a/src/sound/munt/c_interface/c_interface.cpp
+++ b/src/sound/munt/c_interface/c_interface.cpp
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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,7 +41,7 @@ static mt32emu_service_version getSynthVersionID(mt32emu_service_i) {
return MT32EMU_SERVICE_VERSION_CURRENT;
}
-static const mt32emu_service_i_v2 SERVICE_VTABLE = {
+static const mt32emu_service_i_v3 SERVICE_VTABLE = {
getSynthVersionID,
mt32emu_get_supported_report_handler_version,
mt32emu_get_supported_midi_receiver_version,
@@ -112,7 +112,13 @@ static const mt32emu_service_i_v2 SERVICE_VTABLE = {
mt32emu_convert_synth_to_output_timestamp,
mt32emu_get_internal_rendered_sample_count,
mt32emu_set_nice_amp_ramp_enabled,
- mt32emu_is_nice_amp_ramp_enabled
+ mt32emu_is_nice_amp_ramp_enabled,
+ mt32emu_set_nice_panning_enabled,
+ mt32emu_is_nice_panning_enabled,
+ mt32emu_set_nice_partial_mixing_enabled,
+ mt32emu_is_nice_partial_mixing_enabled,
+ mt32emu_preallocate_reverb_memory,
+ mt32emu_configure_midi_event_queue_sysex_storage
};
} // namespace MT32Emu
@@ -323,7 +329,7 @@ extern "C" {
mt32emu_service_i mt32emu_get_service_i() {
mt32emu_service_i i;
- i.v2 = &SERVICE_VTABLE;
+ i.v3 = &SERVICE_VTABLE;
return i;
}
@@ -450,9 +456,7 @@ void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analo
}
void mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate) {
- if (0.0 <= samplerate) {
- context->srcState->outputSampleRate = samplerate;
- }
+ context->srcState->outputSampleRate = SampleRateConverter::getSupportedOutputSampleRate(samplerate);
}
void mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality) {
@@ -519,6 +523,10 @@ mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context,
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_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data) {
delete context->midiParser;
context->midiParser = (midi_receiver.v0 != NULL) ? new DelegatingMidiStreamParser(context, midi_receiver, instance_data) : new DefaultMidiStreamParser(*context->synth);
@@ -612,6 +620,10 @@ mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_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_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode) {
context->synth->setDACInputMode(static_cast(mode));
}
@@ -660,6 +672,22 @@ mt32emu_boolean 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) {
+ context->synth->setNicePanningEnabled(enabled != MT32EMU_BOOL_FALSE);
+}
+
+MT32EMU_EXPORT mt32emu_boolean 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) {
+ context->synth->setNicePartialMixingEnabled(enabled != MT32EMU_BOOL_FALSE);
+}
+
+MT32EMU_EXPORT mt32emu_boolean 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 != NULL) {
context->srcState->src->getOutputSamples(stream, len);
diff --git a/src/sound/munt/c_interface/c_interface.h b/src/sound/munt/c_interface/c_interface.h
index 2ca3a3b04..0924dcce5 100644
--- a/src/sound/munt/c_interface/c_interface.h
+++ b/src/sound/munt/c_interface/c_interface.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -35,7 +35,7 @@ extern "C" {
/* === Interface handling === */
/** Returns mt32emu_service_i interface. */
-MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i();
+MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i(void);
#if MT32EMU_EXPORTS_TYPE == 2
#undef MT32EMU_EXPORT
@@ -46,13 +46,13 @@ MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i();
* 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();
+MT32EMU_EXPORT mt32emu_report_handler_version 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();
+MT32EMU_EXPORT mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version(void);
/**
* Returns library version as an integer in format: 0x00MMmmpp, where:
@@ -60,12 +60,12 @@ 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();
+MT32EMU_EXPORT mt32emu_bit32u 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();
+MT32EMU_EXPORT const char *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.
@@ -201,6 +201,19 @@ MT32EMU_EXPORT void mt32emu_flush_midi_queue(mt32emu_const_context context);
*/
MT32EMU_EXPORT mt32emu_bit32u 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.
+ * Supplying 0 in the storage_buffer_size argument makes the SysEx data stored
+ * in multiple dynamically allocated buffers per MIDI event. These buffers are only disposed
+ * when a new MIDI event replaces the SysEx event in the queue, thus never on the rendering thread.
+ * This is the default behaviour.
+ * In contrast, when a positive value is specified, SysEx data will be stored in a single preallocated buffer,
+ * which makes this kind of storage safe for use in a realtime thread. Additionally, the space retained
+ * 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);
+
/**
* Installs custom MIDI receiver object intended for receiving MIDI messages generated by MIDI stream parser.
* MIDI stream parser is involved when functions mt32emu_parse_stream() and mt32emu_play_short_message() or the likes are called.
@@ -316,6 +329,13 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu
/** 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);
+/**
+ * If enabled, reverb buffers for all modes are keept 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);
+
/** Sets new DAC input mode. See mt32emu_dac_input_mode for details. */
MT32EMU_EXPORT void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode);
/** Returns current DAC input mode. See mt32emu_dac_input_mode for details. */
@@ -366,6 +386,33 @@ MT32EMU_EXPORT void mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context cont
/** Returns whether NiceAmpRamp mode is enabled. */
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context);
+/**
+ * Allows to toggle the NicePanning mode.
+ * Despite the Roland's manual specifies allowed panpot values in range 0-14,
+ * the LA-32 only receives 3-bit pan setting in fact. In particular, this
+ * makes it impossible to set the "middle" panning for a single partial.
+ * In the NicePanning mode, we enlarge the pan setting accuracy to 4 bits
+ * 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);
+/** Returns whether NicePanning mode is enabled. */
+MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_panning_enabled(mt32emu_const_context context);
+
+/**
+ * Allows to toggle the NicePartialMixing mode.
+ * LA-32 is known to mix partials either in-phase (so that they are added)
+ * or in counter-phase (so that they are subtracted instead).
+ * In some cases, this quirk isn't highly desired because a pair of closely
+ * sounding partials may occasionally cancel out.
+ * In the NicePartialMixing mode, the mixing is always performed in-phase,
+ * 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);
+/** Returns whether NicePartialMixing mode is enabled. */
+MT32EMU_EXPORT mt32emu_boolean 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.
* If the output sample rate is not specified explicitly, the default output sample rate is used which depends on the current
diff --git a/src/sound/munt/c_interface/c_types.h b/src/sound/munt/c_interface/c_types.h
index db612e282..74bae8df4 100644
--- a/src/sound/munt/c_interface/c_types.h
+++ b/src/sound/munt/c_interface/c_types.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -121,7 +121,8 @@ typedef enum {
MT32EMU_SERVICE_VERSION_0 = 0,
MT32EMU_SERVICE_VERSION_1 = 1,
MT32EMU_SERVICE_VERSION_2 = 2,
- MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_2
+ MT32EMU_SERVICE_VERSION_3 = 3,
+ MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_3
} mt32emu_service_version;
/* === Report Handler Interface === */
@@ -216,11 +217,11 @@ 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)(); \
- mt32emu_midi_receiver_version (*getSupportedMIDIReceiverVersionID)(); \
+ mt32emu_report_handler_version (*getSupportedReportHandlerVersionID)(void); \
+ mt32emu_midi_receiver_version (*getSupportedMIDIReceiverVersionID)(void); \
\
- mt32emu_bit32u (*getLibraryVersionInt)(); \
- const char *(*getLibraryVersionString)(); \
+ mt32emu_bit32u (*getLibraryVersionInt)(void); \
+ const char *(*getLibraryVersionString)(void); \
\
mt32emu_bit32u (*getStereoOutputSamplerate)(const mt32emu_analog_output_mode analog_output_mode); \
\
@@ -303,6 +304,14 @@ typedef union mt32emu_service_i mt32emu_service_i;
void (*setNiceAmpRampEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \
mt32emu_boolean (*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);
+
typedef struct {
MT32EMU_SERVICE_I_V0
} mt32emu_service_i_v0;
@@ -318,6 +327,13 @@ typedef struct {
MT32EMU_SERVICE_I_V2
} mt32emu_service_i_v2;
+typedef struct {
+ MT32EMU_SERVICE_I_V0
+ MT32EMU_SERVICE_I_V1
+ MT32EMU_SERVICE_I_V2
+ MT32EMU_SERVICE_I_V3
+} mt32emu_service_i_v3;
+
/**
* 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.
@@ -327,10 +343,12 @@ union mt32emu_service_i {
const mt32emu_service_i_v0 *v0;
const mt32emu_service_i_v1 *v1;
const mt32emu_service_i_v2 *v2;
+ const mt32emu_service_i_v3 *v3;
};
#undef MT32EMU_SERVICE_I_V0
#undef MT32EMU_SERVICE_I_V1
#undef MT32EMU_SERVICE_I_V2
+#undef MT32EMU_SERVICE_I_V3
#endif /* #ifndef MT32EMU_C_TYPES_H */
diff --git a/src/sound/munt/c_interface/cpp_interface.h b/src/sound/munt/c_interface/cpp_interface.h
index 3b02c0325..82fa44b2e 100644
--- a/src/sound/munt/c_interface/cpp_interface.h
+++ b/src/sound/munt/c_interface/cpp_interface.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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,6 +60,7 @@ mt32emu_service_i mt32emu_get_service_i();
#define mt32emu_convert_synth_to_output_timestamp iV1()->convertSynthToOutputTimestamp
#define mt32emu_flush_midi_queue i.v0->flushMIDIQueue
#define mt32emu_set_midi_event_queue_size i.v0->setMIDIEventQueueSize
+#define mt32emu_configure_midi_event_queue_sysex_storage iV3()->configureMIDIEventQueueSysexStorage
#define mt32emu_set_midi_receiver i.v0->setMIDIReceiver
#define mt32emu_get_internal_rendered_sample_count iV2()->getInternalRenderedSampleCount
#define mt32emu_parse_stream i.v0->parseStream
@@ -81,6 +82,7 @@ mt32emu_service_i mt32emu_get_service_i();
#define mt32emu_set_reverb_compatibility_mode i.v0->setReverbCompatibilityMode
#define mt32emu_is_mt32_reverb_compatibility_mode i.v0->isMT32ReverbCompatibilityMode
#define mt32emu_is_default_reverb_mt32_compatible i.v0->isDefaultReverbMT32Compatible
+#define mt32emu_preallocate_reverb_memory iV3()->preallocateReverbMemory
#define mt32emu_set_dac_input_mode i.v0->setDACInputMode
#define mt32emu_get_dac_input_mode i.v0->getDACInputMode
#define mt32emu_set_midi_delay_mode i.v0->setMIDIDelayMode
@@ -93,6 +95,10 @@ mt32emu_service_i mt32emu_get_service_i();
#define mt32emu_is_reversed_stereo_enabled i.v0->isReversedStereoEnabled
#define mt32emu_set_nice_amp_ramp_enabled iV2()->setNiceAmpRampEnabled
#define mt32emu_is_nice_amp_ramp_enabled iV2()->isNiceAmpRampEnabled
+#define mt32emu_set_nice_panning_enabled iV3()->setNicePanningEnabled
+#define mt32emu_is_nice_panning_enabled iV3()->isNicePanningEnabled
+#define mt32emu_set_nice_partial_mixing_enabled iV3()->setNicePartialMixingEnabled
+#define mt32emu_is_nice_partial_mixing_enabled iV3()->isNicePartialMixingEnabled
#define mt32emu_render_bit16s i.v0->renderBit16s
#define mt32emu_render_float i.v0->renderFloat
#define mt32emu_render_bit16s_streams i.v0->renderBit16sStreams
@@ -213,6 +219,7 @@ public:
Bit32u convertSynthToOutputTimestamp(Bit32u synth_timestamp) { return mt32emu_convert_synth_to_output_timestamp(c, synth_timestamp); }
void flushMIDIQueue() { mt32emu_flush_midi_queue(c); }
Bit32u setMIDIEventQueueSize(const Bit32u queue_size) { return mt32emu_set_midi_event_queue_size(c, queue_size); }
+ void configureMIDIEventQueueSysexStorage(const Bit32u storage_buffer_size) { mt32emu_configure_midi_event_queue_sysex_storage(c, storage_buffer_size); }
void setMIDIReceiver(mt32emu_midi_receiver_i midi_receiver, void *instance_data) { mt32emu_set_midi_receiver(c, midi_receiver, instance_data); }
void setMIDIReceiver(IMidiReceiver &midi_receiver) { setMIDIReceiver(CppInterfaceImpl::getMidiReceiverThunk(), &midi_receiver); }
@@ -238,6 +245,7 @@ public:
void setReverbCompatibilityMode(const bool mt32_compatible_mode) { mt32emu_set_reverb_compatibility_mode(c, mt32_compatible_mode ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
bool isMT32ReverbCompatibilityMode() { return mt32emu_is_mt32_reverb_compatibility_mode(c) != MT32EMU_BOOL_FALSE; }
bool isDefaultReverbMT32Compatible() { return mt32emu_is_default_reverb_mt32_compatible(c) != MT32EMU_BOOL_FALSE; }
+ void preallocateReverbMemory(const bool enabled) { mt32emu_preallocate_reverb_memory(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
void setDACInputMode(const DACInputMode mode) { mt32emu_set_dac_input_mode(c, static_cast(mode)); }
DACInputMode getDACInputMode() { return static_cast(mt32emu_get_dac_input_mode(c)); }
@@ -256,6 +264,12 @@ public:
void setNiceAmpRampEnabled(const bool enabled) { mt32emu_set_nice_amp_ramp_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
bool isNiceAmpRampEnabled() { return mt32emu_is_nice_amp_ramp_enabled(c) != MT32EMU_BOOL_FALSE; }
+ void setNicePanningEnabled(const bool enabled) { mt32emu_set_nice_panning_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
+ bool isNicePanningEnabled() { return mt32emu_is_nice_panning_enabled(c) != MT32EMU_BOOL_FALSE; }
+
+ void setNicePartialMixingEnabled(const bool enabled) { mt32emu_set_nice_partial_mixing_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); }
+ bool isNicePartialMixingEnabled() { return mt32emu_is_nice_partial_mixing_enabled(c) != MT32EMU_BOOL_FALSE; }
+
void renderBit16s(Bit16s *stream, Bit32u len) { mt32emu_render_bit16s(c, stream, len); }
void renderFloat(float *stream, Bit32u len) { mt32emu_render_float(c, stream, len); }
void renderBit16sStreams(const mt32emu_dac_output_bit16s_streams *streams, Bit32u len) { mt32emu_render_bit16s_streams(c, streams, len); }
@@ -279,6 +293,7 @@ private:
#if MT32EMU_API_TYPE == 2
const mt32emu_service_i_v1 *iV1() { return (getVersionID() < MT32EMU_SERVICE_VERSION_1) ? NULL : i.v1; }
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; }
#endif
};
@@ -428,6 +443,7 @@ static mt32emu_midi_receiver_i getMidiReceiverThunk() {
#undef mt32emu_convert_synth_to_output_timestamp
#undef mt32emu_flush_midi_queue
#undef mt32emu_set_midi_event_queue_size
+#undef mt32emu_configure_midi_event_queue_sysex_storage
#undef mt32emu_set_midi_receiver
#undef mt32emu_get_internal_rendered_sample_count
#undef mt32emu_parse_stream
@@ -449,6 +465,7 @@ static mt32emu_midi_receiver_i getMidiReceiverThunk() {
#undef mt32emu_set_reverb_compatibility_mode
#undef mt32emu_is_mt32_reverb_compatibility_mode
#undef mt32emu_is_default_reverb_mt32_compatible
+#undef mt32emu_preallocate_reverb_memory
#undef mt32emu_set_dac_input_mode
#undef mt32emu_get_dac_input_mode
#undef mt32emu_set_midi_delay_mode
@@ -461,6 +478,10 @@ static mt32emu_midi_receiver_i getMidiReceiverThunk() {
#undef mt32emu_is_reversed_stereo_enabled
#undef mt32emu_set_nice_amp_ramp_enabled
#undef mt32emu_is_nice_amp_ramp_enabled
+#undef mt32emu_set_nice_panning_enabled
+#undef mt32emu_is_nice_panning_enabled
+#undef mt32emu_set_nice_partial_mixing_enabled
+#undef mt32emu_is_nice_partial_mixing_enabled
#undef mt32emu_render_bit16s
#undef mt32emu_render_float
#undef mt32emu_render_bit16s_streams
diff --git a/src/sound/munt/config.h b/src/sound/munt/config.h
index 5f5b6c9fb..e41d4664b 100644
--- a/src/sound/munt/config.h
+++ b/src/sound/munt/config.h
@@ -18,9 +18,9 @@
#ifndef MT32EMU_CONFIG_H
#define MT32EMU_CONFIG_H
-#define MT32EMU_VERSION "2.2.0"
+#define MT32EMU_VERSION "2.4.0"
#define MT32EMU_VERSION_MAJOR 2
-#define MT32EMU_VERSION_MINOR 2
+#define MT32EMU_VERSION_MINOR 4
#define MT32EMU_VERSION_PATCH 0
/* Library Exports Configuration
@@ -37,4 +37,9 @@
#define MT32EMU_API_TYPE 0
+#define MT32EMU_WITH_LIBSOXR_RESAMPLER 0
+#define MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER 0
+#define MT32EMU_WITH_INTERNAL_RESAMPLER 1
+
+
#endif
diff --git a/src/sound/munt/config.h.in b/src/sound/munt/config.h.in
new file mode 100644
index 000000000..48dfb0076
--- /dev/null
+++ b/src/sound/munt/config.h.in
@@ -0,0 +1,38 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011-2020 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 .
+ */
+
+#ifndef MT32EMU_CONFIG_H
+#define MT32EMU_CONFIG_H
+
+#define MT32EMU_VERSION "@libmt32emu_VERSION@"
+#define MT32EMU_VERSION_MAJOR @libmt32emu_VERSION_MAJOR@
+#define MT32EMU_VERSION_MINOR @libmt32emu_VERSION_MINOR@
+#define MT32EMU_VERSION_PATCH @libmt32emu_VERSION_PATCH@
+
+/* Library Exports Configuration
+ *
+ * This reflects the API types actually provided by the library build.
+ * 0: The full-featured C++ API is only available in this build. The client application may ONLY use MT32EMU_API_TYPE 0.
+ * 1: The C-compatible API is only available. The library is built as a shared object, only C functions are exported,
+ * and thus the client application may NOT use MT32EMU_API_TYPE 0.
+ * 2: The C-compatible API is only available. The library is built as a shared object, only the factory function
+ * is exported, and thus the client application may ONLY use MT32EMU_API_TYPE 2.
+ * 3: All the available API types are provided by the library build.
+ */
+#define MT32EMU_EXPORTS_TYPE @libmt32emu_EXPORTS_TYPE@
+
+#endif
diff --git a/src/sound/munt/globals.h b/src/sound/munt/globals.h
index 2d984c82b..243ff82ae 100644
--- a/src/sound/munt/globals.h
+++ b/src/sound/munt/globals.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/internals.h b/src/sound/munt/internals.h
index 0bae8d9f7..8a609546c 100644
--- a/src/sound/munt/internals.h
+++ b/src/sound/munt/internals.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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
@@ -81,12 +81,6 @@
// Configuration
-// If non-zero, deletes reverb buffers that are not in use to save memory.
-// If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path.
-#ifndef MT32EMU_REDUCE_REVERB_MEMORY
-#define MT32EMU_REDUCE_REVERB_MEMORY 1
-#endif
-
// 0: Maximum speed at the cost of a bit lower emulation accuracy.
// 1: Maximum achievable emulation accuracy.
#ifndef MT32EMU_BOSS_REVERB_PRECISE_MODE
diff --git a/src/sound/munt/mmath.h b/src/sound/munt/mmath.h
index 9a9e642ba..a66fad566 100644
--- a/src/sound/munt/mmath.h
+++ b/src/sound/munt/mmath.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/mt32emu.h b/src/sound/munt/mt32emu.h
index 6b93121be..cfb50fb28 100644
--- a/src/sound/munt/mt32emu.h
+++ b/src/sound/munt/mt32emu.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
- * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ * Copyright (C) 2011-2020 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/src/sound/munt/srchelper/InternalResampler.cpp b/src/sound/munt/srchelper/InternalResampler.cpp
index 782d39bbe..56bd1ac05 100644
--- a/src/sound/munt/srchelper/InternalResampler.cpp
+++ b/src/sound/munt/srchelper/InternalResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 Sergey V. Mikayev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -16,8 +16,8 @@
#include "InternalResampler.h"
-#include
-#include
+#include "srctools/include/SincResampler.h"
+#include "srctools/include/ResamplerModel.h"
#include "../Synth.h"
diff --git a/src/sound/munt/srchelper/InternalResampler.h b/src/sound/munt/srchelper/InternalResampler.h
index 87f8ff25d..cf08c8261 100644
--- a/src/sound/munt/srchelper/InternalResampler.h
+++ b/src/sound/munt/srchelper/InternalResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 Sergey V. Mikayev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -19,7 +19,7 @@
#include "../Enumerations.h"
-#include "FloatSampleProvider.h"
+#include "srctools/include/FloatSampleProvider.h"
namespace MT32Emu {
diff --git a/src/sound/munt/srchelper/SamplerateAdapter.cpp b/src/sound/munt/srchelper/SamplerateAdapter.cpp
index 715d29872..2a417ed2e 100644
--- a/src/sound/munt/srchelper/SamplerateAdapter.cpp
+++ b/src/sound/munt/srchelper/SamplerateAdapter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/SamplerateAdapter.h b/src/sound/munt/srchelper/SamplerateAdapter.h
index 0991fd771..eed9799a9 100644
--- a/src/sound/munt/srchelper/SamplerateAdapter.h
+++ b/src/sound/munt/srchelper/SamplerateAdapter.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/SoxrAdapter.cpp b/src/sound/munt/srchelper/SoxrAdapter.cpp
index 5e8dca97d..a88c133ec 100644
--- a/src/sound/munt/srchelper/SoxrAdapter.cpp
+++ b/src/sound/munt/srchelper/SoxrAdapter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/SoxrAdapter.h b/src/sound/munt/srchelper/SoxrAdapter.h
index b97ca4da5..c6b9d3ade 100644
--- a/src/sound/munt/srchelper/SoxrAdapter.h
+++ b/src/sound/munt/srchelper/SoxrAdapter.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/FIRResampler.h b/src/sound/munt/srchelper/srctools/include/FIRResampler.h
index 7c09bf8de..9032131dc 100644
--- a/src/sound/munt/srchelper/srctools/include/FIRResampler.h
+++ b/src/sound/munt/srchelper/srctools/include/FIRResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/FloatSampleProvider.h b/src/sound/munt/srchelper/srctools/include/FloatSampleProvider.h
index 9820769f7..4056db373 100644
--- a/src/sound/munt/srchelper/srctools/include/FloatSampleProvider.h
+++ b/src/sound/munt/srchelper/srctools/include/FloatSampleProvider.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/IIR2xResampler.h b/src/sound/munt/srchelper/srctools/include/IIR2xResampler.h
index 0bfe1c4c8..ea150f9db 100644
--- a/src/sound/munt/srchelper/srctools/include/IIR2xResampler.h
+++ b/src/sound/munt/srchelper/srctools/include/IIR2xResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/LinearResampler.h b/src/sound/munt/srchelper/srctools/include/LinearResampler.h
index c81ff2a38..0e30ea2e9 100644
--- a/src/sound/munt/srchelper/srctools/include/LinearResampler.h
+++ b/src/sound/munt/srchelper/srctools/include/LinearResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/ResamplerModel.h b/src/sound/munt/srchelper/srctools/include/ResamplerModel.h
index f0ac23707..b7a64f02e 100644
--- a/src/sound/munt/srchelper/srctools/include/ResamplerModel.h
+++ b/src/sound/munt/srchelper/srctools/include/ResamplerModel.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/ResamplerStage.h b/src/sound/munt/srchelper/srctools/include/ResamplerStage.h
index e335c0c38..edd7678c1 100644
--- a/src/sound/munt/srchelper/srctools/include/ResamplerStage.h
+++ b/src/sound/munt/srchelper/srctools/include/ResamplerStage.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/include/SincResampler.h b/src/sound/munt/srchelper/srctools/include/SincResampler.h
index 1551a1eda..bac844043 100644
--- a/src/sound/munt/srchelper/srctools/include/SincResampler.h
+++ b/src/sound/munt/srchelper/srctools/include/SincResampler.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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/src/sound/munt/srchelper/srctools/src/FIRResampler.cpp b/src/sound/munt/srchelper/srctools/src/FIRResampler.cpp
index 2cded0c3d..b5ab5585c 100644
--- a/src/sound/munt/srchelper/srctools/src/FIRResampler.cpp
+++ b/src/sound/munt/srchelper/srctools/src/FIRResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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
@@ -17,7 +17,7 @@
#include
#include
-#include "FIRResampler.h"
+#include "../include/FIRResampler.h"
using namespace SRCTools;
diff --git a/src/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp b/src/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp
index 0016f23c9..98f7a3a5b 100644
--- a/src/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp
+++ b/src/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 Sergey V. Mikayev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -16,7 +16,7 @@
#include
-#include "IIR2xResampler.h"
+#include "../include/IIR2xResampler.h"
namespace SRCTools {
diff --git a/src/sound/munt/srchelper/srctools/src/LinearResampler.cpp b/src/sound/munt/srchelper/srctools/src/LinearResampler.cpp
index 98b9c77c7..1ca143a38 100644
--- a/src/sound/munt/srchelper/srctools/src/LinearResampler.cpp
+++ b/src/sound/munt/srchelper/srctools/src/LinearResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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,7 +14,7 @@
* along with this program. If not, see .
*/
-#include "LinearResampler.h"
+#include "../include/LinearResampler.h"
using namespace SRCTools;
diff --git a/src/sound/munt/srchelper/srctools/src/ResamplerModel.cpp b/src/sound/munt/srchelper/srctools/src/ResamplerModel.cpp
index 4d2d93083..2a7f75822 100644
--- a/src/sound/munt/srchelper/srctools/src/ResamplerModel.cpp
+++ b/src/sound/munt/srchelper/srctools/src/ResamplerModel.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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
@@ -17,12 +17,12 @@
#include
#include
-#include "ResamplerModel.h"
+#include "../include/ResamplerModel.h"
-#include "ResamplerStage.h"
-#include "SincResampler.h"
-#include "IIR2xResampler.h"
-#include "LinearResampler.h"
+#include "../include/ResamplerStage.h"
+#include "../include/SincResampler.h"
+#include "../include/IIR2xResampler.h"
+#include "../include/LinearResampler.h"
namespace SRCTools {
diff --git a/src/sound/munt/srchelper/srctools/src/SincResampler.cpp b/src/sound/munt/srchelper/srctools/src/SincResampler.cpp
index 38d0ebe45..60a18256c 100644
--- a/src/sound/munt/srchelper/srctools/src/SincResampler.cpp
+++ b/src/sound/munt/srchelper/srctools/src/SincResampler.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2017 Sergey V. Mikayev
+/* Copyright (C) 2015-2020 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,7 +20,7 @@
#include
#endif
-#include "SincResampler.h"
+#include "../include/SincResampler.h"
#ifndef M_PI
static const double M_PI = 3.1415926535897932;
diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw
index 4fc57b182..e50cdbf57 100644
--- a/src/win/Makefile.mingw
+++ b/src/win/Makefile.mingw
@@ -250,7 +250,7 @@ VPATH := $(EXPATH) . cpu cpu_common \
printer \
sound \
sound/munt sound/munt/c_interface sound/munt/sha1 \
- sound/munt/srchelper \
+ sound/munt/srchelper sound/munt/srchelper/srctools/src \
sound/resid-fp \
scsi video network network/slirp win
ifeq ($(X64), y)
@@ -384,8 +384,10 @@ MUNTOBJ := midi_mt32.o \
Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \
LA32FloatWaveGenerator.o LA32WaveGenerator.o \
MidiStreamParser.o Part.o Partial.o PartialManager.o \
- Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \
- Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o
+ Poly.o ROMInfo.o SampleRateConverter.o \
+ FIRResampler.o IIR2xResampler.o LinearResampler.o ResamplerModel.o \
+ SincResampler.o InternalResampler.o \
+ Synth.o Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o
endif
ifeq ($(VNC), y)
diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw
index 606ecf2e4..20ae9f98e 100644
--- a/src/win/Makefile_ndr.mingw
+++ b/src/win/Makefile_ndr.mingw
@@ -247,7 +247,7 @@ VPATH := $(EXPATH) . cpu_new cpu_common \
printer \
sound \
sound/munt sound/munt/c_interface sound/munt/sha1 \
- sound/munt/srchelper \
+ sound/munt/srchelper sound/munt/srchelper/srctools/src \
sound/resid-fp \
scsi video network network/slirp win
ifeq ($(X64), y)
@@ -393,8 +393,10 @@ MUNTOBJ := midi_mt32.o \
Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \
LA32FloatWaveGenerator.o LA32WaveGenerator.o \
MidiStreamParser.o Part.o Partial.o PartialManager.o \
- Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \
- Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o
+ Poly.o ROMInfo.o SampleRateConverter.o \
+ FIRResampler.o IIR2xResampler.o LinearResampler.o ResamplerModel.o \
+ SincResampler.o InternalResampler.o \
+ Synth.o Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o
endif
ifeq ($(VNC), y)