From 4c302641363b0397b4479e03d74ddc9af6e3934b Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 23 Feb 2022 15:53:19 +1300 Subject: [PATCH] DirectSoundBuffer visualization debug view - Visualize play progress, play region, loop region - Buffer streaming controls - Scale visualization to window by RadWolfie --- src/core/common/imgui/audio.cpp | 6 +- src/core/common/imgui/settings.h | 1 + .../DSOUND/DirectSound/DirectSoundGlobal.cpp | 102 ++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/core/common/imgui/audio.cpp b/src/core/common/imgui/audio.cpp index ba7637ca8..40e949cdd 100644 --- a/src/core/common/imgui/audio.cpp +++ b/src/core/common/imgui/audio.cpp @@ -25,6 +25,7 @@ void ImGuiAudio::DrawMenu() { if (ImGui::BeginMenu("Audio")) { ImGui::MenuItem("Debug General Cache Stats", NULL, &m_windows.cache_stats_general); + ImGui::MenuItem("SoundBuffer Visualization", NULL, &m_windows.cache_visualization); ImGui::EndMenu(); } } @@ -32,6 +33,9 @@ void ImGuiAudio::DrawMenu() void ImGuiAudio::DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler) { //TODO: In need of make interface class to return generic info in some way. - extern void DSound_PrintStats(bool, ImGuiWindowFlags, bool m_show_audio_stats); + extern void DSound_PrintStats(bool, ImGuiWindowFlags, bool m_show_audio_stats); DSound_PrintStats(is_focus, input_handler, m_windows.cache_stats_general); + + extern void DSound_DrawBufferVisualization(bool, bool *p_show, ImGuiWindowFlags); + DSound_DrawBufferVisualization(is_focus, &m_windows.cache_visualization, input_handler); } diff --git a/src/core/common/imgui/settings.h b/src/core/common/imgui/settings.h index a1790545a..9b9e56682 100644 --- a/src/core/common/imgui/settings.h +++ b/src/core/common/imgui/settings.h @@ -44,6 +44,7 @@ typedef struct { typedef struct { bool cache_stats_general; + bool cache_visualization; bool Reserved[3]; } imgui_audio_windows; diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp index 1f483dd84..1818ecdf3 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp @@ -32,6 +32,10 @@ #include #include #include "DirectSoundGlobal.hpp" +#include "DirectSoundInline.hpp" + +#define IMGUI_DEFINE_MATH_OPERATORS +#include "imgui_internal.h" Settings::s_audio g_XBAudio = { 0 }; std::recursive_mutex g_DSoundMutex; @@ -56,6 +60,104 @@ DWORD g_dwFree3DBuffers = 0; DsBufferStreaming g_dsBufferStreaming; +void DrawAudioProgress(xbox::XbHybridDSBuffer* pHybrid, float scaleWidth, ImDrawList* drawList) { + const auto& pBuffer = pHybrid->emuDSBuffer; + + auto cursor = ImGui::GetCursorScreenPos(); + auto width = ImGui::GetContentRegionAvail().x; + + DWORD rawCursor; + HybridDirectSoundBuffer_GetCurrentPosition(pBuffer->EmuDirectSoundBuffer8, &rawCursor, nullptr, pBuffer->EmuFlags); + float scale = (width / pBuffer->X_BufferCacheSize) / scaleWidth; + float playCursor = rawCursor * scale; + + bool isLooping = pBuffer->EmuPlayFlags & X_DSBPLAY_LOOPING; + + auto colSpan = ImColor(0.8f, 0.1f, 0.1f, 0.3f); + auto colRegion = ImColor(0.1f, 0.8f, 0.1, 0.3f); + auto colRegionLoop = ImColor(0.1f, 0.2f, 0.8, 0.3f); + auto colPlay = ImColor(0.8f, 0.8f, 0.1f, 0.6); + float height = 8; + + float sBuf = height * 0.4; + float sReg = height * 1; + float sPlay = height * 0.4; + + // Buffer + auto start = cursor + ImVec2(0, (height - sBuf) / 2); + drawList->AddRectFilled(start, start + ImVec2(pBuffer->X_BufferCacheSize * scale, sBuf), colSpan, 0); + + DWORD bufferRangeStart; + DWORD bufferRangeSize; + DSoundBufferRegionCurrentLocation(pHybrid, pBuffer->EmuPlayFlags, bufferRangeStart, bufferRangeSize); + + bufferRangeStart *= scale; + bufferRangeSize *= scale; + + // Region + start = cursor + ImVec2(bufferRangeStart, (height - sReg) / 2); + drawList->AddRectFilled(start, start + ImVec2(bufferRangeSize, sReg), isLooping ? colRegionLoop : colRegion); + + // Play area + start = cursor + ImVec2(bufferRangeStart, (height - sPlay) / 2); + drawList->AddRectFilled(start, start + ImVec2(playCursor, sPlay), colPlay); + // Play cursor + start = cursor + ImVec2(bufferRangeStart + playCursor, 0); + drawList->AddLine(start, start + ImVec2(0, height), colPlay); + + ImGui::Dummy(ImVec2(pBuffer->X_BufferCacheSize * scale, height)); +} + +void DSound_DrawBufferVisualization(bool is_focus, bool* p_show, ImGuiWindowFlags input_handler) { + if (!*p_show) return; + + DSoundMutexGuardLock; + + ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver); + if (ImGui::Begin("DSBuffer Visualization", p_show, input_handler)) { + + static bool showPlayingOnly = true; + ImGui::Checkbox("Show playing only", &showPlayingOnly); + + static float bufferScale = 1; + ImGui::PushItemWidth(100); + ImGui::DragFloat("Audio Scale", &bufferScale, 1 / 1000.f, 1 / 24000.f, 1.f, "%.7f", ImGuiSliderFlags_Logarithmic); + + if (ImGui::CollapsingHeader("Buffering Controls")) { + ImGui::SliderInt("Stream interval (ms)", (int*)&g_dsBufferStreaming.streamInterval, 0, 50); + ImGui::SliderInt("Stream ahead (ms)", (int*)&g_dsBufferStreaming.streamAhead, 0, 1000); + ImGui::SliderFloat("Tweak copy offset", &g_dsBufferStreaming.tweakCopyOffset, -1, 1); + } + + if (ImGui::BeginChild("DSBuffer Graph", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { + + auto drawList = ImGui::GetWindowDrawList(); + + int index = 0; + for (const auto& i : g_pDSoundBufferCache) { + if (showPlayingOnly) { + DWORD dwStatus; + auto hRet = i->emuDSBuffer->EmuDirectSoundBuffer8->GetStatus(&dwStatus); + if (hRet != DS_OK || !(dwStatus & DSBSTATUS_PLAYING)) { + continue; + } + } + + // Required to add controls inside the loop + ImGui::PushID(index++); + + DrawAudioProgress(i, bufferScale, drawList); + + ImGui::PopID(); + } + ImGui::EndChild(); + } + + ImGui::End(); + } +} + void DSound_PrintStats(bool is_focus, ImGuiWindowFlags input_handler, bool m_show_audio_stats) { DSoundMutexGuardLock;