diff options
Diffstat (limited to 'gearboy/src/audio/Gb_Apu_State.cpp')
| -rw-r--r-- | gearboy/src/audio/Gb_Apu_State.cpp | 119 |
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; +} + |
