1 // Common aspects of emulators which use Blip_Buffer for sound output
2 
3 // Game_Music_Emu 0.6.0
4 #ifndef CLASSIC_EMU_H
5 #define CLASSIC_EMU_H
6 
7 #include "blargg_common.h"
8 #include "Blip_Buffer.h"
9 #include "Music_Emu.h"
10 
11 class Classic_Emu : public Music_Emu {
12 public:
13 	Classic_Emu();
14 	~Classic_Emu();
15 	void set_buffer( Multi_Buffer* );
16 protected:
17 	// Services
18 	enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
set_voice_types(int const * t)19 	void set_voice_types( int const* t ) { voice_types = t; }
20 	blargg_err_t setup_buffer( long clock_rate );
clock_rate()21 	long clock_rate() const { return clock_rate_; }
22 	void change_clock_rate( long ); // experimental
23 
24 	// Overridable
25 	virtual void set_voice( int index, Blip_Buffer* center,
26 			Blip_Buffer* left, Blip_Buffer* right ) = 0;
27 	virtual void update_eq( blip_eq_t const& ) = 0;
28 	virtual blargg_err_t start_track_( int track ) = 0;
29 	virtual blargg_err_t run_clocks( blip_time_t& time_io, int msec ) = 0;
30 protected:
31 	blargg_err_t set_sample_rate_( long sample_rate );
32 	void mute_voices_( int );
33 	void set_equalizer_( equalizer_t const& );
34 	blargg_err_t play_( long, sample_t* );
35 private:
36 	Multi_Buffer* buf;
37 	Multi_Buffer* stereo_buffer; // NULL if using custom buffer
38 	long clock_rate_;
39 	unsigned buf_changed_count;
40 	int const* voice_types;
41 };
42 
set_buffer(Multi_Buffer * new_buf)43 inline void Classic_Emu::set_buffer( Multi_Buffer* new_buf )
44 {
45 	assert( !buf && new_buf );
46 	buf = new_buf;
47 }
48 
49 // ROM data handler, used by several Classic_Emu derivitives. Loads file data
50 // with padding on both sides, allowing direct use in bank mapping. The main purpose
51 // is to allow all file data to be loaded with only one read() call (for efficiency).
52 
53 class Rom_Data_ {
54 public:
55 	typedef unsigned char byte;
56 protected:
57 	enum { pad_extra = 8 };
58 	blargg_vector<byte> rom;
59 	long file_size_;
60 	blargg_long rom_addr;
61 	blargg_long mask;
62 	blargg_long size_; // TODO: eliminate
63 
64 	blargg_err_t load_rom_data_( Data_Reader& in, int header_size, void* header_out,
65 			int fill, long pad_size );
66 	void set_addr_( long addr, int unit );
67 };
68 
69 template<int unit>
70 class Rom_Data : public Rom_Data_ {
71 	enum { pad_size = unit + pad_extra };
72 public:
73 	// Load file data, using already-loaded header 'h' if not NULL. Copy header
74 	// from loaded file data into *out and fill unmapped bytes with 'fill'.
load(Data_Reader & in,int header_size,void * header_out,int fill)75 	blargg_err_t load( Data_Reader& in, int header_size, void* header_out, int fill )
76 	{
77 		return load_rom_data_( in, header_size, header_out, fill, pad_size );
78 	}
79 
80 	// Size of file data read in (excluding header)
file_size()81 	long file_size() const { return file_size_; }
82 
83 	// Pointer to beginning of file data
begin()84 	byte* begin() const { return rom.begin() + pad_size; }
85 
86 	// Set address that file data should start at
set_addr(long addr)87 	void set_addr( long addr ) { set_addr_( addr, unit ); }
88 
89 	// Free data
clear()90 	void clear() { rom.clear(); }
91 
92 	// Size of data + start addr, rounded to a multiple of unit
size()93 	long size() const { return size_; }
94 
95 	// Pointer to unmapped page filled with same value
unmapped()96 	byte* unmapped() { return rom.begin(); }
97 
98 	// Mask address to nearest power of two greater than size()
mask_addr(blargg_long addr)99 	blargg_long mask_addr( blargg_long addr ) const
100 	{
101 		#ifdef check
102 			check( addr <= mask );
103 		#endif
104 		return addr & mask;
105 	}
106 
107 	// Pointer to page starting at addr. Returns unmapped() if outside data.
at_addr(blargg_long addr)108 	byte* at_addr( blargg_long addr )
109 	{
110 		blargg_ulong offset = mask_addr( addr ) - rom_addr;
111 		if ( offset > blargg_ulong (rom.size() - pad_size) )
112 			offset = 0; // unmapped
113 		return &rom [offset];
114 	}
115 };
116 
117 #ifndef GME_APU_HOOK
118 	#define GME_APU_HOOK( emu, addr, data ) ((void) 0)
119 #endif
120 
121 #ifndef GME_FRAME_HOOK
122 	#define GME_FRAME_HOOK( emu ) ((void) 0)
123 #else
124 	#define GME_FRAME_HOOK_DEFINED 1
125 #endif
126 
127 #endif
128