From acb0917556fc33681c1df5a530cf754193e67705 Mon Sep 17 00:00:00 2001 From: Andree Buschmann Date: Sun, 7 Aug 2011 20:01:04 +0000 Subject: Submit initial patch from FS#12176. Adds support for several new game music formats (AY, GBS, HES, KSS, SGC, VGM and VGZ) and replaces the current NSF and NSFE with a new implementation based on a port of the Game Music Emu library 'GME'. This first submit does not cover the full functionality provided by the author's original patch: Coleco-SGV is not supported, some GME-specific m3u-support has been removed and IRAM is not used yet. Further changes are very likely to follow this submit. Thanks to Mauricio Garrido. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30264 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libgme/gb_oscs.h | 198 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 apps/codecs/libgme/gb_oscs.h (limited to 'apps/codecs/libgme/gb_oscs.h') diff --git a/apps/codecs/libgme/gb_oscs.h b/apps/codecs/libgme/gb_oscs.h new file mode 100644 index 0000000000..0cc9d3f567 --- /dev/null +++ b/apps/codecs/libgme/gb_oscs.h @@ -0,0 +1,198 @@ +// 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 + +enum { clk_mul = GB_APU_OVERCLOCK }; +enum { dac_bias = 7 }; + +struct Gb_Osc { + struct Blip_Buffer* outputs [4];// NULL, right, left, center + struct Blip_Buffer* output; // where to output sound + 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 + + struct Blip_Synth* synth; + + int delay; // clocks until frequency timer expires + int length_ctr; // length counter + unsigned phase; // waveform phase (or equivalent) + bool enabled; // internal enabled flag +}; + +// 11-bit frequency in NRx3 and NRx4 +static inline int Osc_frequency( struct Gb_Osc* this ) { return (this->regs [4] & 7) * 0x100 + this->regs [3]; } + +void Osc_update_amp( struct Gb_Osc* this, blip_time_t, int new_amp ) ICODE_ATTR; +int Osc_write_trig( struct Gb_Osc* this, int frame_phase, int max_len, int old_data ) ICODE_ATTR; +void Osc_clock_length( struct Gb_Osc* this ) ICODE_ATTR; +void Osc_reset( struct Gb_Osc* this ); + +// Square + +enum { period_mask = 0x70 }; +enum { shift_mask = 0x07 }; + +struct Gb_Square { + struct Gb_Osc osc; + + int env_delay; + int volume; + bool env_enabled; + + // Sweep square + int sweep_freq; + int sweep_delay; + bool sweep_enabled; + bool sweep_neg; +}; + +bool Square_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; +void Square_run( struct Gb_Square* this, blip_time_t, blip_time_t ) ICODE_ATTR; +void Square_clock_envelope( struct Gb_Square* this ) ICODE_ATTR; + +static inline void Square_reset( struct Gb_Square* this ) +{ + this->env_delay = 0; + this->volume = 0; + Osc_reset( &this->osc ); + this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) +} +// Frequency timer period +static inline int Square_period( struct Gb_Square* this ) { return (2048 - Osc_frequency( &this->osc )) * (4 * clk_mul); } +static inline int Square_dac_enabled( struct Gb_Square* this) { return this->osc.regs [2] & 0xF8; } +static inline int Square_reload_env_timer( struct Gb_Square* this ) +{ + int raw = this->osc.regs [2] & 7; + this->env_delay = (raw ? raw : 8); + return raw; +} + +// Sweep square + +void clock_sweep( struct Gb_Square* this ) ICODE_ATTR; +void Sweep_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; + +static inline void Sweep_reset( struct Gb_Square* this ) +{ + this->sweep_freq = 0; + this->sweep_delay = 0; + this->sweep_enabled = false; + this->sweep_neg = false; + + this->env_delay = 0; + this->volume = 0; + Osc_reset( &this->osc ); + this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) +} + +void calc_sweep( struct Gb_Square* this, bool update ) ICODE_ATTR; +void reload_sweep_timer( struct Gb_Square* this ) ICODE_ATTR; + +// Noise + +enum { period2_mask = 0x1FFFF }; + +struct Gb_Noise { + struct Gb_Osc osc; + + int env_delay; + int volume; + bool env_enabled; + + int divider; // noise has more complex frequency divider setup +}; + +void Noise_run( struct Gb_Noise* this, blip_time_t, blip_time_t ) ICODE_ATTR; +void Noise_write_register( struct Gb_Noise* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; + +static inline void Noise_reset( struct Gb_Noise* this ) +{ + this->divider = 0; + + this->env_delay = 0; + this->volume = 0; + Osc_reset( &this->osc ); + this->osc.delay = 4 * clk_mul; // TODO: remove? +} + +void Noise_clock_envelope( struct Gb_Noise* this ) ICODE_ATTR; + +// Non-zero if DAC is enabled +static inline int Noise_dac_enabled( struct Gb_Noise* this) { return this->osc.regs [2] & 0xF8; } +static inline int Noise_reload_env_timer( struct Gb_Noise* this ) +{ + int raw = this->osc.regs [2] & 7; + this->env_delay = (raw ? raw : 8); + return raw; +} + +static inline int period2_index( struct Gb_Noise* this ) { return this->osc.regs [3] >> 4; } +static inline int period2( struct Gb_Noise* this, int base ) { return base << period2_index( this ); } +static inline unsigned lfsr_mask( struct Gb_Noise* this ) { return (this->osc.regs [3] & 0x08) ? ~0x4040 : ~0x4000; } + +// Wave + +enum { bank40_mask = 0x40 }; +enum { wave_bank_size = 32 }; + +struct Gb_Wave { + struct Gb_Osc osc; + + int sample_buf; // last wave RAM byte read (hardware has this as well) + + int agb_mask; // 0xFF if AGB features enabled, 0 otherwise + uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU +}; + +void Wave_write_register( struct Gb_Wave* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; +void Wave_run( struct Gb_Wave* this, blip_time_t, blip_time_t ) ICODE_ATTR; + +static inline void Wave_reset( struct Gb_Wave* this ) +{ + this->sample_buf = 0; + Osc_reset( &this->osc ); +} + +// Frequency timer period +static inline int Wave_period( struct Gb_Wave* this ) { return (2048 - Osc_frequency( &this->osc )) * (2 * clk_mul); } + +// Non-zero if DAC is enabled +static inline int Wave_dac_enabled( struct Gb_Wave* this ) { return this->osc.regs [0] & 0x80; } + +void corrupt_wave( struct Gb_Wave* this ); + +static inline uint8_t* wave_bank( struct Gb_Wave* this ) { return &this->wave_ram [(~this->osc.regs [0] & bank40_mask) >> 2 & this->agb_mask]; } + +// Wave index that would be accessed, or -1 if no access would occur +int wave_access( struct Gb_Wave* this, int addr ) ICODE_ATTR; + +// Reads/writes wave RAM +static inline int Wave_read( struct Gb_Wave* this, int addr ) +{ + int index = wave_access( this, addr ); + return (index < 0 ? 0xFF : wave_bank( this ) [index]); +} + +static inline void Wave_write( struct Gb_Wave* this, int addr, int data ) +{ + int index = wave_access( this, addr ); + if ( index >= 0 ) + wave_bank( this ) [index] = data;; +} + +#endif -- cgit v1.2.3