vbagx/source/vba/gb_apu/Gb_Apu_State.cpp

119 lines
3.5 KiB
C++

// 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;
}