SoundStream* InitSoundStream() { CMixer *mixer = new CMixer(48000); // TODO: possible memleak with mixer std::string backend = SConfig::GetInstance().sBackend; if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer); else if (backend == BACKEND_NULLSOUND && NullSound::isValid()) soundStream = new NullSound(mixer); else if (backend == BACKEND_XAUDIO2) { if (XAudio2::isValid()) soundStream = new XAudio2(mixer); else if (XAudio2_7::isValid()) soundStream = new XAudio2_7(mixer); } else if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer); else if (backend == BACKEND_ALSA && AlsaSound::isValid()) soundStream = new AlsaSound(mixer); else if (backend == BACKEND_COREAUDIO && CoreAudioSound::isValid()) soundStream = new CoreAudioSound(mixer); else if (backend == BACKEND_PULSEAUDIO && PulseAudio::isValid()) soundStream = new PulseAudio(mixer); else if (backend == BACKEND_OPENSLES && OpenSLESStream::isValid()) soundStream = new OpenSLESStream(mixer); if (!soundStream && NullSound::isValid()) { WARN_LOG(DSPHLE, "Could not initialize backend %s, using %s instead.", backend.c_str(), BACKEND_NULLSOUND); soundStream = new NullSound(mixer); } if (soundStream) { UpdateSoundStream(); if (soundStream->Start()) { if (SConfig::GetInstance().m_DumpAudio) { std::string audio_file_name = File::GetUserPath(D_DUMPAUDIO_IDX) + "audiodump.wav"; File::CreateFullPath(audio_file_name); mixer->StartLogAudio(audio_file_name); } return soundStream; } PanicAlertT("Could not initialize backend %s.", backend.c_str()); } PanicAlertT("Sound backend %s is not valid.", backend.c_str()); delete soundStream; soundStream = nullptr; return nullptr; }
void SendAIBuffer(short *samples, unsigned int num_samples) { if (!soundStream) return; CMixer* pMixer = soundStream->GetMixer(); if (pMixer && samples) { pMixer->PushSamples(samples, num_samples); } soundStream->Update(); }
void DSPLLE::DSP_SendAIBuffer(unsigned int address, unsigned int num_samples) { if (!soundStream) return; CMixer *pMixer = soundStream->GetMixer(); if (pMixer && address) { address &= (address & 0x10000000) ? 0x13ffffff : 0x01ffffff; const short *samples = (const short *)&g_dsp.cpu_ram[address]; pMixer->PushSamples(samples, num_samples); } soundStream->Update(); }
void PauseAndLock(bool doLock, bool unpauseOnUnlock) { if (soundStream) { // audio typically doesn't maintain its own "paused" state // (that's already handled by the CPU and whatever else being paused) // so it should be good enough to only lock/unlock here. CMixer* pMixer = soundStream->GetMixer(); if (pMixer) { std::mutex& csMixing = pMixer->MixerCritical(); if (doLock) csMixing.lock(); else csMixing.unlock(); } } }
void SendAIBuffer(short *samples, unsigned int num_samples) { if (!g_sound_stream) return; if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start) StartAudioDump(); else if (!SConfig::GetInstance().m_DumpAudio && s_audio_dump_start) StopAudioDump(); CMixer* pMixer = g_sound_stream->GetMixer(); if (pMixer && samples) { pMixer->PushSamples(samples, num_samples); } g_sound_stream->Update(); }
void UpdateTitle() { u32 ElapseTime = (u32)s_timer.GetTimeDifference(); s_request_refresh_info = false; SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; if (ElapseTime == 0) ElapseTime = 1; float FPS = (float) (Common::AtomicLoad(s_drawn_frame) * 1000.0 / ElapseTime); float VPS = (float) (s_drawn_video * 1000.0 / ElapseTime); float Speed = (float) (s_drawn_video * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime)); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC", g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE"); std::string SFPS; if (Movie::IsPlayingInput()) SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); else if (Movie::IsRecordingInput()) SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); else { SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed); if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo) { // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. static u64 ticks = 0; static u64 idleTicks = 0; u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); } } // This is our final "frame counter" string std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); // Update the audio timestretcher with the current speed if (g_sound_stream) { CMixer* pMixer = g_sound_stream->GetMixer(); pMixer->UpdateSpeed((float)Speed / 100); } Host_UpdateTitle(SMessage); }
// The audio thread. void SoundStream::SoundLoop() { Common::SetCurrentThreadName("Audio thread"); InitializeSoundLoop(); bool surroundSupported = SupportSurroundOutput() && SConfig::GetInstance().bDPL2Decoder; memset(realtimeBuffer, 0, SOUND_MAX_FRAME_SIZE * sizeof(u16)); memset(dpl2buffer, 0, SOUND_MAX_FRAME_SIZE * sizeof(soundtouch::SAMPLETYPE)); memset(samplebuffer, 0, SOUND_MAX_FRAME_SIZE * sizeof(soundtouch::SAMPLETYPE)); u32 channelmultiplier = surroundSupported ? SOUND_SAMPLES_SURROUND : SOUND_SAMPLES_STEREO; CMixer* mixer = GetMixer(); if (SConfig::GetInstance().bTimeStretching) { float ratemultiplier = 1.0f; soundtouch::SoundTouch sTouch; sTouch.setChannels(2); sTouch.setSampleRate(mixer->GetSampleRate()); sTouch.setTempo(1.0); sTouch.setSetting(SETTING_USE_QUICKSEEK, 0); sTouch.setSetting(SETTING_USE_AA_FILTER, 1); while (threadData.load()) { u32 availablesamples = mixer->AvailableSamples(); u32 numsamples = std::min(availablesamples, 400u); if (numsamples == 400u) { float rate = mixer->GetCurrentSpeed(); if (rate <= 0) { rate = 1.0f; } numsamples = mixer->Mix(samplebuffer, numsamples); rate *= ratemultiplier; rate = rate < 0.5f ? 0.5f : rate; rate = roundf(rate * 16.0f) / 16.0f; sTouch.setTempo(rate); sTouch.putSamples(samplebuffer, numsamples); } u32 samplesneeded = SamplesNeeded(); availablesamples = sTouch.numSamples(); if (samplesneeded >= SOUND_FRAME_SIZE && availablesamples > 0) { ratemultiplier = std::fmaxf(std::fminf((float)availablesamples / (float)samplesneeded, 1.1f), 0.9f); numsamples = std::min(availablesamples, SOUND_FRAME_SIZE); if (surroundSupported) { numsamples = sTouch.receiveSamples(dpl2buffer, numsamples); DPL2Decode(dpl2buffer, numsamples, samplebuffer); } else { numsamples = sTouch.receiveSamples(samplebuffer, numsamples); } floatTos16(realtimeBuffer, samplebuffer, numsamples, channelmultiplier); WriteSamples(realtimeBuffer, numsamples); } else { Common::SleepCurrentThread(1); } } } else { while (threadData.load()) { u32 neededsamples = std::min(SamplesNeeded(), SOUND_FRAME_SIZE); u32 availablesamples = mixer->AvailableSamples() & (~(0xF)); if (neededsamples == SOUND_FRAME_SIZE && availablesamples > 0) { u32 numsamples = std::min(availablesamples, neededsamples); if (surroundSupported) { numsamples = mixer->Mix(dpl2buffer, numsamples); DPL2Decode(dpl2buffer, numsamples, samplebuffer); floatTos16(realtimeBuffer, samplebuffer, numsamples, channelmultiplier); } else { numsamples = mixer->Mix(realtimeBuffer, numsamples); } WriteSamples(realtimeBuffer, numsamples); } else { Common::SleepCurrentThread(1); } } } }
void UpdateTitle() { u32 ElapseTime = (u32)Timer.GetTimeDifference(); g_requestRefreshInfo = false; SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; if (ElapseTime == 0) ElapseTime = 1; u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime; u32 VPS = DrawnVideo * 1000 / ElapseTime; u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC"); // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. //#define EXTENDED_INFO #ifdef EXTENDED_INFO u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); #else // Summary information std::string SFPS; if (Movie::IsPlayingInput()) SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); else if (Movie::IsRecordingInput()) SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); else SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); #endif // This is our final "frame counter" string std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); std::string TMessage = StringFromFormat("%s | ", scm_rev_str) + SMessage; // Show message g_video_backend->UpdateFPSDisplay(SMessage.c_str()); // Update the audio timestretcher with the current speed if (soundStream) { CMixer* pMixer = soundStream->GetMixer(); pMixer->UpdateSpeed((float)Speed / 100); } if (_CoreParameter.bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) { Host_UpdateStatusBar(SMessage.c_str()); Host_UpdateTitle(scm_rev_str); } else Host_UpdateTitle(TMessage.c_str()); }