yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
music_audio_debug_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_MUSIC_PANELS_MUSIC_AUDIO_DEBUG_PANEL_H_
2#define YAZE_APP_EDITOR_MUSIC_PANELS_MUSIC_AUDIO_DEBUG_PANEL_H_
3
4#include <string>
5
8#include "app/emu/emulator.h"
10#include "imgui/imgui.h"
11
12namespace yaze {
13namespace editor {
14
26 public:
28 : player_(player) {}
29
30 // ==========================================================================
31 // WindowContent Identity
32 // ==========================================================================
33
34 std::string GetId() const override { return "music.audio_debug"; }
35 std::string GetDisplayName() const override { return "Audio Debug"; }
36 std::string GetIcon() const override { return ICON_MD_BUG_REPORT; }
37 std::string GetEditorCategory() const override { return "Music"; }
38 int GetPriority() const override { return 95; } // Just before Help
39
40 // ==========================================================================
41 // WindowContent Drawing
42 // ==========================================================================
43
44 void Draw(bool* p_open) override {
45 if (!player_) {
46 ImGui::TextDisabled("Music player not available");
47 return;
48 }
49
50 emu::Emulator* debug_emu = player_->emulator();
51 if (!debug_emu || !debug_emu->is_snes_initialized()) {
52 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.4f, 1.0f),
53 ICON_MD_INFO " Play a song to initialize audio");
54 ImGui::Separator();
55 ImGui::TextDisabled("Audio emulator not initialized");
56 return;
57 }
58
59 auto* audio_backend = debug_emu->audio_backend();
60 if (!audio_backend) {
61 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
62 ICON_MD_ERROR " No audio backend!");
63 return;
64 }
65
66 DrawBackendInfo(audio_backend);
67 ImGui::Separator();
68 DrawQueueStatus(audio_backend);
69 ImGui::Separator();
70 DrawResamplingStatus(audio_backend);
71 ImGui::Separator();
73 ImGui::Separator();
75 ImGui::Separator();
77 }
78
79 private:
81 auto config = backend->GetConfig();
82
83 ImGui::Text(ICON_MD_SPEAKER " Backend Configuration");
84 ImGui::Indent();
85 ImGui::Text("Backend: %s", backend->GetBackendName().c_str());
86 ImGui::Text("Device Rate: %d Hz", config.sample_rate);
87 ImGui::Text("Native Rate: 32040 Hz (SPC700)");
88 ImGui::Text("Channels: %d", config.channels);
89 ImGui::Text("Buffer Frames: %d", config.buffer_frames);
90 ImGui::Unindent();
91 }
92
94 auto status = backend->GetStatus();
95
96 ImGui::Text(ICON_MD_QUEUE_MUSIC " Queue Status");
97 ImGui::Indent();
98
99 if (status.is_playing) {
100 ImGui::TextColored(ImVec4(0.3f, 0.9f, 0.3f, 1.0f), "Status: Playing");
101 } else {
102 ImGui::TextColored(ImVec4(0.9f, 0.9f, 0.3f, 1.0f), "Status: Stopped");
103 }
104
105 ImGui::Text("Queued Frames: %u", status.queued_frames);
106 ImGui::Text("Queued Bytes: %u", status.queued_bytes);
107
108 if (status.has_underrun) {
109 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
110 ICON_MD_WARNING " Underrun detected!");
111 }
112
113 ImGui::Unindent();
114 }
115
117 auto config = backend->GetConfig();
118 bool resampling_enabled = backend->IsAudioStreamEnabled();
119
120 ImGui::Text(ICON_MD_TRANSFORM " Resampling");
121 ImGui::Indent();
122
123 if (resampling_enabled) {
124 float ratio = static_cast<float>(config.sample_rate) / 32040.0f;
125 ImGui::TextColored(ImVec4(0.3f, 0.9f, 0.3f, 1.0f),
126 "Status: ENABLED (32040 -> %d Hz)",
127 config.sample_rate);
128 ImGui::Text("Ratio: %.3f", ratio);
129
130 // Check for correct ratio (should be ~1.498 for 32040->48000)
131 if (ratio < 1.4f || ratio > 1.6f) {
132 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
133 ICON_MD_WARNING " Unexpected ratio!");
134 }
135 } else {
136 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Status: DISABLED");
137 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
138 ICON_MD_WARNING " Audio will play at 1.5x speed!");
139 }
140
141 // Playback speed info
142 auto player_state = player_->GetState();
143 ImGui::Text("Playback Speed: %.2fx", player_state.playback_speed);
144 ImGui::Text("Effective Rate: %.0f Hz",
145 32040.0f * player_state.playback_speed);
146
147 ImGui::Unindent();
148 }
149
151 auto dsp_status = player_->GetDspStatus();
152
153 ImGui::Text(ICON_MD_MEMORY " DSP Status");
154 ImGui::Indent();
155
156 ImGui::Text("Sample Offset: %u", dsp_status.sample_offset);
157 ImGui::Text("Frame Boundary: %u", dsp_status.frame_boundary);
158 ImGui::Text("Master Vol L/R: %d / %d", dsp_status.master_vol_l,
159 dsp_status.master_vol_r);
160
161 if (dsp_status.mute) {
162 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "Muted");
163 }
164 if (dsp_status.reset) {
165 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Reset");
166 }
167
168 ImGui::Text("Echo: %s (delay: %u)", dsp_status.echo_enabled ? "ON" : "OFF",
169 dsp_status.echo_delay);
170
171 ImGui::Unindent();
172 }
173
175 auto apu_status = player_->GetApuStatus();
176
177 ImGui::Text(ICON_MD_TIMER " APU Status");
178 ImGui::Indent();
179
180 ImGui::Text("Cycles: %llu", apu_status.cycles);
181
182 // Timers in columns
183 if (ImGui::BeginTable("ApuTimers", 4, ImGuiTableFlags_Borders)) {
184 ImGui::TableSetupColumn("Timer");
185 ImGui::TableSetupColumn("Enabled");
186 ImGui::TableSetupColumn("Counter");
187 ImGui::TableSetupColumn("Target");
188 ImGui::TableHeadersRow();
189
190 // Timer 0
191 ImGui::TableNextRow();
192 ImGui::TableSetColumnIndex(0);
193 ImGui::Text("T0");
194 ImGui::TableSetColumnIndex(1);
195 ImGui::Text("%s", apu_status.timer0_enabled ? "ON" : "OFF");
196 ImGui::TableSetColumnIndex(2);
197 ImGui::Text("%u", apu_status.timer0_counter);
198 ImGui::TableSetColumnIndex(3);
199 ImGui::Text("%u", apu_status.timer0_target);
200
201 // Timer 1
202 ImGui::TableNextRow();
203 ImGui::TableSetColumnIndex(0);
204 ImGui::Text("T1");
205 ImGui::TableSetColumnIndex(1);
206 ImGui::Text("%s", apu_status.timer1_enabled ? "ON" : "OFF");
207 ImGui::TableSetColumnIndex(2);
208 ImGui::Text("%u", apu_status.timer1_counter);
209 ImGui::TableSetColumnIndex(3);
210 ImGui::Text("%u", apu_status.timer1_target);
211
212 // Timer 2
213 ImGui::TableNextRow();
214 ImGui::TableSetColumnIndex(0);
215 ImGui::Text("T2");
216 ImGui::TableSetColumnIndex(1);
217 ImGui::Text("%s", apu_status.timer2_enabled ? "ON" : "OFF");
218 ImGui::TableSetColumnIndex(2);
219 ImGui::Text("%u", apu_status.timer2_counter);
220 ImGui::TableSetColumnIndex(3);
221 ImGui::Text("%u", apu_status.timer2_target);
222
223 ImGui::EndTable();
224 }
225
226 // Ports
227 ImGui::Text("Ports In: %02X %02X", apu_status.port0_in,
228 apu_status.port1_in);
229 ImGui::Text("Ports Out: %02X %02X", apu_status.port0_out,
230 apu_status.port1_out);
231
232 ImGui::Unindent();
233 }
234
236 ImGui::Text(ICON_MD_BUILD " Debug Actions");
237 ImGui::Indent();
238
239 if (ImGui::Button("Clear Audio Queue")) {
241 }
242 ImGui::SameLine();
243 if (ImGui::Button("Reset DSP Buffer")) {
245 }
246 ImGui::SameLine();
247 if (ImGui::Button("Force NewFrame")) {
249 }
250
251 if (ImGui::Button("Reinit Audio")) {
253 }
254
255 ImGui::Unindent();
256 }
257
259};
260
261} // namespace editor
262} // namespace yaze
263
264#endif // YAZE_APP_EDITOR_MUSIC_PANELS_MUSIC_AUDIO_DEBUG_PANEL_H_
WindowContent providing audio diagnostics for debugging the music editor.
void DrawBackendInfo(emu::audio::IAudioBackend *backend)
void DrawResamplingStatus(emu::audio::IAudioBackend *backend)
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
void Draw(bool *p_open) override
Draw the panel content.
int GetPriority() const override
Get display priority for menu ordering.
std::string GetId() const override
Unique identifier for this panel.
MusicAudioDebugPanel(editor::music::MusicPlayer *player)
std::string GetIcon() const override
Material Design icon for this panel.
std::string GetEditorCategory() const override
Editor category this panel belongs to.
void DrawQueueStatus(emu::audio::IAudioBackend *backend)
Base interface for all logical window content components.
Handles audio playback for the music editor using the SNES APU emulator.
ApuDebugStatus GetApuStatus() const
Get APU timing diagnostic status.
void ReinitAudio()
Reinitialize the audio system.
void ForceNewFrame()
Force a DSP NewFrame() call.
DspDebugStatus GetDspStatus() const
Get DSP buffer diagnostic status.
PlaybackState GetState() const
void ResetDspBuffer()
Reset the DSP sample buffer.
void ClearAudioQueue()
Clear the audio queue (stops sound immediately).
A class for emulating and debugging SNES games.
Definition emulator.h:41
bool is_snes_initialized() const
Definition emulator.h:129
audio::IAudioBackend * audio_backend()
Definition emulator.h:77
Abstract audio backend interface.
virtual std::string GetBackendName() const =0
virtual AudioStatus GetStatus() const =0
virtual AudioConfig GetConfig() const =0
virtual bool IsAudioStreamEnabled() const
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_MEMORY
Definition icons.h:1195
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_QUEUE_MUSIC
Definition icons.h:1538
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_ERROR
Definition icons.h:686
#define ICON_MD_TIMER
Definition icons.h:1982
#define ICON_MD_SPEAKER
Definition icons.h:1812
#define ICON_MD_TRANSFORM
Definition icons.h:2008
#define ICON_MD_BUILD
Definition icons.h:328