From faf058870c6bfd5c9eb9ed17d9a0634fe3ba07f4 Mon Sep 17 00:00:00 2001 From: mudlord Date: Thu, 6 Dec 2007 08:16:35 +0000 Subject: [PATCH] Added support for OpenAL software audio mixing Updated GBA sound engine to support new audiosavestate format Several improvements to audio cores Updated sample buffer length in DirectSound git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@167 a31d4220-a93d-0410-bf67-fe4944624d44 --- src/GBA.h | 3 +- src/Sound.cpp | 361 +++++++++++++++++++++++++++++---- src/Sound.h | 30 +-- src/gb/gbSound.cpp | 160 ++++++++++++++- src/gb/gb_apu/Gb_Apu_State.cpp | 2 +- src/gb/gb_apu/blargg_config.h | 2 + src/win32/DirectSound.cpp | 4 +- src/win32/MainWndOptions.cpp | 1 + src/win32/OpenAL.cpp | 4 + src/win32/VBA.cpp | 2 + src/win32/VBA.h | 1 + src/win32/resource.h | 3 +- 12 files changed, 505 insertions(+), 68 deletions(-) diff --git a/src/GBA.h b/src/GBA.h index 30bf450f..08e000a4 100644 --- a/src/GBA.h +++ b/src/GBA.h @@ -31,7 +31,8 @@ #define SAVE_GAME_VERSION_7 7 #define SAVE_GAME_VERSION_8 8 #define SAVE_GAME_VERSION_9 9 -#define SAVE_GAME_VERSION SAVE_GAME_VERSION_9 +#define SAVE_GAME_VERSION_10 10 +#define SAVE_GAME_VERSION SAVE_GAME_VERSION_10 typedef struct { u8 *address; diff --git a/src/Sound.cpp b/src/Sound.cpp index 24f23903..94573461 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -27,40 +27,42 @@ #include "Util.h" #include "Port.h" +#ifdef _WIN32 +//#include +#endif + #include "gb/gb_apu/Gb_Apu.h" #include "gb/gb_apu/Multi_Buffer.h" -#define USE_TICKS_AS 380 - extern bool stopState; // TODO: silence sound when true -int soundQuality = 2; // sample rate = 44100 / soundQuality -int soundInterpolation = 0; // 1 if PCM should have low-pass filtering -int soundVolume = 0; // emulator volume code (not linear) +int soundQuality = 2; +int soundInterpolation = 0; +float soundFiltering = 1; +static float soundFiltering_; +int soundVolume = 0; static int soundVolume_; bool soundEcho = false; -bool soundLowPass = false; -bool soundReverse = false; int soundEnableFlag = 0x3ff; // emulator channels enabled -// Number of 16.8 MHz clocks until soundTick() will be called -int soundTicks = soundQuality * USE_TICKS_AS; +int const SOUND_CLOCK_TICKS_ = 167772; +int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; +int soundTicks = SOUND_CLOCK_TICKS_; -// Number of 16.8 MHz clocks between calls to soundTick() -int SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; - -u16 soundFinalWave [1470]; // 16-bit SIGNED stereo sample buffer -int soundBufferLen = 1470; // size of sound buffer in BYTES +u16 soundFinalWave [1470]; +int soundBufferLen = 1470; int soundBufferTotalLen = 14700; - void interp_rate() { /* empty for now */ } - -// Unknown purpose int soundDebug = 0; u32 soundNextPosition = 0; bool soundOffFlag = false; bool soundPaused = true; +bool soundLowPass = false; +bool soundReverse = false; + +void interp_rate() { /* empty for now */ } + class Gba_Pcm { public: void init(); @@ -83,15 +85,17 @@ public: void write_control( int data ); void write_fifo( int data ); void timer_overflowed( int which_timer ); - -private: + + // public only so save state routines can access it int readIndex; int count; int writeIndex; - bool enabled; - int timer; u8 fifo [32]; int dac; +private: + + int timer; + bool enabled; }; static Gba_Pcm_Fifo pcm [2]; @@ -157,7 +161,7 @@ void Gba_Pcm::update( int dac ) { blip_time_t time = blip_time(); - dac >>= shift; + dac = (s8) dac >> shift; int delta = dac - last_amp; if ( delta ) { @@ -193,7 +197,7 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer ) CPUCheckDMA( 3, which ? 4 : 2 ); if ( count <= 16 ) { - // Not filled by DMA, so fill with silence + // Not filled by DMA, so fill with 16 bytes of silence int reg = which ? FIFOB_L : FIFOA_L; for ( int n = 4; n--; ) { @@ -205,7 +209,7 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer ) // Read next sample from FIFO count--; - dac = (s8) fifo [readIndex]; + dac = fifo [readIndex]; readIndex = (readIndex + 1) & 31; pcm.update( dac ); } @@ -299,15 +303,20 @@ static void apply_volume( bool apu_only = false ) } } +static void write_SGCNT0_H( int data ) +{ + WRITE16LE( &ioMem [SGCNT0_H], data & 0x770F ); + pcm [0].write_control( data ); + pcm [1].write_control( data >> 4 ); + apply_volume( true ); +} + void soundEvent(u32 address, u16 data) { switch ( address ) { case SGCNT0_H: - WRITE16LE( &ioMem[address], data ); - pcm [0].write_control( data ); - pcm [1].write_control( data >> 4 ); - apply_volume( true ); + write_SGCNT0_H( data ); break; case FIFOA_L: @@ -351,6 +360,9 @@ static void end_frame( blip_time_t time ) static void flush_samples() { + // soundBufferLen should have a whole number of sample pairs + assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 ); + // number of samples in output buffer int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; @@ -368,6 +380,22 @@ static void flush_samples() } } +static void apply_filtering() +{ + soundFiltering_ = soundFiltering; + + int const base_freq = (int) (32768 - soundFiltering_ * 16384); + int const nyquist = stereo_buffer->sample_rate() / 2; + + for ( int i = 0; i < 3; i++ ) + { + int cutoff = base_freq >> i; + if ( cutoff > nyquist ) + cutoff = nyquist; + pcm_synth [i].treble_eq( blip_eq_t( 0, 0, stereo_buffer->sample_rate(), cutoff ) ); + } +} + static void soundTick() { if ( systemSoundOn && gb_apu && stereo_buffer ) @@ -377,6 +405,9 @@ static void soundTick() flush_samples(); + if ( soundFiltering_ != soundFiltering ) + apply_filtering(); + if ( soundVolume_ != soundVolume ) apply_volume(); } @@ -386,9 +417,9 @@ void (*psoundTickfn)() = soundTick; static void apply_muting() { - -if ( !stereo_buffer || !ioMem ) - return; + if ( !stereo_buffer || !ioMem ) + return; + // PCM apply_control(); @@ -406,8 +437,27 @@ if ( !stereo_buffer || !ioMem ) } } +static void reset_apu() +{ + gb_apu->reset( gb_apu->mode_agb, true ); + + if ( stereo_buffer ) + stereo_buffer->clear(); + + soundTicks = SOUND_CLOCK_TICKS; +} + static void remake_stereo_buffer() { + if ( !ioMem ) + return; + +#ifdef _WIN32 + // Direct3D might mess with FPU mode. Try uncommenting if more sound problems + // occur (also need to uncomment #include above). + //_fpreset(); +#endif + // Clears pointers kept to old stereo_buffer pcm [0].pcm.init(); pcm [1].pcm.init(); @@ -424,17 +474,14 @@ static void remake_stereo_buffer() // PCM pcm [0].which = 0; pcm [1].which = 1; - for ( int i = 0; i < 3; i++ ) - { - int freq = 32768 >> i; - pcm_synth [i].treble_eq( blip_eq_t( 0, 0, sample_rate, freq / 2 ) ); - } + apply_filtering(); // APU if ( !gb_apu ) + { gb_apu = new Gb_Apu; // TODO: handle out of memory - - gb_apu->reset( gb_apu->mode_agb, true ); + reset_apu(); + } apply_muting(); apply_volume(); @@ -458,7 +505,7 @@ void soundShutdown() void soundPause() { systemSoundPause(); - setsoundPaused(true); + setsoundPaused(true); } void soundResume() @@ -489,10 +536,11 @@ void soundReset() systemSoundReset(); remake_stereo_buffer(); + reset_apu(); setsoundPaused(true); - SOUND_CLOCK_TICKS = 167772; - soundTicks = SOUND_CLOCK_TICKS; + SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; + soundTicks = SOUND_CLOCK_TICKS_; soundNextPosition = 0; @@ -533,12 +581,235 @@ void soundSetQuality(int quality) } } -void soundSaveGame(gzFile gzFile) +static int dummy_state [16]; + +#define SKIP( type, name ) { dummy_state, sizeof (type) } + +#define LOAD( type, name ) { &name, sizeof (type) } + +static struct { + gb_apu_state_t apu; + + // old state + u8 soundDSAValue; + int soundDSBValue; +} state; + +// Old GBA sound state format +static variable_desc old_gba_state [] = { - // TODO: implement + SKIP( int, soundPaused ), + SKIP( int, soundPlay ), + SKIP( int, soundTicks ), + SKIP( int, SOUND_CLOCK_TICKS ), + SKIP( int, soundLevel1 ), + SKIP( int, soundLevel2 ), + SKIP( int, soundBalance ), + SKIP( int, soundMasterOn ), + SKIP( int, soundIndex ), + SKIP( int, sound1On ), + SKIP( int, sound1ATL ), + SKIP( int, sound1Skip ), + SKIP( int, sound1Index ), + SKIP( int, sound1Continue ), + SKIP( int, sound1EnvelopeVolume ), + SKIP( int, sound1EnvelopeATL ), + SKIP( int, sound1EnvelopeATLReload ), + SKIP( int, sound1EnvelopeUpDown ), + SKIP( int, sound1SweepATL ), + SKIP( int, sound1SweepATLReload ), + SKIP( int, sound1SweepSteps ), + SKIP( int, sound1SweepUpDown ), + SKIP( int, sound1SweepStep ), + SKIP( int, sound2On ), + SKIP( int, sound2ATL ), + SKIP( int, sound2Skip ), + SKIP( int, sound2Index ), + SKIP( int, sound2Continue ), + SKIP( int, sound2EnvelopeVolume ), + SKIP( int, sound2EnvelopeATL ), + SKIP( int, sound2EnvelopeATLReload ), + SKIP( int, sound2EnvelopeUpDown ), + SKIP( int, sound3On ), + SKIP( int, sound3ATL ), + SKIP( int, sound3Skip ), + SKIP( int, sound3Index ), + SKIP( int, sound3Continue ), + SKIP( int, sound3OutputLevel ), + SKIP( int, sound4On ), + SKIP( int, sound4ATL ), + SKIP( int, sound4Skip ), + SKIP( int, sound4Index ), + SKIP( int, sound4Clock ), + SKIP( int, sound4ShiftRight ), + SKIP( int, sound4ShiftSkip ), + SKIP( int, sound4ShiftIndex ), + SKIP( int, sound4NSteps ), + SKIP( int, sound4CountDown ), + SKIP( int, sound4Continue ), + SKIP( int, sound4EnvelopeVolume ), + SKIP( int, sound4EnvelopeATL ), + SKIP( int, sound4EnvelopeATLReload ), + SKIP( int, sound4EnvelopeUpDown ), + LOAD( int, soundEnableFlag ), + SKIP( int, soundControl ), + LOAD( int, pcm [0].readIndex ), + LOAD( int, pcm [0].count ), + LOAD( int, pcm [0].writeIndex ), + SKIP( u8, soundDSAEnabled ), // was bool, which was one byte on MS compiler + SKIP( int, soundDSATimer ), + LOAD( u8 [32], pcm [0].fifo ), + LOAD( u8, state.soundDSAValue ), + LOAD( int, pcm [1].readIndex ), + LOAD( int, pcm [1].count ), + LOAD( int, pcm [1].writeIndex ), + SKIP( int, soundDSBEnabled ), + SKIP( int, soundDSBTimer ), + LOAD( u8 [32], pcm [1].fifo ), + LOAD( int, state.soundDSBValue ), + + // skipped manually + //LOAD( int, soundBuffer[0][0], 6*735 }, + //LOAD( int, soundFinalWave[0], 2*735 }, + { NULL, 0 } +}; + +variable_desc old_gba_state2 [] = +{ + LOAD( u8 [0x20], state.apu.regs [0x20] ), + SKIP( int, sound3Bank ), + SKIP( int, sound3DataSize ), + SKIP( int, sound3ForcedOutput ), + { NULL, 0 } +}; + +// New state format +static variable_desc gba_state [] = +{ + // PCM + LOAD( int, pcm [0].readIndex ), + LOAD( int, pcm [0].count ), + LOAD( int, pcm [0].writeIndex ), + LOAD(u8[32],pcm[0].fifo ), + LOAD( int, pcm [0].dac ), + + SKIP( int [4], room_for_expansion ), + + LOAD( int, pcm [1].readIndex ), + LOAD( int, pcm [1].count ), + LOAD( int, pcm [1].writeIndex ), + LOAD(u8[32],pcm[1].fifo ), + LOAD( int, pcm [1].dac ), + + SKIP( int [4], room_for_expansion ), + + // APU + LOAD( u8 [0x40], state.apu.regs ), // last values written to registers and wave RAM (both banks) + LOAD( int, state.apu.frame_time ), // clocks until next frame sequencer action + LOAD( int, state.apu.frame_phase ), // next step frame sequencer will run + + LOAD( int, state.apu.sweep_freq ), // sweep's internal frequency register + LOAD( int, state.apu.sweep_delay ), // clocks until next sweep action + LOAD( int, state.apu.sweep_enabled ), + LOAD( int, state.apu.sweep_neg ), // obscure internal flag + LOAD( int, state.apu.noise_divider ), + LOAD( int, state.apu.wave_buf ), // last read byte of wave RAM + + LOAD( int [4], state.apu.delay ), // clocks until next channel action + LOAD( int [4], state.apu.length_ctr ), + LOAD( int [4], state.apu.phase ), // square/wave phase, noise LFSR + LOAD( int [4], state.apu.enabled ), // internal enabled flag + + LOAD( int [3], state.apu.env_delay ), // clocks until next envelope action + LOAD( int [3], state.apu.env_volume ), + LOAD( int [3], state.apu.env_enabled ), + + SKIP( int [13], room_for_expansion ), + + // Emulator + LOAD( int, soundEnableFlag ), + + SKIP( int [15], room_for_expansion ), + + { NULL, 0 } +}; + +// Reads and discards count bytes from in +static void skip_read( gzFile in, int count ) +{ + char buf [512]; + + while ( count ) + { + int n = sizeof buf; + if ( n > count ) + n = count; + + count -= n; + utilGzRead( in, buf, n ); + } } -void soundReadGame(gzFile gzFile, int version) +void soundSaveGame( gzFile out ) { - // TODO: implement + gb_apu->save_state( &state.apu ); + + // Be sure areas for expansion get written as zero + memset( dummy_state, 0, sizeof dummy_state ); + + utilWriteData( out, gba_state ); +} + +static void soundReadGameOld( gzFile in, int version ) +{ + // Read main data + utilReadData( in, old_gba_state ); + skip_read( in, 6*735 + 2*735 ); + + // Copy APU regs + static int const regs_to_copy [] = { + NR10, NR11, NR12, NR13, NR14, + NR21, NR22, NR23, NR24, + NR30, NR31, NR32, NR33, NR34, + NR41, NR42, NR43, NR44, + NR50, NR51, NR52, -1 + }; + + ioMem [NR52] |= 0x80; // old sound played even when this wasn't set (power on) + + for ( int i = 0; regs_to_copy [i] >= 0; i++ ) + state.apu.regs [gba_to_gb_sound( regs_to_copy [i] ) - 0xFF10] = ioMem [regs_to_copy [i]]; + + // Copy wave RAM to both banks + memcpy( &state.apu.regs [0x20], &ioMem [0x90], 0x10 ); + memcpy( &state.apu.regs [0x30], &ioMem [0x90], 0x10 ); + + // Read both banks of wave RAM if available + if ( version >= SAVE_GAME_VERSION_3 ) + utilReadData( in, old_gba_state2 ); + + // Restore PCM + pcm [0].dac = state.soundDSAValue; + pcm [1].dac = state.soundDSBValue; + + int quality = utilReadInt( in ); // ignore this crap +} + +#include + +void soundReadGame( gzFile in, int version ) +{ + // Prepare APU and default state + reset_apu(); + gb_apu->save_state( &state.apu ); + + if ( version > SAVE_GAME_VERSION_9 ) + utilReadData( in, gba_state ); + else + soundReadGameOld( in, version ); + + gb_apu->load_state( state.apu ); + write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F ); + + apply_muting(); } diff --git a/src/Sound.h b/src/Sound.h index 620e61c3..05da614c 100644 --- a/src/Sound.h +++ b/src/Sound.h @@ -69,20 +69,26 @@ extern void setsystemSoundOn(bool value); extern void setsoundPaused(bool value); extern void interp_rate(); -extern int SOUND_CLOCK_TICKS; -extern int soundTicks; -extern bool soundOffFlag; -extern bool soundPaused; -extern int soundQuality; -extern int soundBufferLen; -extern int soundBufferTotalLen; -extern u32 soundNextPosition; -extern u16 soundFinalWave[1470]; -extern int soundVolume; -extern int soundInterpolation; +extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to soundTick() +extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called +extern int soundQuality; // sample rate = 44100 / soundQuality +extern int soundBufferLen; // size of sound buffer in BYTES +extern u16 soundFinalWave[1470];// 16-bit SIGNED stereo sample buffer +extern int soundVolume; // emulator volume code (not linear) -extern bool soundEcho; +extern int soundInterpolation; // 1 if PCM should have low-pass filtering +extern float soundFiltering; // 0.0 = none, 1.0 = max (only if soundInterpolation!=0) + +extern bool soundEcho; // enables echo for GB, not GBA + +// Not used anymore extern bool soundLowPass; extern bool soundReverse; +// Unknown purpose +extern int soundBufferTotalLen; +extern u32 soundNextPosition; +extern bool soundPaused; +extern bool soundOffFlag; + #endif // VBA_SOUND_H diff --git a/src/gb/gbSound.cpp b/src/gb/gbSound.cpp index 7e290294..dc0cd5aa 100644 --- a/src/gb/gbSound.cpp +++ b/src/gb/gbSound.cpp @@ -137,6 +137,8 @@ void gbSoundTick() end_frame( SOUND_CLOCK_TICKS * ticks_to_time ); flush_samples(); + + gb_effects_config.enabled = soundEcho; // Update effects config if it was changed if ( memcmp( &gb_effects_config_current, &gb_effects_config, @@ -145,6 +147,17 @@ void gbSoundTick() } } +static void reset_apu() +{ + // Use DMG or CGB sound differences based on type of game + gb_apu->reset( gbHardware & 1 ? gb_apu->mode_dmg : gb_apu->mode_cgb ); + + if ( stereo_buffer ) + stereo_buffer->clear(); + + soundTicks = SOUND_CLOCK_TICKS; +} + static void remake_stereo_buffer() { // Stereo_Buffer @@ -163,21 +176,26 @@ static void remake_stereo_buffer() stereo_buffer->set_channel_count( chan_count, chan_types ); if ( !gb_apu ) + { gb_apu = new Gb_Apu; + reset_apu(); + } apply_effects(); - - // Use DMG or CGB sound differences based on type of game - gb_apu->reset( gbHardware & 1 ? gb_apu->mode_dmg : gb_apu->mode_cgb ); } void gbSoundReset() { + gb_effects_config.echo = 0.20; + gb_effects_config.stereo = 0.15; + gb_effects_config.surround = false; + + SOUND_CLOCK_TICKS = 20000; + remake_stereo_buffer(); + reset_apu(); soundPaused = 1; - SOUND_CLOCK_TICKS = 20000; - soundTicks = SOUND_CLOCK_TICKS; soundNextPosition = 0; // don't translate @@ -253,12 +271,142 @@ void gbSoundSetQuality(int quality) } } +static char dummy_buf [735 * 2]; + +#define SKIP( type, name ) { dummy_buf, sizeof (type) } + +// funny expr at end ensures that type matches type of variable +#define LOAD( type, name ) { &name, sizeof (name) + (&name - (type*) &name) } + +static variable_desc gbsound_format [] = +{ + SKIP( int, soundPaused ), + SKIP( int, soundPlay ), + SKIP( int, soundTicks ), + SKIP( int, SOUND_CLOCK_TICKS ), + SKIP( int, soundLevel1 ), + SKIP( int, soundLevel2 ), + SKIP( int, soundBalance ), + SKIP( int, soundMasterOn ), + SKIP( int, soundIndex ), + SKIP( int, soundVIN ), + SKIP( int, soundOn [0] ), + SKIP( int, soundATL [0] ), + SKIP( int, sound1Skip ), + SKIP( int, soundIndex [0] ), + SKIP( int, sound1Continue ), + SKIP( int, soundEnvelopeVolume [0] ), + SKIP( int, soundEnvelopeATL [0] ), + SKIP( int, sound1EnvelopeATLReload ), + SKIP( int, sound1EnvelopeUpDown ), + SKIP( int, sound1SweepATL ), + SKIP( int, sound1SweepATLReload ), + SKIP( int, sound1SweepSteps ), + SKIP( int, sound1SweepUpDown ), + SKIP( int, sound1SweepStep ), + SKIP( int, soundOn [1] ), + SKIP( int, soundATL [1] ), + SKIP( int, sound2Skip ), + SKIP( int, soundIndex [1] ), + SKIP( int, sound2Continue ), + SKIP( int, soundEnvelopeVolume [1] ), + SKIP( int, soundEnvelopeATL [1] ), + SKIP( int, sound2EnvelopeATLReload ), + SKIP( int, sound2EnvelopeUpDown ), + SKIP( int, soundOn [2] ), + SKIP( int, soundATL [2] ), + SKIP( int, sound3Skip ), + SKIP( int, soundIndex [2] ), + SKIP( int, sound3Continue ), + SKIP( int, sound3OutputLevel ), + SKIP( int, soundOn [3] ), + SKIP( int, soundATL [3] ), + SKIP( int, sound4Skip ), + SKIP( int, soundIndex [3] ), + SKIP( int, sound4Clock ), + SKIP( int, sound4ShiftRight ), + SKIP( int, sound4ShiftSkip ), + SKIP( int, sound4ShiftIndex ), + SKIP( int, sound4NSteps ), + SKIP( int, sound4CountDown ), + SKIP( int, sound4Continue ), + SKIP( int, soundEnvelopeVolume [2] ), + SKIP( int, soundEnvelopeATL [2] ), + SKIP( int, sound4EnvelopeATLReload ), + SKIP( int, sound4EnvelopeUpDown ), + SKIP( int, soundEnableFlag ), + { NULL, 0 } +}; + +static variable_desc gbsound_format2 [] = +{ + SKIP( int, sound1ATLreload ), + SKIP( int, freq1low ), + SKIP( int, freq1high ), + SKIP( int, sound2ATLreload ), + SKIP( int, freq2low ), + SKIP( int, freq2high ), + SKIP( int, sound3ATLreload ), + SKIP( int, freq3low ), + SKIP( int, freq3high ), + SKIP( int, sound4ATLreload ), + SKIP( int, freq4 ), + { NULL, 0 } +}; + +static variable_desc gbsound_format3 [] = +{ + SKIP( u8[2*735], soundBuffer ), + SKIP( u8[2*735], soundBuffer ), + SKIP( u16[735], soundFinalWave ), + { NULL, 0 } +}; + void gbSoundSaveGame(gzFile gzFile) { // TODO: implement } +enum { + nr10 = 0, + nr11, nr12, nr13, nr14, + nr20, nr21, nr22, nr23, nr24, + nr30, nr31, nr32, nr33, nr34, + nr40, nr41, nr42, nr43, nr44, + nr50, nr51, nr52 +}; + void gbSoundReadGame(int version,gzFile gzFile) { - // TODO: implement + return; // TODO: apparently GB save states don't work in the main emulator + + // Load state + utilReadData( gzFile, gbsound_format ); + + if ( version >= 11 ) + utilReadData( gzFile, gbsound_format2 ); + + utilReadData( gzFile, gbsound_format3 ); + + int quality = 1; + if ( version >= 7 ) + quality = utilReadInt( gzFile ); + + gbSoundSetQuality( quality ); + + // Convert to format Gb_Apu uses + reset_apu(); + gb_apu_state_t s; + gb_apu->save_state( &s ); // use fresh values for anything not restored + + // Only some registers are properly preserved + static int const regs_to_copy [] = { + nr10, nr11, nr12, nr21, nr22, nr30, nr32, nr42, nr43, nr50, nr51, nr52, -1 + }; + for ( int i = 0; regs_to_copy [i] >= 0; i++ ) + s.regs [regs_to_copy [i]] = gbMemory [0xFF10 + regs_to_copy [i]]; + + memcpy( &s.regs [0x20], &gbMemory [0xFF30], 0x10 ); // wave + + gb_apu->load_state( s ); } diff --git a/src/gb/gb_apu/Gb_Apu_State.cpp b/src/gb/gb_apu/Gb_Apu_State.cpp index 5fdd123b..78c27973 100644 --- a/src/gb/gb_apu/Gb_Apu_State.cpp +++ b/src/gb/gb_apu/Gb_Apu_State.cpp @@ -1,4 +1,4 @@ -// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/ +// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ #include "Gb_Apu.h" diff --git a/src/gb/gb_apu/blargg_config.h b/src/gb/gb_apu/blargg_config.h index bcdde837..961e0453 100644 --- a/src/gb/gb_apu/blargg_config.h +++ b/src/gb/gb_apu/blargg_config.h @@ -7,6 +7,8 @@ // a Game Boy Advance emulator. #define GB_APU_OVERCLOCK 4 +#define GB_APU_CUSTOM_STATE 1 + // Uncomment to enable platform-specific (and possibly non-portable) optimizations. //#define BLARGG_NONPORTABLE 1 diff --git a/src/win32/DirectSound.cpp b/src/win32/DirectSound.cpp index 4c0fa10c..e814c614 100644 --- a/src/win32/DirectSound.cpp +++ b/src/win32/DirectSound.cpp @@ -166,7 +166,7 @@ bool DirectSound::init() freq = 44100; break; } - soundBufferLen = freq*2/30; + soundBufferLen = freq/60*4; soundBufferTotalLen = soundBufferLen * 10; ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); @@ -310,7 +310,7 @@ void DirectSound::write() if( !speedup && synchronize && !theApp.throttle ) { hr = dsbSecondary->GetStatus(&status); if( status & DSBSTATUS_PLAYING ) { - if( !soundPaused ) { + if( soundPaused ) { while( true ) { dsbSecondary->GetCurrentPosition(&play, NULL); int BufferLeft = ((soundNextPosition <= play) ? diff --git a/src/win32/MainWndOptions.cpp b/src/win32/MainWndOptions.cpp index 07d680f1..06216232 100644 --- a/src/win32/MainWndOptions.cpp +++ b/src/win32/MainWndOptions.cpp @@ -2007,3 +2007,4 @@ void MainWnd::OnUpdateOutputapiOpenal(CCmdUI *pCmdUI) pCmdUI->SetCheck( ( theApp.audioAPI == OPENAL ) ? 1 : 0 ); #endif } + diff --git a/src/win32/OpenAL.cpp b/src/win32/OpenAL.cpp index 2afb03d4..37a2decb 100644 --- a/src/win32/OpenAL.cpp +++ b/src/win32/OpenAL.cpp @@ -160,6 +160,10 @@ bool OpenAL::init() winlog( "OpenAL::init\n" ); assert( initialized == false ); + if (theApp.OpenALAudiomixing) + { + device = alcOpenDevice( "Generic Software" ); + } device = alcOpenDevice( NULL ); assert( device != NULL ); diff --git a/src/win32/VBA.cpp b/src/win32/VBA.cpp index 0690d8c8..808f7391 100644 --- a/src/win32/VBA.cpp +++ b/src/win32/VBA.cpp @@ -304,6 +304,7 @@ VBA::VBA() input = NULL; joypadDefault = 0; autoFire = 0; + OpenALAudiomixing = false; autoFireToggle = false; winPauseNextFrame = false; soundRecording = false; @@ -1420,6 +1421,7 @@ void VBA::loadSettings() audioAPI = DIRECTSOUND; } + OpenALAudiomixing = regQueryDwordValue( "OpenALAudiomixing", 0 ); windowPositionX = regQueryDwordValue("windowX", 0); if(windowPositionX < 0) windowPositionX = 0; diff --git a/src/win32/VBA.h b/src/win32/VBA.h index 9cae5d49..f67402c5 100644 --- a/src/win32/VBA.h +++ b/src/win32/VBA.h @@ -148,6 +148,7 @@ class VBA : public CWinApp u32 autoFrameSkipLastTime; bool autoFrameSkip; bool vsync; + bool OpenALAudiomixing; bool changingVideoSize; GUID videoDriverGUID; GUID *pVideoDriverGUID; diff --git a/src/win32/resource.h b/src/win32/resource.h index 60aa37b3..a46d8254 100644 --- a/src/win32/resource.h +++ b/src/win32/resource.h @@ -806,13 +806,14 @@ #define IDC_COMBO_PLUGIN 40345 #define ID_OUTPUTAPI_DIRECTSOUND 40346 #define ID_OUTPUTAPI_OPENAL 40347 +#define ID_OUTPUTAPI_SOFTWAREMIXING 40348 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 159 -#define _APS_NEXT_COMMAND_VALUE 40348 +#define _APS_NEXT_COMMAND_VALUE 40349 #define _APS_NEXT_CONTROL_VALUE 1269 #define _APS_NEXT_SYMED_VALUE 103 #endif