Hello community,

here is the log from the commit of package dosbox for openSUSE:Factory checked 
in at 2020-11-03 15:32:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/dosbox (Old)
 and      /work/SRC/openSUSE:Factory/.dosbox.new.3463 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "dosbox"

Tue Nov  3 15:32:03 2020 rev:34 rq:845589 version:0.74.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/dosbox/dosbox.changes    2019-08-06 
15:12:08.867737527 +0200
+++ /work/SRC/openSUSE:Factory/.dosbox.new.3463/dosbox.changes  2020-11-03 
15:32:04.764929421 +0100
@@ -1,0 +2,7 @@
+Mon Nov  2 17:50:22 UTC 2020 - Илья Индиго <i...@ilya.pp.ua>
+
+- Refresh spec-file via spec-cleaner and manual optimizations.
+- Add patch dosbox-0.74-3-mt32-patch.diff for Roland MT-32 support.
+- Add manual CONFIG-midi-mt32-gm for config midi sound devices.
+
+-------------------------------------------------------------------
@@ -378,2 +384,0 @@
-
-

New:
----
  CONFIG-midi-mt32-gm
  dosbox-0.74-3-mt32-patch.diff

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ dosbox.spec ++++++
--- /var/tmp/diff_new_pack.nY69g7/_old  2020-11-03 15:32:05.480930001 +0100
+++ /var/tmp/diff_new_pack.nY69g7/_new  2020-11-03 15:32:05.484930004 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package dosbox
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -22,11 +22,14 @@
 Summary:        DOS Emulator Well-Suited for Playing Games
 License:        GPL-2.0-or-later AND GPL-3.0-only
 Group:          System/Emulators/PC
-URL:            http://dosbox.sourceforge.net/
+URL:            https://www.dosbox.com
 Source:         https://downloads.sf.net/dosbox/dosbox-0.74-3.tar.gz
 Source1:        dosbox.desktop
 Source2:        dosbox.png
+Source3:        CONFIG-midi-mt32-gm
 Patch0:         dosbox-0.71-manpage.diff
+# Patch from https://github.com/munt/munt/releases the latest release 
libmt32emu.
+Patch1:         dosbox-0.74-3-mt32-patch.diff
 BuildRequires:  Mesa-devel
 BuildRequires:  SDL_net-devel
 BuildRequires:  SDL_sound-devel
@@ -38,6 +41,9 @@
 BuildRequires:  pkgconfig
 BuildRequires:  pkgconfig(glu)
 BuildRequires:  pkgconfig(sdl)
+%if 0%{?suse_version} >= 1550 || 0%{?sle_version} >= 150300
+BuildRequires:  libmt32emu-devel
+%endif
 
 %description
 dosbox is a DOS emulator that, thanks to its good graphics and sound
@@ -46,30 +52,37 @@
 Linux file system and is therefore very easy to use.
 
 %prep
-%autosetup -p1 -n dosbox-0.74-3
+%setup -q -n dosbox-0.74-3
+%patch0 -p1
+%if 0%{?suse_version} >= 1550 || 0%{?sle_version} >= 150300
+%patch1 -p1
+%endif
 
 %build
 autoreconf -f -i
 export CFLAGS="%{optflags}"
 export CXXFLAGS="%{optflags} -fno-strict-aliasing"
 %configure
-make %{?_smp_mflags}
+%make_build
 
 %check
-make %{?_smp_mflags} check
+%make_build check
 
 %install
 %make_install
-
-# we copy the docs ourselves
-rm -rf %{buildroot}%{_datadir}/doc/dosbox
-install -d -m 755 %{buildroot}%{_datadir}/pixmaps
-install -m 644 %{SOURCE2} %{buildroot}%{_datadir}/pixmaps/dosbox.png
+install -dpm0755 %{buildroot}%{_datadir}/pixmaps
+install -pm0644 %{SOURCE2} %{buildroot}%{_datadir}/pixmaps/dosbox.png
 desktop-file-install --dir=%{buildroot}%{_datadir}/applications %{SOURCE1}
+%if 0%{?suse_version} >= 1550 || 0%{?sle_version} >= 150300
+install -pm0644 %{SOURCE3} .
+%endif
 
 %files
 %license COPYING
 %doc AUTHORS ChangeLog NEWS README THANKS
