diff options
author | 2017-12-01 18:27:56 +1100 | |
---|---|---|
committer | 2017-12-01 18:27:56 +1100 | |
commit | 7d09c0e817e8573fc3a2ee8e57dc4b7896c05c63 (patch) | |
tree | 470ab49c09f854ed3b5f76838d1ece7510e35c7a /src/devices/sound/fmopl.cpp | |
parent | d8a3eb07c24a590d94c19d2316931f3c1413060a (diff) |
turn a bit more of fmopl into something resembling C++ (nw)
Diffstat (limited to 'src/devices/sound/fmopl.cpp')
-rw-r--r-- | src/devices/sound/fmopl.cpp | 503 |
1 files changed, 249 insertions, 254 deletions
diff --git a/src/devices/sound/fmopl.cpp b/src/devices/sound/fmopl.cpp index a9c15478779..2e1be1b4266 100644 --- a/src/devices/sound/fmopl.cpp +++ b/src/devices/sound/fmopl.cpp @@ -309,11 +309,37 @@ struct OPL_CH SLOT.eg_sel_rr = eg_rate_select[SLOT.rr + SLOT.ksr ]; } } + + /* CSM Key Control */ + void CSMKeyControll() + { + SLOT[SLOT1].KEYON(4); + SLOT[SLOT2].KEYON(4); + + /* The key off should happen exactly one sample later - not implemented correctly yet */ + + SLOT[SLOT1].KEYOFF(~4); + SLOT[SLOT2].KEYOFF(~4); + } }; /* OPL state */ -struct FM_OPL +class FM_OPL { +protected: + FM_OPL() +#if BUILD_Y8950 + : deltat(nullptr, [] (YM_DELTAT *p) { p->~YM_DELTAT(); }) +#endif + { + } + +public: + ~FM_OPL() + { + UnLockTable(); + } + /* FM channel slots */ OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ @@ -349,7 +375,7 @@ struct FM_OPL #if BUILD_Y8950 /* Delta-T ADPCM unit (Y8950) */ - YM_DELTAT *deltat; + std::unique_ptr<YM_DELTAT, void (*)(YM_DELTAT *)> deltat; /* Keyboard and I/O ports interface */ uint8_t portDirection; @@ -908,39 +934,183 @@ struct FM_OPL } - void WriteReg(int r, int v); void ResetChip(); void postload(); + void clock_changed(uint32_t c, uint32_t r) + { + clock = c; + rate = r; - /* lock/unlock for common table */ - static int LockTable(device_t *device) + /* init global tables */ + initialize(); + } + + int Write(int a, int v) { - num_lock++; - if(num_lock>1) return 0; + if( !(a&1) ) + { /* address port */ + address = v & 0xff; + } + else + { /* data port */ + if (UpdateHandler) UpdateHandler(UpdateParam, 0); + WriteReg(address, v); + } + return status>>7; + } - /* first time */ + unsigned char Read(int a) + { + if( !(a&1) ) + { + /* status port */ - /* allocate total level table (128kb space) */ - if( !init_tables() ) + #if BUILD_Y8950 + + if(type&OPL_TYPE_ADPCM) /* Y8950 */ + { + return (status & (statusmask|0x80)) | (deltat->PCM_BSY&1); + } + + #endif + + /* OPL and OPL2 */ + return status & (statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(address) { - num_lock--; - return -1; + case 0x05: /* KeyBoard IN */ + if(type&OPL_TYPE_KEYBOARD) + { + if(keyboardhandler_r) + return keyboardhandler_r(keyboard_param); + else + device->logerror("Y8950: read unmapped KEYBOARD port\n"); + } + return 0; + + case 0x0f: /* ADPCM-DATA */ + if(type&OPL_TYPE_ADPCM) + { + uint8_t val; + + val = deltat->ADPCM_Read(); + /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ + return val; + } + return 0; + + case 0x19: /* I/O DATA */ + if(type&OPL_TYPE_IO) + { + if(porthandler_r) + return porthandler_r(port_param); + else + device->logerror("Y8950:read unmapped I/O port\n"); + } + return 0; + case 0x1a: /* PCM-DATA */ + if(type&OPL_TYPE_ADPCM) + { + device->logerror("Y8950 A/D conversion is accessed but not implemented !\n"); + return 0x80; /* 2's complement PCM data - result from A/D conversion */ + } + return 0; } +#endif - return 0; + return 0xff; } - static void UnLockTable() + + int TimerOver(int c) { - if(num_lock) num_lock--; - if(num_lock) return; + if( c ) + { /* Timer B */ + STATUS_SET(0x20); + } + else + { /* Timer A */ + STATUS_SET(0x40); + /* CSM mode key,TL controll */ + if( mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(UpdateHandler) UpdateHandler(UpdateParam,0); + for(ch=0; ch<9; ch++) + P_CH[ch].CSMKeyControll(); + } + } + /* reload timer */ + if (timer_handler) (timer_handler)(TimerParam,c,TimerBase * T[c]); + return status>>7; + } - /* last time */ - CloseTable(); + + /* Create one of virtual YM3812/YM3526/Y8950 */ + /* 'clock' is chip clock in Hz */ + /* 'rate' is sampling rate */ + static FM_OPL *Create(device_t *device, uint32_t clock, uint32_t rate, int type) + { + if (LockTable(device) == -1) + return nullptr; + + /* calculate OPL state size */ + size_t state_size = sizeof(FM_OPL); +#if BUILD_Y8950 + if (type & OPL_TYPE_ADPCM) + state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + char *ptr = reinterpret_cast<char *>(::operator new(state_size)); + std::fill_n(ptr, state_size, 0); + + FM_OPL *const OPL = new(ptr) FM_OPL; + + ptr += sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type & OPL_TYPE_ADPCM) + { + OPL->deltat.reset(reinterpret_cast<YM_DELTAT *>(ptr)); + ptr += sizeof(YM_DELTAT); + } +#endif + + OPL->device = device; + OPL->type = type; + OPL->clock_changed(clock, rate); + + return OPL; + } + + + /* Optional handlers */ + + void SetTimerHandler(OPL_TIMERHANDLER handler, device_t *device) + { + timer_handler = handler; + TimerParam = device; + } + void SetIRQHandler(OPL_IRQHANDLER handler, device_t *device) + { + IRQHandler = handler; + IRQParam = device; + } + void SetUpdateHandler(OPL_UPDATEHANDLER handler, device_t *device) + { + UpdateHandler = handler; + UpdateParam = device; } private: + void WriteReg(int r, int v); + uint32_t volume_calc(OPL_SLOT const &OP) const { return OP.TLL + uint32_t(OP.volume) + (LFO_AM & OP.AMmask); @@ -961,6 +1131,33 @@ private: } + /* lock/unlock for common table */ + static int LockTable(device_t *device) + { + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + + return 0; + } + + static void UnLockTable() + { + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + CloseTable(); + } + static int init_tables(); static void CloseTable() @@ -1781,13 +1978,11 @@ void FM_OPL::ResetChip() #if BUILD_Y8950 if(type&OPL_TYPE_ADPCM) { - YM_DELTAT *DELTAT = deltat; - - DELTAT->freqbase = freqbase; - DELTAT->output_pointer = &output_deltat[0]; - DELTAT->portshift = 5; - DELTAT->output_range = 1<<23; - DELTAT->ADPCM_Reset(0,YM_DELTAT::EMULATION_MODE_NORMAL,device); + deltat->freqbase = freqbase; + deltat->output_pointer = &output_deltat[0]; + deltat->portshift = 5; + deltat->output_range = 1<<23; + deltat->ADPCM_Reset(0,YM_DELTAT::EMULATION_MODE_NORMAL,device); } #endif } @@ -1936,197 +2131,6 @@ static void OPL_save_state(FM_OPL *OPL, device_t *device) device->machine().save().register_postload(save_prepost_delegate(FUNC(FM_OPL::postload), OPL)); } -static void OPL_clock_changed(FM_OPL *OPL, uint32_t clock, uint32_t rate) -{ - OPL->clock = clock; - OPL->rate = rate; - - /* init global tables */ - OPL->initialize(); -} - - -/* Create one of virtual YM3812/YM3526/Y8950 */ -/* 'clock' is chip clock in Hz */ -/* 'rate' is sampling rate */ -static FM_OPL *OPLCreate(device_t *device, uint32_t clock, uint32_t rate, int type) -{ - char *ptr; - FM_OPL *OPL; - int state_size; - - if (FM_OPL::LockTable(device) == -1) return nullptr; - - /* calculate OPL state size */ - state_size = sizeof(FM_OPL); - -#if BUILD_Y8950 - if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); -#endif - - /* allocate memory block */ - ptr = (char *)auto_alloc_array_clear(device->machine(), uint8_t, state_size); - - OPL = (FM_OPL *)ptr; - - ptr += sizeof(FM_OPL); - -#if BUILD_Y8950 - if (type&OPL_TYPE_ADPCM) - { - OPL->deltat = (YM_DELTAT *)ptr; - } - ptr += sizeof(YM_DELTAT); -#endif - - OPL->device = device; - OPL->type = type; - OPL_clock_changed(OPL, clock, rate); - - return OPL; -} - -/* Destroy one of virtual YM3812 */ -static void OPLDestroy(FM_OPL *OPL) -{ - FM_OPL::UnLockTable(); - auto_free(OPL->device->machine(), OPL); -} - -/* Optional handlers */ - -static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,device_t *device) -{ - OPL->timer_handler = timer_handler; - OPL->TimerParam = device; -} -static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,device_t *device) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = device; -} -static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,device_t *device) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = device; -} - -static int OPLWrite(FM_OPL *OPL,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - OPL->address = v & 0xff; - } - else - { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - OPL->WriteReg(OPL->address,v); - } - return OPL->status>>7; -} - -static unsigned char OPLRead(FM_OPL *OPL,int a) -{ - if( !(a&1) ) - { - /* status port */ - - #if BUILD_Y8950 - - if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ - { - return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); - } - - #endif - - /* OPL and OPL2 */ - return OPL->status & (OPL->statusmask|0x80); - } - -#if BUILD_Y8950 - /* data port */ - switch(OPL->address) - { - case 0x05: /* KeyBoard IN */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_r) - return OPL->keyboardhandler_r(OPL->keyboard_param); - else - OPL->device->logerror("Y8950: read unmapped KEYBOARD port\n"); - } - return 0; - - case 0x0f: /* ADPCM-DATA */ - if(OPL->type&OPL_TYPE_ADPCM) - { - uint8_t val; - - val = OPL->deltat->ADPCM_Read(); - /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ - return val; - } - return 0; - - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - if(OPL->porthandler_r) - return OPL->porthandler_r(OPL->port_param); - else - OPL->device->logerror("Y8950:read unmapped I/O port\n"); - } - return 0; - case 0x1a: /* PCM-DATA */ - if(OPL->type&OPL_TYPE_ADPCM) - { - OPL->device->logerror("Y8950 A/D conversion is accessed but not implemented !\n"); - return 0x80; /* 2's complement PCM data - result from A/D conversion */ - } - return 0; - } -#endif - - return 0xff; -} - -/* CSM Key Controll */ -static inline void CSMKeyControll(OPL_CH *CH) -{ - CH->SLOT[SLOT1].KEYON(4); - CH->SLOT[SLOT2].KEYON(4); - - /* The key off should happen exactly one sample later - not implemented correctly yet */ - - CH->SLOT[SLOT1].KEYOFF(~4); - CH->SLOT[SLOT2].KEYOFF(~4); -} - - -static int OPLTimerOver(FM_OPL *OPL,int c) -{ - if( c ) - { /* Timer B */ - OPL->STATUS_SET(0x20); - } - else - { /* Timer A */ - OPL->STATUS_SET(0x40); - /* CSM mode key,TL controll */ - if( OPL->mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - for(ch=0; ch<9; ch++) - CSMKeyControll( &OPL->P_CH[ch] ); - } - } - /* reload timer */ - if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,OPL->TimerBase * OPL->T[c]); - return OPL->status>>7; -} - #define MAX_OPL_CHIPS 2 @@ -2135,13 +2139,13 @@ static int OPLTimerOver(FM_OPL *OPL,int c) void ym3812_clock_changed(void *chip, uint32_t clock, uint32_t rate) { - OPL_clock_changed((FM_OPL *)chip, clock, rate); + reinterpret_cast<FM_OPL *>(chip)->clock_changed(clock, rate); } void * ym3812_init(device_t *device, uint32_t clock, uint32_t rate) { /* emulator create */ - FM_OPL *YM3812 = OPLCreate(device,clock,rate,OPL_TYPE_YM3812); + FM_OPL *YM3812 = FM_OPL::Create(device,clock,rate,OPL_TYPE_YM3812); if (YM3812) { OPL_save_state(YM3812, device); @@ -2155,7 +2159,7 @@ void ym3812_shutdown(void *chip) FM_OPL *YM3812 = (FM_OPL *)chip; /* emulator shutdown */ - OPLDestroy(YM3812); + delete YM3812; } void ym3812_reset_chip(void *chip) { @@ -2166,35 +2170,32 @@ void ym3812_reset_chip(void *chip) int ym3812_write(void *chip, int a, int v) { FM_OPL *YM3812 = (FM_OPL *)chip; - return OPLWrite(YM3812, a, v); + return YM3812->Write(a, v); } unsigned char ym3812_read(void *chip, int a) { FM_OPL *YM3812 = (FM_OPL *)chip; /* YM3812 always returns bit2 and bit1 in HIGH state */ - return OPLRead(YM3812, a) | 0x06 ; + return YM3812->Read(a) | 0x06 ; } int ym3812_timer_over(void *chip, int c) { FM_OPL *YM3812 = (FM_OPL *)chip; - return OPLTimerOver(YM3812, c); + return YM3812->TimerOver(c); } void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, device_t *device) { - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetTimerHandler(YM3812, timer_handler, device); + reinterpret_cast<FM_OPL *>(chip)->SetTimerHandler(timer_handler, device); } void ym3812_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,device_t *device) { - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetIRQHandler(YM3812, IRQHandler, device); + reinterpret_cast<FM_OPL *>(chip)->SetIRQHandler(IRQHandler, device); } void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,device_t *device) { - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetUpdateHandler(YM3812, UpdateHandler, device); + reinterpret_cast<FM_OPL *>(chip)->SetUpdateHandler(UpdateHandler, device); } @@ -2268,13 +2269,13 @@ void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length) void ym3526_clock_changed(void *chip, uint32_t clock, uint32_t rate) { - OPL_clock_changed((FM_OPL *)chip, clock, rate); + reinterpret_cast<FM_OPL *>(chip)->clock_changed(clock, rate); } void *ym3526_init(device_t *device, uint32_t clock, uint32_t rate) { /* emulator create */ - FM_OPL *YM3526 = OPLCreate(device,clock,rate,OPL_TYPE_YM3526); + FM_OPL *YM3526 = FM_OPL::Create(device,clock,rate,OPL_TYPE_YM3526); if (YM3526) { OPL_save_state(YM3526, device); @@ -2287,7 +2288,7 @@ void ym3526_shutdown(void *chip) { FM_OPL *YM3526 = (FM_OPL *)chip; /* emulator shutdown */ - OPLDestroy(YM3526); + delete YM3526; } void ym3526_reset_chip(void *chip) { @@ -2298,35 +2299,32 @@ void ym3526_reset_chip(void *chip) int ym3526_write(void *chip, int a, int v) { FM_OPL *YM3526 = (FM_OPL *)chip; - return OPLWrite(YM3526, a, v); + return YM3526->Write(a, v); } unsigned char ym3526_read(void *chip, int a) { FM_OPL *YM3526 = (FM_OPL *)chip; /* YM3526 always returns bit2 and bit1 in HIGH state */ - return OPLRead(YM3526, a) | 0x06 ; + return YM3526->Read(a) | 0x06 ; } int ym3526_timer_over(void *chip, int c) { FM_OPL *YM3526 = (FM_OPL *)chip; - return OPLTimerOver(YM3526, c); + return YM3526->TimerOver(c); } void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, device_t *device) { - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLSetTimerHandler(YM3526, timer_handler, device); + reinterpret_cast<FM_OPL *>(chip)->SetTimerHandler(timer_handler, device); } void ym3526_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,device_t *device) { - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLSetIRQHandler(YM3526, IRQHandler, device); + reinterpret_cast<FM_OPL *>(chip)->SetIRQHandler(IRQHandler, device); } void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,device_t *device) { - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLSetUpdateHandler(YM3526, UpdateHandler, device); + reinterpret_cast<FM_OPL *>(chip)->SetUpdateHandler(UpdateHandler, device); } @@ -2413,7 +2411,7 @@ static void Y8950_deltat_status_reset(void *chip, uint8_t changebits) void *y8950_init(device_t *device, uint32_t clock, uint32_t rate) { /* emulator create */ - FM_OPL *Y8950 = OPLCreate(device,clock,rate,OPL_TYPE_Y8950); + FM_OPL *Y8950 = FM_OPL::Create(device,clock,rate,OPL_TYPE_Y8950); if (Y8950) { Y8950->deltat->status_set_handler = Y8950_deltat_status_set; @@ -2436,7 +2434,7 @@ void y8950_shutdown(void *chip) { FM_OPL *Y8950 = (FM_OPL *)chip; /* emulator shutdown */ - OPLDestroy(Y8950); + delete Y8950; } void y8950_reset_chip(void *chip) { @@ -2447,34 +2445,31 @@ void y8950_reset_chip(void *chip) int y8950_write(void *chip, int a, int v) { FM_OPL *Y8950 = (FM_OPL *)chip; - return OPLWrite(Y8950, a, v); + return Y8950->Write(a, v); } unsigned char y8950_read(void *chip, int a) { FM_OPL *Y8950 = (FM_OPL *)chip; - return OPLRead(Y8950, a); + return Y8950->Read(a); } int y8950_timer_over(void *chip, int c) { FM_OPL *Y8950 = (FM_OPL *)chip; - return OPLTimerOver(Y8950, c); + return Y8950->TimerOver(c); } void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, device_t *device) { - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLSetTimerHandler(Y8950, timer_handler, device); + reinterpret_cast<FM_OPL *>(chip)->SetTimerHandler(timer_handler, device); } void y8950_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,device_t *device) { - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLSetIRQHandler(Y8950, IRQHandler, device); + reinterpret_cast<FM_OPL *>(chip)->SetIRQHandler(IRQHandler, device); } void y8950_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,device_t *device) { - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLSetUpdateHandler(Y8950, UpdateHandler, device); + reinterpret_cast<FM_OPL *>(chip)->SetUpdateHandler(UpdateHandler, device); } void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ) @@ -2496,7 +2491,7 @@ void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length) int i; FM_OPL *OPL = (FM_OPL *)chip; uint8_t rhythm = OPL->rhythm&0x20; - YM_DELTAT *DELTAT = OPL->deltat; + YM_DELTAT &DELTAT = *OPL->deltat; OPLSAMPLE *buf = buffer; for( i=0; i < length ; i++ ) @@ -2509,8 +2504,8 @@ void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length) OPL->advance_lfo(); /* deltaT ADPCM */ - if( DELTAT->portstate&0x80 ) - DELTAT->ADPCM_CALC(); + if( DELTAT.portstate&0x80 ) + DELTAT.ADPCM_CALC(); /* FM part */ OPL->CALC_CH(OPL->P_CH[0]); |