diff options
Diffstat (limited to 'plugins/gme/game-music-emu-0.6pre/gme/Gb_Oscs.h')
-rw-r--r-- | plugins/gme/game-music-emu-0.6pre/gme/Gb_Oscs.h | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/plugins/gme/game-music-emu-0.6pre/gme/Gb_Oscs.h b/plugins/gme/game-music-emu-0.6pre/gme/Gb_Oscs.h new file mode 100644 index 00000000..100b4f2d --- /dev/null +++ b/plugins/gme/game-music-emu-0.6pre/gme/Gb_Oscs.h @@ -0,0 +1,188 @@ +// Private oscillators used by Gb_Apu + +// Gb_Snd_Emu 0.1.4 +#ifndef GB_OSCS_H +#define GB_OSCS_H + +#include "blargg_common.h" +#include "Blip_Buffer.h" + +#ifndef GB_APU_OVERCLOCK + #define GB_APU_OVERCLOCK 1 +#endif + +#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1) + #error "GB_APU_OVERCLOCK must be a power of 2" +#endif + +class Gb_Osc { +protected: + + // 11-bit frequency in NRx3 and NRx4 + int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; } + + void update_amp( blip_time_t, int new_amp ); + int write_trig( int frame_phase, int max_len, int old_data ); +public: + + enum { clk_mul = GB_APU_OVERCLOCK }; + enum { dac_bias = 7 }; + + Blip_Buffer* outputs [4];// NULL, right, left, center + Blip_Buffer* output; // where to output sound + BOOST::uint8_t* regs; // osc's 5 registers + int mode; // mode_dmg, mode_cgb, mode_agb + int dac_off_amp;// amplitude when DAC is off + int last_amp; // current amplitude in Blip_Buffer + Blip_Synth_Norm const* norm_synth; + Blip_Synth_Fast const* fast_synth; + + int delay; // clocks until frequency timer expires + int length_ctr; // length counter + unsigned phase; // waveform phase (or equivalent) + bool enabled; // internal enabled flag + + void clock_length(); + void reset(); +}; + +class Gb_Env : public Gb_Osc { +public: + int env_delay; + int volume; + bool env_enabled; + + void clock_envelope(); + bool write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + env_delay = 0; + volume = 0; + Gb_Osc::reset(); + } +protected: + // Non-zero if DAC is enabled + int dac_enabled() const { return regs [2] & 0xF8; } +private: + void zombie_volume( int old, int data ); + int reload_env_timer(); +}; + +class Gb_Square : public Gb_Env { +public: + bool write_register( int frame_phase, int reg, int old_data, int data ); + void run( blip_time_t, blip_time_t ); + + void reset() + { + Gb_Env::reset(); + delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) + } +private: + // Frequency timer period + int period() const { return (2048 - frequency()) * (4 * clk_mul); } +}; + +class Gb_Sweep_Square : public Gb_Square { +public: + int sweep_freq; + int sweep_delay; + bool sweep_enabled; + bool sweep_neg; + + void clock_sweep(); + void write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + sweep_freq = 0; + sweep_delay = 0; + sweep_enabled = false; + sweep_neg = false; + Gb_Square::reset(); + } +private: + enum { period_mask = 0x70 }; + enum { shift_mask = 0x07 }; + + void calc_sweep( bool update ); + void reload_sweep_timer(); +}; + +class Gb_Noise : public Gb_Env { +public: + + int divider; // noise has more complex frequency divider setup + + void run( blip_time_t, blip_time_t ); + void write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + divider = 0; + Gb_Env::reset(); + delay = 4 * clk_mul; // TODO: remove? + } +private: + enum { period2_mask = 0x1FFFF }; + + int period2_index() const { return regs [3] >> 4; } + int period2( int base = 8 ) const { return base << period2_index(); } + unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; } +}; + +class Gb_Wave : public Gb_Osc { +public: + int sample_buf; // last wave RAM byte read (hardware has this as well) + + void write_register( int frame_phase, int reg, int old_data, int data ); + void run( blip_time_t, blip_time_t ); + + // Reads/writes wave RAM + int read( int addr ) const; + void write( int addr, int data ); + + void reset() + { + sample_buf = 0; + Gb_Osc::reset(); + } + +private: + enum { bank40_mask = 0x40 }; + enum { bank_size = 32 }; + + int agb_mask; // 0xFF if AGB features enabled, 0 otherwise + BOOST::uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU + + friend class Gb_Apu; + + // Frequency timer period + int period() const { return (2048 - frequency()) * (2 * clk_mul); } + + // Non-zero if DAC is enabled + int dac_enabled() const { return regs [0] & 0x80; } + + void corrupt_wave(); + + BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } + + // Wave index that would be accessed, or -1 if no access would occur + int access( int addr ) const; +}; + +inline int Gb_Wave::read( int addr ) const +{ + int index = access( addr ); + return (index < 0 ? 0xFF : wave_bank() [index]); +} + +inline void Gb_Wave::write( int addr, int data ) +{ + int index = access( addr ); + if ( index >= 0 ) + wave_bank() [index] = data;; +} + +#endif |