| 
 | 
 
 
 楼主 |
发表于 2009-11-8 14:47:50
|
显示全部楼层
 
 
 
这是我手中源码Apu.cpp的内容,敬请赐教:. H' O; d7 d% y7 ^1 w6 M  X 
(由于很多专用术语和算法机理都不明白,所以看不大懂……) 
' _( e+ x! {9 b/ N' Y  g5 G; l////////////////////////////////////////////////////////////////////////// 
# t* m! L* f' Z3 q' l//                                                                      //+ w* ?* O% W3 l 
//      NES APU core                                                    // 
8 s+ I. A" Z( F6 i3 U//                                                           Norix      // 
% V; e. Z+ l2 t  w: O, k//                                               written     2002/06/27 //& w" \8 h* O. ?) ]8 S# _1 c6 J 
//                                               last modify ----/--/-- //. s! E# K" p' h9 w) n! N# Y# M 
////////////////////////////////////////////////////////////////////////// 
8 s* A5 _; t6 C  m#include "DebugOut.h" 
* Y- x, v# ^( U2 \1 y3 h#include "App.h" 
. v* c4 Q  \  I# ~8 F9 o#include "Config.h" 
( [! P; O! h, o# x/ @4 G( y* x 
2 `+ `! D+ c! X5 D7 Z3 z( p9 u#include "nes.h"+ T) E5 i* G  G) g7 p- Q* v 
#include "mmu.h" 
3 e  K8 ]& R2 n; l9 T7 q& b  j7 H8 l#include "cpu.h"8 s3 _$ i; I7 k 
#include "ppu.h") w; }' d7 Q8 ]. _6 x' V9 J; h 
#include "rom.h"4 N0 i$ j6 `  C8 Q0 A# N 
#include "apu.h"2 j( x# I1 P4 S6 M+ S/ I$ ~ 
  @* l9 x$ b, y7 W0 o 
// Volume adjust/ r5 l. Q% j- P- N 
// Internal sounds 
0 i) ?9 H- [/ l2 h  X& g#define        RECTANGLE_VOL        (0x0F0)) l% l1 r* W4 N3 H6 T3 n 
#define        TRIANGLE_VOL        (0x130); r* _2 F+ H, }. R( h7 s 
#define        NOISE_VOL        (0x0C0): }: c8 P6 p4 _6 D7 ^8 k 
#define        DPCM_VOL        (0x0F0)6 X% `9 m$ H, K, `, c 
// Extra sounds' {' r% G* D; ?% V3 P( w6 O 
#define        VRC6_VOL        (0x0F0) 
' m, D* f+ M$ P& T- q+ i#define        VRC7_VOL        (0x130)) @* p0 T* Y! L6 n. B7 M8 N. L 
#define        FDS_VOL                (0x0F0) 
# O' V7 g3 q" m( H4 l9 N5 l( U#define        MMC5_VOL        (0x0F0) 
0 \  B' F1 u2 A5 L: V#define        N106_VOL        (0x088) 
3 }0 v# Z3 v# t& V9 c$ u7 E#define        FME7_VOL        (0x130)/ G6 f# T: n/ I# u7 E* c2 f/ l 
 
4 P" y9 b" G3 L/ t% k: h4 MAPU::APU( NES* parent ) 
" S' H0 y5 i0 K! m% Q{4 o' s& r- L7 Z 
        exsound_select = 0; 
, ^$ o( q$ x  {% F6 E: m! P) X4 ^ 
" J. j( g2 |: w) K7 r/ W% ~        nes = parent;6 _4 ^% O* b) u 
        internal.SetParent( parent ); 
* }/ B% R& Z/ m. D2 r& n/ U& H  _( j+ X: l! [$ \( F0 Y 
        last_data = last_diff = 0; 
+ G, N" _3 q+ r5 O$ ^( l1 }0 L0 B9 S8 f# ^. Y8 F$ ^7 M3 [: C( F 
        ZEROMEMORY( m_SoundBuffer, sizeof(m_SoundBuffer) ); 
9 ]6 ^+ N9 \- i1 D4 v7 j4 C+ e) Z1 W9 | 
        ZEROMEMORY( lowpass_filter, sizeof(lowpass_filter) ); 
: O& w1 }" F# h+ O, p) a        ZEROMEMORY( &queue, sizeof(queue) ); 
1 F! {6 R5 @. D- |7 ]        ZEROMEMORY( &exqueue, sizeof(exqueue) ); 
$ x* _  x8 l3 U5 ?8 S& p, r, T& e1 s4 T8 X 
        for( INT i = 0; i < 16; i++ ) {0 Z; {8 Y1 q8 h4 @5 W5 f 
                m_bMute = TRUE;) B) g( B! L7 v! \7 P$ U 
        }) r" d9 o' p' c7 q 
} 
3 G% Q) ?2 |+ m% u( Z 
6 B7 p' w. }4 L& G9 b; ~2 k! gAPU::~APU() 
2 {1 p, S/ R7 J! H- M{; B) c- @* v, Y! G0 G 
} 
- {3 \. s* ?; D/ x- F# b3 J5 f5 u: @2 A 
void        APU::SetQueue( INT writetime, WORD addr, BYTE data )! H  l1 S5 U& X* b1 o6 c! a+ e 
{ 
% |# {/ c7 T5 t; R- A        queue.data[queue.wrptr].time = writetime; 
# `  U8 K( @9 R        queue.data[queue.wrptr].addr = addr;3 s( D% P! @7 l, B" |3 r 
        queue.data[queue.wrptr].data = data; 
0 e. \2 ~1 w# X9 ]# @- v1 i( n        queue.wrptr++;! ^# [+ l6 z% e2 d4 N 
        queue.wrptr&=QUEUE_LENGTH-1; 
4 f7 U2 B  O, q% ^        if( queue.wrptr == queue.rdptr ) { 
" z" J* M$ ^5 {                DEBUGOUT( "queue overflow.\n" ); 
% O, p' R$ o6 y. f, k        } 
( f5 [6 u$ J' b# I7 K  U}" O+ Y8 }+ l# H7 E0 b) p( c2 D 
 
' |& w! N' x+ X! b, x7 {$ rBOOL        APU::GetQueue( INT writetime, QUEUEDATA& ret )* A. A, f! J. j 
{ 
! a- C$ L+ |) D        if( queue.wrptr == queue.rdptr ) { 
  y9 s0 G" k* d                return        FALSE;  f6 b) ^% P) U/ E7 b* S 
        } 
7 k& ?3 u5 f( r4 T6 J& A! C" ?        if( queue.data[queue.rdptr].time <= writetime ) { 
$ ~" [  r8 R# A  r5 l! @                ret = queue.data[queue.rdptr];4 v. }) ]+ E" t5 C/ x 
                queue.rdptr++;, |3 s$ n1 ~% m3 b* T$ L 
                queue.rdptr&=QUEUE_LENGTH-1; 
7 n+ u! P5 ^* K                return        TRUE;1 G! T; S% \# j! {% X9 `; j9 n9 D4 a 
        }  {+ ?( K3 ?' S$ l2 D 
        return        FALSE;' J, @, z" ]8 [/ i4 t# ?4 `9 q 
} 
) Z- |7 Q8 O) M2 o. Y) C 
, T" O( d1 s- R+ d2 I/ s. [, N" l1 Mvoid        APU::SetExQueue( INT writetime, WORD addr, BYTE data )- J. w9 `) H- j( u" b7 v 
{ 
$ [: w& t: p9 J) a# B5 }& n        exqueue.data[exqueue.wrptr].time = writetime;$ d- Q3 `) R1 l, V2 J, @# \ 
        exqueue.data[exqueue.wrptr].addr = addr; 
: I. v8 \; D& A        exqueue.data[exqueue.wrptr].data = data; 
$ ?, ^( r; b7 ~7 A# y/ z        exqueue.wrptr++; 
( X8 l" `' J! i/ p; E' ^        exqueue.wrptr&=QUEUE_LENGTH-1;) q( X: ^0 R9 m& \# z 
        if( exqueue.wrptr == exqueue.rdptr ) {4 g+ M3 _# [. A 
                DEBUGOUT( "exqueue overflow.\n" ); 
# R; ?2 p# E! s4 C) k        } 
0 H  @! L: C! Q. M}! O  g) ?- m5 i% L1 U+ h& V" I* B 
 
! {$ H5 e6 {4 l5 Z6 w! VBOOL        APU::GetExQueue( INT writetime, QUEUEDATA& ret ) 
! n- \: G  `, [; @/ G+ p{8 |% P- M* ?2 x0 V" }. N7 F; e* i: d 
        if( exqueue.wrptr == exqueue.rdptr ) {# _' Z. Z8 P; V9 e: U  s) N2 n) o 
                return        FALSE; 
& h" \9 @- f" M, A        }2 t3 j; j) p4 b% c8 G 
        if( exqueue.data[exqueue.rdptr].time <= writetime ) {: G# Y2 [; P7 }: H 
                ret = exqueue.data[exqueue.rdptr]; 
' Z' ^3 B/ b8 d# @. T                exqueue.rdptr++; 
- `# R8 `# N/ {4 L                exqueue.rdptr&=QUEUE_LENGTH-1; 
+ {6 \; P( j) z' I/ d                return        TRUE; 
5 A# S/ o7 _5 W& q* f3 J; f( f* B6 M        } 
3 m, x- }4 K* q" \: r        return        FALSE;2 [! C' s8 n% k( H) t 
}' `" M$ r9 B; n# u2 H7 s+ @0 v 
 
% u! F) x- ?* c+ l4 u4 q6 |void        APU::QueueClear()4 C3 c4 B5 p& z7 n 
{ 
/ r9 f9 O" M& Z1 f        ZEROMEMORY( &queue, sizeof(queue) );" h. h$ k7 U6 K3 R9 @: x7 V 
        ZEROMEMORY( &exqueue, sizeof(exqueue) );- D3 N5 x0 |, x- X 
} 
1 L/ O/ }% t1 a- b$ r4 D0 B! s  R- }7 F 
void        APU::QueueFlush()/ u2 T+ v% L1 Y* M0 P: P! N 
{; P/ _+ a  @, w# {* b; C 
        while( queue.wrptr != queue.rdptr ) {3 u8 w7 e* m# q7 v0 x  \ 
                WriteProcess( queue.data[queue.rdptr].addr, queue.data[queue.rdptr].data ); 
' ]6 I; B+ X. h0 |                queue.rdptr++;' f6 T; R0 M% ~6 J& w 
                queue.rdptr&=QUEUE_LENGTH-1; 
' Y: {5 z3 ^7 h: M        }. b) A0 f* |2 i9 R& Q& R 
" c( A6 R9 \- r/ @ 
        while( exqueue.wrptr != exqueue.rdptr ) { 
8 i% A8 ~) a; @6 Z                WriteExProcess( exqueue.data[exqueue.rdptr].addr, exqueue.data[exqueue.rdptr].data );3 n$ `6 L( Q5 M$ t4 ]0 u0 S 
                exqueue.rdptr++;$ R6 c% M2 T4 R# X+ H5 u. P 
                exqueue.rdptr&=QUEUE_LENGTH-1;7 \) q# _8 P$ z2 O: A 
        }5 b# G8 E0 F- I* i# R8 { 
}& b% ~  B; a; ?8 U5 C# Q7 e 
9 O7 N) e% z7 j4 Q! b: K 
void        APU::SoundSetup(). b) A9 D5 A6 K6 g 
{ 
# U7 D$ p! f, @9 w6 l5 y        FLOAT        fClock = nes->nescfg->CpuClock;8 D# o2 H; Q1 V0 y, {! _$ Y 
        INT        nRate = (INT)Config.sound.nRate; 
( u1 A( T! [" H& ~/ V! w        internal.Setup( fClock, nRate );6 Y- w' f/ [7 D6 t& m 
        vrc6.Setup( fClock, nRate ); 
; p. H# I4 [0 |        vrc7.Setup( fClock, nRate ); 
& T3 {/ S5 r, g0 V8 B# A/ o6 A        mmc5.Setup( fClock, nRate );0 h* E4 w1 }6 g 
        fds.Setup ( fClock, nRate ); 
, e" F; P% i( M7 t% u4 b        n106.Setup( fClock, nRate ); 
& \) X% Z, v" w* Y# A        fme7.Setup( fClock, nRate ); 
( u) n2 D1 J) y+ L} 
# G5 j; V6 |& h0 K9 M9 F 
+ g1 R; e& Z8 B/ Avoid        APU::Reset() 
! x  m  x7 Q* J" m0 W' n{ 
  d6 g6 A% @: u0 \6 J9 C        ZEROMEMORY( &queue, sizeof(queue) );) B6 Z% L8 ~4 x 
        ZEROMEMORY( &exqueue, sizeof(exqueue) );0 g# x  M1 S. r9 @' r' b 
4 V' e! `% V) D 
        elapsed_time = 0; 
% H3 P# `7 i( R* Q4 i1 ~ 
( }7 J% z8 y2 H1 C. Q( C        FLOAT        fClock = nes->nescfg->CpuClock;" h' L% j( J6 {0 \ 
        INT        nRate = (INT)Config.sound.nRate; 
% w6 R+ g* T/ j        internal.Reset( fClock, nRate );. X& }" k% z( x  G' L5 b 
        vrc6.Reset( fClock, nRate ); 
. V+ q6 G$ ~9 h        vrc7.Reset( fClock, nRate );6 n, T7 h4 m3 f5 J% P2 n6 b 
        mmc5.Reset( fClock, nRate );5 `0 A' ?# |4 n4 _6 ?8 }4 N$ { 
        fds.Reset ( fClock, nRate );5 T) I8 ]2 S9 g$ ]' P5 h/ I1 A 
        n106.Reset( fClock, nRate );* Q& j% N, `: ~ 
        fme7.Reset( fClock, nRate );' |  J5 m2 W" U" {# M 
! Q' b" q( f9 Q( ?9 [3 L, @ 
        SoundSetup();6 i3 S# P5 y8 s8 X 
}5 o* ^$ _& f$ q' ?& B" l 
 
" E; |8 J* p$ |1 U; G. Xvoid        APU::SelectExSound( BYTE data ) 
  `' E4 v1 s* E) }: K0 j1 }4 w2 ?{ 
& B' u* _- G& G3 i        exsound_select = data; 
8 n( A' P9 C+ L. v3 W$ n* E/ A} 
' K+ _  d  R; q  w2 B- X* P# \4 h  b+ E 
BYTE        APU::Read( WORD addr ) 
  g0 }4 z+ ^$ {{ 
" j1 f8 d' \3 e5 h        return        internal.SyncRead( addr );+ ]9 U/ K- Y, m; S+ g* T 
} 
2 R6 c" g; m5 m1 E6 \! d+ v 
/ d, N' e1 P* v  ?" gvoid        APU::Write( WORD addr, BYTE data ) 
2 T2 V1 N' h3 P{' ]6 i$ M! C1 d8 O( h- s# R7 s 
        // $4018偼VirtuaNES屌桳億乕僩 
, Q/ T. D" D( ?& n5 p6 k: h/ O        if( addr >= 0x4000 && addr <= 0x401F ) { 
8 i! w; ]3 D4 y. U$ r* P- k# \                internal.SyncWrite( addr, data );3 O$ i% |& B) u5 R7 m 
                SetQueue( nes->cpu->GetTotalCycles(), addr, data ); 
0 l  m8 ?6 \0 V9 w: _, ]9 q        }  W" |1 D9 ?3 X# E5 u, O 
} 
  O) H5 t" b* a) Z. m6 h- r" w* ~4 q8 |; X) i9 B 
BYTE        APU::ExRead( WORD addr ) 
3 M. `& P: O! ]1 {+ T  W" p{2 K! N/ b. R' y 
BYTE        data = 0; 
& ~) D' A2 @$ ~* T% G0 f. \8 T+ m# U 
9 {" z0 X8 p, _/ |0 W! e( C        if( exsound_select & 0x10 ) { 
' ?) i3 Q6 _4 y+ [                if( addr == 0x4800 ) { 
5 Q+ t4 k" f- e6 B% k- t                        SetExQueue( nes->cpu->GetTotalCycles(), 0, 0 );; v/ g! U7 J( e/ |' E, `+ {+ q 
                } 
; S  j* e, W+ M0 I9 H9 X. H; I        }( U! A3 ?  p! X3 H1 q 
        if( exsound_select & 0x04 ) { 
: g. O1 n) p: T( r                if( addr >= 0x4040 && addr < 0x4100 ) {7 \, U! D5 @) q( X$ V) K/ `, f$ R 
                        data = fds.SyncRead( addr );4 R6 E# ?9 e4 b/ w* b1 R5 }& N 
                }) q  l- I, u; [& R9 P 
        } 
6 Z- m: @* h- l- Z        if( exsound_select & 0x08 ) {, w" o/ j1 a# @4 C8 { 
                if( addr >= 0x5000 && addr <= 0x5015 ) {& Q2 e) m/ H& u; F 
                        data = mmc5.SyncRead( addr ); 
: [0 y- j( M: t3 m* [4 R                }! G+ X% q4 n! S3 _6 x 
        } 
# Q) H9 e; x) K. A5 A% `- }2 `; {  q  q& p  _$ N# g 
        return        data; 
/ K# s, f+ [$ L# N) s7 M}; m' |* n) F) f& u 
$ t# U! L' |7 B& v' R% K 
void        APU::ExWrite( WORD addr, BYTE data ) 
7 r& J; L0 E/ {{ 
( R# l& a  d2 y* V7 F        SetExQueue( nes->cpu->GetTotalCycles(), addr, data );  ~. ~- S1 x, t# r; ]  G! r' X 
 
6 S& \/ ^+ t; s, a' R) x% x        if( exsound_select & 0x04 ) {5 Z" v- A8 s# s* U3 I# _8 [ 
                if( addr >= 0x4040 && addr < 0x4100 ) {* |/ {$ ?- v# q1 H6 m; ^/ `3 u 
                        fds.SyncWrite( addr, data );. D: D# x+ G6 D% W. F6 \ 
                } 
: F3 {3 _1 t* K& Y" @  d5 K        }, X4 a7 ]0 b; _) o" U 
 
) `6 t! ]6 C& O' q. y        if( exsound_select & 0x08 ) {" U1 k1 P& w" I8 C  W0 N 
                if( addr >= 0x5000 && addr <= 0x5015 ) { 
2 o$ u  ]# t+ a- {4 g) T                        mmc5.SyncWrite( addr, data );6 s8 J7 A- f  _6 W0 R9 h 
                } 
2 E0 H$ T; ?+ _5 u) d  K        }% z% B% k' g* ]- y 
}. L% O+ b+ `: ? 
9 m) y: Y% z. |0 g4 L% q9 d3 D 
void        APU::Sync()( P+ K* r, C; V8 m! w9 ]4 L7 k 
{+ J- l. P% S3 o 
}3 x& Z; _- {  j! O; f) ~# Q 
) d  J2 f6 _2 G 
void        APU::SyncDPCM( INT cycles ) 
' j) U" T& y* t6 M$ {  E0 J{ 
6 ]$ y) k$ f% F. R- N( \8 o        internal.Sync( cycles );2 h5 c( t1 A# T) B$ g 
 
6 f* }7 s  s4 n, c! {        if( exsound_select & 0x04 ) {2 o: U" o) J% H0 U 
                fds.Sync( cycles );: _/ |% Y; Y) n* H, T/ X 
        }* ~# ~' p9 N3 S! s( T* w 
        if( exsound_select & 0x08 ) {. ]2 y4 i; U9 @ 
                mmc5.Sync( cycles ); 
) ~; O& h- Z2 U) B+ J        } 
# _+ F0 \6 T9 q+ W' s  b  G9 H% ~}8 n1 E% \1 M. M" y5 P8 f% R8 r. X 
* s0 c% b! K! `! a3 \/ {3 a 
void        APU::WriteProcess( WORD addr, BYTE data ) 
; F% R. U7 \5 y' @9 {{ 
( }8 m. T6 B3 D8 w4 C: E5 b        // $4018偼VirtuaNES屌桳億乕僩 
& d2 L5 Y( {% D0 e* R! }' W        if( addr >= 0x4000 && addr <= 0x401F ) {4 @, G1 e2 P5 o 
                internal.Write( addr, data ); 
1 E0 s2 H& o7 z        }3 ~- X& G  ]; a7 M( ~ 
}/ t, M. ^5 @1 i/ d 
 
6 I# j6 Z& x" }8 T  Dvoid        APU::WriteExProcess( WORD addr, BYTE data )2 f2 ?) W+ [- x4 [ 
{ 
+ }/ g- z% d: ^& }1 A        if( exsound_select & 0x01 ) { 
$ z$ I; g: j- U  l3 v                vrc6.Write( addr, data ); 
% I5 R. F" f! m% u; @        }  S4 r/ \. S( b- z; c; }! ` 
        if( exsound_select & 0x02 ) {$ }7 y& C7 X0 A0 A 
                vrc7.Write( addr, data ); 
. P' ?! B1 G  Y# a6 ]) I0 P4 k# C        }1 O* U( H1 E8 z0 j, c 
        if( exsound_select & 0x04 ) { 
, R3 C# o1 T& }5 v' T% u- V# x                fds.Write( addr, data ); 
8 @- Y6 O6 U/ d! x( _% e        } 
$ q0 `4 I! F1 n* z# @        if( exsound_select & 0x08 ) { 
" I$ b/ m* e! u2 Y4 S; j' {9 `% d                mmc5.Write( addr, data ); 
4 F4 o! ]2 G: M' M        } 
8 F6 l0 n- ?: k8 ^& m4 {# u        if( exsound_select & 0x10 ) {# G6 |3 L( N; |7 n' G 
                if( addr == 0x0000 ) {; q& h7 {, v1 O. n+ n# k6 `/ e7 ? 
                        BYTE        dummy = n106.Read( addr );. d& Z2 d8 H- h. X& o5 K7 B 
                } else {- X4 G2 _0 R* v9 v: L 
                        n106.Write( addr, data );+ l4 O9 N4 I5 S 
                } 
$ s& [+ O, `0 {/ e8 o        } 
* n$ }1 d" e+ G% {4 ?" O3 x. u* i        if( exsound_select & 0x20 ) { 
/ d7 y- Y. K  Y) r4 q/ z8 c                fme7.Write( addr, data );6 H- `/ ?, O" D( l: S5 _( A 
        }7 ?* b* ]# D" _/ F3 d8 M 
}" ~* E% R+ ~6 w. c 
3 f3 i; H0 I" \# M  P  p1 N 
void        APU::Process( LPBYTE lpBuffer, DWORD dwSize ) 
5 b$ ^; A6 m+ j0 |{/ u, E2 M0 a, ?! W 
INT        nBits = Config.sound.nBits; 
. ?2 t7 g8 m' ~' Q' |' Q' Q! JDWORD        dwLength = dwSize / (nBits/8);  `( h$ p) }1 [" d1 r  g 
INT        output; 
# a7 q: s6 \) X  |QUEUEDATA q;$ ~- O1 o% Y8 T+ [" ]4 w( ^8 L 
DWORD        writetime;* W! T; u$ F3 @2 ?% u0 r& v 
 
* \! M7 `- ]  y# Z1 i; d: mLPSHORT        pSoundBuf = m_SoundBuffer;' M1 @2 z3 Z; S  ]$ G 
INT        nCcount = 0;; J: a; `4 ^6 |/ O 
 
. x( t# M. A+ T, J" tINT        nFilterType = Config.sound.nFilterType;; s0 j# a) s/ `' {8 g8 V, O  S0 v+ m 
 
/ L8 N8 G. r0 y" ]- D        if( !Config.sound.bEnable ) {1 h% U2 d' _; ?- @5 z 
                ::FillMemory( lpBuffer, dwSize, (BYTE)(Config.sound.nRate==8?128:0) ); 
+ S7 O, Z' A( T+ d9 H                return;/ J3 p. i( I8 U1 ^7 q" t 
        } 
8 D& I2 e8 Y1 K8 f+ \+ C) s 
3 W! {; i3 ~5 Z% A        // Volume setup 
) g5 x1 q: E8 H& i( T( ~- O  M% k        //  0:Master 
( W% L. @6 I2 O- K9 j        //  1:Rectangle 19 \7 ?1 k( k& F- Q9 j 
        //  2:Rectangle 2 
# [/ g/ D! o2 E, a2 Q9 U        //  3:Triangle 
  [- I( b8 p& N8 ]2 V; ?6 ~# l1 c. }( C        //  4:Noise4 d& I# H7 v5 s0 ?" f 
        //  5:DPCM 
" H, w7 g! v: [8 d        //  6:VRC6 
  ~% l$ S- L5 |        //  7:VRC7( n! o8 @4 L. ?0 j; W 
        //  8:FDS# ]0 D; p( q+ z: Z! X) d. z 
        //  9:MMC5 
$ d/ s4 {4 D4 T) C5 M% @, g0 J        // 10:N106 
; j( A- p$ Q  B1 e! S6 |" G2 j        // 11:FME7 
6 |( D0 O2 M7 F: a0 t        INT        vol[24];( n/ Z; e3 G" N: [$ }$ C 
        BOOL*        bMute = m_bMute;' y4 J. X# z7 d0 U* o  m5 s+ N$ [+ T, j 
        SHORT*        nVolume = Config.sound.nVolume;, s) e# I' y$ g( o9 s/ ~5 ~ 
 
( K  w6 {4 c! o% ^: f        INT        nMasterVolume = bMute[0]?nVolume[0]:0;" c- q1 l4 x. o  u  g$ @2 k% n 
2 V7 y: c& A. C6 d4 I  T1 h2 h9 w9 L 
        // Internal 
! L. G5 P; P  m4 y4 C- j$ r        vol[ 0] = bMute[1]?(RECTANGLE_VOL*nVolume[1]*nMasterVolume)/(100*100):0;4 y7 T7 L7 z3 G 
        vol[ 1] = bMute[2]?(RECTANGLE_VOL*nVolume[2]*nMasterVolume)/(100*100):0; 
' |9 y% T: K  s( }+ y% u        vol[ 2] = bMute[3]?(TRIANGLE_VOL *nVolume[3]*nMasterVolume)/(100*100):0;& V5 M& A: {+ K. \7 |9 ]6 ] 
        vol[ 3] = bMute[4]?(NOISE_VOL    *nVolume[4]*nMasterVolume)/(100*100):0;6 _2 ~6 B- Z2 D9 t" k, R* Z2 [ 
        vol[ 4] = bMute[5]?(DPCM_VOL     *nVolume[5]*nMasterVolume)/(100*100):0; 
- M8 m9 L5 D3 P% J; ]" K 
! [/ |2 n, Z) Q( d# G2 v: x" W        // VRC65 X2 m" V. A; W 
        vol[ 5] = bMute[6]?(VRC6_VOL*nVolume[6]*nMasterVolume)/(100*100):0;- d! e9 w7 T: u! U$ b& ` 
        vol[ 6] = bMute[7]?(VRC6_VOL*nVolume[6]*nMasterVolume)/(100*100):0;3 o. N7 H: w7 z% U 
        vol[ 7] = bMute[8]?(VRC6_VOL*nVolume[6]*nMasterVolume)/(100*100):0;- @, d& S+ @; L" s, \, @( u% l& I3 p 
 
* ~3 ^( @# w4 z( Y: R* ?2 }        // VRC7 
) g; I/ ]1 n% W9 @6 G        vol[ 8] = bMute[6]?(VRC7_VOL*nVolume[7]*nMasterVolume)/(100*100):0; 
3 I' Q: ?, N/ U5 Y# I  N+ c8 ?9 U$ z! i# I) ~ 
        // FDS/ o. v: C# P6 L; R 
        vol[ 9] = bMute[6]?(FDS_VOL*nVolume[8]*nMasterVolume)/(100*100):0; 
# k6 G& u7 V! t; u/ s# q- m4 u7 Y+ J5 q  h" N/ E3 X7 A' w; n4 B% b 
        // MMC5 
. v* Q; l" V" R: s5 |8 |        vol[10] = bMute[6]?(MMC5_VOL*nVolume[9]*nMasterVolume)/(100*100):0;& Y9 t7 a" V4 s) n 
        vol[11] = bMute[7]?(MMC5_VOL*nVolume[9]*nMasterVolume)/(100*100):0;, |" z( {- Z) g. Y* M& d 
        vol[12] = bMute[8]?(MMC5_VOL*nVolume[9]*nMasterVolume)/(100*100):0; 
, Y) Z. C% J) Z8 d1 z2 D$ T) o( @$ K 
        // N106 
% d. \; L2 m3 Z0 [/ Q; k        vol[13] = bMute[ 6]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0; 
- h5 H/ Q. _, A9 n        vol[14] = bMute[ 7]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0; 
5 Z8 ]; t( D% I! }6 W4 G! Y7 c; j        vol[15] = bMute[ 8]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0;) c& S7 o) `6 R' C6 d% y 
        vol[16] = bMute[ 9]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0; 
( }0 ?  ?; K1 P- e        vol[17] = bMute[10]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0; 
9 C$ A# u0 o  K# b  I& {# ]        vol[18] = bMute[11]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0;$ g/ e4 o/ _) Q8 v, k. @. f 
        vol[19] = bMute[12]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0; 
6 \. O8 g* e4 w% n        vol[20] = bMute[13]?(N106_VOL*nVolume[10]*nMasterVolume)/(100*100):0; 
6 r9 _' K6 J$ C 
: V! p, P# |/ M6 r; v: w- M        // FME78 P4 Q! I& P  Q$ q7 } 
        vol[21] = bMute[6]?(FME7_VOL*nVolume[11]*nMasterVolume)/(100*100):0; 
1 l! x' P! u( A* ^( D: V4 X9 }        vol[22] = bMute[7]?(FME7_VOL*nVolume[11]*nMasterVolume)/(100*100):0;( ?- A- X. f! v+ ^: a 
        vol[23] = bMute[8]?(FME7_VOL*nVolume[11]*nMasterVolume)/(100*100):0; 
5 y/ @+ t( U; F- M3 M  I" L7 w3 p' L; d: U6 Z 
//        double        cycle_rate = ((double)FRAME_CYCLES*60.0/12.0)/(double)Config.sound.nRate; 
2 i) p* |; U" I* K' @8 ~6 @: M        double        cycle_rate = ((double)nes->nescfg->FrameCycles*60.0/12.0)/(double)Config.sound.nRate;8 G$ |9 P$ W$ ] 
0 a- `. m" P- H 
        // CPU僒僀僋儖悢偑儖乕僾偟偰偟傑偭偨帪偺懳嶔張棟 
. `2 g) b" v. L6 n! g        if( elapsed_time > nes->cpu->GetTotalCycles() ) {6 \) U2 @. o( c0 j 
                QueueFlush(); 
7 {8 U- }) P# V: N$ [+ |/ f        }0 @) q1 z8 |* O7 ?' {( ^/ p 
 
' _1 H1 P$ e& m+ l. ^! q; N% ~1 ?6 C        while( dwLength-- ) {' ^3 h  Y0 C6 \+ p 
                writetime = (DWORD)elapsed_time;2 A/ d5 g0 B0 R/ g! J 
 
$ ?9 ]$ o7 U( F2 ?                while( GetQueue( writetime, q ) ) { 
" p- L8 B% B, q/ w/ n- e- {3 K8 u                        WriteProcess( q.addr, q.data ); 
! w3 n. o4 J% J: g                }" H2 k9 k9 N% H 
 
1 K9 M( m  H7 L# J( U: M                while( GetExQueue( writetime, q ) ) { 
9 C3 b8 G# H) l3 {! d& g" [. G                        WriteExProcess( q.addr, q.data ); 
2 D* e4 X; z- Y/ c                }3 B5 J; e$ h9 h9 G, ^7 ?) i' m; n 
 
( ~) O' F+ d( P$ b1 J' Z/ M                // 0-4:internal 5-7:VRC6 8:VRC7 9:FDS 10-12:MMC5 13-20:N106 21-23:FME7; S) n! H( T- [  l% h1 v- f6 n 
                output = 0;6 N0 W1 W  F& g( l 
                output += internal.Process( 0 )*vol[0]; 
1 U1 o- n" X$ M                output += internal.Process( 1 )*vol[1]; 
+ L$ G/ [' @4 p, R                output += internal.Process( 2 )*vol[2]; 
, r, X4 y. {, s                output += internal.Process( 3 )*vol[3];  I+ v& }* X1 S; G8 ~- U  t 
                output += internal.Process( 4 )*vol[4]; 
" {% ^0 r, ]' l2 Y: ?" W9 ~8 K 
) [  L* n$ H9 h0 h                if( exsound_select & 0x01 ) { 
" I0 N4 H2 a. z. j% L. u, h  D                        output += vrc6.Process( 0 )*vol[5];6 i" }/ M+ [2 H  N$ y6 R( } 
                        output += vrc6.Process( 1 )*vol[6];. S. E6 I. h/ d9 O 
                        output += vrc6.Process( 2 )*vol[7];6 r# e6 `) J* G* h+ @. x& q( l 
                }/ n: G2 X2 v) `- X9 [: O9 E) j 
                if( exsound_select & 0x02 ) {8 y$ Z# }) S8 G 
                        output += vrc7.Process( 0 )*vol[8];6 \  b0 K7 y7 D 
                }- [+ \: [/ ~' a5 m$ c) u 
                if( exsound_select & 0x04 ) {: i. z( d2 x; e7 y9 D 
                        output += fds.Process( 0 )*vol[9];3 I7 K9 f! Q* S. w# ~$ O9 K$ A3 @& { 
                } 
. b# _" C; _. @  m                if( exsound_select & 0x08 ) {! g5 H0 a& l" A/ x7 d3 a; [ 
                        output += mmc5.Process( 0 )*vol[10]; 
8 l7 c  r3 K2 K9 U                        output += mmc5.Process( 1 )*vol[11];$ ]9 m# N3 y" U5 p) l4 T 
                        output += mmc5.Process( 2 )*vol[12];# f9 W0 r' C/ P! G9 i 
                }8 A+ }7 F) q2 [) p* @( a: R0 X 
                if( exsound_select & 0x10 ) { 
) n+ o2 h; r) \                        output += n106.Process( 0 )*vol[13]; 
( ~) R4 {  B/ f" ?                        output += n106.Process( 1 )*vol[14]; 
: @: y; J* x& e, ], g0 c  u                        output += n106.Process( 2 )*vol[15];1 i: ^' d' ?9 K% Z5 m 
                        output += n106.Process( 3 )*vol[16]; 
, p0 {. p" `" j9 h  f, S6 t# V. |                        output += n106.Process( 4 )*vol[17]; 
; _5 U7 }- v$ Z; T$ `                        output += n106.Process( 5 )*vol[18];, ?- @6 i6 Z+ s9 G' [5 l: ] 
                        output += n106.Process( 6 )*vol[19]; 
  k) W4 ~! t* m/ R& Y) ]; x6 _                        output += n106.Process( 7 )*vol[20]; 
6 Q% X4 a. U- @                } 
# ]2 `+ J$ B7 l8 F% m1 P2 ?8 W                if( exsound_select & 0x20 ) { 
% p8 I6 g; l; [4 E! D& T6 `0 k. t                        fme7.Process( 3 );        // Envelope & Noise  q5 X% p/ f# w. f' X3 s5 u9 E 
                        output += fme7.Process( 0 )*vol[21];1 c6 s: \; x& Y 
                        output += fme7.Process( 1 )*vol[22];1 ]0 `+ K# Y8 h6 |$ S2 T9 ^ 
                        output += fme7.Process( 2 )*vol[23];( `& O4 Y9 ~4 _+ y. G) u 
                }" D) ~" D( Y0 a7 d$ ]" Q 
 
; `0 W/ L+ z6 Y                output >>= 8; 
# D; N; S1 }9 J5 c% P2 u5 [4 l7 M9 _$ u4 X: w9 F 
                if( nFilterType == 1 ) { 
" T7 v# o1 y0 U% \- F$ C0 J                        //儘乕僷僗僼傿儖僞乕TYPE 1(Simple)$ @' t  U9 \" g8 @ 
                        output = (lowpass_filter[0]+output)/2; 
5 X9 N# M% s. _                        lowpass_filter[0] = output;" S6 `' M0 g' y1 }0 I* T. \ 
                } else if( nFilterType == 2 ) {, U1 u$ i/ X7 S" P/ v/ e0 s) d 
                        //儘乕僷僗僼傿儖僞乕TYPE 2(Weighted type 1) 
' p$ N& I1 l; g, m! p% u& r5 p' o* Y                        output = (lowpass_filter[1]+lowpass_filter[0]+output)/3; 
( x$ p# e% A+ O% z* @- x* O                        lowpass_filter[1] = lowpass_filter[0];, u$ ]# N. X. v" s9 E 
                        lowpass_filter[0] = output;& K5 [1 h+ ~. ]: f. B& p0 { 
                } else if( nFilterType == 3 ) { 
; j: k3 k) _% g; r2 S                        //儘乕僷僗僼傿儖僞乕TYPE 3(Weighted type 2); E0 K$ L" ]" U4 Z1 Y 
                        output = (lowpass_filter[2]+lowpass_filter[1]+lowpass_filter[0]+output)/4; 
. A7 V% S+ h+ U3 J  _+ s                        lowpass_filter[2] = lowpass_filter[1];- N+ y8 S$ G$ }9 F! A 
                        lowpass_filter[1] = lowpass_filter[0]; 
9 m9 ]/ `9 }, D2 E# w                        lowpass_filter[0] = output; 
# b1 h, w% ], E& T7 S+ }- ~* g, {4 X                } else if( nFilterType == 4 ) { 
/ E0 |) S, o' u4 V                        //儘乕僷僗僼傿儖僞乕TYPE 4(Weighted type 3)  f/ Q" }& m5 t 
                        output = (lowpass_filter[1]+lowpass_filter[0]*2+output)/4; 
8 n% ?( K( p( k                        lowpass_filter[1] = lowpass_filter[0]; 
, R& I# g& u; @- Q7 s: X  B. ~( m                        lowpass_filter[0] = output;3 Y' V; e$ Q+ K! O1 m$ c" B3 T 
                } 
" }5 t9 @4 J# h$ _( y% n9 p4 }) a, C1 J& Q4 @  V7 ? 
#if        0 
  C4 Z  ?2 S5 |  E, [2 A! a, V7 V, E                // DC惉暘偺僇僢僩 
$ V. O7 G0 Q4 {( q5 K$ x1 B4 E9 ~0 |                {* Q9 f) ?$ r- R. e 
                static double ave = 0.0, max=0.0, min=0.0; 
- d% j" }2 K7 Y- c2 O                double delta;. R+ S9 L6 ]7 {4 W  X 
                delta = (max-min)/32768.0; 
5 W- d* X( R4 _2 \                max -= delta; 
$ V- r; B* M0 `  I                min += delta; 
( A8 u! N* L0 L# R; {4 [                if( output > max ) max = output;* c7 O% O! ?9 e0 U: j 
                if( output < min ) min = output;: G9 m1 C% k2 Q6 @6 r0 b 
                ave -= ave/1024.0; 
  d+ s# L3 K& }. g. c+ y8 S                ave += (max+min)/2048.0; 
; t) A( \( y' Z# V5 n% d  S; O                output -= (INT)ave;: S: w5 Z5 M/ E8 Y( c4 R( P 
                } 
5 S* P) f, ^, k  W6 H#endif/ \5 m  H* c7 e! a* W3 I# i! ` 
#if        11 a# A. s# i' R6 ^8 o- ` 
                // DC惉暘偺僇僢僩(HPF TEST) 
3 Z6 X* Y3 u4 K' x: d% R8 I& ]- i                {/ ~6 B) U; c/ a6 m' t' J0 s 
//                static        double        cutoff = (2.0*3.141592653579*40.0/44100.0);8 f7 ^/ \" F! G3 x" k 
                static        double        cutofftemp = (2.0*3.141592653579*40.0); 
- V4 I) H8 O( @1 E, Q( q* X                double        cutoff = cutofftemp/(double)Config.sound.nRate; 
. X" `! b$ }, E( ^* K/ v! {                static        double        tmp = 0.0; 
, u9 [" U. b- L& q                double        in, out;: l3 Q1 W) f6 Z' t 
! Y" k- n/ E7 y# F 
                in = (double)output; 
; u* l/ |" ?1 l. H& Y5 U7 Y& f' h6 b                out = (in - tmp);2 H0 n! P5 d, {9 }& I" E# ~: D 
                tmp = tmp + cutoff * out; 
  c" c+ f( G2 E# W2 ?" l5 | 
( o# O5 H1 N" S+ {, t                output = (INT)out; 
' z' V# c$ ^8 A+ s2 D8 x& Q1 W% U                }1 X/ p( J- K6 u( I& ] 
#endif 
& ]( h( y4 |' t# r# g4 C#if        0 
9 O$ a& a) S! J8 `' Y                // 僗僷僀僋僲僀僘偺彍嫀(AGC TEST) 
9 `3 W6 d) y* k: K! X                { 
; X5 k- M5 T0 |                INT        diff = abs(output-last_data); 
5 \/ w2 b- n9 g9 U( w! b                if( diff > 0x4000 ) {9 s4 P* }; X7 |7 C/ z 
                        output /= 4;# H8 P+ _: J( p1 D3 D 
                } else  
9 R, l$ Z# W- A5 p                if( diff > 0x3000 ) {. g8 ]( q) ?3 W) }7 M 
                        output /= 3; 
; x) _5 `5 j+ o1 P4 N7 X; t4 C3 {0 L                } else4 r# B" S+ ]8 ?- V7 B* D/ B2 r 
                if( diff > 0x2000 ) { 
1 u' ~+ M) k, J                        output /= 2;1 h6 z2 r& H$ O: D8 z3 |: t+ \: t' i 
                }7 `2 v' d, D8 H6 p3 j4 V9 z  C 
                last_data = output;) i! [5 K  e0 e2 B) c 
                } 
# r8 D& k4 z' m) G#endif5 s% C/ Q( Y* E. @% [( \8 A, c 
                // Limit9 v' S3 q7 j; u: R0 C" r" @ 
                if( output > 0x7FFF ) {$ V# c: L5 W1 t2 S3 j- B& \( G 
                        output = 0x7FFF;/ g2 |9 n) P# L% `7 A; q+ |% I$ z 
                } else if( output < -0x8000 ) { 
9 u! x# [7 o  h3 {. D5 |2 W                        output = -0x8000;5 b  c$ D% g* a9 z1 M) D6 F) c 
                }/ F$ t4 ]" H; R( L/ y7 @! i 
0 D7 T% X6 ^* x* V: r4 m 
                if( nBits != 8 ) { 
, Q9 x$ S6 s' A- V                        *(SHORT*)lpBuffer = (SHORT)output;" e) j& |: x. v- X- g+ n 
                        lpBuffer += sizeof(SHORT);8 V# \+ ]7 w. E5 M& X+ u 
                } else {: O* G5 n' Q/ X8 d( s3 S! U! u" ^ 
                        *lpBuffer++ = (output>>8)^0x80; 
( {+ {% e0 N# h$ W# s* W9 g! n3 ?                } 
( t# }8 j. G7 H! w# S, \" c+ f$ N5 M' `7 \* C& ]3 y 
                if( nCcount < 0x0100 )$ [$ `' v* T3 @  Q) Y2 d 
                        pSoundBuf[nCcount++] = (SHORT)output; 
) w7 r3 O! q. y2 {9 N( O 
( j+ }. A. [$ j& A) E0 b//                elapsedtime += cycle_rate; 
' d' Z% @4 U3 I                elapsed_time += cycle_rate;, S1 o) ]2 n) x 
        } 
% h! q, l: e. C! L5 c. e 
( @$ Y, t# _# h3 n7 I$ `#if        1" w) f$ U' I' U9 E- ~ 
        if( elapsed_time > ((nes->nescfg->FrameCycles/24)+nes->cpu->GetTotalCycles()) ) { 
7 f7 ?% I: T+ S+ N( m/ g                elapsed_time = nes->cpu->GetTotalCycles(); 
1 Y. i! D- w" Z% r9 p7 m4 d        } 
) X- ]& q, j4 I        if( (elapsed_time+(nes->nescfg->FrameCycles/6)) < nes->cpu->GetTotalCycles() ) {5 V- M5 z/ x% Z$ n, h* z. V9 L 
                elapsed_time = nes->cpu->GetTotalCycles(); 
, y! l# ?! ~( y. R( l  ^. S        } 
+ d8 e5 ^* ~6 v: H#else 
0 c0 D5 H+ @/ T5 q/ ~        elapsed_time = nes->cpu->GetTotalCycles(); 
4 ?) o' e% g2 r! ?8 K& j1 z6 N8 y7 H#endif) D9 i3 |8 j9 s4 ] 
}3 U, s+ ~$ f' R 
 
) v, y" D, d& s+ D! m( Q( a// 僠儍儞僱儖偺廃攇悢庢摼僒僽儖乕僠儞(NSF梡)# y0 ]. n" g, I0 g" K 
INT        APU::GetChannelFrequency( INT no )$ S# u9 p  c8 p9 p8 w' }6 u0 U 
{, k1 @4 s& O3 [8 S2 l 
        if( !m_bMute[0] ) 
9 i1 N& J; z1 |' a/ ]: [0 ~                return        0;/ }4 m! k, f& N9 S7 z$ s 
' i: l, A! N4 ~- }- L! a/ w 
        // Internal 
  w$ ]5 E6 R; F+ V4 ^3 M, E        if( no < 5 ) {& x) k3 ]$ G* R: q 
                return        m_bMute[no+1]?internal.GetFreq( no ):0;  o- I: ~  O, o! p) ^+ A$ W 
        }6 f. I& W% V( I 
        // VRC6 
: u4 |) v* |4 ]7 B, {: C3 n        if( (exsound_select & 0x01) && no >= 0x0100 && no < 0x0103 ) {  I. K  ]) a6 ]7 v4 o) r5 Z9 [ 
                return        m_bMute[6+(no&0x03)]?vrc6.GetFreq( no & 0x03 ):0; 
7 R3 |& X" C, I        }  b6 {% j5 B* W3 M7 h4 Q- L8 U 
        // FDS 
7 z1 Z7 |5 f. z$ z8 }        if( (exsound_select & 0x04) && no == 0x300 ) {0 x5 f' ?% c* A, i 
                return        m_bMute[6]?fds.GetFreq( 0 ):0; 
4 Y2 d- g8 X7 F' L        }; M! v4 ]' v; Y0 Q3 F 
        // MMC5 
/ v: m' ~! p/ {0 n$ Y$ o' u! T        if( (exsound_select & 0x08) && no >= 0x0400 && no < 0x0402 ) {8 u; A5 }! E) ^ 
                return        m_bMute[6+(no&0x03)]?mmc5.GetFreq( no & 0x03 ):0;% n6 Q( R" P2 w/ [3 X: ?9 }# m 
        } 
: j$ D# a0 p, t5 k  }& j" U0 d        // N106, ]) R# p' R, E3 k3 x  M7 b 
        if( (exsound_select & 0x10) && no >= 0x0500 && no < 0x0508 ) { 
3 O; r8 L7 F0 [                return        m_bMute[6+(no&0x07)]?n106.GetFreq( no & 0x07 ):0; 
' e4 I$ `4 d0 X' |$ P        } 
4 ^1 Y7 P' o( }2 n* ^* a        // FME71 i# t: b: c) v" b) j( C/ K 
        if( (exsound_select & 0x20) && no >= 0x0600 && no < 0x0603 ) { 
, ~* b& q  r1 k+ r, r                return        m_bMute[6+(no&0x03)]?fme7.GetFreq( no & 0x03 ):0;, Z! |% K% B5 P8 K+ H 
        } 
' }  v; n( s* W* H' d1 j6 I# |6 T        // VRC71 t1 g7 K- v6 q 
        if( (exsound_select & 0x02) && no >= 0x0700 && no < 0x0709 ) { 
. Y  k1 u' f8 M4 u                return        m_bMute[6]?vrc7.GetFreq(no&0x0F):0;4 Q; R' _4 x4 I0 s 
        } 
+ B; ?: P5 J! {9 P5 L( W- l        return        0;; {9 L: w9 r4 H) [) _+ H' n 
} 
- E' Y/ U6 B3 q% i0 S* V- F$ ]: ]; [3 A0 y7 c. t 
// State Save/Load 
3 a7 E& n8 z% c+ @1 ?9 ^void        APU::SaveState( LPBYTE p )4 _+ W8 z6 ^: |* u& T 
{) l1 C$ z* L2 f! h 
#ifdef        _DEBUG 
' N9 U5 W' H9 F/ x; v. J0 GLPBYTE        pold = p; 
1 Z' O- v% k! U#endif4 c3 c; h2 R7 o6 _ 
7 S( |( R8 e3 Q) H 
        // 帪娫幉傪摨婜偝偣傞堊Flush偡傞 
( B' }! G& J- a' v. h        QueueFlush(); 
' Z( E# S/ q5 H! K* w& p; {# A: F& a+ ?2 M0 h- F# b2 {* z 
        internal.SaveState( p );  J, r1 e" u) q$ ?  w 
        p += (internal.GetStateSize()+15)&(~0x0F);        // Padding 
, V2 U/ ]# `) M. y; B( ^, S0 M  a/ `7 X+ y 
        // VRC69 ~  F. z7 c' p: [# F4 e+ u; V 
        if( exsound_select & 0x01 ) { 
; i7 Y. z- ^$ V5 s( [4 b                vrc6.SaveState( p );! a' P+ B2 @% N% b9 L 
                p += (vrc6.GetStateSize()+15)&(~0x0F);        // Padding 
. H" U, q  T& }1 \5 X4 J' |        } 
5 p7 `6 N/ {4 G) Z- Z0 V( l        // VRC7 (not support) 
- c) k4 I# k5 ^* k        if( exsound_select & 0x02 ) {% C+ N8 n$ i5 \! i2 d  l 
                vrc7.SaveState( p ); 
0 n& r# R/ k& @1 ]) a8 g. ]+ n6 V                p += (vrc7.GetStateSize()+15)&(~0x0F);        // Padding 
& R) ]2 d* o' z2 Z* X        }) {- w6 h# \; W! f, h- H 
        // FDS 
7 N: x* {  O- T        if( exsound_select & 0x04 ) { 
  [: b* Z: z# l8 b; A9 C& y                fds.SaveState( p ); 
* C! K2 @3 [3 {& {                p += (fds.GetStateSize()+15)&(~0x0F);        // Padding9 i' B, |( a! B3 ] 
        }$ H& l2 E# ?$ r7 B/ V, L 
        // MMC5* F' Y3 h4 }2 a) t. M# x 
        if( exsound_select & 0x08 ) { 
7 M9 {& a3 ~1 f: F' u+ k6 P                mmc5.SaveState( p ); 
7 o  T5 o9 {/ ^) ?7 p, s; K6 A                p += (mmc5.GetStateSize()+15)&(~0x0F);        // Padding 
4 [3 k% R5 f2 u7 d  I# D) @( B        } 
$ @% @8 W8 D  x" |% k) G5 L- F        // N106 
/ F; }  t! b9 v( h: Z8 i        if( exsound_select & 0x10 ) { 
1 a+ H# t; v: F6 v7 W/ y, A4 z& k! K1 j                n106.SaveState( p );6 @1 f7 ?# K7 O1 ?* E8 v 
                p += (n106.GetStateSize()+15)&(~0x0F);        // Padding/ [1 A, t8 d: ]1 r 
        } 
4 ?  x- ~1 s4 \8 V9 k, @9 H2 V+ H        // FME7 
0 D9 b8 Z4 m+ x: x% @        if( exsound_select & 0x20 ) { 
/ n7 f+ r, S) [" R                fme7.SaveState( p ); 
1 y7 ?% h( Y- H  l, a% N                p += (fme7.GetStateSize()+15)&(~0x0F);        // Padding/ q/ P& z9 Q" c 
        }2 T+ S  Q3 G( o9 b( D0 q 
+ s! [. ^( A, N' e* g( e0 ? 
#ifdef        _DEBUG 
0 f8 c0 O* [% ^0 O, z- g( q" x. U6 }DEBUGOUT( "SAVE APU SIZE:%d\n", p-pold ); 
) l" J6 F; X2 i4 O: K5 q" ?# @#endif' H/ W! g  R+ q, J! \ 
}( {1 j! w4 R8 }- L 
 
) ]8 `% _. d8 x9 e1 w7 vvoid        APU::LoadState( LPBYTE p )9 L" t: V  \1 q3 ~. U7 j6 R& l 
{/ L. b3 ?: m2 {9 p0 m 
        // 帪娫幉傪摨婜偝偣傞堊偵徚偡! H# L: n* i, T( ?0 I9 z3 c 
        QueueClear(); 
! b/ S. g7 \4 {/ l2 c6 p  X; |7 _+ @) [' X 
        internal.LoadState( p );5 A" ~. J3 g" O9 v& k/ U 
        p += (internal.GetStateSize()+15)&(~0x0F);        // Padding& W8 y! i! b' q" z$ x& l  @ 
 
" _0 N/ Q' P: ~: I) g. ?        // VRC6' n- y5 m# G  I. L, K( k  k 
        if( exsound_select & 0x01 ) { 
  p/ q. e. |. ^* [/ e' C* M                vrc6.LoadState( p );2 {8 x/ g8 t( L2 D6 y 
                p += (vrc6.GetStateSize()+15)&(~0x0F);        // Padding, q- H7 f& `( M: y7 T# c7 u 
        } 
: q# E6 J9 n. k( E- p. g        // VRC7 (not support)  q+ }- m- W6 r: `% r 
        if( exsound_select & 0x02 ) { 
1 [# ]& R/ e7 ]% s) F2 Y" D                vrc7.LoadState( p );. g9 d" t" @! j! b- b; N$ Q 
                p += (vrc7.GetStateSize()+15)&(~0x0F);        // Padding 
0 T6 E4 j+ X0 H; t# D: j  W        }6 I6 L0 i- ?1 D; h 
        // FDS: C: B/ M! Q: p: U4 H' U2 I" ? 
        if( exsound_select & 0x04 ) {* s6 O6 i# z+ a) y1 k( B$ b& }$ [ 
                fds.LoadState( p );) w+ ]/ F: o5 S 
                p += (fds.GetStateSize()+15)&(~0x0F);        // Padding: y+ M/ u1 w3 X7 E. i+ o 
        } 
2 w; Q! P% O: o& d7 y        // MMC5& c. A+ v- k: B* z% X 
        if( exsound_select & 0x08 ) { 
% b3 I8 z* J. K( v% x$ Q) ~7 @                mmc5.LoadState( p ); 
, \* Y4 {/ D+ p! g$ e+ u7 J                p += (mmc5.GetStateSize()+15)&(~0x0F);        // Padding4 F  o; N6 H  _9 u/ `4 Y! W8 x 
        }8 L5 }+ {6 A& M3 a4 r& d% R 
        // N106 
3 @  ?1 f+ }# E: Q- z$ k: U' d        if( exsound_select & 0x10 ) { 
+ M* H  @4 f7 F4 O) E0 Z/ t! K                n106.LoadState( p ); 
6 L- m, P; P; ~( y; T  u# z                p += (n106.GetStateSize()+15)&(~0x0F);        // Padding 
5 C9 F/ U: U2 J. x$ I        }4 Z, e% B/ i3 o: a/ I 
        // FME7 
& E* I$ i* f3 p$ q' O7 Y/ }7 b        if( exsound_select & 0x20 ) {; H% i3 d, K  J# u. w- B* I0 T 
                fme7.LoadState( p ); 
& {* @; v) i, k" z2 p/ O                p += (fme7.GetStateSize()+15)&(~0x0F);        // Padding 
9 j& ^, q! G9 N9 V$ }( p' I" d  |        } 
8 m* F% x+ R( Y} |   
 
 
 
 |