summaryrefslogtreecommitdiffstats
path: root/gearboy/src/audio/Gb_Apu_State.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gearboy/src/audio/Gb_Apu_State.cpp')
-rw-r--r--gearboy/src/audio/Gb_Apu_State.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/gearboy/src/audio/Gb_Apu_State.cpp b/gearboy/src/audio/Gb_Apu_State.cpp
new file mode 100644
index 00000000..6a523460
--- /dev/null
+++ b/gearboy/src/audio/Gb_Apu_State.cpp
@@ -0,0 +1,119 @@
+// Gb_Snd_Emu $vers. http://www.slack.net/~ant/
+
+#include "Gb_Apu.h"
+
+#include <string.h>
+
+/* Copyright (C) 2007 Shay Green. This module is free software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser
+General Public License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version. This
+module is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details. You should have received a copy of the GNU Lesser General Public
+License along with this module; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "blargg_source.h"
+
+#if GB_APU_CUSTOM_STATE
+ #define REFLECT( x, y ) (save ? (io->y) = (x) : (x) = (io->y) )
+#else
+ #define REFLECT( x, y ) (save ? set_val( io->y, x ) : (void) ((x) = get_val( io->y )))
+
+ static blargg_ulong get_val( byte const* p )
+ {
+ return p [3] * 0x1000000 + p [2] * 0x10000 + p [1] * 0x100 + p [0];
+ }
+
+ static void set_val( byte* p, blargg_ulong n )
+ {
+ p [0] = (byte) (n );
+ p [1] = (byte) (n >> 8);
+ p [2] = (byte) (n >> 16);
+ p [3] = (byte) (n >> 24);
+ }
+#endif
+
+inline const char* Gb_Apu::save_load( gb_apu_state_t* io, bool save )
+{
+ #if !GB_APU_CUSTOM_STATE
+ assert( sizeof (gb_apu_state_t) == 256 );
+ #endif
+
+ int format = io->format0;
+ REFLECT( format, format );
+ if ( format != io->format0 )
+ return "Unsupported sound save state format";
+
+ int version = 0;
+ REFLECT( version, version );
+
+ // Registers and wave RAM
+ assert( regs_size == sizeof io->regs );
+ if ( save )
+ memcpy( io->regs, regs, sizeof io->regs );
+ else
+ memcpy( regs, io->regs, sizeof regs );
+
+ // Frame sequencer
+ REFLECT( frame_time, frame_time );
+ REFLECT( frame_phase, frame_phase );
+
+ REFLECT( square1.sweep_freq, sweep_freq );
+ REFLECT( square1.sweep_delay, sweep_delay );
+ REFLECT( square1.sweep_enabled, sweep_enabled );
+ REFLECT( square1.sweep_neg, sweep_neg );
+
+ REFLECT( noise.divider, noise_divider );
+ REFLECT( wave.sample_buf, wave_buf );
+
+ return 0;
+}
+
+// second function to avoid inline limits of some compilers
+inline void Gb_Apu::save_load2( gb_apu_state_t* io, bool save )
+{
+ for ( int i = osc_count; --i >= 0; )
+ {
+ Gb_Osc& osc = *oscs [i];
+ REFLECT( osc.delay, delay [i] );
+ REFLECT( osc.length_ctr, length_ctr [i] );
+ REFLECT( osc.phase, phase [i] );
+ REFLECT( osc.enabled, enabled [i] );
+
+ if ( i != 2 )
+ {
+ int j = min( i, 2 );
+ Gb_Env& env = STATIC_CAST(Gb_Env&,osc);
+ REFLECT( env.env_delay, env_delay [j] );
+ REFLECT( env.volume, env_volume [j] );
+ REFLECT( env.env_enabled, env_enabled [j] );
+ }
+ }
+}
+
+void Gb_Apu::save_state( gb_apu_state_t* out )
+{
+ (void) save_load( out, true );
+ save_load2( out, true );
+
+ #if !GB_APU_CUSTOM_STATE
+ memset( out->unused, 0, sizeof out->unused );
+ #endif
+}
+
+blargg_err_t Gb_Apu::load_state( gb_apu_state_t const& in )
+{
+ RETURN_ERR( save_load( CONST_CAST(gb_apu_state_t*,&in), false ) );
+ save_load2( CONST_CAST(gb_apu_state_t*,&in), false );
+
+ apply_stereo();
+ synth_volume( 0 ); // suppress output for the moment
+ run_until_( last_time ); // get last_amp updated
+ apply_volume(); // now use correct volume
+
+ return 0;
+}
+