diff options
| author | skidau <skidau@gmail.com> | 2013-01-09 22:57:32 +1100 |
|---|---|---|
| committer | skidau <skidau@gmail.com> | 2013-01-09 22:57:32 +1100 |
| commit | 63b38be97c12e6b6f0ec39008f6b0dd06dbcf3f0 (patch) | |
| tree | d7fae9dfd060af3d1736b0156368e300efd6b32b /Source/Core/AudioCommon/Src/OpenALStream.cpp | |
| parent | c8c78e0aa9c7ec1ef738ca064daad5903a9e7b48 (diff) | |
Added audio time stretching by using the SoundTouch library.
Diffstat (limited to 'Source/Core/AudioCommon/Src/OpenALStream.cpp')
| -rw-r--r-- | Source/Core/AudioCommon/Src/OpenALStream.cpp | 79 |
1 files changed, 56 insertions, 23 deletions
diff --git a/Source/Core/AudioCommon/Src/OpenALStream.cpp b/Source/Core/AudioCommon/Src/OpenALStream.cpp index 4cc64a17de..6f429db495 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.cpp +++ b/Source/Core/AudioCommon/Src/OpenALStream.cpp @@ -19,11 +19,12 @@ #include "aldlist.h" #include "OpenALStream.h" -#include "../../Core/Src/HW/SystemTimers.h" -#include "../../Core/Src/HW/AudioInterface.h" #if defined HAVE_OPENAL && HAVE_OPENAL +using namespace soundtouch; +SoundTouch soundTouch; + // // AyuanX: Spec says OpenAL1.1 is thread safe already // @@ -67,6 +68,7 @@ bool OpenALStream::Start() PanicAlertT("OpenAL: can't find sound devices"); } + soundTouch.clear(); return bReturn; } @@ -76,6 +78,8 @@ void OpenALStream::Stop() // kick the thread if it's waiting soundSyncEvent.Set(); + soundTouch.clear(); + thread.join(); alSourceStop(uiSource); @@ -105,6 +109,7 @@ void OpenALStream::SetVolume(int volume) void OpenALStream::Update() { soundSyncEvent.Set(); + mainSyncEvent.Wait(); } void OpenALStream::Clear(bool mute) @@ -113,6 +118,7 @@ void OpenALStream::Clear(bool mute) if(m_muted) { + soundTouch.clear(); alSourceStop(uiSource); } else @@ -136,9 +142,10 @@ void OpenALStream::SoundLoop() alGenSources(1, &uiSource); // Short Silence + memset(sampleBuffer, 0, OAL_MAX_SAMPLES * 4 * OAL_NUM_BUFFERS); memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * 4); for (int i = 0; i < OAL_NUM_BUFFERS; i++) - alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES, ulFrequency); + alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES * 4, ulFrequency); alSourceQueueBuffers(uiSource, OAL_NUM_BUFFERS, uiBuffers); alSourcePlay(uiSource); @@ -152,42 +159,68 @@ void OpenALStream::SoundLoop() ALint iBuffersProcessed = 0; ALuint uiBufferTemp[OAL_NUM_BUFFERS] = {0}; + soundTouch.setChannels(2); + soundTouch.setSampleRate(ulFrequency); + soundTouch.setSetting(SETTING_USE_QUICKSEEK, 0); + soundTouch.setSetting(SETTING_USE_AA_FILTER, 0); + soundTouch.setSetting(SETTING_SEQUENCE_MS, 1); + soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28); + soundTouch.setSetting(SETTING_OVERLAP_MS, 12); + while (!threadData) { - if (iBuffersProcessed == iBuffersFilled) - { - alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); - iBuffersFilled = 0; - } - // num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD. const u32 stereo_16_bit_size = 4; const u32 dma_length = 32; - const u64 audio_dma_period = SystemTimers::GetTicksPerSecond() / (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length); const u64 ais_samples_per_second = 48000 * stereo_16_bit_size; - const u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond(); + u64 audio_dma_period = SystemTimers::GetTicksPerSecond() / (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length); + u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond(); unsigned int numSamples = (unsigned int)num_samples_to_render; + numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples; + numSamples = m_mixer->Mix(realtimeBuffer, numSamples); + soundTouch.putSamples(realtimeBuffer, numSamples); + + if (iBuffersProcessed == iBuffersFilled) + { + alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); + iBuffersFilled = 0; + } + if (iBuffersProcessed) { - numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples; - // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer) - if (iBuffersFilled == 0) - alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp); - - m_mixer->Mix(realtimeBuffer, numSamples); - alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, realtimeBuffer, numSamples * 4, ulFrequency); - alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]); - iBuffersFilled++; - - if (iBuffersFilled == OAL_NUM_BUFFERS) - alSourcePlay(uiSource); + float rate = m_mixer->GetCurrentSpeed(); + if (rate <= 0) + { + Core::RequestRefreshInfo(); + rate = m_mixer->GetCurrentSpeed(); + } + if (rate > 0) + { + // Adjust SETTING_SEQUENCE_MS to balance between lag vs hollow audio + soundTouch.setSetting(SETTING_SEQUENCE_MS, (int)pow(1 / rate, 2)); + soundTouch.setTempo(rate); + } + unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * 2 * OAL_NUM_BUFFERS); + if (nSamples > 0) + { + // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer) + if (iBuffersFilled == 0) + alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp); + alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, sampleBuffer, nSamples * 4, ulFrequency); + alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]); + iBuffersFilled++; + + if (iBuffersFilled == OAL_NUM_BUFFERS) + alSourcePlay(uiSource); + } } else { soundSyncEvent.Wait(); } + mainSyncEvent.Set(); } } |
