// 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