From b2a7a5b90f4188227275e0b94c303e7ac3197c50 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 7 Jun 2020 02:06:15 +0200 Subject: [PATCH] Updated the Munt code to 2.4.0 (port from VARCem). --- src/sound/munt/Analog.cpp | 2 +- src/sound/munt/Analog.h | 2 +- src/sound/munt/BReverbModel.cpp | 2 +- src/sound/munt/BReverbModel.h | 2 +- src/sound/munt/Enumerations.h | 2 +- src/sound/munt/File.cpp | 2 +- src/sound/munt/File.h | 2 +- src/sound/munt/FileStream.cpp | 17 +- src/sound/munt/FileStream.h | 2 +- src/sound/munt/LA32FloatWaveGenerator.cpp | 2 +- src/sound/munt/LA32FloatWaveGenerator.h | 2 +- src/sound/munt/LA32Ramp.cpp | 2 +- src/sound/munt/LA32Ramp.h | 2 +- src/sound/munt/LA32WaveGenerator.cpp | 2 +- src/sound/munt/LA32WaveGenerator.h | 2 +- src/sound/munt/MemoryRegion.h | 2 +- src/sound/munt/MidiEventQueue.h | 52 ++- src/sound/munt/MidiStreamParser.cpp | 2 +- src/sound/munt/MidiStreamParser.h | 2 +- src/sound/munt/Part.cpp | 2 +- src/sound/munt/Part.h | 2 +- src/sound/munt/Partial.cpp | 37 +- src/sound/munt/Partial.h | 9 +- src/sound/munt/PartialManager.cpp | 57 ++- src/sound/munt/PartialManager.h | 7 +- src/sound/munt/Poly.cpp | 2 +- src/sound/munt/Poly.h | 2 +- src/sound/munt/ROMInfo.cpp | 2 +- src/sound/munt/ROMInfo.h | 2 +- src/sound/munt/SampleRateConverter.cpp | 26 +- src/sound/munt/SampleRateConverter.h | 6 +- src/sound/munt/SampleRateConverter_dummy.cpp | 2 +- src/sound/munt/Structures.h | 2 +- src/sound/munt/Synth.cpp | 435 +++++++++++++----- src/sound/munt/Synth.h | 46 +- src/sound/munt/TVA.cpp | 2 +- src/sound/munt/TVA.h | 2 +- src/sound/munt/TVF.cpp | 2 +- src/sound/munt/TVF.h | 2 +- src/sound/munt/TVP.cpp | 8 +- src/sound/munt/TVP.h | 2 +- src/sound/munt/Tables.cpp | 2 +- src/sound/munt/Tables.h | 2 +- src/sound/munt/Types.h | 2 +- src/sound/munt/c_interface/c_interface.cpp | 42 +- src/sound/munt/c_interface/c_interface.h | 59 ++- src/sound/munt/c_interface/c_types.h | 30 +- src/sound/munt/c_interface/cpp_interface.h | 23 +- src/sound/munt/config.h | 9 +- src/sound/munt/config.h.in | 38 ++ src/sound/munt/globals.h | 2 +- src/sound/munt/internals.h | 8 +- src/sound/munt/mmath.h | 2 +- src/sound/munt/mt32emu.h | 2 +- .../munt/srchelper/InternalResampler.cpp | 6 +- src/sound/munt/srchelper/InternalResampler.h | 4 +- .../munt/srchelper/SamplerateAdapter.cpp | 2 +- src/sound/munt/srchelper/SamplerateAdapter.h | 2 +- src/sound/munt/srchelper/SoxrAdapter.cpp | 2 +- src/sound/munt/srchelper/SoxrAdapter.h | 2 +- .../srchelper/srctools/include/FIRResampler.h | 2 +- .../srctools/include/FloatSampleProvider.h | 2 +- .../srctools/include/IIR2xResampler.h | 2 +- .../srctools/include/LinearResampler.h | 2 +- .../srctools/include/ResamplerModel.h | 2 +- .../srctools/include/ResamplerStage.h | 2 +- .../srctools/include/SincResampler.h | 2 +- .../srchelper/srctools/src/FIRResampler.cpp | 4 +- .../srchelper/srctools/src/IIR2xResampler.cpp | 4 +- .../srctools/src/LinearResampler.cpp | 4 +- .../srchelper/srctools/src/ResamplerModel.cpp | 12 +- .../srchelper/srctools/src/SincResampler.cpp | 4 +- src/win/Makefile.mingw | 8 +- src/win/Makefile_ndr.mingw | 8 +- 74 files changed, 747 insertions(+), 310 deletions(-) create mode 100644 src/sound/munt/config.h.in 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)