diff --git a/source/ngc/audio.cpp b/source/ngc/audio.cpp index 9f73c35..0c22524 100644 --- a/source/ngc/audio.cpp +++ b/source/ngc/audio.cpp @@ -13,6 +13,8 @@ #include #include +#include "audio.h" + extern int ConfigRequested; /** Locals **/ @@ -31,7 +33,7 @@ static int IsPlaying = 0; /**************************************************************************** * MIXER_GetSamples ***************************************************************************/ -static int MIXER_GetSamples( u8 *dstbuffer, int maxlen ) +static int MIXER_GetSamples(u8 *dstbuffer, int maxlen) { u32 *src = (u32 *)mixerdata; u32 *dst = (u32 *)dstbuffer; @@ -55,61 +57,17 @@ static int MIXER_GetSamples( u8 *dstbuffer, int maxlen ) static void AudioPlayer() { - if ( !ConfigRequested ) + if (IsPlaying) { int len = MIXER_GetSamples(soundbuffer[whichab], 3200); - DCFlushRange(soundbuffer[whichab],len); AUDIO_InitDMA((u32)soundbuffer[whichab],len); - AUDIO_StartDMA(); + DCFlushRange(soundbuffer[whichab],len); whichab ^= 1; - IsPlaying = 1; - } - else - IsPlaying = 0; -} - -/**************************************************************************** -* MIXER_AddSamples -* -* Upsample from 11025 to 48000 -* 11025 == 15052 -* 22050 == 30106 -* 44100 == 60211 -* -* Audio officianados should look away now ! -****************************************************************************/ -void MIXER_AddSamples( u8 *sampledata, int len ) -{ - u32 *src = (u32 *)sampledata; - u32 *dst = (u32 *)mixerdata; - u32 intlen = (3200 >> 2); - u32 fixofs = 0; - u32 fixinc; - - if ( !len ) - fixinc = 30106; - else - fixinc = 60211; - - do - { - // Do simple linear interpolate, and swap channels from L-R to R-L - dst[head++] = SWAP(src[fixofs >> 16]); - head &= MIXERMASK; - fixofs += fixinc; - } - while( --intlen ); - - // Restart Sound Processing if stopped - if (IsPlaying == 0) - { - ConfigRequested = 0; - AudioPlayer(); } } /**************************************************************************** - * MIXER_GetSamples + * InitialiseSound ***************************************************************************/ void InitialiseSound() @@ -122,21 +80,72 @@ void InitialiseSound() } /**************************************************************************** - * MIXER_GetSamples + * SoundDriver ***************************************************************************/ -void ResetAudio() +SoundWii::SoundWii() { memset(soundbuffer, 0, 3840*2); memset(mixerdata, 0, MIXBUFFSIZE); + AudioPlayer(); + AUDIO_StartDMA(); } /**************************************************************************** - * MIXER_GetSamples - ***************************************************************************/ +* SoundWii::write +* +* Upsample from 11025 to 48000 +* 11025 == 15052 +* 22050 == 30106 +* 44100 == 60211 +* +* Audio officianados should look away now ! +****************************************************************************/ -void StopAudio() +void SoundWii::write(u16 * finalWave, int length) +{ + u32 *src = (u32 *)finalWave; + u32 *dst = (u32 *)mixerdata; + u32 intlen = (3200 >> 2); + u32 fixofs = 0; + u32 fixinc; + + if (length < 2940) // length = 1468 - GBA + fixinc = 30106; + else // length = 2940 - GB + fixinc = 60211; + + do + { + // Do simple linear interpolate, and swap channels from L-R to R-L + dst[head++] = SWAP(src[fixofs >> 16]); + head &= MIXERMASK; + fixofs += fixinc; + } + while( --intlen ); +} + +bool SoundWii::init(long sampleRate) +{ + return true; +} + +SoundWii::~SoundWii() +{ +} + +void SoundWii::pause() { AUDIO_StopDMA(); IsPlaying = 0; } + +void SoundWii::resume() +{ + AUDIO_StartDMA(); + IsPlaying = 1; +} + +void SoundWii::reset() +{ +} diff --git a/source/ngc/audio.h b/source/ngc/audio.h index 6ae5fd1..c37d46c 100644 --- a/source/ngc/audio.h +++ b/source/ngc/audio.h @@ -11,9 +11,21 @@ #ifndef __AUDIOMIXER__ #define __AUDIOMIXER__ -void MIXER_AddSamples( u8 *sampledata, int len ); -void StopAudio(); -void ResetAudio(); +#include "common/SoundDriver.h" + void InitialiseSound(); +class SoundWii: public SoundDriver +{ +public: + SoundWii(); + virtual ~SoundWii(); + + virtual bool init(long sampleRate); + virtual void pause(); + virtual void reset(); + virtual void resume(); + virtual void write(u16 * finalWave, int length); +}; + #endif diff --git a/source/ngc/input.cpp b/source/ngc/input.cpp index 8a29e7a..b059e62 100644 --- a/source/ngc/input.cpp +++ b/source/ngc/input.cpp @@ -13,7 +13,6 @@ #include #include #include - #include #include #include @@ -331,7 +330,6 @@ u32 GetJoy(int pad) #endif ) { - StopAudio(); ConfigRequested = 1; return 0; } diff --git a/source/ngc/vba.cpp b/source/ngc/vba.cpp index c814a2d..fc6e1b8 100644 --- a/source/ngc/vba.cpp +++ b/source/ngc/vba.cpp @@ -22,6 +22,8 @@ extern "C" { } #endif +#include "gba/Sound.h" + #include "vba.h" #include "vbasupport.h" #include "preferences.h" @@ -246,6 +248,7 @@ int main(int argc, char *argv[]) LWP_SuspendThread (devicethread); ResetVideo_Emu(); + soundResume(); while (emulating) // emulation loop { @@ -259,6 +262,7 @@ int main(int argc, char *argv[]) if(ConfigRequested) { + soundPause(); ResetVideo_Menu (); // change to menu video mode if (GCSettings.AutoSave == 1) @@ -277,7 +281,6 @@ int main(int argc, char *argv[]) // save zoom level SavePrefs(SILENT); - ConfigRequested = 0; break; } diff --git a/source/ngc/vbasupport.cpp b/source/ngc/vbasupport.cpp index 8f5c4c2..60f217e 100644 --- a/source/ngc/vbasupport.cpp +++ b/source/ngc/vbasupport.cpp @@ -444,15 +444,10 @@ bool SaveBatteryOrState(int method, int action, bool silent) * Sound ****************************************************************************/ -void systemWriteDataToSoundBuffer() +SoundDriver * systemSoundInit() { - MIXER_AddSamples((u8 *)soundFinalWave, (cartridgeType == 1)); -} - -bool systemSoundInit() -{ - ResetAudio(); - return true; + soundShutdown(); + return new SoundWii(); } bool systemCanChangeSoundQuality() @@ -460,10 +455,13 @@ bool systemCanChangeSoundQuality() return true; } -void systemSoundPause() {} -void systemSoundResume() {} -void systemSoundReset() {} -void systemSoundShutdown() {} +void systemOnWriteDataToSoundBuffer(const u16 * finalWave, int length) +{ +} + +void systemOnSoundShutdown() +{ +} /**************************************************************************** * systemReadJoypads @@ -773,8 +771,7 @@ bool LoadVBAROM(int method) hAspect = 70; vAspect = 46; srcPitch = 484; - soundQuality = 2; - soundBufferLen = 736 * 2; + soundSetSampleRate(44100 / 2); cpuSaveType = 0; break; @@ -807,8 +804,7 @@ bool LoadVBAROM(int method) hAspect = 60; vAspect = 46; srcPitch = 324; - soundQuality = 1; - soundBufferLen = 1470 * 2; + soundSetSampleRate(44100); break; } @@ -833,7 +829,6 @@ bool LoadVBAROM(int method) LoadPatch(method); gbSoundReset(); - gbSoundSetQuality(soundQuality); gbSoundSetDeclicking(true); gbReset(); } @@ -851,7 +846,6 @@ bool LoadVBAROM(int method) doMirroring(mirroringEnable); soundReset(); - soundSetQuality(soundQuality); CPUInit("BIOS.GBA", 1); LoadPatch(method); CPUReset(); diff --git a/source/vba/System.h b/source/vba/System.h index c31e968..a81889a 100644 --- a/source/vba/System.h +++ b/source/vba/System.h @@ -51,12 +51,9 @@ extern u32 systemReadJoypad(int); extern u32 systemGetClock(); extern void systemMessage(int, const char *, ...); extern void systemSetTitle(const char *); -extern void systemWriteDataToSoundBuffer(); -extern void systemSoundShutdown(); -extern void systemSoundPause(); -extern void systemSoundResume(); -extern void systemSoundReset(); -extern bool systemSoundInit(); +extern SoundDriver * systemSoundInit(); +extern void systemOnWriteDataToSoundBuffer(const u16 * finalWave, int length); +extern void systemOnSoundShutdown(); extern void systemScreenMessage(const char *); extern void systemUpdateMotionSensor(); extern int systemGetSensorX(); diff --git a/source/vba/gb/gbSound.cpp b/source/vba/gb/gbSound.cpp index 08fa654..fe1f011 100644 --- a/source/vba/gb/gbSound.cpp +++ b/source/vba/gb/gbSound.cpp @@ -9,6 +9,7 @@ #include "../apu/Effects_Buffer.h" extern int gbHardware; +extern long soundSampleRate; // current sound quality gb_effects_config_t gb_effects_config = { false, 0.20f, 0.15f, false }; @@ -50,22 +51,6 @@ static void end_frame( blip_time_t time ) stereo_buffer->end_frame( time ); } -static void flush_samples() -{ - // number of samples in output buffer - int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; - - // Keep filling and writing soundFinalWave until it can't be fully filled - while ( stereo_buffer->samples_avail() >= out_buf_size ) - { - stereo_buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); - if(soundPaused) - soundResume(); - - systemWriteDataToSoundBuffer(); - } -} - static void apply_effects() { prevSoundEnable = soundGetEnable(); @@ -106,7 +91,7 @@ void gbSoundTick() // Run sound hardware to present end_frame( SOUND_CLOCK_TICKS * ticks_to_time ); - flush_samples(); + flush_samples(stereo_buffer); // Update effects config if it was changed if ( memcmp( &gb_effects_config_current, &gb_effects_config, @@ -141,7 +126,7 @@ static void remake_stereo_buffer() stereo_buffer = 0; stereo_buffer = new Simple_Effects_Buffer; // TODO: handle out of memory - if ( stereo_buffer->set_sample_rate( 44100 / soundQuality ) ) { } // TODO: handle out of memory + if ( stereo_buffer->set_sample_rate( soundSampleRate ) ) { } // TODO: handle out of memory stereo_buffer->clock_rate( gb_apu->clock_rate ); // APU @@ -231,19 +216,19 @@ void gbSoundReset() } } -void gbSoundSetQuality(int quality) +void gbSoundSetSampleRate( long sampleRate ) { - if ( soundQuality != quality ) + if ( soundSampleRate != sampleRate ) { if ( systemCanChangeSoundQuality() ) { soundShutdown(); - soundQuality = quality; + soundSampleRate = sampleRate; soundInit(); } else { - soundQuality = quality; + soundSampleRate = sampleRate; } remake_stereo_buffer(); @@ -380,7 +365,7 @@ static void gbSoundReadGameOld(int version,gzFile gzFile) if ( version >= 7 ) quality = utilReadInt( gzFile ); - gbSoundSetQuality( quality ); + gbSoundSetSampleRate( 44100 / quality ); // Convert to format Gb_Apu uses gb_apu_state_t& s = state.apu; diff --git a/source/vba/gb/gbSound.h b/source/vba/gb/gbSound.h index 73bfe4d..d130fad 100644 --- a/source/vba/gb/gbSound.h +++ b/source/vba/gb/gbSound.h @@ -7,9 +7,7 @@ //// GB sound options -// Sets sample rate to 44100 / quality -void gbSoundSetQuality( int quality ); -extern int soundQuality; // current sound quality +void gbSoundSetSampleRate( long sampleRate ); // Manages declicking mode. When enabled, clicks are reduced. Note that clicks // are normal for GB and GBC sound hardware. diff --git a/source/vba/gba/GBA.cpp b/source/vba/gba/GBA.cpp index 6747dc6..1cb0afc 100644 --- a/source/vba/gba/GBA.cpp +++ b/source/vba/gba/GBA.cpp @@ -1951,9 +1951,9 @@ void CPUSoftwareInterrupt(int comment) } #endif if(reg[0].I) - systemSoundPause(); + soundPause(); else - systemSoundResume(); + soundResume(); break; case 0x1F: BIOS_MidiKey2Freq(); diff --git a/source/vba/gba/Sound.cpp b/source/vba/gba/Sound.cpp index 8b0fe28..5f31364 100644 --- a/source/vba/gba/Sound.cpp +++ b/source/vba/gba/Sound.cpp @@ -10,6 +10,8 @@ #include "../apu/Gb_Apu.h" #include "../apu/Multi_Buffer.h" +#include "../common/SoundDriver.h" + #define NR10 0x60 #define NR11 0x62 #define NR12 0x63 @@ -32,21 +34,21 @@ #define NR51 0x81 #define NR52 0x84 +SoundDriver * soundDriver = 0; + extern bool stopState; // TODO: silence sound when true int const SOUND_CLOCK_TICKS_ = 167772; // 1/100 second -u16 soundFinalWave [1470]; -int soundBufferLen = sizeof soundFinalWave; -int soundQuality = 1; +static u16 soundFinalWave [1600]; +long soundSampleRate = 44100; bool soundInterpolation = true; bool soundPaused = true; float soundFiltering = 0.5f; -float soundVolume = 1.0f; -bool soundEcho = false; int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; int soundTicks = SOUND_CLOCK_TICKS_; +static float soundVolume = 1.0f; static int soundEnableFlag = 0x3ff; // emulator channels enabled static float soundFiltering_ = -1; static float soundVolume_ = -1; @@ -344,8 +346,14 @@ static void end_frame( blip_time_t time ) stereo_buffer->end_frame( time ); } -static void flush_samples() +void flush_samples(Multi_Buffer * buffer) { + // We want to write the data frame by frame to support legacy audio drivers + // that don't use the length parameter of the write method. + // TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the + // samples at once to help reducing the audio delay on all platforms. + int soundBufferLen = ( soundSampleRate / 60 ) * 4; + // soundBufferLen should have a whole number of sample pairs assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 ); @@ -353,13 +361,14 @@ static void flush_samples() int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; // Keep filling and writing soundFinalWave until it can't be fully filled - while ( stereo_buffer->samples_avail() >= out_buf_size ) + while ( buffer->samples_avail() >= out_buf_size ) { - stereo_buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); + buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); if(soundPaused) soundResume(); - systemWriteDataToSoundBuffer(); + soundDriver->write(soundFinalWave, soundBufferLen); + systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen); } } @@ -386,7 +395,7 @@ void psoundTickfn() // Run sound hardware to present end_frame( SOUND_CLOCK_TICKS ); - flush_samples(); + flush_samples(stereo_buffer); if ( soundFiltering_ != soundFiltering ) apply_filtering(); @@ -442,8 +451,7 @@ static void remake_stereo_buffer() stereo_buffer = 0; stereo_buffer = new Stereo_Buffer; // TODO: handle out of memory - long const sample_rate = 44100 / soundQuality; - stereo_buffer->set_sample_rate( sample_rate ); // TODO: handle out of memory + stereo_buffer->set_sample_rate( soundSampleRate ); // TODO: handle out of memory stereo_buffer->clock_rate( gb_apu->clock_rate ); // PCM @@ -464,19 +472,27 @@ static void remake_stereo_buffer() void soundShutdown() { - systemSoundShutdown(); + if (soundDriver) + { + delete soundDriver; + soundDriver = 0; + } + + systemOnSoundShutdown(); } void soundPause() { soundPaused = true; - systemSoundPause(); + if (soundDriver) + soundDriver->pause(); } void soundResume() { soundPaused = false; - systemSoundResume(); + if (soundDriver) + soundDriver->resume(); } void soundSetVolume( float volume ) @@ -502,7 +518,7 @@ int soundGetEnable() void soundReset() { - systemSoundReset(); + soundDriver->reset(); remake_stereo_buffer(); reset_apu(); @@ -516,26 +532,35 @@ void soundReset() bool soundInit() { - if ( !systemSoundInit() ) + soundDriver = systemSoundInit(); + if ( !soundDriver ) + return false; + + if (!soundDriver->init(soundSampleRate)) return false; soundPaused = true; return true; } -void soundSetQuality(int quality) +long soundGetSampleRate() { - if ( soundQuality != quality ) + return soundSampleRate; +} + +void soundSetSampleRate(long sampleRate) +{ + if ( soundSampleRate != sampleRate ) { if ( systemCanChangeSoundQuality() ) { soundShutdown(); - soundQuality = quality; + soundSampleRate = sampleRate; soundInit(); } else { - soundQuality = quality; + soundSampleRate = sampleRate; } remake_stereo_buffer(); diff --git a/source/vba/gba/Sound.h b/source/vba/gba/Sound.h index e27134a..24e8e72 100644 --- a/source/vba/gba/Sound.h +++ b/source/vba/gba/Sound.h @@ -33,16 +33,10 @@ extern bool soundPaused; // current paused state // Cleans up sound. Afterwards, soundInit() can be called again. void soundShutdown(); -// Sound buffering -extern int soundBufferLen; // size of sound buffer in BYTES -extern u16 soundFinalWave[1470];// 16-bit SIGNED stereo sample buffer - - //// GBA sound options -// Sets sample rate to 44100 / quality -void soundSetQuality( int quality ); -extern int soundQuality; // current sound quality +long soundGetSampleRate(); +void soundSetSampleRate(long sampleRate); // Sound settings extern bool soundInterpolation; // 1 if PCM should have low-pass filtering @@ -80,4 +74,8 @@ extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() w void soundSaveGame( gzFile ); void soundReadGame( gzFile, int version ); +class Multi_Buffer; + +void flush_samples(Multi_Buffer * buffer); + #endif // SOUND_H