PageRenderTime 40ms CodeModel.GetById 10ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/gme/Nes_Fme7_Apu.h

http://game-music-emu.googlecode.com/
C++ Header | 131 lines | 99 code | 25 blank | 7 comment | 3 complexity | f795b52db6697a36a776d4a897957030 MD5 | raw file
  1// Sunsoft FME-7 sound emulator
  2
  3// Game_Music_Emu 0.5.5
  4#ifndef NES_FME7_APU_H
  5#define NES_FME7_APU_H
  6
  7#include "blargg_common.h"
  8#include "Blip_Buffer.h"
  9
 10struct fme7_apu_state_t
 11{
 12	enum { reg_count = 14 };
 13	BOOST::uint8_t regs [reg_count];
 14	BOOST::uint8_t phases [3]; // 0 or 1
 15	BOOST::uint8_t latch;
 16	BOOST::uint16_t delays [3]; // a, b, c
 17};
 18
 19class Nes_Fme7_Apu : private fme7_apu_state_t {
 20public:
 21	// See Nes_Apu.h for reference
 22	void reset();
 23	void volume( double );
 24	void treble_eq( blip_eq_t const& );
 25	void output( Blip_Buffer* );
 26	enum { osc_count = 3 };
 27	void osc_output( int index, Blip_Buffer* );
 28	void end_frame( blip_time_t );
 29	void save_state( fme7_apu_state_t* ) const;
 30	void load_state( fme7_apu_state_t const& );
 31	
 32	// Mask and addresses of registers
 33	enum { addr_mask = 0xE000 };
 34	enum { data_addr = 0xE000 };
 35	enum { latch_addr = 0xC000 };
 36	
 37	// (addr & addr_mask) == latch_addr
 38	void write_latch( int );
 39	
 40	// (addr & addr_mask) == data_addr
 41	void write_data( blip_time_t, int data );
 42	
 43public:
 44	Nes_Fme7_Apu();
 45	BLARGG_DISABLE_NOTHROW
 46private:
 47	// noncopyable
 48	Nes_Fme7_Apu( const Nes_Fme7_Apu& );
 49	Nes_Fme7_Apu& operator = ( const Nes_Fme7_Apu& );
 50	
 51	static unsigned char const amp_table [16];
 52	
 53	struct {
 54		Blip_Buffer* output;
 55		int last_amp;
 56	} oscs [osc_count];
 57	blip_time_t last_time;
 58	
 59	enum { amp_range = 192 }; // can be any value; this gives best error/quality tradeoff
 60	Blip_Synth<blip_good_quality,1> synth;
 61	
 62	void run_until( blip_time_t );
 63};
 64
 65inline void Nes_Fme7_Apu::volume( double v )
 66{
 67	synth.volume( 0.38 / amp_range * v ); // to do: fine-tune
 68}
 69
 70inline void Nes_Fme7_Apu::treble_eq( blip_eq_t const& eq )
 71{
 72	synth.treble_eq( eq );
 73}
 74
 75inline void Nes_Fme7_Apu::osc_output( int i, Blip_Buffer* buf )
 76{
 77	assert( (unsigned) i < osc_count );
 78	oscs [i].output = buf;
 79}
 80
 81inline void Nes_Fme7_Apu::output( Blip_Buffer* buf )
 82{
 83	for ( int i = 0; i < osc_count; i++ )
 84		osc_output( i, buf );
 85}
 86
 87inline Nes_Fme7_Apu::Nes_Fme7_Apu()
 88{
 89	output( NULL );
 90	volume( 1.0 );
 91	reset();
 92}
 93
 94inline void Nes_Fme7_Apu::write_latch( int data ) { latch = data; }
 95
 96inline void Nes_Fme7_Apu::write_data( blip_time_t time, int data )
 97{
 98	if ( (unsigned) latch >= reg_count )
 99	{
100		#ifdef debug_printf
101			debug_printf( "FME7 write to %02X (past end of sound registers)\n", (int) latch );
102		#endif
103		return;
104	}
105	
106	run_until( time );
107	regs [latch] = data;
108}
109
110inline void Nes_Fme7_Apu::end_frame( blip_time_t time )
111{
112	if ( time > last_time )
113		run_until( time );
114	
115	assert( last_time >= time );
116	last_time -= time;
117}
118
119inline void Nes_Fme7_Apu::save_state( fme7_apu_state_t* out ) const
120{
121	*out = *this;
122}
123
124inline void Nes_Fme7_Apu::load_state( fme7_apu_state_t const& in )
125{
126	reset();
127	fme7_apu_state_t* state = this;
128	*state = in;
129}
130
131#endif