diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp
index 5f9d99f2f..ea595c01a 100644
--- a/src/oplsynth/fmopl.cpp
+++ b/src/oplsynth/fmopl.cpp
@@ -102,6 +102,17 @@ Revision History:
//#include "driver.h" /* use M.A.M.E. */
#include "fmopl.h"
+/* compiler dependence */
+#ifndef OSD_CPU_H
+#define OSD_CPU_H
+typedef unsigned char UINT8; /* unsigned 8bit */
+typedef unsigned short UINT16; /* unsigned 16bit */
+typedef unsigned int UINT32; /* unsigned 32bit */
+typedef signed char INT8; /* signed 8bit */
+typedef signed short INT16; /* signed 16bit */
+typedef signed int INT32; /* signed 32bit */
+#endif
+
#ifndef PI
#define PI 3.14159265358979323846
#endif
@@ -1343,13 +1354,11 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
/* timer 2 */
if(OPL->st[1] != st2)
{
- double interval = st2 ? (double)OPL->T[1]*OPL_TIMERBASE : 0.0;
OPL->st[1] = st2;
}
/* timer 1 */
if(OPL->st[0] != st1)
{
- double interval = st1 ? (double)OPL->T[0]*OPL_TIMERBASE : 0.0;
OPL->st[0] = st1;
}
}
@@ -1560,194 +1569,140 @@ static void OPLResetChip(FM_OPL *OPL)
}
}
-/* Create one of virtual YM3812 */
-/* 'clock' is chip clock in Hz */
-/* 'rate' is sampling rate */
-static FM_OPL *OPLCreate()
+
+class YM3812 : public OPLEmul
{
- char *ptr;
- FM_OPL *OPL;
- int state_size;
+private:
+ FM_OPL Chip;
- if (OPL_LockTable() ==-1) return NULL;
-
- /* calculate OPL state size */
- state_size = sizeof(FM_OPL);
-
- /* allocate memory block */
- ptr = (char *)malloc(state_size);
-
- if (ptr==NULL)
- return NULL;
-
- /* clear */
- memset(ptr,0,state_size);
-
- OPL = (FM_OPL *)ptr;
-
- ptr += sizeof(FM_OPL);
-
- /* init global tables */
- OPL_initalize(OPL);
-
- return OPL;
-}
-
-/* Destroy one of virtual YM3812 */
-static void OPLDestroy(FM_OPL *OPL)
-{
- OPL_UnLockTable();
- free(OPL);
-}
-
-/* YM3812 I/O interface */
-static int OPLWrite(FM_OPL *OPL,int a,int v)
-{
- if( !(a&1) )
- { /* address port */
- OPL->address = v & 0xff;
- }
- else
- { /* data port */
- OPLWriteReg(OPL,OPL->address,v);
- }
- return OPL->status>>7;
-}
-
-static unsigned char OPLRead(FM_OPL *OPL,int a)
-{
- if( !(a&1) )
+public:
+ /* Create one of virtual YM3812 */
+ YM3812(bool stereo)
{
- /* status port */
- /* OPL and OPL2 */
- return OPL->status & (OPL->statusmask|0x80);
+ if (OPL_LockTable() == -1) return;
+
+ /* clear */
+ memset(&Chip, 0, sizeof(Chip));
+
+ /* init global tables */
+ OPL_initalize(&Chip);
+
+ Chip.IsStereo = true;
+
+ Reset();
}
- return 0xff;
-}
-
-/* CSM Key Controll */
-INLINE void CSMKeyControll(OPL_CH *CH)
-{
- FM_KEYON (&CH->SLOT[SLOT1], 4);
- FM_KEYON (&CH->SLOT[SLOT2], 4);
-
- /* The key off should happen exactly one sample later - not implemented correctly yet */
-
- FM_KEYOFF(&CH->SLOT[SLOT1], ~4);
- FM_KEYOFF(&CH->SLOT[SLOT2], ~4);
-}
-
-
-void *YM3812Init()
-{
- /* emulator create */
- FM_OPL *YM3812 = OPLCreate();
- if (YM3812)
- YM3812ResetChip(YM3812);
- return YM3812;
-}
-
-void YM3812Shutdown(void *chip)
-{
- FM_OPL *YM3812 = (FM_OPL *)chip;
-
- /* emulator shutdown */
- OPLDestroy(YM3812);
-}
-void YM3812ResetChip(void *chip)
-{
- FM_OPL *YM3812 = (FM_OPL *)chip;
- OPLResetChip(YM3812);
-}
-
-int YM3812Write(void *chip, int a, int v)
-{
- FM_OPL *YM3812 = (FM_OPL *)chip;
- return OPLWrite(YM3812, a, v);
-}
-
-unsigned char YM3812Read(void *chip, int a)
-{
- FM_OPL *YM3812 = (FM_OPL *)chip;
- /* YM3812 always returns bit2 and bit1 in HIGH state */
- return OPLRead(YM3812, a) | 0x06 ;
-}
-
-/* [RH] Full support for MIDI panning */
-void YM3812SetStereo(void *chip, bool stereo)
-{
- if (chip != NULL)
+ /* Destroy one of virtual YM3812 */
+ ~YM3812()
{
- FM_OPL *YM3812 = (FM_OPL *)chip;
- YM3812->IsStereo = stereo;
+ OPL_UnLockTable();
}
-}
-void YM3812SetPanning(void *chip, int c, int pan)
-{
- if (chip != NULL)
+ /* YM3812 I/O interface */
+ int Write(int a, int v)
+ {
+ if( !(a&1) )
+ { /* address port */
+ Chip.address = v & 0xff;
+ }
+ else
+ { /* data port */
+ OPLWriteReg(&Chip, Chip.address, v);
+ }
+ return Chip.status>>7;
+ }
+
+ void Reset()
+ {
+ OPLResetChip(&Chip);
+ }
+
+ /* [RH] Full support for MIDI panning */
+ void SetPanning(int c, int pan)
{
- FM_OPL *YM3812 = (FM_OPL *)chip;
// This is the MIDI-recommended pan formula. 0 and 1 are
// both hard left so that 64 can be perfectly center.
double level = (pan <= 1) ? 0 : (pan - 1) / 126.0;
- YM3812->P_CH[c].LeftVol = (float)cos(HALF_PI * level);
- YM3812->P_CH[c].RightVol = (float)sin(HALF_PI * level);
- }
-}
-
-/*
-** Generate samples for one of the YM3812's
-**
-** 'which' is the virtual YM3812 number
-** '*buffer' is the output buffer pointer
-** 'length' is the number of samples that should be generated
-*/
-void YM3812UpdateOne(void *chip, float *buffer, int length)
-{
- FM_OPL *OPL = (FM_OPL *)chip;
- int i;
-
- if (OPL == NULL)
- {
- return;
+ Chip.P_CH[c].LeftVol = (float)cos(HALF_PI * level);
+ Chip.P_CH[c].RightVol = (float)sin(HALF_PI * level);
}
- UINT8 rhythm = OPL->rhythm&0x20;
- UINT32 lfo_am_cnt_bak = OPL->lfo_am_cnt;
- UINT32 eg_timer_bak = OPL->eg_timer;
- UINT32 eg_cnt_bak = OPL->eg_cnt;
-
- UINT32 lfo_am_cnt_out = lfo_am_cnt_bak;
- UINT32 eg_timer_out = eg_timer_bak;
- UINT32 eg_cnt_out = eg_cnt_bak;
-
- for (i = 0; i <= (rhythm ? 5 : 8); ++i)
+ /*
+ ** Generate samples for one of the YM3812's
+ **
+ ** '*buffer' is the output buffer pointer
+ ** 'length' is the number of samples that should be generated
+ */
+ void Update(float *buffer, int length)
{
- OPL->lfo_am_cnt = lfo_am_cnt_bak;
- OPL->eg_timer = eg_timer_bak;
- OPL->eg_cnt = eg_cnt_bak;
- if (CalcVoice (OPL, i, buffer, length))
+ int i;
+
+ UINT8 rhythm = Chip.rhythm&0x20;
+
+ UINT32 lfo_am_cnt_bak = Chip.lfo_am_cnt;
+ UINT32 eg_timer_bak = Chip.eg_timer;
+ UINT32 eg_cnt_bak = Chip.eg_cnt;
+
+ UINT32 lfo_am_cnt_out = lfo_am_cnt_bak;
+ UINT32 eg_timer_out = eg_timer_bak;
+ UINT32 eg_cnt_out = eg_cnt_bak;
+
+ for (i = 0; i <= (rhythm ? 5 : 8); ++i)
{
- lfo_am_cnt_out = OPL->lfo_am_cnt;
- eg_timer_out = OPL->eg_timer;
- eg_cnt_out = OPL->eg_cnt;
+ Chip.lfo_am_cnt = lfo_am_cnt_bak;
+ Chip.eg_timer = eg_timer_bak;
+ Chip.eg_cnt = eg_cnt_bak;
+ if (CalcVoice (&Chip, i, buffer, length))
+ {
+ lfo_am_cnt_out = Chip.lfo_am_cnt;
+ eg_timer_out = Chip.eg_timer;
+ eg_cnt_out = Chip.eg_cnt;
+ }
+ }
+
+ Chip.lfo_am_cnt = lfo_am_cnt_out;
+ Chip.eg_timer = eg_timer_out;
+ Chip.eg_cnt = eg_cnt_out;
+
+ if (rhythm) /* Rhythm part */
+ {
+ Chip.lfo_am_cnt = lfo_am_cnt_bak;
+ Chip.eg_timer = eg_timer_bak;
+ Chip.eg_cnt = eg_cnt_bak;
+ CalcRhythm (&Chip, buffer, length);
}
}
- OPL->lfo_am_cnt = lfo_am_cnt_out;
- OPL->eg_timer = eg_timer_out;
- OPL->eg_cnt = eg_cnt_out;
-
- if (rhythm) /* Rhythm part */
+ FString GetVoiceString(void *chip)
{
- OPL->lfo_am_cnt = lfo_am_cnt_bak;
- OPL->eg_timer = eg_timer_bak;
- OPL->eg_cnt = eg_cnt_bak;
- CalcRhythm (OPL, buffer, length);
+ FM_OPL *OPL = (FM_OPL *)chip;
+ char out[9*3];
+
+ for (int i = 0; i <= 8; ++i)
+ {
+ int color;
+
+ if (OPL != NULL && (OPL->P_CH[i].SLOT[0].state != EG_OFF || OPL->P_CH[i].SLOT[1].state != EG_OFF))
+ {
+ color = 'D'; // Green means in use
+ }
+ else
+ {
+ color = 'A'; // Brick means free
+ }
+ out[i*3+0] = '\x1c';
+ out[i*3+1] = color;
+ out[i*3+2] = '*';
+ }
+ return FString (out, 9*3);
}
+};
+
+OPLEmul *YM3812Init(bool stereo)
+{
+ /* emulator create */
+ return new YM3812(stereo);
}
// [RH] Render a whole voice at once. If nothing else, it lets us avoid
@@ -1813,27 +1768,3 @@ static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length)
}
return true;
}
-
-FString YM3812GetVoiceString(void *chip)
-{
- FM_OPL *OPL = (FM_OPL *)chip;
- char out[9*3];
-
- for (int i = 0; i <= 8; ++i)
- {
- int color;
-
- if (OPL != NULL && (OPL->P_CH[i].SLOT[0].state != EG_OFF || OPL->P_CH[i].SLOT[1].state != EG_OFF))
- {
- color = 'D'; // Green means in use
- }
- else
- {
- color = 'A'; // Brick means free
- }
- out[i*3+0] = '\x1c';
- out[i*3+1] = color;
- out[i*3+2] = '*';
- }
- return FString (out, 9*3);
-}
diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h
index 850317a40..6a5f65256 100644
--- a/src/oplsynth/fmopl.h
+++ b/src/oplsynth/fmopl.h
@@ -1,39 +1,11 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
-#include "zstring.h"
+#include "opl.h"
// Multiplying OPL_SAMPLE_RATE by ADLIB_CLOCK_MUL gives the number
// Adlib clocks per second, as used by the RAWADATA file format.
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char UINT8; /* unsigned 8bit */
-typedef unsigned short UINT16; /* unsigned 16bit */
-typedef unsigned int UINT32; /* unsigned 32bit */
-typedef signed char INT8; /* signed 8bit */
-typedef signed short INT16; /* signed 16bit */
-typedef signed int INT32; /* signed 32bit */
-#endif
-
-
-typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
-
-
-void *YM3812Init();
-void YM3812Shutdown(void *chip);
-void YM3812ResetChip(void *chip);
-int YM3812Write(void *chip, int a, int v);
-unsigned char YM3812Read(void *chip, int a);
-void YM3812UpdateOne(void *chip, float *buffer, int length);
-void YM3812SetStereo(void *chip, bool stereo);
-void YM3812SetPanning(void *chip, int c, int pan);
-
-FString YM3812GetVoiceString(void *chip);
+OPLEmul *YM3812Init(bool stereo);
#endif
diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp
index 598366717..8ec6f49f7 100644
--- a/src/oplsynth/mlopl_io.cpp
+++ b/src/oplsynth/mlopl_io.cpp
@@ -58,8 +58,8 @@ void OPLio::WriteDelay(int ticks)
void OPLio::OPLwriteReg(int which, uint reg, uchar data)
{
- YM3812Write (chips[which], 0, reg);
- YM3812Write (chips[which], 1, data);
+ chips[which]->Write(0, reg);
+ chips[which]->Write(1, data);
}
/*
@@ -256,7 +256,7 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan)
// Set real panning if we're using emulated chips.
if (chips[0] != NULL)
{
- YM3812SetPanning(chips[channel/9], channel%9, pan+64);
+ chips[channel/9]->SetPanning(channel%9, pan+64);
}
}
}
@@ -307,33 +307,22 @@ void OPLio::OPLshutup(void)
int OPLio::OPLinit(uint numchips, bool stereo)
{
assert(numchips >= 1 && numchips <= 2);
- chips[0] = YM3812Init();
- chips[1] = NULL;
- if (chips[0] != NULL)
+ uint i;
+ memset(chips, 0, sizeof(chips));
+ for (i = 0; i < numchips; ++i)
{
- YM3812SetStereo(chips[0], stereo);
- if (numchips > 1)
+ OPLEmul *chip = YM3812Init(stereo);
+
+ if (chip == NULL)
{
- chips[1] = YM3812Init();
- if (chips[1] == NULL)
- {
- YM3812Shutdown(chips[0]);
- chips[0] = NULL;
- return -1;
- }
- else
- {
- YM3812SetStereo(chips[1], stereo);
- }
+ break;
}
+ chips[i] = chip;
}
- else
- {
- return -1;
- }
- OPLchannels = OPL2CHANNELS * numchips;
+ NumChips = i;
+ OPLchannels = OPL2CHANNELS * i;
OPLwriteInitState();
- return 0;
+ return i;
}
void OPLio::OPLwriteInitState()
@@ -352,8 +341,12 @@ void OPLio::OPLwriteInitState()
*/
void OPLio::OPLdeinit(void)
{
- YM3812Shutdown (chips[0]);
- chips[0] = NULL;
- YM3812Shutdown (chips[1]);
- chips[1] = NULL;
+ for (size_t i = 0; i < countof(chips); ++i)
+ {
+ if (chips[i] != NULL)
+ {
+ delete chips[i];
+ chips[i] = NULL;
+ }
+ }
}
diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp
index d36bacb54..bd3736fe9 100644
--- a/src/oplsynth/music_opl_mididevice.cpp
+++ b/src/oplsynth/music_opl_mididevice.cpp
@@ -92,7 +92,7 @@ OPLMIDIDevice::OPLMIDIDevice()
int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
{
- if (io == NULL || io->OPLinit(TwoChips + 1, IsStereo))
+ if (io == NULL || 0 == io->OPLinit(TwoChips + 1, IsStereo))
{
return 1;
}
diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp
index 55c1fdc0c..bfd0f212d 100644
--- a/src/oplsynth/music_opldumper_mididevice.cpp
+++ b/src/oplsynth/music_opldumper_mididevice.cpp
@@ -155,7 +155,7 @@ int DiskWriterIO::OPLinit(uint numchips, bool dontcare)
if (File == NULL)
{
Printf("Could not open %s for writing.\n", Filename.GetChars());
- return -1;
+ return 0;
}
if (Format == FMT_RDOS)
@@ -189,7 +189,7 @@ int DiskWriterIO::OPLinit(uint numchips, bool dontcare)
CurChip = 0;
OPLchannels = OPL2CHANNELS * numchips;
OPLwriteInitState();
- return 0;
+ return 1;
}
//==========================================================================
diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h
index 189649551..75539b2f6 100644
--- a/src/oplsynth/muslib.h
+++ b/src/oplsynth/muslib.h
@@ -183,8 +183,9 @@ struct OPLio {
virtual void SetClockRate(double samples_per_tick);
virtual void WriteDelay(int ticks);
+ class OPLEmul *chips[2];
uint OPLchannels;
- void *chips[2];
+ uint NumChips;
};
struct DiskWriterIO : public OPLio
diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h
new file mode 100644
index 000000000..fbb7c412c
--- /dev/null
+++ b/src/oplsynth/opl.h
@@ -0,0 +1,21 @@
+#ifndef OPL_H
+#define OPL_H
+
+#include "zstring.h"
+
+// Abstract base class for OPL emulators
+
+class OPLEmul
+{
+public:
+ OPLEmul() {}
+ virtual ~OPLEmul() {}
+
+ virtual void Reset() = 0;
+ virtual int Write(int a, int v) = 0;
+ virtual void Update(float *buffer, int length) = 0;
+ virtual void SetPanning(int c, int pan) = 0;
+ virtual FString GetVoiceString() { return FString(); }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp
index 6df36e707..6be111430 100644
--- a/src/oplsynth/opl_mus_player.cpp
+++ b/src/oplsynth/opl_mus_player.cpp
@@ -40,7 +40,7 @@ void OPLmusicBlock::ResetChips ()
TwoChips = !opl_onechip;
ChipAccess.Enter();
io->OPLdeinit ();
- io->OPLinit (TwoChips + 1, IsStereo);
+ TwoChips = io->OPLinit(TwoChips + 1, IsStereo) == 2;
ChipAccess.Leave();
}
@@ -77,7 +77,7 @@ fail: delete[] scoredata;
memcpy(scoredata, &musiccache[0], len);
}
- if (io->OPLinit (TwoChips + 1))
+ if (0 == io->OPLinit (TwoChips + 1))
{
goto fail;
}
@@ -236,11 +236,14 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
double ticky = NextTickIn;
int tick_in = int(NextTickIn);
int samplesleft = MIN(numsamples, tick_in);
+ size_t i;
if (samplesleft > 0)
{
- YM3812UpdateOne (io->chips[0], samples1, samplesleft);
- YM3812UpdateOne (io->chips[1], samples1, samplesleft);
+ for (i = 0; i < io->NumChips; ++i)
+ {
+ io->chips[i]->Update(samples1, samplesleft);
+ }
OffsetSamples(samples1, samplesleft << int(IsStereo));
assert(NextTickIn == ticky);
NextTickIn -= samplesleft;
@@ -259,8 +262,10 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
{
if (numsamples > 0)
{
- YM3812UpdateOne (io->chips[0], samples1, numsamples);
- YM3812UpdateOne (io->chips[1], samples1, numsamples);
+ for (i = 0; i < io->NumChips; ++i)
+ {
+ io->chips[i]->Update(samples1, samplesleft);
+ }
OffsetSamples(samples1, numsamples << int(IsStereo));
}
res = false;
diff --git a/zdoom.vcproj b/zdoom.vcproj
index 817f53b70..0b144ce26 100644
--- a/zdoom.vcproj
+++ b/zdoom.vcproj
@@ -2618,6 +2618,10 @@
RelativePath=".\src\oplsynth\muslib.h"
>
+
+