From b085ac3efb87a75f83d216a2f57c2cf10dc8f76a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 26 Sep 2019 19:33:28 +0200 Subject: [PATCH] - cleaned up the dependencies of the OPL interface layer. This also removes the OPL dumper because I wasn't able to get any non-broken output from it and have no desire to fix such a niche feature. --- src/CMakeLists.txt | 1 - .../mididevices/music_opl_mididevice.cpp | 2 +- .../music_opldumper_mididevice.cpp | 385 ------------------ src/sound/music/i_music.cpp | 33 -- src/sound/music/i_musicinterns.h | 13 - src/sound/musicformats/music_midistream.cpp | 17 - src/sound/musicformats/music_opl.cpp | 12 +- src/sound/oplsynth/o_swap.h | 255 ++++++++++++ src/sound/oplsynth/opl_mus_player.cpp | 105 ++--- src/sound/oplsynth/opl_mus_player.h | 14 +- 10 files changed, 308 insertions(+), 529 deletions(-) delete mode 100644 src/sound/mididevices/music_opldumper_mididevice.cpp create mode 100644 src/sound/oplsynth/o_swap.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8454c303b..0f6cfe1f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1191,7 +1191,6 @@ set (PCH_SOURCES sound/music/i_soundfont.cpp sound/backend/i_sound.cpp sound/mididevices/music_adlmidi_mididevice.cpp - sound/mididevices/music_opldumper_mididevice.cpp sound/mididevices/music_opl_mididevice.cpp sound/mididevices/music_opnmidi_mididevice.cpp sound/mididevices/music_timiditypp_mididevice.cpp diff --git a/src/sound/mididevices/music_opl_mididevice.cpp b/src/sound/mididevices/music_opl_mididevice.cpp index d92c53ae8..91bc7f687 100644 --- a/src/sound/mididevices/music_opl_mididevice.cpp +++ b/src/sound/mididevices/music_opl_mididevice.cpp @@ -84,7 +84,7 @@ int getOPLCore(const char* args) OPLMIDIDevice::OPLMIDIDevice(const char *args) - : SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(getOPLCore(args)) + : SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(getOPLCore(args), opl_numchips) { FullPan = opl_fullpan; auto lump = Wads.CheckNumForName("GENMIDI", ns_global); diff --git a/src/sound/mididevices/music_opldumper_mididevice.cpp b/src/sound/mididevices/music_opldumper_mididevice.cpp deleted file mode 100644 index 43f421c96..000000000 --- a/src/sound/mididevices/music_opldumper_mididevice.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* -** music_opl_mididevice.cpp -** Writes raw OPL commands from the emulated OPL MIDI output to disk. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "i_musicinterns.h" -#include "templates.h" -#include "opl.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class OPLDump : public OPLEmul -{ -public: - OPLDump(FileWriter *file) : File(file), TimePerTick(0), CurTime(0), - CurIntTime(0), TickMul(1), CurChip(0) {} - - // If we're doing things right, these should never be reset. - virtual void Reset() { assert(0); } - - // Update() is only used for getting waveform data, which dumps don't do. - virtual void Update(float *buffer, int length) { assert(0); } - - // OPL dumps don't pan beyond what OPL3 is capable of (which is - // already written using registers from the original data). - virtual void SetPanning(int c, float left, float right) {} - - // Only for the OPL dumpers, not the emulators - virtual void SetClockRate(double samples_per_tick) {} - virtual void WriteDelay(int ticks) = 0; - -protected: - FileWriter *File; - double TimePerTick; // in milliseconds - double CurTime; - int CurIntTime; - int TickMul; - uint8_t CurChip; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -class OPL_RDOSdump : public OPLDump -{ -public: - OPL_RDOSdump(FileWriter *file) : OPLDump(file) - { - assert(File != NULL); - file->Write("RAWADATA\0", 10); - NeedClockRate = true; - } - virtual ~OPL_RDOSdump() - { - if (File != NULL) - { - uint16_t endmark = 0xFFFF; - File->Write(&endmark, 2); - delete File; - } - } - - virtual void WriteReg(int reg, int v) - { - assert(File != NULL); - uint8_t chipnum = reg >> 8; - if (chipnum != CurChip) - { - uint8_t switcher[2] = { (uint8_t)(chipnum + 1), 2 }; - File->Write(switcher, 2); - } - reg &= 255; - if (reg != 0 && reg != 2 && (reg != 255 || v != 255)) - { - uint8_t cmd[2] = { uint8_t(v), uint8_t(reg) }; - File->Write(cmd, 2); - } - } - - virtual void SetClockRate(double samples_per_tick) - { - TimePerTick = samples_per_tick / OPL_SAMPLE_RATE * 1000.0; - - double clock_rate; - int clock_mul; - uint16_t clock_word; - - clock_rate = samples_per_tick * ADLIB_CLOCK_MUL; - clock_mul = 1; - - // The RDos raw format's clock rate is stored in a word. Therefore, - // the longest tick that can be stored is only ~55 ms. - while (clock_rate / clock_mul + 0.5 > 65535.0) - { - clock_mul++; - } - clock_word = uint16_t(clock_rate / clock_mul + 0.5); - - if (NeedClockRate) - { // Set the initial clock rate. - clock_word = LittleShort(clock_word); - File->Seek(8, SEEK_SET); - File->Write(&clock_word, 2); - File->Seek(0, SEEK_END); - NeedClockRate = false; - } - else - { // Change the clock rate in the middle of the song. - uint8_t clock_change[4] = { 0, 2, uint8_t(clock_word & 255), uint8_t(clock_word >> 8) }; - File->Write(clock_change, 4); - } - } - virtual void WriteDelay(int ticks) - { - if (ticks > 0) - { // RDos raw has very precise delays but isn't very efficient at - // storing long delays. - uint8_t delay[2]; - - ticks *= TickMul; - delay[1] = 0; - while (ticks > 255) - { - ticks -= 255; - delay[0] = 255; - File->Write(delay, 2); - } - delay[0] = uint8_t(ticks); - File->Write(delay, 2); - } - } -protected: - bool NeedClockRate; -}; - -class OPL_DOSBOXdump : public OPLDump -{ -public: - OPL_DOSBOXdump(FileWriter *file, bool dual) : OPLDump(file), Dual(dual) - { - assert(File != NULL); - File->Write("DBRAWOPL" - "\0\0" // Minor version number - "\1\0" // Major version number - "\0\0\0\0" // Total milliseconds - "\0\0\0", // Total data - 20); - char type[4] = { (char)(Dual * 2), 0, 0, 0 }; // Single or dual OPL-2 - File->Write(type, 4); - } - virtual ~OPL_DOSBOXdump() - { - if (File != NULL) - { - long where_am_i =File->Tell(); - uint32_t len[2]; - - File->Seek(12, SEEK_SET); - len[0] = LittleLong(CurIntTime); - len[1] = LittleLong(uint32_t(where_am_i - 24)); - File->Write(len, 8); - delete File; - } - } - virtual void WriteReg(int reg, int v) - { - assert(File != NULL); - uint8_t chipnum = reg >> 8; - if (chipnum != CurChip) - { - CurChip = chipnum; - chipnum += 2; - File->Write(&chipnum, 1); - } - reg &= 255; - uint8_t cmd[3] = { 4, uint8_t(reg), uint8_t(v) }; - File->Write(cmd + (reg > 4), 3 - (reg > 4)); - } - virtual void WriteDelay(int ticks) - { - if (ticks > 0) - { // DosBox only has millisecond-precise delays. - int delay; - - CurTime += TimePerTick * ticks; - delay = int(CurTime + 0.5) - CurIntTime; - CurIntTime += delay; - while (delay > 65536) - { - uint8_t cmd[3] = { 1, 255, 255 }; - File->Write(cmd, 2); - delay -= 65536; - } - delay--; - if (delay <= 255) - { - uint8_t cmd[2] = { 0, uint8_t(delay) }; - File->Write(cmd, 2); - } - else - { - assert(delay <= 65535); - uint8_t cmd[3] = { 1, uint8_t(delay & 255), uint8_t(delay >> 8) }; - File->Write(cmd, 3); - } - } - } -protected: - bool Dual; -}; - -//========================================================================== -// -// OPLDumperMIDIDevice Constructor -// -//========================================================================== - -OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename) - : OPLMIDIDevice(NULL) -{ - // Replace the standard OPL device with a disk writer. - delete io; - io = new DiskWriterIO(filename); -} - -//========================================================================== -// -// OPLDumperMIDIDevice Destructor -// -//========================================================================== - -OPLDumperMIDIDevice::~OPLDumperMIDIDevice() -{ -} - -//========================================================================== -// -// OPLDumperMIDIDevice :: Resume -// -//========================================================================== - -int OPLDumperMIDIDevice::Resume() -{ - int time; - - time = PlayTick(); - while (time != 0) - { - io->WriteDelay(time); - time = PlayTick(); - } - return 0; -} - -//========================================================================== -// -// OPLDumperMIDIDevice :: Stop -// -//========================================================================== - -void OPLDumperMIDIDevice::Stop() -{ -} - -//========================================================================== -// -// DiskWriterIO Constructor -// -//========================================================================== - -DiskWriterIO::DiskWriterIO(const char *filename) - : Filename(filename) -{ -} - -//========================================================================== -// -// DiskWriterIO Destructor -// -//========================================================================== - -DiskWriterIO::~DiskWriterIO() -{ - Reset(); -} - -//========================================================================== -// -// DiskWriterIO :: Init -// -//========================================================================== - -int DiskWriterIO::Init(uint32_t numchips, bool, bool initopl3) -{ - FileWriter *file = FileWriter::Open(Filename); - if (file == NULL) - { - Printf("Could not open %s for writing.\n", Filename.GetChars()); - return 0; - } - - numchips = clamp(numchips, 1u, 2u); - memset(chips, 0, sizeof(chips)); - // If the file extension is unknown or not present, the default format - // is RAW. Otherwise, you can use DRO. - if (Filename.Len() < 5 || stricmp(&Filename[Filename.Len() - 4], ".dro") != 0) - { - chips[0] = new OPL_RDOSdump(file); - } - else - { - chips[0] = new OPL_DOSBOXdump(file, numchips > 1); - } - NumChannels = OPL_NUM_VOICES * numchips; - NumChips = numchips; - IsOPL3 = numchips > 1; - WriteInitState(initopl3); - return numchips; -} - -//========================================================================== -// -// DiskWriterIO :: SetClockRate -// -//========================================================================== - -void DiskWriterIO::SetClockRate(double samples_per_tick) -{ - static_cast(chips[0])->SetClockRate(samples_per_tick); -} - -//========================================================================== -// -// DiskWriterIO :: WriteDelay -// -//========================================================================== - -void DiskWriterIO :: WriteDelay(int ticks) -{ - static_cast(chips[0])->WriteDelay(ticks); -} diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index 3c9a08759..028d4dcc2 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -694,39 +694,6 @@ static MIDISource *GetMIDISource(const char *fn) } return source; } -//========================================================================== -// -// CCMD writeopl -// -// If the current song can be played with OPL instruments, dump it to -// the specified file on disk. -// -//========================================================================== - -UNSAFE_CCMD (writeopl) -{ - if (argv.argc() >= 3 && argv.argc() <= 7) - { - auto source = GetMIDISource(argv[1]); - if (source == nullptr) return; - - // We must stop the currently playing music to avoid interference between two synths. - auto savedsong = mus_playing; - S_StopMusic(true); - auto streamer = new MIDIStreamer(MDEV_OPL, nullptr); - streamer->SetMIDISource(source); - streamer->DumpOPL(argv[2], argv.argc() <4 ? 0 : (int)strtol(argv[3], nullptr, 10)); - delete streamer; - S_ChangeMusic(savedsong.name, savedsong.baseorder, savedsong.loop, true); - - } - else - { - Printf("Usage: writeopl [subsong]\n" - " - use '*' as song name to dump the currently playing song\n" - " - use 0 for subsong to play the default\n"); - } -} //========================================================================== // diff --git a/src/sound/music/i_musicinterns.h b/src/sound/music/i_musicinterns.h index 81aaa4203..3e1c0ac26 100644 --- a/src/sound/music/i_musicinterns.h +++ b/src/sound/music/i_musicinterns.h @@ -140,18 +140,6 @@ protected: // OPL dumper implementation of a MIDI output device ------------------------ -struct DiskWriterIO : public OPLio -{ - DiskWriterIO(const char* filename); - ~DiskWriterIO(); - - int Init(uint32_t numchips, bool notused, bool initopl3); - void SetClockRate(double samples_per_tick); - void WriteDelay(int ticks); - - FString Filename; -}; - class OPLDumperMIDIDevice : public OPLMIDIDevice { public: @@ -226,7 +214,6 @@ public: } bool DumpWave(const char *filename, int subsong, int samplerate); - bool DumpOPL(const char *filename, int subsong); protected: diff --git a/src/sound/musicformats/music_midistream.cpp b/src/sound/musicformats/music_midistream.cpp index 63206c622..ea46cf04d 100644 --- a/src/sound/musicformats/music_midistream.cpp +++ b/src/sound/musicformats/music_midistream.cpp @@ -313,23 +313,6 @@ void MIDIStreamer::Play(bool looping, int subsong) // //========================================================================== -bool MIDIStreamer::DumpOPL(const char *filename, int subsong) -{ - m_Looping = false; - if (source == nullptr) return false; // We have nothing to play so abort. - source->SetMIDISubsong(subsong); - - assert(MIDI == NULL); - MIDI = new OPLDumperMIDIDevice(filename); - return InitPlayback(); -} - -//========================================================================== -// -// MIDIStreamer :: DumpWave -// -//========================================================================== - bool MIDIStreamer::DumpWave(const char *filename, int subsong, int samplerate) { m_Looping = false; diff --git a/src/sound/musicformats/music_opl.cpp b/src/sound/musicformats/music_opl.cpp index d3cf14ec9..d2e87b326 100644 --- a/src/sound/musicformats/music_opl.cpp +++ b/src/sound/musicformats/music_opl.cpp @@ -65,9 +65,17 @@ int getOPLCore(const char* args); OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args) { int samples = int(OPL_SAMPLE_RATE / 14); + const char* error; int core = getOPLCore(args); - Music = new OPLmusicFile (reader, core); + auto data = reader.Read(); + Music = new OPLmusicFile (data.Data(), data.Size(), core, opl_numchips, error); + if (!Music->IsValid()) + { + Printf(PRINT_BOLD, "%s", error? error : "Invalid OPL format\n"); + delete Music; + return; + } m_Stream = GSnd->CreateStream (FillStream, samples*4, (core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); @@ -97,7 +105,7 @@ bool OPLMUSSong::IsValid () const void OPLMUSSong::ResetChips () { - Music->ResetChips (); + Music->ResetChips (opl_numchips); } bool OPLMUSSong::IsPlaying () diff --git a/src/sound/oplsynth/o_swap.h b/src/sound/oplsynth/o_swap.h new file mode 100644 index 000000000..de9b7780a --- /dev/null +++ b/src/sound/oplsynth/o_swap.h @@ -0,0 +1,255 @@ +// +// DESCRIPTION: +// Endianess handling, swapping 16bit and 32bit. +// +//----------------------------------------------------------------------------- + + +#ifndef __M_SWAP_H__ +#define __M_SWAP_H__ + +#include + +// Endianess handling. +// WAD files are stored little endian. + +#ifdef __APPLE__ +#include + +inline short LittleShort(short x) +{ + return (short)OSSwapLittleToHostInt16((uint16_t)x); +} + +inline unsigned short LittleShort(unsigned short x) +{ + return OSSwapLittleToHostInt16(x); +} + +inline short LittleShort(int x) +{ + return OSSwapLittleToHostInt16((uint16_t)x); +} + +inline unsigned short LittleShort(unsigned int x) +{ + return OSSwapLittleToHostInt16((uint16_t)x); +} + +inline int LittleLong(int x) +{ + return OSSwapLittleToHostInt32((uint32_t)x); +} + +inline unsigned int LittleLong(unsigned int x) +{ + return OSSwapLittleToHostInt32(x); +} + +inline short BigShort(short x) +{ + return (short)OSSwapBigToHostInt16((uint16_t)x); +} + +inline unsigned short BigShort(unsigned short x) +{ + return OSSwapBigToHostInt16(x); +} + +inline int BigLong(int x) +{ + return OSSwapBigToHostInt32((uint32_t)x); +} + +inline unsigned int BigLong(unsigned int x) +{ + return OSSwapBigToHostInt32(x); +} + +#elif defined __BIG_ENDIAN__ + +// Swap 16bit, that is, MSB and LSB byte. +// No masking with 0xFF should be necessary. +inline short LittleShort (short x) +{ + return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); +} + +inline unsigned short LittleShort (unsigned short x) +{ + return (unsigned short)((x>>8) | (x<<8)); +} + +inline short LittleShort (int x) +{ + return LittleShort((short)x); +} + +inline unsigned short LittleShort (unsigned int x) +{ + return LittleShort((unsigned short)x); +} + +// Swapping 32bit. +inline unsigned int LittleLong (unsigned int x) +{ + return (unsigned int)( + (x>>24) + | ((x>>8) & 0xff00) + | ((x<<8) & 0xff0000) + | (x<<24)); +} + +inline int LittleLong (int x) +{ + return (int)( + (((unsigned int)x)>>24) + | ((((unsigned int)x)>>8) & 0xff00) + | ((((unsigned int)x)<<8) & 0xff0000) + | (((unsigned int)x)<<24)); +} + +inline short BigShort(short x) +{ + return x; +} + +inline unsigned short BigShort(unsigned short x) +{ + return x; +} + +inline unsigned int BigLong(unsigned int x) +{ + return x; +} + +inline int BigLong(int x) +{ + return x; +} + +#else + +inline short LittleShort(short x) +{ + return x; +} + +inline unsigned short LittleShort(unsigned short x) +{ + return x; +} + +inline unsigned int LittleLong(unsigned int x) +{ + return x; +} + +inline int LittleLong(int x) +{ + return x; +} + +#ifdef _MSC_VER + +inline short BigShort(short x) +{ + return (short)_byteswap_ushort((unsigned short)x); +} + +inline unsigned short BigShort(unsigned short x) +{ + return _byteswap_ushort(x); +} + +inline int BigLong(int x) +{ + return (int)_byteswap_ulong((unsigned long)x); +} + +inline unsigned int BigLong(unsigned int x) +{ + return (unsigned int)_byteswap_ulong((unsigned long)x); +} +#pragma warning (default: 4035) + +#else + +inline short BigShort (short x) +{ + return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); +} + +inline unsigned short BigShort (unsigned short x) +{ + return (unsigned short)((x>>8) | (x<<8)); +} + +inline unsigned int BigLong (unsigned int x) +{ + return (unsigned int)( + (x>>24) + | ((x>>8) & 0xff00) + | ((x<<8) & 0xff0000) + | (x<<24)); +} + +inline int BigLong (int x) +{ + return (int)( + (((unsigned int)x)>>24) + | ((((unsigned int)x)>>8) & 0xff00) + | ((((unsigned int)x)<<8) & 0xff0000) + | (((unsigned int)x)<<24)); +} + +#endif + +#endif // __BIG_ENDIAN__ + +// These may be destructive so they should create errors +unsigned long BigLong(unsigned long) = delete; +long BigLong(long) = delete; +unsigned long LittleLong(unsigned long) = delete; +long LittleLong(long) = delete; + + +// Data accessors, since some data is highly likely to be unaligned. +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) +inline int GetShort(const unsigned char *foo) +{ + return *(const short *)foo; +} +inline int GetInt(const unsigned char *foo) +{ + return *(const int *)foo; +} +#else +inline int GetShort(const unsigned char *foo) +{ + return short(foo[0] | (foo[1] << 8)); +} +inline int GetInt(const unsigned char *foo) +{ + return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); +} +#endif +inline int GetBigInt(const unsigned char *foo) +{ + return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]); +} + +#ifdef __BIG_ENDIAN__ +inline int GetNativeInt(const unsigned char *foo) +{ + return GetBigInt(foo); +} +#else +inline int GetNativeInt(const unsigned char *foo) +{ + return GetInt(foo); +} +#endif + +#endif // __M_SWAP_H__ diff --git a/src/sound/oplsynth/opl_mus_player.cpp b/src/sound/oplsynth/opl_mus_player.cpp index 218bd9ada..09fff7e13 100644 --- a/src/sound/oplsynth/opl_mus_player.cpp +++ b/src/sound/oplsynth/opl_mus_player.cpp @@ -37,26 +37,22 @@ #include #include #include +#include #include "opl_mus_player.h" #include "opl.h" -#include "w_wad.h" -#include "templates.h" -#include "c_cvars.h" -#include "doomtype.h" -#include "i_musicinterns.h" +#include "o_swap.h" + #define IMF_RATE 700.0 -EXTERN_CVAR (Int, opl_numchips) - -OPLmusicBlock::OPLmusicBlock(int core) +OPLmusicBlock::OPLmusicBlock(int core, int numchips) { currentCore = core; scoredata = NULL; NextTickIn = 0; LastOffset = 0; - NumChips = MIN(*opl_numchips, 2); + NumChips = std::min(numchips, 2); Looping = false; FullPan = false; io = NULL; @@ -68,11 +64,11 @@ OPLmusicBlock::~OPLmusicBlock() delete io; } -void OPLmusicBlock::ResetChips () +void OPLmusicBlock::ResetChips (int numchips) { std::lock_guard lock(ChipAccess); io->Reset (); - NumChips = io->Init(currentCore, MIN(*opl_numchips, 2), FullPan, false); + NumChips = io->Init(currentCore, std::min(numchips, 2), FullPan, false); } void OPLmusicBlock::Restart() @@ -83,22 +79,18 @@ void OPLmusicBlock::Restart() LastOffset = 0; } -OPLmusicFile::OPLmusicFile (FileReader &reader, int core) - : OPLmusicBlock(core), ScoreLen ((int)reader.GetLength()) +OPLmusicFile::OPLmusicFile (const void *data, size_t length, int core, int numchips, const char *&errormessage) + : OPLmusicBlock(core, numchips), ScoreLen ((int)length) { - if (io == NULL) + static char errorbuffer[80]; + errormessage = nullptr; + if (io == nullptr) { return; } scoredata = new uint8_t[ScoreLen]; - - if (reader.Read(scoredata, ScoreLen) != ScoreLen) - { -fail: delete[] scoredata; - scoredata = NULL; - return; - } + memcpy(scoredata, data, length); if (0 == (NumChips = io->Init(core, NumChips, false, false))) { @@ -106,8 +98,7 @@ fail: delete[] scoredata; } // Check for RDosPlay raw OPL format - if (((uint32_t *)scoredata)[0] == MAKE_ID('R','A','W','A') && - ((uint32_t *)scoredata)[1] == MAKE_ID('D','A','T','A')) + if (!memcmp(scoredata, "RAWADATA", 8)) { RawPlayer = RDosPlay; if (*(uint16_t *)(scoredata + 8) == 0) @@ -117,26 +108,27 @@ fail: delete[] scoredata; SamplesPerTick = LittleShort(*(uint16_t *)(scoredata + 8)) / ADLIB_CLOCK_MUL; } // Check for DosBox OPL dump - else if (((uint32_t *)scoredata)[0] == MAKE_ID('D','B','R','A') && - ((uint32_t *)scoredata)[1] == MAKE_ID('W','O','P','L')) + else if (!memcmp(scoredata, "DBRAWOPL", 8)) { if (LittleShort(((uint16_t *)scoredata)[5]) == 1) { RawPlayer = DosBox1; SamplesPerTick = OPL_SAMPLE_RATE / 1000; - ScoreLen = MIN(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24; + ScoreLen = std::min(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24; } - else if (((uint32_t *)scoredata)[2] == MAKE_ID(2,0,0,0)) + else if (LittleLong(((uint32_t *)scoredata)[2]) == 2) { bool okay = true; if (scoredata[21] != 0) { - Printf("Unsupported DOSBox Raw OPL format %d\n", scoredata[20]); + snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL format %d\n", scoredata[20]); + errormessage = errorbuffer; okay = false; } if (scoredata[22] != 0) { - Printf("Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]); + snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]); + errormessage = errorbuffer; okay = false; } if (!okay) @@ -144,17 +136,17 @@ fail: delete[] scoredata; RawPlayer = DosBox2; SamplesPerTick = OPL_SAMPLE_RATE / 1000; int headersize = 0x1A + scoredata[0x19]; - ScoreLen = MIN(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize; + ScoreLen = std::min(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize; } else { - Printf("Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((uint16_t *)scoredata)[4]), LittleShort(((uint16_t *)scoredata)[5])); + snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((uint16_t *)scoredata)[4]), LittleShort(((uint16_t *)scoredata)[5])); + errormessage = errorbuffer; goto fail; } } // Check for modified IMF format (includes a header) - else if (((uint32_t *)scoredata)[0] == MAKE_ID('A','D','L','I') && - scoredata[4] == 'B' && scoredata[5] == 1) + else if (!memcmp(scoredata, "ADLIB\1", 6)) { int songlen; uint8_t *max = scoredata + ScoreLen; @@ -170,9 +162,7 @@ fail: delete[] scoredata; if (score < max) score++; // Skip unknown byte if (score + 8 > max) { // Not enough room left for song data - delete[] scoredata; - scoredata = NULL; - return; + goto fail; } songlen = LittleLong(*(uint32_t *)score); if (songlen != 0 && (songlen +=4) < ScoreLen - (score - scoredata)) @@ -182,10 +172,18 @@ fail: delete[] scoredata; } else { + errormessage = "Unknown OPL format"; goto fail; } Restart (); + return; + +fail: + delete[] scoredata; + scoredata = nullptr; + return; + } OPLmusicFile::~OPLmusicFile () @@ -262,7 +260,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { double ticky = NextTickIn; int tick_in = int(NextTickIn); - int samplesleft = MIN(numsamples, tick_in); + int samplesleft = std::min(numsamples, tick_in); size_t i; if (samplesleft > 0) @@ -367,7 +365,7 @@ void OPLmusicBlock::OffsetSamples(float *buff, int count) } else { - ramp = MIN(count, MAX(196, largest_at)); + ramp = std::min(count, std::max(196, largest_at)); step = (offset - LastOffset) / ramp; } offset = LastOffset; @@ -531,34 +529,3 @@ int OPLmusicFile::PlayTick () return 0; } -OPLmusicFile::OPLmusicFile(int core, const OPLmusicFile *source, const char *filename) - : OPLmusicBlock(core) -{ - ScoreLen = source->ScoreLen; - scoredata = new uint8_t[ScoreLen]; - memcpy(scoredata, source->scoredata, ScoreLen); - SamplesPerTick = source->SamplesPerTick; - RawPlayer = source->RawPlayer; - score = source->score; - NumChips = source->NumChips; - WhichChip = 0; - if (io != NULL) - { - delete io; - } - io = new DiskWriterIO(filename); - NumChips = io->Init(core, NumChips, false, false); - Restart(); -} - -void OPLmusicFile::Dump() -{ - int time; - - time = PlayTick(); - while (time != 0) - { - io->WriteDelay(time); - time = PlayTick(); - } -} diff --git a/src/sound/oplsynth/opl_mus_player.h b/src/sound/oplsynth/opl_mus_player.h index 8fb89e1f7..28f09b244 100644 --- a/src/sound/oplsynth/opl_mus_player.h +++ b/src/sound/oplsynth/opl_mus_player.h @@ -1,17 +1,17 @@ #pragma once #include +#include +#include #include "musicblock.h" -class FileReader; - class OPLmusicBlock : public musicBlock { public: - OPLmusicBlock(int core); + OPLmusicBlock(int core, int numchips); virtual ~OPLmusicBlock(); bool ServiceStream(void *buff, int numbytes); - void ResetChips(); + void ResetChips(int numchips); virtual void Restart(); @@ -36,17 +36,15 @@ protected: class OPLmusicFile : public OPLmusicBlock { public: - OPLmusicFile(FileReader &reader, int core); - OPLmusicFile(int core, const OPLmusicFile *source, const char *filename); + OPLmusicFile(const void *data, size_t length, int core, int numchips, const char *&errormessage); virtual ~OPLmusicFile(); bool IsValid() const; void SetLooping(bool loop); void Restart(); - void Dump(); protected: - OPLmusicFile(int core) : OPLmusicBlock(core) {} + OPLmusicFile(int core, int numchips) : OPLmusicBlock(core, numchips) {} int PlayTick(); enum { RDosPlay, IMF, DosBox1, DosBox2 } RawPlayer;