- 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.
This commit is contained in:
Christoph Oelckers 2019-09-26 19:33:28 +02:00
parent 17eac1c57b
commit b085ac3efb
10 changed files with 308 additions and 529 deletions

View file

@ -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

View file

@ -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);

View file

@ -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<OPLDump *>(chips[0])->SetClockRate(samples_per_tick);
}
//==========================================================================
//
// DiskWriterIO :: WriteDelay
//
//==========================================================================
void DiskWriterIO :: WriteDelay(int ticks)
{
static_cast<OPLDump *>(chips[0])->WriteDelay(ticks);
}

View file

@ -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 <midi> <filename> [subsong]\n"
" - use '*' as song name to dump the currently playing song\n"
" - use 0 for subsong to play the default\n");
}
}
//==========================================================================
//

View file

@ -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:

View file

@ -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;

View file

@ -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 ()

255
src/sound/oplsynth/o_swap.h Normal file
View file

@ -0,0 +1,255 @@
//
// DESCRIPTION:
// Endianess handling, swapping 16bit and 32bit.
//
//-----------------------------------------------------------------------------
#ifndef __M_SWAP_H__
#define __M_SWAP_H__
#include <stdlib.h>
// Endianess handling.
// WAD files are stored little endian.
#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
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__

View file

@ -37,26 +37,22 @@
#include <string.h>
#include <assert.h>
#include <math.h>
#include <algorithm>
#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<std::mutex> 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<int>(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24;
ScoreLen = std::min<int>(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<int>(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize;
ScoreLen = std::min<int>(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();
}
}

View file

@ -1,17 +1,17 @@
#pragma once
#include <mutex>
#include <vector>
#include <string>
#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;