summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.6pre/gme/Gb_Apu.h
blob: f7ffb037e3f9a3f268ccd2ff1d22c25d5e27f362 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Nintendo Game Boy sound hardware emulator with save state support

// Gb_Snd_Emu 0.1.4
#ifndef GB_APU_H
#define GB_APU_H

#include "Gb_Oscs.h"

struct gb_apu_state_t;

class Gb_Apu {
public:
// Basics

	// Sets buffer(s) to generate sound into, or NULL to mute. If only center is not NULL,
	// output is mono.
	void set_output( Blip_Buffer* center, Blip_Buffer* left = NULL, Blip_Buffer* right = NULL );
	
	// Emulates to time t, then writes data to addr
	void write_register( blip_time_t t, int addr, int data );
	
	// Emulates to time t, then subtracts t from the current time.
	// OK if previous write call had time slightly after t.
	void end_frame( blip_time_t t );
	
// More features
	
	// Clock rate sound hardware runs at
	enum { clock_rate = 4194304 * GB_APU_OVERCLOCK };
	
	// Registers are at io_addr to io_addr+io_size-1
	enum { io_addr = 0xFF10 };
	enum { io_size = 0x30 };
	
	// Emulates to time t, then reads from addr
	int read_register( blip_time_t t, int addr );
	
	// Resets hardware to state after power, BEFORE boot ROM runs. Mode selects
	// sound hardware. If agb_wave is true, enables AGB's extra wave features.
	enum mode_t {
		mode_dmg,   // Game Boy monochrome
		mode_cgb,   // Game Boy Color
		mode_agb    // Game Boy Advance
	};
	void reset( mode_t mode = mode_cgb, bool agb_wave = false );
	
	// Same as set_output(), but for a particular channel
	// 0: Square 1, 1: Square 2, 2: Wave, 3: Noise
	enum { osc_count = 4 }; // 0 <= chan < osc_count
	void set_output( int chan, Blip_Buffer* center,
			Blip_Buffer* left = NULL, Blip_Buffer* right = NULL );
	
	// Sets overall volume, where 1.0 is normal
	void volume( double );
	
	// Sets treble equalization
	void treble_eq( blip_eq_t const& );
	
	// Treble and bass values for various hardware.
	enum {
		speaker_treble =  -47, // speaker on system
		speaker_bass   = 2000,
		dmg_treble     =    0, // headphones on each system
		dmg_bass       =   30,
		cgb_treble     =    0,
		cgb_bass       =  300, // CGB has much less bass
		agb_treble     =    0,
		agb_bass       =   30
	};
	
	// If true, reduces clicking by disabling DAC biasing. Note that this reduces
	// emulation accuracy, since the clicks are authentic.
	void reduce_clicks( bool reduce = true );
	
	// Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the
	// tempo in a music player.
	void set_tempo( double );
	
	// Saves full emulation state to state_out. Data format is portable and
	// includes some extra space to avoid expansion in case more state needs
	// to be stored in the future.
	void save_state( gb_apu_state_t* state_out );
	
	// Loads state. You should call reset() BEFORE this.
	blargg_err_t load_state( gb_apu_state_t const& in );

private:
	// noncopyable
	Gb_Apu( const Gb_Apu& );
	Gb_Apu& operator = ( const Gb_Apu& );

// Implementation
public:
	Gb_Apu();
	
	// Use set_output() in place of these
	BLARGG_DEPRECATED( void output    (        Blip_Buffer* c                                 ); )
	BLARGG_DEPRECATED( void output    (        Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ); )
	BLARGG_DEPRECATED( void osc_output( int i, Blip_Buffer* c                                 ) { set_output( i, c, c, c ); } )
	BLARGG_DEPRECATED( void osc_output( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( i, c, l, r ); } )
	
	BLARGG_DEPRECATED_TEXT( enum { start_addr = 0xFF10 }; )
	BLARGG_DEPRECATED_TEXT( enum { end_addr   = 0xFF3F }; )
	BLARGG_DEPRECATED_TEXT( enum { register_count = end_addr - start_addr + 1 }; )

private:    
	Gb_Osc*     oscs [osc_count];
	blip_time_t last_time;          // time sound emulator has been run to
	blip_time_t frame_period;       // clocks between each frame sequencer step
	double      volume_;
	bool        reduce_clicks_;
	
	Gb_Sweep_Square square1;
	Gb_Square       square2;
	Gb_Wave         wave;
	Gb_Noise        noise;
	blip_time_t     frame_time;     // time of next frame sequencer action
	int             frame_phase;    // phase of next frame sequencer step
	enum { regs_size = io_size + 0x10 };
	BOOST::uint8_t  regs [regs_size];// last values written to registers
	
	// large objects after everything else
	Blip_Synth_Norm norm_synth;
	Blip_Synth_Fast fast_synth;
	
	void reset_lengths();
	void reset_regs();
	int calc_output( int osc ) const;
	void apply_stereo();
	void apply_volume();
	void synth_volume( int );
	void run_until_( blip_time_t );
	void run_until( blip_time_t );
	void silence_osc( Gb_Osc& );
	void write_osc( int reg, int old_data, int data );
	const char* save_load( gb_apu_state_t*, bool save );
	void save_load2( gb_apu_state_t*, bool save );
	friend class Gb_Apu2;
};

// Format of save state. Should be stable across versions of the library,
// with earlier versions properly opening later save states. Includes some
// room for expansion so the state size shouldn't increase.
struct gb_apu_state_t
{
#if GB_APU_CUSTOM_STATE
	// Values stored as plain int so your code can read/write them easily.
	// Structure can NOT be written to disk, since format is not portable.
	typedef int val_t;
#else
	// Values written in portable little-endian format, allowing structure
	// to be written directly to disk.
	typedef unsigned char val_t [4];
#endif
	
	enum { format0 = 0x50414247 }; // 'GBAP'
	
	val_t format;   // format of all following data
	val_t version;  // later versions just add fields to end
	
	unsigned char regs [0x40];
	val_t frame_time;
	val_t frame_phase;
	
	val_t sweep_freq;
	val_t sweep_delay;
	val_t sweep_enabled;
	val_t sweep_neg;
	val_t noise_divider;
	val_t wave_buf;
	
	val_t delay      [4];
	val_t length_ctr [4];
	val_t phase      [4];
	val_t enabled    [4];
	
	val_t env_delay   [3];
	val_t env_volume  [3];
	val_t env_enabled [3];
	
	val_t unused  [13]; // for future expansion
};

inline void Gb_Apu::set_output( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
{
	for ( int i = osc_count; --i >= 0; )
		set_output( i, c, l, r );
}

BLARGG_DEPRECATED_TEXT( inline void Gb_Apu::output( Blip_Buffer* c                                 ) { set_output(    c, c, c ); } )
BLARGG_DEPRECATED_TEXT( inline void Gb_Apu::output( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output(    c, l, r ); } )

#endif