OSDN Git Service

[FMGEN] Initial implementation of OPN2 (YM2612) from OPNA.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmgen / opna.cpp
index c440ee5..00628c7 100644 (file)
@@ -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 \97p
 
@@ -45,6 +50,8 @@ OPNBase::OPNBase()
 {
        is_ay3_891x = false;
        prescale = 0;
+       static int __num = 0;
+       chip_num = __num++;
 }
 
 //     \83p\83\89\83\81\81[\83^\83Z\83b\83g
@@ -192,42 +199,65 @@ void OPNBase::Intr(bool value)
 //
 #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_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);
+       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_BE() != OPN_BASE_STATE_VERSION) {
-               return false;
-       }
-       if(!Timer::LoadState(f)) {
-               return false;
+       bool mb = false;
+       if(state_entry != NULL) {
+               mb = state_entry->load_state(state_fio);
        }
-       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();
+       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;
@@ -243,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
@@ -452,22 +482,40 @@ void OPN::Mix(Sample* buffer, int nsamples)
 //
 #define OPN_STATE_VERSION      2
 
-void OPN::SaveState(void *f)
+void OPN::DeclState(void *f)
 {
-       FILEIO *state_fio = (FILEIO *)f;
-       
-       state_fio->FputUint32_BE(OPN_STATE_VERSION);
+
+       p_logger = (CSP_Logger *)f;
+       state_entry = new csp_state_utils(OPN_STATE_VERSION, chip_num, _T("FMGEN::OPN::"), p_logger);
+
+       OPNBase::DeclState(f);
        
-       OPNBase::SaveState(f);
        for(int i = 0; i < 3; i++) {
-               state_fio->FputUint32_BE(fnum[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++) {
-               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);
+               ch[i].DeclState(f);
+       }
+}
+
+void OPN::SaveState(void *f)
+{
+       FILEIO *state_fio = (FILEIO *)f;
+       OPNBase::SaveState(f);
+//     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);
        }
@@ -477,21 +525,24 @@ bool OPN::LoadState(void *f)
 {
        FILEIO *state_fio = (FILEIO *)f;
        
-       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);
+       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;
@@ -1324,61 +1375,124 @@ void OPNABase::Mix6(Sample* buffer, int nsamples, int activech)
 //
 #define OPNA_BASE_STATE_VERSION        2
 
-void OPNABase::SaveState(void *f)
+void OPNABase::DeclState(void *f)
 {
-       FILEIO *state_fio = (FILEIO *)f;
-       
-       state_fio->FputUint32_BE(OPNA_BASE_STATE_VERSION);
+
+       OPNBase::DeclState(f);
        
-       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);
+       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++) {
-               state_fio->FputUint32_BE(fnum[i]);
+               DECL_STATE_ENTRY_UINT32_MEMBER((fnum[i]), i);
        }               
        for(int i = 0; i < 3; i++) {
-               state_fio->FputUint32_BE(fnum3[i]);
+               DECL_STATE_ENTRY_UINT32_MEMBER((fnum3[i]), 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_);
+       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_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_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);
        }
@@ -1388,60 +1502,77 @@ bool OPNABase::LoadState(void *f)
 {
        FILEIO *state_fio = (FILEIO *)f;
        
-       if(state_fio->FgetUint32_BE() != 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_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();
+//     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;
@@ -1565,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);
                
@@ -1615,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;
@@ -1631,6 +1785,7 @@ bool OPNA::LoadRhythmSample(const _TCHAR* path)
                }
                return false;
        }
+//     printf("OK\n");
        return true;
 }
 
@@ -1801,43 +1956,64 @@ void OPNA::Mix(Sample* buffer, int nsamples)
 //
 #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_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);
+//     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_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();
+       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;
 }
 