+%if 0%{?suse_version} >= 1550 || 0%{?sle_version} >= 150300
+%doc CONFIG-midi-mt32-gm
+%endif
 %{_bindir}/dosbox
 %{_mandir}/man?/*
 %{_datadir}/applications/*

++++++ CONFIG-midi-mt32-gm ++++++
This dosbox version supports the built-in emulation of the Roland MT-32 
synthesizer,
which is used in games that support the MT-32 sound device.

For it to work, you need to configure dosbox.

1 If you already have the config ~/.dosbox/dosbox-0.74-3.conf, if necessary, 
make a backup and delete it.
Then. start dosbox from the console, then type exit.
You will have a clean config, which already contains a description of the midi 
options required
to enable and configure the mt32 device.

2 Minimum settings to enable mt32:
mpu401=intelligent
mididevice=default
midiconfig=128:0
#mt32.romdir=/home/your_username/.dosbox

Please note, unfortunately, you cannot write mt32.romdir=~/.dosbox in the 
mt32.romdir option,
so for now you only need to write the absolute path.
By default, roms are looked for in the directory with the game executable file.

3 Place the ROMs in the ~/.dosbox config directory and rename the two firmware 
files to the correct names.
CM32L_CONTROL.ROM 64kB SHA1 a439fbb390da38cada95a7cbb1d6ca199cd66ef8
CM32L_PCM.ROM      1MB SHA1 289cc298ad532b702461bfc738009d9ebe8025ea

This section of the vogons forum https://www.vogons.org/viewtopic.php?t=31362 
has a link to download them.
Please note that ROMs must be named exactly the same, with the same case,
all letters are capitalized, otherwise they will not be found!

4 Please note that the GM and MT-32 audio devices use the same mpu401 midi 
interface and the same port
(default 128:0), and they are configured in the game the same, but they are not 
compatible with each other.
If you use the MT-32, on a game that only supports GM, and vice versa, then the 
sound will be there,
but it will not play correctly.
Therefore, when launching the game, you must know in advance which midi device 
(GM or MT-32) each game supports!
This can be found by running the sound setup, usually the setup.exe file.
Then there are 3 ways to enable mt32 as well as GM.

Therefore, there are 3 ways to enable mt32, considering GM.

4.1 MT-32 is enabled globally and always. The MT-32 will be turned on all the 
time for all games,
including those that support only GM, while GM cannot be turned on, even via 
fluidsynth.
To do this, uncomment the mt32.romdir configuration parameter without 
forgetting to specify your username.
mt32.romdir=/home/your_username/.dosbox

4.2 MT-32 is enabled locally for every game that supports MT-32.
MT-32 will only be enabled for games that support it, and other games can use 
GM via fluidsynth.
To do this, comment out the mt32.romdir configuration parameter if you 
uncommented it earlier.
#mt32.romdir=/home/your_username/.dosbox

For each game that supports MT-32, you need to create 2 symlinks for each ROM 
from ~/.dosbox
and place them in the directory with the executable file of this game.

4.3 MT-32 or GM is manually turned on every time before starting the game.
To install / uninstall MT-32, run "sudo zypper in mt32emu-qt" / "sudo zypper rm 
mt32emu-qt"
in the console and enter the root password.
To start MT-32, run "Munt: MT-32 Emulator" from KDE menu or run krunner 
(Alt+F2) and enter mt32emu-qt and Enter.
To configure mt32emu-qt, start and stop mt32emu-qt, copy two ROMs files
from ~/.dosbox to ~/.config/muntemu.org, start mt32emu-qt again, check all 
checkboxes in the options,
then select the "ROM Configuration..." and specify the path to the 
~/.config/muntemu.org directory
2 ROMs should appear with marked checkboxes and click OK.

To install / uninstall fluidsynth from GM, run "sudo zypper in fluidsynth" / 
"sudo zypper rm fluidsynth"
in the console and enter the root password.
To start / stop fluidsynth from the GM, run "sudo systemctl start fluidsynth" / 
"sudo systemctl stop fluidsynth"
in the console and enter the root password.
To enable / disable fluidsynth immediately at boot time, run the command "sudo 
systemctl enable fluidsynth" /
"sudo systemctl disable fluidsynth" in the console and enter the root password.
Remember that fluidsynth with GM soundfont loaded (default) consumes 157 MB of 
RAM!
To check if midi ports are available, run "aplaymidi -l".

If you run mt32emu-qt and fluidsynth at the same time, they will end up on 
different ports "aplaymidi -l".
The device will be used, the port of which is specified in the value of the 
midiconfig option
(previously we specified 128:0).

It is recommended to use method 4.2, it allows you to automatically start games 
with correct midi devices
without any additional actions on your part, except for setting, specifying 
synlinks
and autorun fluidsynth, if the extra 157 MB of RAM is acceptable for you.

If you find it easier to manually start mt32emu-qt or fluidsynth in advance, 
and not configure anything,
then use method 4.3.

If you only have games with MT-32 support, and method 4.2 does not suit you,
and you do not want to manually launch mt32emu-qt each time, use method 4.1.

P.S. One note about alsa parameter period_size and possible extraneous clicks 
and jerks in the sound!
fluidsynth asks to set period_size (alsa config parameter) to 64, although it 
works fine at higher values.
However, if you do this, you will have problems with methods 4.1 and 4.2,
expressed in extraneous clicks and jerks in the sound.
Methods 4.1 and 4.2 require a period_size (alsa config parameter) of at least 
128,
but method 4.3 works fine with period_size 64.
Even if you set period_size to 128, you will have these problems in native 
games,
for example in Dune Legacy, where even 128 is too small.
If you know how to do this, I recommend setting the period_size parameter to 
256 (by default, 1024).
++++++ dosbox-0.74-3-mt32-patch.diff ++++++
diff --git a/src/Makefile.am b/src/Makefile.am
index a4029e8..3869353 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,4 +18,4 @@ dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a 
fpu/libfpu.a  hardware
 
 EXTRA_DIST = winres.rc dosbox.ico
 
-
+LIBS +=  -lmt32emu
diff --git a/src/dosbox.cpp b/src/dosbox.cpp
index edee31a..917b3c0 100644
--- a/src/dosbox.cpp
+++ b/src/dosbox.cpp
@@ -543,7 +543,7 @@ void DOSBOX_Init(void) {
        
        const char* mputypes[] = { "intelligent", "uart", "none",0};
        // FIXME: add some way to offer the actually available choices.
-       const char *devices[] = { "default", "win32", "alsa", "oss", 
"coreaudio", "coremidi","none", 0};
+       const char *devices[] = { "default", "win32", "alsa", "oss", 
"coreaudio", "coremidi", "mt32", "none", 0};
        Pstring = 
secprop->Add_string("mpu401",Property::Changeable::WhenIdle,"intelligent");
        Pstring->Set_values(mputypes);
        Pstring->Set_help("Type of MPU-401 to emulate.");
@@ -558,6 +558,8 @@ void DOSBOX_Init(void) {
                          "  Or in the case of coreaudio, you can specify a 
soundfont here.\n"
                          "  See the README/Manual for more details.");
 
+#include "mt32options.h"
+
 #if C_DEBUG
        secprop=control->AddSection_prop("debug",&DEBUG_Init);
 #endif
diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
index 3fed5e6..d4aeabc 100644
--- a/src/gui/Makefile.am
+++ b/src/gui/Makefile.am
@@ -7,5 +7,5 @@ libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp dosbox_logo.h \
        render_templates_sai.h render_templates_hq.h \
        render_templates_hq2x.h render_templates_hq3x.h \
        midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h \
-       midi_coremidi.h sdl_gui.cpp dosbox_splash.h
+       midi_coremidi.h midi_mt32.h sdl_gui.cpp dosbox_splash.h
 
diff --git a/src/gui/midi.cpp b/src/gui/midi.cpp
index 61d15e5..0ec8ebc 100644
--- a/src/gui/midi.cpp
+++ b/src/gui/midi.cpp
@@ -98,6 +98,11 @@ MidiHandler Midi_none;
 
 #endif
 
+#define DOSBOX_MIDI_H
+#include "midi_mt32.cpp"
+static MidiHandler_mt32 &Midi_mt32 = MidiHandler_mt32::GetInstance();
+#undef DOSBOX_MIDI_H
+
 static struct {
        Bitu status;
        Bitu cmd_len;
diff --git a/src/gui/midi_mt32.cpp b/src/gui/midi_mt32.cpp
new file mode 100644
index 0000000..b036547
--- /dev/null
+++ b/src/gui/midi_mt32.cpp
@@ -0,0 +1,299 @@
+#include <SDL_thread.h>
+#include <SDL_endian.h>
+#include "control.h"
+
+#ifndef DOSBOX_MIDI_H
+#include "midi.h"
+#endif
+
+#include "midi_mt32.h"
+
+static const Bitu MILLIS_PER_SECOND = 1000;
+
+MidiHandler_mt32 &MidiHandler_mt32::GetInstance() {
+       static MidiHandler_mt32 midiHandler_mt32;
+       return midiHandler_mt32;
+}
+
+const char *MidiHandler_mt32::GetName(void) {
+       return "mt32";
+}
+
+bool MidiHandler_mt32::Open(const char *conf) {
+       service = new MT32Emu::Service();
+       Bit32u version = service->getLibraryVersionInt();
+       if (version < 0x020100) {
+               delete service;
+               service = NULL;
+               LOG_MSG("MT32: libmt32emu version is too old: %s", 
service->getLibraryVersionString());
+               return false;
+       }
+       service->createContext(getReportHandlerInterface(), this);
+       mt32emu_return_code rc;
+
+       Section_prop *section = static_cast<Section_prop 
*>(control->GetSection("midi"));
+       const char *romDir = section->Get_string("mt32.romdir");
+       if (romDir == NULL) romDir = "./"; // Paranoid NULL-check, should never 
happen
+       size_t romDirLen = strlen(romDir);
+       bool addPathSeparator = false;
+       if (romDirLen < 1) {
+               romDir = "./";
+       } else if (4080 < romDirLen) {
+               LOG_MSG("MT32: mt32.romdir is too long, using the current 
dir.");
+               romDir = "./";
+       } else {
+               char lastChar = romDir[strlen(romDir) - 1];
+               addPathSeparator = lastChar != '/' && lastChar != '\\';
+       }
+
+       char pathName[4096];
+
+       makeROMPathName(pathName, romDir, "CM32L_CONTROL.ROM", 
addPathSeparator);
+       if (MT32EMU_RC_ADDED_CONTROL_ROM != service->addROMFile(pathName)) {
+               makeROMPathName(pathName, romDir, "MT32_CONTROL.ROM", 
addPathSeparator);
+               if (MT32EMU_RC_ADDED_CONTROL_ROM != 
service->addROMFile(pathName)) {
+                       delete service;
+                       service = NULL;
+                       LOG_MSG("MT32: Control ROM file not found");
+                       return false;
+               }
+       }
+       makeROMPathName(pathName, romDir, "CM32L_PCM.ROM", addPathSeparator);
+       if (MT32EMU_RC_ADDED_PCM_ROM != service->addROMFile(pathName)) {
+               makeROMPathName(pathName, romDir, "MT32_PCM.ROM", 
addPathSeparator);
+               if (MT32EMU_RC_ADDED_PCM_ROM != service->addROMFile(pathName)) {
+                       delete service;
+                       service = NULL;
+                       LOG_MSG("MT32: PCM ROM file not found");
+                       return false;
+               }
+       }
+
+       service->setPartialCount(Bit32u(section->Get_int("mt32.partials")));
+       
service->setAnalogOutputMode((MT32Emu::AnalogOutputMode)section->Get_int("mt32.analog"));
+       int sampleRate = section->Get_int("mt32.rate");
+       service->setStereoOutputSampleRate(sampleRate);
+       
service->setSamplerateConversionQuality((MT32Emu::SamplerateConversionQuality)section->Get_int("mt32.src.quality"));
+
+       if (MT32EMU_RC_OK != (rc = service->openSynth())) {
+               delete service;
+               service = NULL;
+               LOG_MSG("MT32: Error initialising emulation: %i", rc);
+               return false;
+       }
+
+       if (strcmp(section->Get_string("mt32.reverb.mode"), "auto") != 0) {
+               Bit8u reverbsysex[] = {0x10, 0x00, 0x01, 0x00, 0x05, 0x03};
+               reverbsysex[3] = 
(Bit8u)atoi(section->Get_string("mt32.reverb.mode"));
+               reverbsysex[4] = (Bit8u)section->Get_int("mt32.reverb.time");
+               reverbsysex[5] = (Bit8u)section->Get_int("mt32.reverb.level");
+               service->writeSysex(16, reverbsysex, 6);
+               service->setReverbOverridden(true);
+       }
+
+       
service->setDACInputMode((MT32Emu::DACInputMode)section->Get_int("mt32.dac"));
+
+       
service->setReversedStereoEnabled(section->Get_bool("mt32.reverse.stereo"));
+       service->setNiceAmpRampEnabled(section->Get_bool("mt32.niceampramp"));
+       noise = section->Get_bool("mt32.verbose");
+       renderInThread = section->Get_bool("mt32.thread");
+
+       if (noise) LOG_MSG("MT32: Set maximum number of partials %d", 
service->getPartialCount());
+
+       if (noise) LOG_MSG("MT32: Adding mixer channel at sample rate %d", 
sampleRate);
+       chan = MIXER_AddChannel(mixerCallBack, sampleRate, "MT32");
+
+       if (renderInThread) {
+               stopProcessing = false;
+               playPos = 0;
+               int chunkSize = section->Get_int("mt32.chunk");
+               minimumRenderFrames = (chunkSize * sampleRate) / 
MILLIS_PER_SECOND;
+               int latency = section->Get_int("mt32.prebuffer");
+               if (latency <= chunkSize) {
+                       latency = 2 * chunkSize;
+                       LOG_MSG("MT32: chunk length must be less than prebuffer 
length, prebuffer length reset to %i ms.", latency);
+               }
+               framesPerAudioBuffer = (latency * sampleRate) / 
MILLIS_PER_SECOND;
+               audioBufferSize = framesPerAudioBuffer << 1;
+               audioBuffer = new Bit16s[audioBufferSize];
+               service->renderBit16s(audioBuffer, framesPerAudioBuffer - 1);
+               renderPos = (framesPerAudioBuffer - 1) << 1;
+               playedBuffers = 1;
+               lock = SDL_CreateMutex();
+               framesInBufferChanged = SDL_CreateCond();
+               thread = SDL_CreateThread(processingThread, NULL);
+       }
+       chan->Enable(true);
+
+       open = true;
+       return true;
+}
+
+void MidiHandler_mt32::Close(void) {
+       if (!open) return;
+       chan->Enable(false);
+       if (renderInThread) {
+               stopProcessing = true;
+               SDL_LockMutex(lock);
+               SDL_CondSignal(framesInBufferChanged);
+               SDL_UnlockMutex(lock);
+               SDL_WaitThread(thread, NULL);
+               thread = NULL;
+               SDL_DestroyMutex(lock);
+               lock = NULL;
+               SDL_DestroyCond(framesInBufferChanged);
+               framesInBufferChanged = NULL;
+               delete[] audioBuffer;
+               audioBuffer = NULL;
+       }
+       MIXER_DelChannel(chan);
+       chan = NULL;
+       service->closeSynth();
+       delete service;
+       service = NULL;
+       open = false;
+}
+
+void MidiHandler_mt32::PlayMsg(Bit8u *msg) {
+       if (renderInThread) {
+               service->playMsgAt(SDL_SwapLE32(*(Bit32u *)msg), 
getMidiEventTimestamp());
+       } else {
+               service->playMsg(SDL_SwapLE32(*(Bit32u *)msg));
+       }
+}
+
+void MidiHandler_mt32::PlaySysex(Bit8u *sysex, Bitu len) {
+       if (renderInThread) {
+               service->playSysexAt(sysex, len, getMidiEventTimestamp());
+       } else {
+               service->playSysex(sysex, len);
+       }
+}
+
+void MidiHandler_mt32::mixerCallBack(Bitu len) {
+       MidiHandler_mt32::GetInstance().handleMixerCallBack(len);
+}
+
+int MidiHandler_mt32::processingThread(void *) {
+       MidiHandler_mt32::GetInstance().renderingLoop();
+       return 0;
+}
+
+void MidiHandler_mt32::makeROMPathName(char pathName[], const char romDir[], 
const char fileName[], bool addPathSeparator) {
+       strcpy(pathName, romDir);
+       if (addPathSeparator) {
+               strcat(pathName, "/");
+       }
+       strcat(pathName, fileName);
+}
+
+mt32emu_report_handler_i MidiHandler_mt32::getReportHandlerInterface() {
+       class ReportHandler {
+       public:
+               static mt32emu_report_handler_version 
getReportHandlerVersionID(mt32emu_report_handler_i) {
+                       return MT32EMU_REPORT_HANDLER_VERSION_0;
+               }
+
+               static void printDebug(void *instance_data, const char *fmt, 
va_list list) {
+                       MidiHandler_mt32 &midiHandler_mt32 = *(MidiHandler_mt32 
*)instance_data;
+                       if (midiHandler_mt32.noise) {
+                               char s[1024];
+                               vsnprintf(s, 1023, fmt, list);
+                               LOG_MSG("MT32: %s", s);
+                       }
+               }
+
+               static void onErrorControlROM(void *) {
+                       LOG_MSG("MT32: Couldn't open Control ROM file");
+               }
+
+               static void onErrorPCMROM(void *) {
+                       LOG_MSG("MT32: Couldn't open PCM ROM file");
+               }
+
+               static void showLCDMessage(void *, const char *message) {
+                       LOG_MSG("MT32: LCD-Message: %s", message);
+               }
+       };
+
+       static const mt32emu_report_handler_i_v0 REPORT_HANDLER_V0_IMPL = {
+               ReportHandler::getReportHandlerVersionID,
+               ReportHandler::printDebug,
+               ReportHandler::onErrorControlROM,
+               ReportHandler::onErrorPCMROM,
+               ReportHandler::showLCDMessage
+       };
+
+       static const mt32emu_report_handler_i REPORT_HANDLER_I = { 
&REPORT_HANDLER_V0_IMPL };
+
+       return REPORT_HANDLER_I;
+}
+
+MidiHandler_mt32::MidiHandler_mt32() : open(false), chan(NULL), service(NULL), 
thread(NULL) {
+}
+
+MidiHandler_mt32::~MidiHandler_mt32() {
+       Close();
+}
+
+void MidiHandler_mt32::handleMixerCallBack(Bitu len) {
+       if (renderInThread) {
+               while (renderPos == playPos) {
+                       SDL_LockMutex(lock);
+                       SDL_CondWait(framesInBufferChanged, lock);
+                       SDL_UnlockMutex(lock);
+                       if (stopProcessing) return;
+               }
+               Bitu renderPosSnap = renderPos;
+               Bitu playPosSnap = playPos;
+               Bitu samplesReady = (renderPosSnap < playPosSnap) ? 
audioBufferSize - playPosSnap : renderPosSnap - playPosSnap;
+               if (len > (samplesReady >> 1)) {
+                       len = samplesReady >> 1;
+               }
+               chan->AddSamples_s16(len, audioBuffer + playPosSnap);
+               playPosSnap += (len << 1);
+               while (audioBufferSize <= playPosSnap) {
+                       playPosSnap -= audioBufferSize;
+                       playedBuffers++;
+               }
+               playPos = playPosSnap;
+               renderPosSnap = renderPos;
+               const Bitu samplesFree = (renderPosSnap < playPosSnap) ? 
playPosSnap - renderPosSnap : audioBufferSize + playPosSnap - renderPosSnap;
+               if (minimumRenderFrames <= (samplesFree >> 1)) {
+                       SDL_LockMutex(lock);
+                       SDL_CondSignal(framesInBufferChanged);
+                       SDL_UnlockMutex(lock);
+               }
+       } else {
+               service->renderBit16s((Bit16s *)MixTemp, len);
+               chan->AddSamples_s16(len, (Bit16s *)MixTemp);
+       }
+}
+
+void MidiHandler_mt32::renderingLoop() {
+       while (!stopProcessing) {
+               const Bitu renderPosSnap = renderPos;
+               const Bitu playPosSnap = playPos;
+               Bitu samplesToRender;
+               if (renderPosSnap < playPosSnap) {
+                       samplesToRender = playPosSnap - renderPosSnap - 2;
+               } else {
+                       samplesToRender = audioBufferSize - renderPosSnap;
+                       if (playPosSnap == 0) samplesToRender -= 2;
+               }
+               Bitu framesToRender = samplesToRender >> 1;
+               if ((framesToRender == 0) || ((framesToRender < 
minimumRenderFrames) && (renderPosSnap < playPosSnap))) {
+                       SDL_LockMutex(lock);
+                       SDL_CondWait(framesInBufferChanged, lock);
+                       SDL_UnlockMutex(lock);
+               } else {
+                       service->renderBit16s(audioBuffer + renderPosSnap, 
framesToRender);
+                       renderPos = (renderPosSnap + samplesToRender) % 
audioBufferSize;
+                       if (renderPosSnap == playPos) {
+                               SDL_LockMutex(lock);
+                               SDL_CondSignal(framesInBufferChanged);
+                               SDL_UnlockMutex(lock);
+                       }
+               }
+       }
+}
diff --git a/src/gui/midi_mt32.h b/src/gui/midi_mt32.h
new file mode 100644
index 0000000..eb32729
--- /dev/null
+++ b/src/gui/midi_mt32.h
@@ -0,0 +1,55 @@
+#ifndef DOSBOX_MIDI_MT32_H
+#define DOSBOX_MIDI_MT32_H
+
+#include "mixer.h"
+
+#define MT32EMU_API_TYPE 3
+#include <mt32emu/mt32emu.h>
+
+#if MT32EMU_VERSION_MAJOR != 2 || MT32EMU_VERSION_MINOR < 1
+#error Incompatible mt32emu library version
+#endif
+
+struct SDL_Thread;
+
+class MidiHandler_mt32 : public MidiHandler {
+public:
+       static MidiHandler_mt32 &GetInstance(void);
+
+       const char *GetName(void);
+       bool Open(const char *conf);
+       void Close(void);
+       void PlayMsg(Bit8u *msg);
+       void PlaySysex(Bit8u *sysex, Bitu len);
+
+private:
+       MixerChannel *chan;
+       MT32Emu::Service *service;
+       SDL_Thread *thread;
+       SDL_mutex *lock;
+       SDL_cond *framesInBufferChanged;
+       Bit16s *audioBuffer;
+       Bitu audioBufferSize;
+       Bitu framesPerAudioBuffer;
+       Bitu minimumRenderFrames;
+       volatile Bitu renderPos, playPos, playedBuffers;
+       volatile bool stopProcessing;
+       bool open, noise, renderInThread;
+
+       static void mixerCallBack(Bitu len);
+       static int processingThread(void *);
+       static void makeROMPathName(char pathName[], const char romDir[], const 
char fileName[], bool addPathSeparator);
+       static mt32emu_report_handler_i getReportHandlerInterface();
+
+       MidiHandler_mt32();
+       ~MidiHandler_mt32();
+
+       Bit32u inline getMidiEventTimestamp() {
+               return 
service->convertOutputToSynthTimestamp(Bit32u(playedBuffers * 
framesPerAudioBuffer + (playPos >> 1)));
+       }
+
+       void handleMixerCallBack(Bitu len);
+       void renderingLoop();
+};
+
+#endif /* DOSBOX_MIDI_MT32_H */
diff --git a/src/mt32options.h b/src/mt32options.h
new file mode 100644
index 0000000..6292f0b
--- /dev/null
+++ b/src/mt32options.h
@@ -0,0 +1,109 @@
+Pstring = secprop->Add_string("mt32.romdir",Property::Changeable::WhenIdle,"");
+Pstring->Set_help("Name of the directory where MT-32 Control and PCM ROM files 
can be found. Emulation requires these files to work.\n"
+       "  Accepted file names are as follows:\n"
+       "    MT32_CONTROL.ROM or CM32L_CONTROL.ROM - control ROM file.\n"
+       "    MT32_PCM.ROM or CM32L_PCM.ROM - PCM ROM file.");
+
+Pbool = 
secprop->Add_bool("mt32.reverse.stereo",Property::Changeable::WhenIdle,false);
+Pbool->Set_help("Reverse stereo channels for MT-32 output");
+
+Pbool = secprop->Add_bool("mt32.verbose",Property::Changeable::WhenIdle,false);
+Pbool->Set_help("MT-32 debug logging");
+
+Pbool = secprop->Add_bool("mt32.thread",Property::Changeable::WhenIdle,false);
+Pbool->Set_help("MT-32 rendering in separate thread");
+
+Pint = secprop->Add_int("mt32.chunk",Property::Changeable::WhenIdle,16);
+Pint->SetMinMax(2,100);
+Pint->Set_help("Minimum milliseconds of data to render at once. (min 2, max 
100)\n"
+       "Increasing this value reduces rendering overhead which may improve 
performance but also increases audio lag.\n"
+       "Valid for rendering in separate thread only.");
+
+Pint = secprop->Add_int("mt32.prebuffer",Property::Changeable::WhenIdle,32);
+Pint->SetMinMax(3,200);
+Pint->Set_help("How many milliseconds of data to render ahead. (min 3, max 
200)\n"
+       "Increasing this value may help to avoid underruns but also increases 
audio lag.\n"
+       "Cannot be set less than or equal to mt32.chunk value.\n"
+       "Valid for rendering in separate thread only.");
+
+Pint = secprop->Add_int("mt32.partials",Property::Changeable::WhenIdle,32);
+Pint->SetMinMax(8,256);
+Pint->Set_help("The maximum number of partials playing simultaneously. (min 8, 
max 256");
+
+const char *mt32DACModes[] = {"0", "1", "2", "3",0};
+Pint = secprop->Add_int("mt32.dac",Property::Changeable::WhenIdle,0);
+Pint->Set_values(mt32DACModes);
+Pint->Set_help("MT-32 DAC input emulation mode\n"
+       "Nice = 0 - default\n"
+       "Produces samples at double the volume, without tricks.\n"
+       "Higher quality than the real devices\n\n"
+
+       "Pure = 1\n"
+       "Produces samples that exactly match the bits output from the emulated 
LA32.\n"
+       "Nicer overdrive characteristics than the DAC hacks (it simply clips 
samples within range)\n"
+       "Much less likely to overdrive than any other mode.\n"
+       "Half the volume of any of the other modes.\n"
+       "Perfect for developers while debugging :)\n\n"
+
+       "GENERATION1 = 2\n"
+       "Re-orders the LA32 output bits as in early generation MT-32s 
(according to Wikipedia).\n"
+       "Bit order at DAC (where each number represents the original LA32 
output bit number, and XX means the bit is always low):\n"
+       "15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX\n\n"
+
+       "GENERATION2 = 3\n"
+       "Re-orders the LA32 output bits as in later generations (personally 
confirmed on my CM-32L - KG).\n"
+       "Bit order at DAC (where each number represents the original LA32 
output bit number):\n"
+       "15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14");
+
+const char *mt32analogModes[] = {"0", "1", "2", "3",0};
+Pint = secprop->Add_int("mt32.analog",Property::Changeable::WhenIdle,2);
+Pint->Set_values(mt32analogModes);
+Pint->Set_help("MT-32 analogue output emulation mode\n"
+       "Digital = 0\n"
+       "Only digital path is emulated. The output samples correspond to the 
digital output signal appeared at the DAC entrance.\n"
+       "Fastest mode.\n\n"
+
+       "Coarse = 1\n"
+       "Coarse emulation of LPF circuit. High frequencies are boosted, sample 
rate remains unchanged.\n"
+       "A bit better sounding but also a bit slower.\n\n"
+
+       "Accurate = 2 - default\n"
+       "Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz 
to allow emulation of audible mirror spectra above 16 kHz,\n"
+       "which is passed through the LPF circuit without significant 
attenuation.\n"
+       "Sounding is closer to the analog output from real hardware but also 
slower than the modes 0 and 1.\n\n"
+
+       "Oversampled = 3\n"
+       "Same as the default mode 2 but the output signal is 2x oversampled, 
i.e. the output sample rate is 96 kHz.\n"
+       "Even slower than all the other modes but better retains highest 
frequencies while further resampled in DOSBox mixer.");
+
+const char *mt32reverbModes[] = {"0", "1", "2", "3", "auto",0};
+Pstring = 
secprop->Add_string("mt32.reverb.mode",Property::Changeable::WhenIdle,"auto");
+Pstring->Set_values(mt32reverbModes);
+Pstring->Set_help("MT-32 reverb mode");
+
+const char *mt32reverbTimes[] = {"0", "1", "2", "3", "4", "5", "6", "7",0};
+Pint = secprop->Add_int("mt32.reverb.time",Property::Changeable::WhenIdle,5);
+Pint->Set_values(mt32reverbTimes);
+Pint->Set_help("MT-32 reverb decaying time");
+
+const char *mt32reverbLevels[] = {"0", "1", "2", "3", "4", "5", "6", "7",0};
+Pint = secprop->Add_int("mt32.reverb.level",Property::Changeable::WhenIdle,3);
+Pint->Set_values(mt32reverbLevels);
+Pint->Set_help("MT-32 reverb level");
+
+Pint = secprop->Add_int("mt32.rate", Property::Changeable::WhenIdle, 44100);
+Pint->Set_values(rates);
+Pint->Set_help("Sample rate of MT-32 emulation.");
+
+const char *mt32srcQuality[] = {"0", "1", "2", "3",0};
+Pint = secprop->Add_int("mt32.src.quality", Property::Changeable::WhenIdle, 2);
+Pint->Set_values(mt32srcQuality);
+Pint->Set_help("MT-32 sample rate conversion quality\n"
+       "Value '0' is for the fastest conversion, value '3' provides for the 
best conversion quality. Default is 2.");
+
+Pbool = secprop->Add_bool("mt32.niceampramp", Property::Changeable::WhenIdle, 
true);
+Pbool->Set_help("Toggles \"Nice Amp Ramp\" mode that improves amplitude ramp 
for sustaining instruments.\n"
+       "Quick changes of volume or expression on a MIDI channel may result in 
amp jumps on real hardware.\n"
+       "When \"Nice Amp Ramp\" mode is enabled, amp changes gradually 
instead.\n"
+       "Otherwise, the emulation accuracy is preserved.\n"
+       "Default is true.");


Reply via email to