X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=source%2Fsrc%2Fvm%2Ffmgen%2Fopna.cpp;h=00628c756f52fc0f20e75ff737521b2c4bd73ecb;hb=7e393b83d3a6a82a67c7b1fa0ed67448e61bdc83;hp=e700f777c62039e8334fb1d111811123364f1a5f;hpb=7b6f18a5c866a570c115fa17060bfeccd26777eb;p=csp-qt%2Fcommon_source_project-fm7.git diff --git a/source/src/vm/fmgen/opna.cpp b/source/src/vm/fmgen/opna.cpp index e700f777c..00628c756 100644 --- a/source/src/vm/fmgen/opna.cpp +++ b/source/src/vm/fmgen/opna.cpp @@ -9,11 +9,16 @@ #include "opna.h" #include "fmgeninl.h" +#include "../../common.h" #include "../../fileio.h" +#include "../../statesub.h" + + #define BUILD_OPN #define BUILD_OPNA #define BUILD_OPNB +#define BUILD_OPN2 // TOFIX: @@ -37,7 +42,7 @@ namespace FM // --------------------------------------------------------------------------- // OPNBase -#if defined(BUILD_OPN) || defined(BUILD_OPNA) || defined (BUILD_OPNB) +#if defined(BUILD_OPN) || defined(BUILD_OPNA) || defined (BUILD_OPNB) || defined(BUILD_OPN2) uint32 OPNBase::lfotable[8]; // OPNA/B —p @@ -45,6 +50,8 @@ OPNBase::OPNBase() { is_ay3_891x = false; prescale = 0; + static int __num = 0; + chip_num = __num++; } // ƒpƒ‰ƒ[ƒ^ƒZƒbƒg @@ -190,45 +197,73 @@ void OPNBase::Intr(bool value) // --------------------------------------------------------------------------- // ƒXƒe[ƒgƒZ[ƒu // -#define OPN_BASE_STATE_VERSION 2 +#define OPN_BASE_STATE_VERSION 4 + +void OPNBase::DeclState(void *f) +{ + Timer::DeclState(f); + DECL_STATE_ENTRY_INT32(fmvolume_l); + DECL_STATE_ENTRY_INT32(fmvolume_r); + DECL_STATE_ENTRY_UINT32(clock); + DECL_STATE_ENTRY_UINT32(rate); + DECL_STATE_ENTRY_UINT32(psgrate); + DECL_STATE_ENTRY_UINT32(status); + DECL_STATE_ENTRY_BOOL(interrupt); + DECL_STATE_ENTRY_UINT8(prescale); + chip.DeclState(f); + psg.DeclState(f); +} void OPNBase::SaveState(void *f) { FILEIO *state_fio = (FILEIO *)f; - state_fio->FputUint32(OPN_BASE_STATE_VERSION); - - Timer::SaveState(f); - state_fio->FputInt32(fmvolume_l); - state_fio->FputInt32(fmvolume_r); - state_fio->FputUint32(clock); - state_fio->FputUint32(rate); - state_fio->FputUint32(psgrate); - state_fio->FputUint32(status); - state_fio->FputBool(interrupt); - state_fio->FputUint8(prescale); + if(state_entry != NULL) { + state_entry->save_state(state_fio); + } chip.SaveState(f); psg.SaveState(f); +// state_fio->FputUint32_BE(OPN_BASE_STATE_VERSION); + +// Timer::SaveState(f); +// state_fio->FputInt32_BE(fmvolume_l); +// state_fio->FputInt32_BE(fmvolume_r); +// state_fio->FputUint32_BE(clock); +// state_fio->FputUint32_BE(rate); +// state_fio->FputUint32_BE(psgrate); +// state_fio->FputUint32_BE(status); +// state_fio->FputBool(interrupt); +// state_fio->FputUint8(prescale); } bool OPNBase::LoadState(void *f) { FILEIO *state_fio = (FILEIO *)f; - - if(state_fio->FgetUint32() != OPN_BASE_STATE_VERSION) { - return false; + bool mb = false; + if(state_entry != NULL) { + mb = state_entry->load_state(state_fio); } - if(!Timer::LoadState(f)) { - return false; + if(!mb) return false; +// if(state_fio->FgetUint32_BE() != OPN_BASE_STATE_VERSION) { +// return false; +// } +// if(!Timer::LoadState(f)) { +// return false; +// } +// fmvolume_l = state_fio->FgetInt32_BE(); +// fmvolume_r = state_fio->FgetInt32_BE(); +// clock = state_fio->FgetUint32_BE(); +// rate = state_fio->FgetUint32_BE(); +// psgrate = state_fio->FgetUint32_BE(); +// status = state_fio->FgetUint32_BE(); +// interrupt = state_fio->FgetBool(); +// prescale = state_fio->FgetUint8(); + { + // Make force-restore around prescaler and timers. 20180625 K.O + uint bak = prescale; + prescale = 10; + SetPrescaler(bak); } - fmvolume_l = state_fio->FgetInt32(); - fmvolume_r = state_fio->FgetInt32(); - clock = state_fio->FgetUint32(); - rate = state_fio->FgetUint32(); - psgrate = state_fio->FgetUint32(); - status = state_fio->FgetUint32(); - interrupt = state_fio->FgetBool(); - prescale = state_fio->FgetUint8(); if(!chip.LoadState(f)) { return false; } @@ -238,7 +273,7 @@ bool OPNBase::LoadState(void *f) return true; } -#endif // defined(BUILD_OPN) || defined(BUILD_OPNA) || defined (BUILD_OPNB) +#endif // defined(BUILD_OPN) || defined(BUILD_OPNA) || defined (BUILD_OPNB) || defined(BUILD_OPN2) // --------------------------------------------------------------------------- // YM2203 @@ -445,18 +480,42 @@ void OPN::Mix(Sample* buffer, int nsamples) // --------------------------------------------------------------------------- // ƒXƒe[ƒgƒZ[ƒu // -#define OPN_STATE_VERSION 1 +#define OPN_STATE_VERSION 2 + +void OPN::DeclState(void *f) +{ + + p_logger = (CSP_Logger *)f; + state_entry = new csp_state_utils(OPN_STATE_VERSION, chip_num, _T("FMGEN::OPN::"), p_logger); + + OPNBase::DeclState(f); + + for(int i = 0; i < 3; i++) { + DECL_STATE_ENTRY_UINT32_MEMBER((fnum[i]), i); + DECL_STATE_ENTRY_UINT32_MEMBER((fnum3[i]), i); + } + DECL_STATE_ENTRY_1D_ARRAY(fnum2, sizeof(fnum2)); + for(int i = 0; i < 3; i++) { + ch[i].DeclState(f); + } +} void OPN::SaveState(void *f) { FILEIO *state_fio = (FILEIO *)f; - - state_fio->FputUint32(OPN_STATE_VERSION); - OPNBase::SaveState(f); - state_fio->Fwrite(fnum, sizeof(fnum), 1); - state_fio->Fwrite(fnum3, sizeof(fnum3), 1); - state_fio->Fwrite(fnum2, sizeof(fnum2), 1); +// state_fio->FputUint32_BE(OPN_STATE_VERSION); +// +// OPNBase::SaveState(f); +// for(int i = 0; i < 3; i++) { +// state_fio->FputUint32_BE(fnum[i]); +// } +// for(int i = 0; i < 3; i++) { +// state_fio->FputUint32_BE(fnum3[i]); +// } +// //state_fio->Fwrite(fnum, sizeof(fnum), 1); +// //state_fio->Fwrite(fnum3, sizeof(fnum3), 1); +// state_fio->Fwrite(fnum2, sizeof(fnum2), 1); for(int i = 0; i < 3; i++) { ch[i].SaveState(f); } @@ -466,15 +525,24 @@ bool OPN::LoadState(void *f) { FILEIO *state_fio = (FILEIO *)f; - if(state_fio->FgetUint32() != OPN_STATE_VERSION) { - return false; - } - if(!OPNBase::LoadState(f)) { - return false; - } - state_fio->Fread(fnum, sizeof(fnum), 1); - state_fio->Fread(fnum3, sizeof(fnum3), 1); - state_fio->Fread(fnum2, sizeof(fnum2), 1); + bool mb = false; + mb = OPNBase::LoadState(f); + if(!mb) return false; +// if(state_fio->FgetUint32_BE() != OPN_STATE_VERSION) { +// return false; +// } +// if(!OPNBase::LoadState(f)) { +// return false; +// } +// for(int i = 0; i < 3; i++) { +// fnum[i] = state_fio->FgetUint32_BE(); +// } +// for(int i = 0; i < 3; i++) { +// fnum3[i] = state_fio->FgetUint32_BE(); +// } +// //state_fio->Fread(fnum, sizeof(fnum), 1); +// //state_fio->Fread(fnum3, sizeof(fnum3), 1); +// state_fio->Fread(fnum2, sizeof(fnum2), 1); for(int i = 0; i < 3; i++) { if(!ch[i].LoadState(f)) { return false; @@ -1307,55 +1375,124 @@ void OPNABase::Mix6(Sample* buffer, int nsamples, int activech) // #define OPNA_BASE_STATE_VERSION 2 +void OPNABase::DeclState(void *f) +{ + + OPNBase::DeclState(f); + + DECL_STATE_ENTRY_1D_ARRAY(pan, sizeof(pan)); + DECL_STATE_ENTRY_1D_ARRAY(fnum2, sizeof(fnum2)); + DECL_STATE_ENTRY_UINT8(reg22); + DECL_STATE_ENTRY_UINT32(reg29); + DECL_STATE_ENTRY_UINT32(stmask); + DECL_STATE_ENTRY_UINT32(statusnext); + DECL_STATE_ENTRY_UINT32(lfocount); + DECL_STATE_ENTRY_UINT32(lfodcount); + //state_fio->Fwrite(fnum, sizeof(fnum), 1); + //state_fio->Fwrite(fnum3, sizeof(fnum3), 1); + for(int i = 0; i < 6; i++) { + DECL_STATE_ENTRY_UINT32_MEMBER((fnum[i]), i); + } + for(int i = 0; i < 3; i++) { + DECL_STATE_ENTRY_UINT32_MEMBER((fnum3[i]), i); + } + DECL_STATE_ENTRY_1D_ARRAY(adpcmbuf, 0x40000); + DECL_STATE_ENTRY_UINT32(adpcmmask); + DECL_STATE_ENTRY_UINT32(adpcmnotice); + DECL_STATE_ENTRY_UINT32(startaddr); + DECL_STATE_ENTRY_UINT32(stopaddr); + DECL_STATE_ENTRY_UINT32(memaddr); + DECL_STATE_ENTRY_UINT32(limitaddr); + DECL_STATE_ENTRY_INT32(adpcmlevel); + DECL_STATE_ENTRY_INT32(adpcmvolume_l); + DECL_STATE_ENTRY_INT32(adpcmvolume_r); + DECL_STATE_ENTRY_INT32(adpcmvol_l); + DECL_STATE_ENTRY_INT32(adpcmvol_r); + DECL_STATE_ENTRY_UINT32(deltan); + DECL_STATE_ENTRY_INT32(adplc); + DECL_STATE_ENTRY_INT32(adpld); + DECL_STATE_ENTRY_UINT32(adplbase); + DECL_STATE_ENTRY_INT32(adpcmx); + DECL_STATE_ENTRY_INT32(adpcmd); + DECL_STATE_ENTRY_INT32(adpcmout_l); + DECL_STATE_ENTRY_INT32(adpcmout_r); + DECL_STATE_ENTRY_INT32(apout0_l); + DECL_STATE_ENTRY_INT32(apout0_r); + DECL_STATE_ENTRY_INT32(apout1_l); + DECL_STATE_ENTRY_INT32(apout1_r); + DECL_STATE_ENTRY_UINT32(adpcmreadbuf); + DECL_STATE_ENTRY_BOOL(adpcmplay); + DECL_STATE_ENTRY_INT8(granuality); + DECL_STATE_ENTRY_BOOL(adpcmmask_); + DECL_STATE_ENTRY_UINT8(control1); + DECL_STATE_ENTRY_UINT8(control2); + DECL_STATE_ENTRY_1D_ARRAY(adpcmreg, sizeof(adpcmreg)); + DECL_STATE_ENTRY_INT32(rhythmmask_); + + for(int i = 0; i < 6; i++) { + ch[i].DeclState(f); + } +} void OPNABase::SaveState(void *f) { FILEIO *state_fio = (FILEIO *)f; + if(state_entry != NULL) { + state_entry->save_state(state_fio); + } + chip.SaveState(f); + psg.SaveState(f); - state_fio->FputUint32(OPNA_BASE_STATE_VERSION); +// state_fio->FputUint32_BE(OPNA_BASE_STATE_VERSION); - OPNBase::SaveState(f); - state_fio->Fwrite(pan, sizeof(pan), 1); - state_fio->Fwrite(fnum2, sizeof(fnum2), 1); - state_fio->FputUint8(reg22); - state_fio->FputUint32(reg29); - state_fio->FputUint32(stmask); - state_fio->FputUint32(statusnext); - state_fio->FputUint32(lfocount); - state_fio->FputUint32(lfodcount); - state_fio->Fwrite(fnum, sizeof(fnum), 1); - state_fio->Fwrite(fnum3, sizeof(fnum3), 1); - state_fio->Fwrite(adpcmbuf, 0x40000, 1); - state_fio->FputUint32(adpcmmask); - state_fio->FputUint32(adpcmnotice); - state_fio->FputUint32(startaddr); - state_fio->FputUint32(stopaddr); - state_fio->FputUint32(memaddr); - state_fio->FputUint32(limitaddr); - state_fio->FputInt32(adpcmlevel); - state_fio->FputInt32(adpcmvolume_l); - state_fio->FputInt32(adpcmvolume_r); - state_fio->FputInt32(adpcmvol_l); - state_fio->FputInt32(adpcmvol_r); - state_fio->FputUint32(deltan); - state_fio->FputInt32(adplc); - state_fio->FputInt32(adpld); - state_fio->FputUint32(adplbase); - state_fio->FputInt32(adpcmx); - state_fio->FputInt32(adpcmd); - state_fio->FputInt32(adpcmout_l); - state_fio->FputInt32(adpcmout_r); - state_fio->FputInt32(apout0_l); - state_fio->FputInt32(apout0_r); - state_fio->FputInt32(apout1_l); - state_fio->FputInt32(apout1_r); - state_fio->FputUint32(adpcmreadbuf); - state_fio->FputBool(adpcmplay); - state_fio->FputInt8(granuality); - state_fio->FputBool(adpcmmask_); - state_fio->FputUint8(control1); - state_fio->FputUint8(control2); - state_fio->Fwrite(adpcmreg, sizeof(adpcmreg), 1); - state_fio->FputInt32(rhythmmask_); +// OPNBase::SaveState(f); +// state_fio->Fwrite(pan, sizeof(pan), 1); +// state_fio->Fwrite(fnum2, sizeof(fnum2), 1); +// state_fio->FputUint8(reg22); +// state_fio->FputUint32_BE(reg29); +// state_fio->FputUint32_BE(stmask); +// state_fio->FputUint32_BE(statusnext); +// state_fio->FputUint32_BE(lfocount); +// state_fio->FputUint32_BE(lfodcount); +// //state_fio->Fwrite(fnum, sizeof(fnum), 1); +// //state_fio->Fwrite(fnum3, sizeof(fnum3), 1); +// for(int i = 0; i < 6; i++) { +// state_fio->FputUint32_BE(fnum[i]); +// } +// for(int i = 0; i < 3; i++) { +// state_fio->FputUint32_BE(fnum3[i]); +// } +// state_fio->Fwrite(adpcmbuf, 0x40000, 1); +// state_fio->FputUint32_BE(adpcmmask); +// state_fio->FputUint32_BE(adpcmnotice); +// state_fio->FputUint32_BE(startaddr); +// state_fio->FputUint32_BE(stopaddr); +// state_fio->FputUint32_BE(memaddr); +// state_fio->FputUint32_BE(limitaddr); +// state_fio->FputInt32_BE(adpcmlevel); +// state_fio->FputInt32_BE(adpcmvolume_l); +// state_fio->FputInt32_BE(adpcmvolume_r); +// state_fio->FputInt32_BE(adpcmvol_l); +// state_fio->FputInt32_BE(adpcmvol_r); +// state_fio->FputUint32_BE(deltan); +// state_fio->FputInt32_BE(adplc); +// state_fio->FputInt32_BE(adpld); +// state_fio->FputUint32_BE(adplbase); +// state_fio->FputInt32_BE(adpcmx); +// state_fio->FputInt32_BE(adpcmd); +// state_fio->FputInt32_BE(adpcmout_l); +// state_fio->FputInt32_BE(adpcmout_r); +// state_fio->FputInt32_BE(apout0_l); +// state_fio->FputInt32_BE(apout0_r); +// state_fio->FputInt32_BE(apout1_l); +// state_fio->FputInt32_BE(apout1_r); +// state_fio->FputUint32_BE(adpcmreadbuf); +// state_fio->FputBool(adpcmplay); +// state_fio->FputInt8(granuality); +// state_fio->FputBool(adpcmmask_); +// state_fio->FputUint8(control1); +// state_fio->FputUint8(control2); +// state_fio->Fwrite(adpcmreg, sizeof(adpcmreg), 1); +// state_fio->FputInt32_BE(rhythmmask_); for(int i = 0; i < 6; i++) { ch[i].SaveState(f); } @@ -1365,54 +1502,77 @@ bool OPNABase::LoadState(void *f) { FILEIO *state_fio = (FILEIO *)f; - if(state_fio->FgetUint32() != OPNA_BASE_STATE_VERSION) { + bool mb = false; + if(state_entry != NULL) { + mb = state_entry->load_state(state_fio); + } + if(!mb) return false; + { + // Make force-restore around prescaler and timers. 20180625 K.O + uint bak = prescale; + prescale = 10; + SetPrescaler(bak); + } + if(!chip.LoadState(f)) { return false; } - if(!OPNBase::LoadState(f)) { + if(!psg.LoadState(f)) { return false; } - state_fio->Fread(pan, sizeof(pan), 1); - state_fio->Fread(fnum2, sizeof(fnum2), 1); - reg22 = state_fio->FgetUint8(); - reg29 = state_fio->FgetUint32(); - stmask = state_fio->FgetUint32(); - statusnext = state_fio->FgetUint32(); - lfocount = state_fio->FgetUint32(); - lfodcount = state_fio->FgetUint32(); - state_fio->Fread(fnum, sizeof(fnum), 1); - state_fio->Fread(fnum3, sizeof(fnum3), 1); - state_fio->Fread(adpcmbuf, 0x40000, 1); - adpcmmask = state_fio->FgetUint32(); - adpcmnotice = state_fio->FgetUint32(); - startaddr = state_fio->FgetUint32(); - stopaddr = state_fio->FgetUint32(); - memaddr = state_fio->FgetUint32(); - limitaddr = state_fio->FgetUint32(); - adpcmlevel = state_fio->FgetInt32(); - adpcmvolume_l = state_fio->FgetInt32(); - adpcmvolume_r = state_fio->FgetInt32(); - adpcmvol_l = state_fio->FgetInt32(); - adpcmvol_r = state_fio->FgetInt32(); - deltan = state_fio->FgetUint32(); - adplc = state_fio->FgetInt32(); - adpld = state_fio->FgetInt32(); - adplbase = state_fio->FgetUint32(); - adpcmx = state_fio->FgetInt32(); - adpcmd = state_fio->FgetInt32(); - adpcmout_l = state_fio->FgetInt32(); - adpcmout_r = state_fio->FgetInt32(); - apout0_l = state_fio->FgetInt32(); - apout0_r = state_fio->FgetInt32(); - apout1_l = state_fio->FgetInt32(); - apout1_r = state_fio->FgetInt32(); - adpcmreadbuf = state_fio->FgetUint32(); - adpcmplay = state_fio->FgetBool(); - granuality = state_fio->FgetInt8(); - adpcmmask_ = state_fio->FgetBool(); - control1 = state_fio->FgetUint8(); - control2 = state_fio->FgetUint8(); - state_fio->Fread(adpcmreg, sizeof(adpcmreg), 1); - rhythmmask_ = state_fio->FgetInt32(); +// if(state_fio->FgetUint32_BE() != OPNA_BASE_STATE_VERSION) { +// return false; +// } +// if(!OPNBase::LoadState(f)) { +// return false; +// } +// state_fio->Fread(pan, sizeof(pan), 1); +// state_fio->Fread(fnum2, sizeof(fnum2), 1); +// reg22 = state_fio->FgetUint8(); +// reg29 = state_fio->FgetUint32_BE(); +// stmask = state_fio->FgetUint32_BE(); +// statusnext = state_fio->FgetUint32_BE(); +// lfocount = state_fio->FgetUint32_BE(); +// lfodcount = state_fio->FgetUint32_BE(); +// //state_fio->Fread(fnum, sizeof(fnum), 1); +// //state_fio->Fread(fnum3, sizeof(fnum3), 1); +// for(int i = 0; i < 6; i++) { +// fnum[i] = state_fio->FgetUint32_BE(); +// } +// for(int i = 0; i < 3; i++) { +// fnum3[i] = state_fio->FgetUint32_BE(); +// } +// state_fio->Fread(adpcmbuf, 0x40000, 1); +// adpcmmask = state_fio->FgetUint32_BE(); +// adpcmnotice = state_fio->FgetUint32_BE(); +// startaddr = state_fio->FgetUint32_BE(); +// stopaddr = state_fio->FgetUint32_BE(); +// memaddr = state_fio->FgetUint32_BE(); +// limitaddr = state_fio->FgetUint32_BE(); +// adpcmlevel = state_fio->FgetInt32_BE(); +// adpcmvolume_l = state_fio->FgetInt32_BE(); +// adpcmvolume_r = state_fio->FgetInt32_BE(); +// adpcmvol_l = state_fio->FgetInt32_BE(); +// adpcmvol_r = state_fio->FgetInt32_BE(); +// deltan = state_fio->FgetUint32_BE(); +// adplc = state_fio->FgetInt32_BE(); +// adpld = state_fio->FgetInt32_BE(); +// adplbase = state_fio->FgetUint32_BE(); +// adpcmx = state_fio->FgetInt32_BE(); +// adpcmd = state_fio->FgetInt32_BE(); +// adpcmout_l = state_fio->FgetInt32_BE(); +// adpcmout_r = state_fio->FgetInt32_BE(); +// apout0_l = state_fio->FgetInt32_BE(); +// apout0_r = state_fio->FgetInt32_BE(); +// apout1_l = state_fio->FgetInt32_BE(); +// apout1_r = state_fio->FgetInt32_BE(); +// adpcmreadbuf = state_fio->FgetUint32_BE(); +// adpcmplay = state_fio->FgetBool(); +// granuality = state_fio->FgetInt8(); +// adpcmmask_ = state_fio->FgetBool(); +// control1 = state_fio->FgetUint8(); +// control2 = state_fio->FgetUint8(); +/// state_fio->Fread(adpcmreg, sizeof(adpcmreg), 1); +// rhythmmask_ = state_fio->FgetInt32_BE(); for(int i = 0; i < 6; i++) { if(!ch[i].LoadState(f)) { return false; @@ -1536,49 +1696,60 @@ bool OPNA::LoadRhythmSample(const _TCHAR* path) FILEIO file; uint32 fsize; _TCHAR buf[_MAX_PATH] = _T(""); + memset(buf, 0x00, sizeof(buf)); if (path) - _tcsncpy(buf, path, _MAX_PATH); - _tcsncat(buf, _T("2608_"), _MAX_PATH); - _tcsncat(buf, rhythmname[i], _MAX_PATH); - _tcsncat(buf, _T(".WAV"), _MAX_PATH); + _tcsncpy(buf, path, _MAX_PATH - 1); + _tcsncat(buf, _T("2608_"), _MAX_PATH - 1); + _tcsncat(buf, rhythmname[i], _MAX_PATH- 1); + _tcsncat(buf, _T(".WAV"), _MAX_PATH - 1); if (!file.Fopen(buf, FILEIO_READ_BINARY)) { if (i != 5) break; - if (path) - _tcsncpy(buf, path, _MAX_PATH); - _tcsncpy(buf, _T("2608_RYM.WAV"), _MAX_PATH); + memset(buf, 0x00, sizeof(buf)); + if (path) { + _tcsncpy(buf, path, _MAX_PATH - 1); + } + _tcsncat(buf, _T("2608_RYM.WAV"), _MAX_PATH - 1); if (!file.Fopen(buf, FILEIO_READ_BINARY)) break; } - struct - { - uint32 chunksize; - uint16 tag; - uint16 nch; - uint32 rate; - uint32 avgbytes; - uint16 align; - uint16 bps; - uint16 size; - } whdr; - - file.Fseek(0x10, FILEIO_SEEK_SET); + wav_header_t whdr; + wav_chunk_t chunk; + file.Fread(&whdr, sizeof(whdr), 1); uint8 subchunkname[4]; - fsize = 4 + whdr.chunksize - sizeof(whdr); - do + bool is_eof = false; + file.Fseek(EndianFromLittle_DWORD(whdr.fmt_chunk.size) - 16, FILEIO_SEEK_CUR); + while(1) { - file.Fseek(fsize, FILEIO_SEEK_CUR); - file.Fread(&subchunkname, 4, 1); - file.Fread(&fsize, 4, 1); - } while (memcmp("data", subchunkname, 4)); - + if(file.Fread(&chunk, sizeof(chunk), 1) != 1) { + is_eof = true; + break; + } + if(strncmp(chunk.id, "data", 4) == 0) { + break; + } + file.Fseek(EndianFromLittle_DWORD(chunk.size), FILEIO_SEEK_CUR); + } + if(is_eof) { +// fsize = 8192; +// rhythm[i].rate = whdr.sample_rate; +// rhythm[i].step = rhythm[i].rate * 1024 / rate; +// rhythm[i].pos = rhythm[i].size = fsize * 1024; +// delete rhythm[i].sample; +// rhythm[i].sample = new int16[fsize]; +// memset(rhythm[i].sample, 0x00, fsize * 2); + file.Fclose(); + break; + } + fsize = EndianFromLittle_DWORD(chunk.size); + fsize /= 2; - if (fsize >= 0x100000 || whdr.tag != 1 || whdr.nch != 1) + if ((fsize >= 0x100000) || (EndianFromLittle_WORD(whdr.format_id) != 1) || (EndianFromLittle_WORD(whdr.channels) != 1)) break; fsize = Max(fsize, (1<<31)/1024); @@ -1586,15 +1757,27 @@ bool OPNA::LoadRhythmSample(const _TCHAR* path) rhythm[i].sample = new int16[fsize]; if (!rhythm[i].sample) break; + for(int __iptr = 0; __iptr < fsize; __iptr++) { + union { + int16_t s16; + struct { + uint8_t l, h; + } b; + } pair16; + pair16.b.l = file.FgetUint8(); + pair16.b.h = file.FgetUint8(); + rhythm[i].sample[__iptr] = pair16.s16; + } + //file.Fread(rhythm[i].sample, fsize * 2, 1); - file.Fread(rhythm[i].sample, fsize * 2, 1); - - rhythm[i].rate = whdr.rate; + rhythm[i].rate = EndianFromLittle_DWORD(whdr.sample_rate); rhythm[i].step = rhythm[i].rate * 1024 / rate; rhythm[i].pos = rhythm[i].size = fsize * 1024; + file.Fclose(); } if (i != 6) { +// printf("NG %d\n", i); for (i=0; i<6; i++) { delete[] rhythm[i].sample; @@ -1602,6 +1785,7 @@ bool OPNA::LoadRhythmSample(const _TCHAR* path) } return false; } +// printf("OK\n"); return true; } @@ -1770,45 +1954,66 @@ void OPNA::Mix(Sample* buffer, int nsamples) // --------------------------------------------------------------------------- // ƒXƒe[ƒgƒZ[ƒu // -#define OPNA_STATE_VERSION 2 +#define OPNA_STATE_VERSION 4 + +void OPNA::DeclState(void *f) +{ + p_logger = (CSP_Logger *)f; + state_entry = new csp_state_utils(OPNA_STATE_VERSION, chip_num, _T("FMGEN::OPNA::"), p_logger); + OPNABase::DeclState(f); + + for(int i = 0; i < 6; i++) { + DECL_STATE_ENTRY_UINT8_MEMBER((rhythm[i].pan), i); + DECL_STATE_ENTRY_INT8_MEMBER((rhythm[i].level), i); + DECL_STATE_ENTRY_UINT32_MEMBER((rhythm[i].pos), i); + } + DECL_STATE_ENTRY_INT8(rhythmtl); + DECL_STATE_ENTRY_INT32(rhythmtvol_l); + DECL_STATE_ENTRY_INT32(rhythmtvol_r); + DECL_STATE_ENTRY_UINT8(rhythmkey); +} void OPNA::SaveState(void *f) { FILEIO *state_fio = (FILEIO *)f; - state_fio->FputUint32(OPNA_STATE_VERSION); - OPNABase::SaveState(f); - for(int i = 0; i < 6; i++) { - state_fio->FputUint8(rhythm[i].pan); - state_fio->FputInt8(rhythm[i].level); - state_fio->FputUint32(rhythm[i].pos); - } - state_fio->FputInt8(rhythmtl); - state_fio->FputInt32(rhythmtvol_l); - state_fio->FputInt32(rhythmtvol_r); - state_fio->FputUint8(rhythmkey); +// state_fio->FputUint32_BE(OPNA_STATE_VERSION); + +// OPNABase::SaveState(f); +// for(int i = 0; i < 6; i++) { +// state_fio->FputUint8(rhythm[i].pan); +// state_fio->FputInt8(rhythm[i].level); +// state_fio->FputUint32_BE(rhythm[i].pos); +// } +// state_fio->FputInt8(rhythmtl); +// state_fio->FputInt32_BE(rhythmtvol_l); +// state_fio->FputInt32_BE(rhythmtvol_r); +// state_fio->FputUint8(rhythmkey); } bool OPNA::LoadState(void *f) { FILEIO *state_fio = (FILEIO *)f; - if(state_fio->FgetUint32() != OPNA_STATE_VERSION) { - return false; - } - if(!OPNABase::LoadState(f)) { - return false; - } - for(int i = 0; i < 6; i++) { - rhythm[i].pan = state_fio->FgetUint8(); - rhythm[i].level = state_fio->FgetInt8(); - rhythm[i].pos = state_fio->FgetUint32(); - } - rhythmtl = state_fio->FgetInt8(); - rhythmtvol_l = state_fio->FgetInt32(); - rhythmtvol_r = state_fio->FgetInt32(); - rhythmkey = state_fio->FgetUint8(); + bool mb = false; + mb = OPNABase::LoadState(f); + if(!mb) return false; +// if(state_fio->FgetUint32_BE() != OPNA_STATE_VERSION) { +// return false; +// } +// if(!OPNABase::LoadState(f)) { +// return false; +// } +// for(int i = 0; i < 6; i++) { +// rhythm[i].pan = state_fio->FgetUint8(); +// rhythm[i].level = state_fio->FgetInt8(); +// rhythm[i].pos = state_fio->FgetUint32_BE(); +// } +// rhythmtl = state_fio->FgetInt8(); +// rhythmtvol_l = state_fio->FgetInt32_BE(); +// rhythmtvol_r = state_fio->FgetInt32_BE(); +// rhythmkey = state_fio->FgetUint8(); return true; } @@ -2226,4 +2431,561 @@ void OPNB::Mix(Sample* buffer, int nsamples) #endif // BUILD_OPNB +// --------------------------------------------------------------------------- +// YM2612 common part +// --------------------------------------------------------------------------- + +#if defined(BUILD_OPN2) + +int OPN2Base::amtable[FM_LFOENTS] = { -1, }; +int OPN2Base::pmtable[FM_LFOENTS]; + +int32 OPN2Base::tltable[FM_TLENTS+FM_TLPOS]; +bool OPN2Base::tablehasmade = false; + +OPN2Base::OPN2Base() +{ + + MakeTable2(); + BuildLFOTable(); + for (int i=0; i<6; i++) + { + ch[i].SetChip(&chip); + ch[i].SetType(typeN); + } +} + +OPN2Base::~OPN2Base() +{ +} + +// --------------------------------------------------------------------------- +// ‰Šú‰» +// +bool OPN2Base::Init(uint c, uint r, bool) +{ + RebuildTimeTable(); + + Reset(); + + SetVolumeFM(0, 0); + SetVolumePSG(0, 0); + SetChannelMask(0); + return true; +} + +// --------------------------------------------------------------------------- +// ƒe[ƒuƒ‹ì¬ +// +void OPN2Base::MakeTable2() +{ + if (!tablehasmade) + { + for (int i=-FM_TLPOS; i> 4); + } + break; + + // Status Mask ----------------------------------------------------------- + case 0x29: + reg29 = data; +// UpdateStatus(); //? + break; + + // Prescaler ------------------------------------------------------------- + case 0x2d: case 0x2e: case 0x2f: + SetPrescaler(addr-0x2d); + break; + + // F-Number -------------------------------------------------------------- + case 0x1a0: case 0x1a1: case 0x1a2: + c += 3; + case 0xa0: case 0xa1: case 0xa2: + fnum[c] = data + fnum2[c] * 0x100; + ch[c].SetFNum(fnum[c]); + break; + + case 0x1a4: case 0x1a5: case 0x1a6: + c += 3; + case 0xa4 : case 0xa5: case 0xa6: + fnum2[c] = uint8(data); + break; + + case 0xa8: case 0xa9: case 0xaa: + fnum3[c] = data + fnum2[c+6] * 0x100; + break; + + case 0xac : case 0xad: case 0xae: + fnum2[c+6] = uint8(data); + break; + + // Algorithm ------------------------------------------------------------- + + case 0x1b0: case 0x1b1: case 0x1b2: + c += 3; + case 0xb0: case 0xb1: case 0xb2: + ch[c].SetFB((data >> 3) & 7); + ch[c].SetAlgorithm(data & 7); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: + c += 3; + case 0xb4: case 0xb5: case 0xb6: + pan[c] = (data >> 6) & 3; + ch[c].SetMS(data); + break; + + // LFO ------------------------------------------------------------------- + case 0x22: + modified = reg22 ^ data; + reg22 = data; + if (modified & 0x8) + lfocount = 0; + lfodcount = reg22 & 8 ? lfotable[reg22 & 7] : 0; + break; + + // PSG ------------------------------------------------------------------- + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: + break; + + // ‰¹F ------------------------------------------------------------------ + default: + if (c < 3) + { + if (addr & 0x100) + c += 3; + OPNBase::SetParameter(&ch[c], addr, data); + } + break; + } +} + +// --------------------------------------------------------------------------- +// ƒXƒe[ƒ^ƒXƒtƒ‰ƒOÝ’è +// +void OPN2Base::SetStatus(uint bits) +{ + if (!(status & bits)) + { +// LOG2("SetStatus(%.2x %.2x)\n", bits, stmask); + status |= bits & stmask; + UpdateStatus(); + } +// else +// LOG1("SetStatus(%.2x) - ignored\n", bits); +} + +void OPN2Base::ResetStatus(uint bits) +{ + status &= ~bits; +// LOG1("ResetStatus(%.2x)\n", bits); + UpdateStatus(); +} + +inline void OPN2Base::UpdateStatus() +{ +// LOG2("%d:INT = %d\n", Diag::GetCPUTick(), (status & stmask & reg29) != 0); + Intr((status & stmask & reg29) != 0); +} + +// --------------------------------------------------------------------------- +// ‡¬ +// in: buffer ‡¬æ +// nsamples ‡¬ƒTƒ“ƒvƒ‹” +// +void OPN2Base::FMMix(Sample* buffer, int nsamples) +{ + if (fmvolume_l > 0 || fmvolume_r > 0) + { + // €”õ + // Set F-Number + if (!(regtc & 0xc0)) + csmch->SetFNum(fnum[csmch-ch]); + else + { + // Œø‰Ê‰¹ƒ‚[ƒh + csmch->op[0].SetFNum(fnum3[1]); csmch->op[1].SetFNum(fnum3[2]); + csmch->op[2].SetFNum(fnum3[0]); csmch->op[3].SetFNum(fnum[2]); + } + + int act = (((ch[2].Prepare() << 2) | ch[1].Prepare()) << 2) | ch[0].Prepare(); + if (reg29 & 0x80) + act |= (ch[3].Prepare() | ((ch[4].Prepare() | (ch[5].Prepare() << 2)) << 2)) << 6; + if (!(reg22 & 0x08)) + act &= 0x555; + + if (act & 0x555) + { + Mix6(buffer, nsamples, act); + } + } +} + +// --------------------------------------------------------------------------- + +void OPN2Base::MixSubSL(int activech, ISample** dest) +{ + if (activech & 0x001) (*dest[0] = ch[0].CalcL()); + if (activech & 0x004) (*dest[1] += ch[1].CalcL()); + if (activech & 0x010) (*dest[2] += ch[2].CalcL()); + if (activech & 0x040) (*dest[3] += ch[3].CalcL()); + if (activech & 0x100) (*dest[4] += ch[4].CalcL()); + if (activech & 0x400) (*dest[5] += ch[5].CalcL()); +} + +inline void OPN2Base::MixSubS(int activech, ISample** dest) +{ + if (activech & 0x001) (*dest[0] = ch[0].Calc()); + if (activech & 0x004) (*dest[1] += ch[1].Calc()); + if (activech & 0x010) (*dest[2] += ch[2].Calc()); + if (activech & 0x040) (*dest[3] += ch[3].Calc()); + if (activech & 0x100) (*dest[4] += ch[4].Calc()); + if (activech & 0x400) (*dest[5] += ch[5].Calc()); +} + +// --------------------------------------------------------------------------- + +void OPN2Base::BuildLFOTable() +{ + if (amtable[0] == -1) + { + for (int c=0; c<256; c++) + { + int v; + if (c < 0x40) v = c * 2 + 0x80; + else if (c < 0xc0) v = 0x7f - (c - 0x40) * 2 + 0x80; + else v = (c - 0xc0) * 2; + pmtable[c] = v; + + if (c < 0x80) v = 0xff - c * 2; + else v = (c - 0x80) * 2; + amtable[c] = v & ~3; + } + } +} + +// --------------------------------------------------------------------------- + +inline void OPN2Base::LFO() +{ +// LOG3("%4d - %8d, %8d\n", c, lfocount, lfodcount); + +// Operator::SetPML(pmtable[(lfocount >> (FM_LFOCBITS+1)) & 0xff]); +// Operator::SetAML(amtable[(lfocount >> (FM_LFOCBITS+1)) & 0xff]); + chip.SetPML(pmtable[(lfocount >> (FM_LFOCBITS+1)) & 0xff]); + chip.SetAML(amtable[(lfocount >> (FM_LFOCBITS+1)) & 0xff]); + lfocount += lfodcount; +} + +// --------------------------------------------------------------------------- +// ‡¬ +// +//#define IStoSampleL(s) ((Limit(s, 0x7fff, -0x8000) * fmvolume_l) >> 14) +//#define IStoSampleR(s) ((Limit(s, 0x7fff, -0x8000) * fmvolume_r) >> 14) + +void OPN2Base::Mix6(Sample* buffer, int nsamples, int activech) +{ + // Mix + ISample ibuf[4]; + ISample* idest[6]; + idest[0] = &ibuf[pan[0]]; + idest[1] = &ibuf[pan[1]]; + idest[2] = &ibuf[pan[2]]; + idest[3] = &ibuf[pan[3]]; + idest[4] = &ibuf[pan[4]]; + idest[5] = &ibuf[pan[5]]; + + Sample* limit = buffer + nsamples * 2; + for (Sample* dest = buffer; dest < limit; dest+=2) + { + ibuf[1] = ibuf[2] = ibuf[3] = 0; + if (activech & 0xaaa) + LFO(), MixSubSL(activech, idest); + else + MixSubS(activech, idest); + StoreSample(dest[0], IStoSampleL(ibuf[2] + ibuf[3])); + StoreSample(dest[1], IStoSampleR(ibuf[1] + ibuf[3])); + } +} +// --------------------------------------------------------------------------- +// ƒXƒe[ƒgƒZ[ƒu +// +#define OPN2_BASE_STATE_VERSION 1 + +void OPN2Base::DeclState(void *f) +{ + + OPNBase::DeclState(f); + + DECL_STATE_ENTRY_1D_ARRAY(pan, sizeof(pan)); + DECL_STATE_ENTRY_1D_ARRAY(fnum2, sizeof(fnum2)); + DECL_STATE_ENTRY_UINT8(reg22); + DECL_STATE_ENTRY_UINT32(reg29); + DECL_STATE_ENTRY_UINT32(stmask); + DECL_STATE_ENTRY_UINT32(statusnext); + DECL_STATE_ENTRY_UINT32(lfocount); + DECL_STATE_ENTRY_UINT32(lfodcount); + //state_fio->Fwrite(fnum, sizeof(fnum), 1); + //state_fio->Fwrite(fnum3, sizeof(fnum3), 1); + for(int i = 0; i < 6; i++) { + DECL_STATE_ENTRY_UINT32_MEMBER((fnum[i]), i); + } + for(int i = 0; i < 3; i++) { + DECL_STATE_ENTRY_UINT32_MEMBER((fnum3[i]), i); + } + for(int i = 0; i < 6; i++) { + ch[i].DeclState(f); + } +} + +void OPN2Base::SaveState(void *f) +{ + FILEIO *state_fio = (FILEIO *)f; + if(state_entry != NULL) { + state_entry->save_state(state_fio); + } + chip.SaveState(f); + for(int i = 0; i < 6; i++) { + ch[i].SaveState(f); + } +} + +bool OPN2Base::LoadState(void *f) +{ + FILEIO *state_fio = (FILEIO *)f; + + bool mb = false; + if(state_entry != NULL) { + mb = state_entry->load_state(state_fio); + } + if(!mb) return false; + { + // Make force-restore around prescaler and timers. 20180625 K.O + uint bak = prescale; + prescale = 10; + SetPrescaler(bak); + } + if(!chip.LoadState(f)) { + return false; + } + for(int i = 0; i < 6; i++) { + if(!ch[i].LoadState(f)) { + return false; + } + } + return true; +} +#endif // defined(BUILD_OPN2) + +// --------------------------------------------------------------------------- +// YM2612(OPN2) +// --------------------------------------------------------------------------- + +#ifdef BUILD_OPN2 + +// --------------------------------------------------------------------------- +// ƒŒƒWƒXƒ^Žæ“¾ +// +uint OPN2::GetReg(uint addr) +{ + return 0; +} + +// --------------------------------------------------------------------------- +// \’z +// +OPN2::OPN2() +{ + csmch = &ch[2]; // ToDo: Check register. +} +// --------------------------------------------------------------------------- + +OPN2::~OPN2() +{ +} + +// --------------------------------------------------------------------------- +// ‰Šú‰» +// +bool OPN2::Init(uint c, uint r, bool ipflag, const _TCHAR* path) +{ + rate = 8000; + if (!SetRate(c, r, ipflag)) + return false; + if (!OPN2Base::Init(c, r, ipflag)) + return false; + + Reset(); + return true; +} +// --------------------------------------------------------------------------- +// ƒŠƒZƒbƒg +// +void OPN2::Reset() +{ + reg29 = 0x1f; + OPN2Base::Reset(); +} +// --------------------------------------------------------------------------- +// ƒTƒ“ƒvƒŠƒ“ƒOƒŒ[ƒg•ÏX +// +bool OPN2::SetRate(uint c, uint r, bool ipflag) +{ + if (!OPN2Base::SetRate(c, r, ipflag)) + return false; + return true; +} + +// --------------------------------------------------------------------------- +// ƒŒƒWƒXƒ^ƒAƒŒƒC‚Ƀf[ƒ^‚ðÝ’è +// +void OPN2::SetReg(uint addr, uint data) +{ + addr &= 0x1ff; + + switch (addr) + { + case 0x29: + reg29 = data; +// UpdateStatus(); //? + break; + + default: + OPN2Base::SetReg(addr, data); + break; + } +} + + + +// --------------------------------------------------------------------------- +// ‡¬ +// in: buffer ‡¬æ +// nsamples ‡¬ƒTƒ“ƒvƒ‹” +// +void OPN2::Mix(Sample* buffer, int nsamples) +{ + FMMix(buffer, nsamples); +} + +// --------------------------------------------------------------------------- +// ƒXƒe[ƒgƒZ[ƒu +// +#define OPN2_STATE_VERSION 1 + +void OPN2::DeclState(void *f) +{ + p_logger = (CSP_Logger *)f; + state_entry = new csp_state_utils(OPN2_STATE_VERSION, chip_num, _T("FMGEN::OPN2::"), p_logger); + + OPN2Base::DeclState(f); +} + +void OPN2::SaveState(void *f) +{ + FILEIO *state_fio = (FILEIO *)f; + OPN2Base::SaveState(f); +} + +bool OPN2::LoadState(void *f) +{ + FILEIO *state_fio = (FILEIO *)f; + + bool mb = false; + mb = OPN2Base::LoadState(f); + if(!mb) return false; + + return true; +} + +#endif // BUILD_OPN2 + } // namespace FM