// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ #include "Gb_Apu.h" #include /* 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; }