summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.6pre/gme/Gb_Oscs.h
diff options
context:
space:
mode:
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.h188
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