122 lines
3.1 KiB
C++
Executable File
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
|