@@ -2255,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()
+{
+}
+
+// ---------------------------------------------------------------------------
+//     \8f\89\8aú\89»
+//
+bool OPN2Base::Init(uint c, uint r, bool)
+{
+       RebuildTimeTable();
+       
+       Reset();
+
+       SetVolumeFM(0, 0);
+       SetVolumePSG(0, 0);
+       SetChannelMask(0);
+       return true;
+}
+
+// ---------------------------------------------------------------------------
+//     \83e\81[\83u\83\8b\8dì\90¬
+//
+void OPN2Base::MakeTable2()
+{
+       if (!tablehasmade)
+       {
+               for (int i=-FM_TLPOS; i<FM_TLENTS; i++)
+               {
+                       tltable[i+FM_TLPOS] = uint(65536. * pow(2.0, i * -16. / FM_TLENTS))-1;
+               }
+
+               tablehasmade = true;
+       }
+}
+
+// ---------------------------------------------------------------------------
+//     \83\8a\83Z\83b\83g
+//
+void OPN2Base::Reset()
+{
+       int i;
+       
+       OPNBase::Reset();
+       for (i=0x20; i<0x28; i++) SetReg(i, 0);
+       for (i=0x30; i<0xc0; i++) SetReg(i, 0);
+       for (i=0x130; i<0x1c0; i++) SetReg(i, 0);
+       for (i=0x100; i<0x110; i++) SetReg(i, 0);
+       for (i=0x10; i<0x20; i++) SetReg(i, 0);
+       for (i=0; i<6; i++)
+       {
+               pan[i] = 3;
+               ch[i].Reset();
+       }
+       
+       stmask = ~0x1c;
+       statusnext = 0;
+       lfocount = 0;
+       status = 0;
+       UpdateStatus();
+}
+
+// ---------------------------------------------------------------------------
+//     \83T\83\93\83v\83\8a\83\93\83O\83\8c\81[\83g\95Ï\8dX
+//
+bool OPN2Base::SetRate(uint c, uint r, bool)
+{
+       c /= 2;         // \8f]\97\88\94Å\82Æ\82Ì\8cÝ\8a·\90«\82ð\8fd\8e\8b\82µ\82½\82¯\82è\82á\83R\83\81\83\93\83g\83A\83E\83g\82µ\82æ\82¤
+       
+       OPNBase::Init(c, r);
+
+       RebuildTimeTable();
+
+       lfodcount = reg22 & 0x08 ? lfotable[reg22 & 7] : 0;
+       return true;
+}
+
+
+// ---------------------------------------------------------------------------
+//     \83`\83\83\83\93\83l\83\8b\83}\83X\83N\82Ì\90Ý\92è
+//
+void OPN2Base::SetChannelMask(uint mask)
+{
+       for (int i=0; i<6; i++)
+               ch[i].Mute(!!(mask & (1 << i)));
+}
+
+// ---------------------------------------------------------------------------
+//     \83\8c\83W\83X\83^\83A\83\8c\83C\82É\83f\81[\83^\82ð\90Ý\92è
+//
+void OPN2Base::SetReg(uint addr, uint data)
+{
+       int     c = addr & 3;
+       switch (addr)
+       {
+               uint modified;
+
+       // Timer -----------------------------------------------------------------
+               case 0x24: case 0x25:
+                       SetTimerA(addr, data);
+                       break;
+
+               case 0x26:
+                       SetTimerB(data);
+                       break;
+
+               case 0x27:
+                       SetTimerControl(data);
+                       break;
+
+       // Misc ------------------------------------------------------------------
+       case 0x28:              // Key On/Off
+               if ((data & 3) < 3)
+               {
+                       c = (data & 3) + (data & 4 ? 3 : 0);
+                       ch[c].KeyControl(data >> 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;
+
+       // \89¹\90F ------------------------------------------------------------------
+       default:
+               if (c < 3)
+               {
+                       if (addr & 0x100)
+                               c += 3;
+                       OPNBase::SetParameter(&ch[c], addr, data);
+               }
+               break;
+       }
+}
+
+// ---------------------------------------------------------------------------
+//     \83X\83e\81[\83^\83X\83t\83\89\83O\90Ý\92è
+//
+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);
+}
+
+// ---------------------------------------------------------------------------
+//     \8d\87\90¬
+//     in:             buffer          \8d\87\90¬\90æ
+//                     nsamples        \8d\87\90¬\83T\83\93\83v\83\8b\90\94
+//
+void OPN2Base::FMMix(Sample* buffer, int nsamples)
+{
+       if (fmvolume_l > 0 || fmvolume_r > 0)
+       {
+               // \8f\80\94õ
+               // Set F-Number
+               if (!(regtc & 0xc0))
+                       csmch->SetFNum(fnum[csmch-ch]);
+               else
+               {
+                       // \8cø\89Ê\89¹\83\82\81[\83h
+                       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;
+}
+
+// ---------------------------------------------------------------------------
+//     \8d\87\90¬
+//
+//#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]));
+       }
+}
+// ---------------------------------------------------------------------------
+//     \83X\83e\81[\83g\83Z\81[\83u
+//
+#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
+
+// ---------------------------------------------------------------------------
+//     \83\8c\83W\83X\83^\8eæ\93¾
+//
+uint OPN2::GetReg(uint addr)
+{
+       return 0;
+}
+
+// ---------------------------------------------------------------------------
+//     \8d\\92z
+//
+OPN2::OPN2()
+{
+       csmch = &ch[2]; // ToDo: Check register.
+}
+// ---------------------------------------------------------------------------
+
+OPN2::~OPN2()
+{
+}
+
+// ---------------------------------------------------------------------------
+//     \8f\89\8aú\89»
+//
+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;
+}
+// ---------------------------------------------------------------------------
+//     \83\8a\83Z\83b\83g
+//
+void OPN2::Reset()
+{
+       reg29 = 0x1f;
+       OPN2Base::Reset();
+}
+// ---------------------------------------------------------------------------
+//     \83T\83\93\83v\83\8a\83\93\83O\83\8c\81[\83g\95Ï\8dX
+//
+bool OPN2::SetRate(uint c, uint r, bool ipflag)
+{
+       if (!OPN2Base::SetRate(c, r, ipflag))
+               return false;
+       return true;
+}
+
+// ---------------------------------------------------------------------------
+//     \83\8c\83W\83X\83^\83A\83\8c\83C\82É\83f\81[\83^\82ð\90Ý\92è
+//
+void OPN2::SetReg(uint addr, uint data)
+{
+       addr &= 0x1ff;
+
+       switch (addr)
+       {
+       case 0x29:
+               reg29 = data;
+//             UpdateStatus(); //?
+               break;
+       
+       default:
+               OPN2Base::SetReg(addr, data);
+               break;
+       }
+}
+
+
+
+// ---------------------------------------------------------------------------
+//     \8d\87\90¬
+//     in:             buffer          \8d\87\90¬\90æ
+//                     nsamples        \8d\87\90¬\83T\83\93\83v\83\8b\90\94
+//
+void OPN2::Mix(Sample* buffer, int nsamples)
+{
+       FMMix(buffer, nsamples);
+}
+
+// ---------------------------------------------------------------------------
+//     \83X\83e\81[\83g\83Z\81[\83u
+//
+#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