mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- 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:
parent
17eac1c57b
commit
b085ac3efb
10 changed files with 308 additions and 529 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
255
src/sound/oplsynth/o_swap.h
Normal 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__
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue