cog/Frameworks/GME/gme/Snes_Spc.h

122 lines
3.1 KiB
C++
Executable File

// Super Nintendo (SNES) SPC-700 APU Emulator
// Game_Music_Emu 0.5.2
#ifndef SNES_SPC_H
#define SNES_SPC_H
#include "blargg_common.h"
#include "Spc_Cpu.h"
#include "Spc_Dsp.h"
class Snes_Spc {
public:
// Load copy of SPC data into emulator. Clear echo buffer if 'clear_echo' is true.
enum { spc_file_size = 0x10180 };
blargg_err_t load_spc( const void* spc, long spc_size );
// Generate 'count' samples and optionally write to 'buf'. Count must be even.
// Sample output is 16-bit 32kHz, signed stereo pairs with the left channel first.
typedef short sample_t;
blargg_err_t play( long count, sample_t* buf = NULL );
// Optional functionality
// Load copy of state into emulator.
typedef Spc_Cpu::registers_t registers_t;
blargg_err_t load_state( const registers_t& cpu_state, const void* ram_64k,
const void* dsp_regs_128 );
// Clear echo buffer, useful because many tracks have junk in the buffer.
void clear_echo();
// Mute voice n if bit n (1 << n) of mask is set
enum { voice_count = Spc_Dsp::voice_count };
void mute_voices( int mask );
// Skip forward by the specified number of samples (64000 samples = 1 second)
blargg_err_t skip( long count );
// Set gain, where 1.0 is normal. When greater than 1.0, output is clamped the
// 16-bit sample range.
void set_gain( double );
// If true, prevent channels and global volumes from being phase-negated
void disable_surround( bool disable = true );
// Set 128 bytes to use for IPL boot ROM. Makes copy. Default is zero filled,
// to avoid including copyrighted code from the SPC-700.
void set_ipl_rom( const void* );
void set_tempo( double );
public:
Snes_Spc();
typedef BOOST::uint8_t uint8_t;
private:
// timers
struct Timer
{
spc_time_t next_tick;
int period;
int count;
int divisor;
int enabled;
int counter;
void run_until_( spc_time_t );
void run_until( spc_time_t time )
{
if ( time >= next_tick )
run_until_( time );
}
};
enum { timer_count = 3 };
Timer timer [timer_count];
// hardware
int extra_cycles;
spc_time_t time() const;
int read( spc_addr_t );
void write( spc_addr_t, int );
friend class Spc_Cpu;
// dsp
sample_t* sample_buf;
sample_t* buf_end; // to do: remove this once possible bug resolved
spc_time_t next_dsp;
Spc_Dsp dsp;
int keys_pressed;
int keys_released;
sample_t skip_sentinel [1]; // special value for play() passed by skip()
void run_dsp( spc_time_t );
void run_dsp_( spc_time_t );
bool echo_accessed;
void check_for_echo_access( spc_addr_t );
// boot rom
enum { rom_size = 64 };
enum { rom_addr = 0xFFC0 };
bool rom_enabled;
void enable_rom( bool );
// CPU and RAM (at end because it's large)
Spc_Cpu cpu;
uint8_t extra_ram [rom_size];
struct {
// padding to catch jumps before beginning or past end
uint8_t padding1 [0x100];
uint8_t ram [0x10000];
uint8_t padding2 [0x100];
} mem;
uint8_t boot_rom [rom_size];
};
inline void Snes_Spc::disable_surround( bool disable ) { dsp.disable_surround( disable ); }
inline void Snes_Spc::mute_voices( int mask ) { dsp.mute_voices( mask ); }
inline void Snes_Spc::set_gain( double v ) { dsp.set_gain( v ); }
#endif