// Nintendo Game Boy sound hardware emulator with save state support
// Gb_Snd_Emu 0.2.0
#ifndef GB_APU_H
#define GB_APU_H
#include "Gb_Oscs.h"
class Gb_Apu
{
public:
// Basics
// Clock rate that sound hardware runs at.
enum { clock_rate = 4194304 * GB_APU_OVERCLOCK };
// Sets buffer(s) to generate sound into. If left and right are NULL, output is mono.
// If all are NULL, no output is generated but other emulation still runs.
// If chan is specified, only that channel's output is changed, otherwise all are.
enum { osc_count = 4 }; // 0: Square 1, 1: Square 2, 2: Wave, 3: Noise
void set_output(Blip_Buffer *center, Blip_Buffer *left = nullptr, Blip_Buffer *right = nullptr, int chan = osc_count);
// Resets hardware to initial power on state BEFORE boot ROM runs. Mode selects
// sound hardware. Additional AGB wave features are enabled separately.
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);
// Reads and writes must be within the start_addr to end_addr range, inclusive.
// Addresses outside this range are not mapped to the sound hardware.
enum { start_addr = 0xFF10 };
enum { end_addr = 0xFF3F };
enum { register_count = end_addr - start_addr + 1 };
// Times are specified as the number of clocks since the beginning of the
// current time frame.
// Emulates CPU write of data to addr at specified time.
void write_register(blip_time_t time, unsigned addr, int data);
// Emulates CPU read from addr at specified time.
int read_register(blip_time_t time, unsigned addr);
// Emulates sound hardware up to specified time, ends current time frame, then
// starts a new frame at time 0.
void end_frame(blip_time_t frame_length);
// Sound adjustments
// Sets overall volume, where 1.0 is normal.
void volume(double);
// 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 treble equalization.
void treble_eq(const blip_eq_t &);
// 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
};
// Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the
// tempo in a game music player.
void set_tempo(double);
Gb_Apu();
private:
// noncopyable
Gb_Apu(const Gb_Apu &);
Gb_Apu &operator=(const Gb_Apu &);
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 = register_count + 0x10 };
uint8_t regs[regs_size];// last values written to registers
// large objects after everything else
Gb_Osc::Good_Synth good_synth;
Gb_Osc::Med_Synth med_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 index, int reg, int old_data, int data);
friend class Gb_Apu_Tester;
public:
int read_status();
};
#endif