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" > + +