commit dosbox for openSUSE:Factory
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 - Илья Индиго <ilya@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.");
participants (1)
-
root