yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
music_playback_control_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_MUSIC_PANELS_MUSIC_PLAYBACK_CONTROL_PANEL_H_
2#define YAZE_APP_EDITOR_MUSIC_PANELS_MUSIC_PLAYBACK_CONTROL_PANEL_H_
3
4#include <array>
5#include <chrono>
6#include <cmath>
7#include <cstdint>
8#include <cstdio>
9#include <functional>
10#include <string>
11
14#include "app/gui/core/icons.h"
15#include "app/gui/core/input.h"
19#include "imgui/imgui.h"
21
22namespace yaze {
23namespace editor {
24
30 public:
32 int* current_song_index,
33 music::MusicPlayer* music_player)
34 : music_bank_(music_bank),
35 current_song_index_(current_song_index),
36 music_player_(music_player) {}
37
38 // ==========================================================================
39 // EditorPanel Identity
40 // ==========================================================================
41
42 std::string GetId() const override { return "music.tracker"; }
43 std::string GetDisplayName() const override { return "Playback Control"; }
44 std::string GetIcon() const override { return ICON_MD_PLAY_CIRCLE; }
45 std::string GetEditorCategory() const override { return "Music"; }
46 int GetPriority() const override { return 10; }
47
48 // ==========================================================================
49 // Callback Setters
50 // ==========================================================================
51
52 void SetOnOpenSong(std::function<void(int)> callback) {
53 on_open_song_ = callback;
54 }
55
56 void SetOnOpenPianoRoll(std::function<void(int)> callback) {
57 on_open_piano_roll_ = callback;
58 }
59
60 // ==========================================================================
61 // EditorPanel Drawing
62 // ==========================================================================
63
64 void Draw(bool* p_open) override {
66 ImGui::TextDisabled("Music system not initialized");
67 return;
68 }
69
71 ImGui::Separator();
75
76 // Debug controls (collapsed by default)
78
79 // Help section (collapsed by default)
80 if (ImGui::CollapsingHeader(ICON_MD_KEYBOARD " Keyboard Shortcuts")) {
81 ImGui::BulletText("Space: Play/Pause toggle");
82 ImGui::BulletText("Escape: Stop playback");
83 ImGui::BulletText("+/-: Increase/decrease speed");
84 ImGui::BulletText("Arrow keys: Navigate in tracker/piano roll");
85 ImGui::BulletText("Z,S,X,D,C,V,G,B,H,N,J,M: Piano keyboard (C to B)");
86 ImGui::BulletText("Ctrl+Wheel: Zoom (Piano Roll)");
87 }
88 }
89
90 private:
91 void DrawToolset() {
92 auto state =
94 bool can_play = music_player_ && music_player_->IsAudioReady();
96
97 if (!can_play) ImGui::BeginDisabled();
98
99 // Transport controls
100 if (state.is_playing && !state.is_paused) {
101 gui::StyleColorGuard pause_guard(ImGuiCol_Button,
103 if (ImGui::Button(ICON_MD_PAUSE "##Pause")) music_player_->Pause();
104 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Pause (Space)");
105 } else if (state.is_paused) {
106 gui::StyleColorGuard resume_guard(ImGuiCol_Button,
108 if (ImGui::Button(ICON_MD_PLAY_ARROW "##Resume")) music_player_->Resume();
109 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Resume (Space)");
110 } else {
111 if (ImGui::Button(ICON_MD_PLAY_ARROW "##Play"))
113 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Play (Space)");
114 }
115
116 ImGui::SameLine();
117 if (ImGui::Button(ICON_MD_STOP "##Stop")) music_player_->Stop();
118 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Stop (Escape)");
119
120 if (!can_play) ImGui::EndDisabled();
121
122 // Song label with playing indicator
123 ImGui::SameLine();
124 if (song) {
125 if (state.is_playing && !state.is_paused) {
126 float t = static_cast<float>(ImGui::GetTime() * 3.0);
127 float alpha = 0.5f + 0.5f * std::sin(t);
128 auto c = gui::GetSuccessColor();
129 ImGui::TextColored(ImVec4(c.x, c.y, c.z, alpha), ICON_MD_GRAPHIC_EQ);
130 ImGui::SameLine();
131 } else if (state.is_paused) {
132 ImGui::TextColored(gui::GetWarningColor(),
134 ImGui::SameLine();
135 }
136 ImGui::Text("%s", song->name.c_str());
137 if (song->modified) {
138 ImGui::SameLine();
139 ImGui::TextColored(gui::GetWarningColor(), ICON_MD_EDIT);
140 }
141 } else {
142 ImGui::TextDisabled("No song selected");
143 }
144
145 // Time display
146 if (state.is_playing || state.is_paused) {
147 ImGui::SameLine();
148 float seconds = state.ticks_per_second > 0
149 ? state.current_tick / state.ticks_per_second
150 : 0.0f;
151 int mins = static_cast<int>(seconds) / 60;
152 int secs = static_cast<int>(seconds) % 60;
153 ImGui::TextColored(gui::GetInfoColor(), " %d:%02d", mins,
154 secs);
155 }
156
157 // Right-aligned controls
158 float right_offset = ImGui::GetWindowWidth() - 200;
159 if (right_offset > 200) {
160 ImGui::SameLine(right_offset);
161
162 ImGui::Text(ICON_MD_SPEED);
163 ImGui::SameLine();
164 ImGui::SetNextItemWidth(70);
165 float speed = state.playback_speed;
166 if (gui::SliderFloatWheel("##Speed", &speed, 0.25f, 2.0f, "%.2fx",
167 0.1f)) {
169 }
170 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Playback speed (+/- keys)");
171
172 ImGui::SameLine();
173 ImGui::Text(ICON_MD_VOLUME_UP);
174 ImGui::SameLine();
175 ImGui::SetNextItemWidth(60);
176 if (gui::SliderIntWheel("##Vol", &current_volume_, 0, 100, "%d%%", 5)) {
178 }
179 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Volume");
180 }
181 }
182
185
186 if (song) {
187 ImGui::Text("Selected Song:");
188 ImGui::SameLine();
189 ImGui::TextColored(gui::GetInfoColor(), "[%02X] %s",
190 *current_song_index_ + 1, song->name.c_str());
191
192 ImGui::SameLine();
193 ImGui::TextDisabled("| %zu segments", song->segments.size());
194 if (song->modified) {
195 ImGui::SameLine();
196 ImGui::TextColored(gui::GetWarningColor(),
197 ICON_MD_EDIT " Modified");
198 }
199 }
200 }
201
203 auto state =
206
207 if (state.is_playing || state.is_paused) {
208 ImGui::Separator();
209
210 // Timeline progress
211 if (song && !song->segments.empty()) {
212 uint32_t total_duration = 0;
213 for (const auto& seg : song->segments) {
214 total_duration += seg.GetDuration();
215 }
216
217 float progress = (total_duration > 0)
218 ? static_cast<float>(state.current_tick) /
219 total_duration
220 : 0.0f;
221 progress = std::clamp(progress, 0.0f, 1.0f);
222
223 float current_seconds =
224 state.ticks_per_second > 0
225 ? state.current_tick / state.ticks_per_second
226 : 0.0f;
227 float total_seconds = state.ticks_per_second > 0
228 ? total_duration / state.ticks_per_second
229 : 0.0f;
230
231 int cur_min = static_cast<int>(current_seconds) / 60;
232 int cur_sec = static_cast<int>(current_seconds) % 60;
233 int tot_min = static_cast<int>(total_seconds) / 60;
234 int tot_sec = static_cast<int>(total_seconds) % 60;
235
236 ImGui::Text("%d:%02d / %d:%02d", cur_min, cur_sec, tot_min, tot_sec);
237 ImGui::SameLine();
238 ImGui::ProgressBar(progress, ImVec2(-1, 0), "");
239 }
240
241 ImGui::Text("Segment: %d | Tick: %u", state.current_segment_index + 1,
242 state.current_tick);
243 ImGui::SameLine();
244 ImGui::TextDisabled("| %.1f ticks/sec | %.2fx speed",
245 state.ticks_per_second, state.playback_speed);
246 }
247 }
248
250 ImGui::Separator();
251
252 if (ImGui::Button(ICON_MD_OPEN_IN_NEW " Open Tracker")) {
254 }
255 if (ImGui::IsItemHovered())
256 ImGui::SetTooltip("Open song in dedicated tracker window");
257
258 ImGui::SameLine();
259 if (ImGui::Button(ICON_MD_PIANO " Open Piano Roll")) {
261 }
262 if (ImGui::IsItemHovered())
263 ImGui::SetTooltip("Open piano roll view for this song");
264 }
265
267 if (!music_player_) return;
268
269 if (!ImGui::CollapsingHeader(ICON_MD_BUG_REPORT " Debug Controls")) return;
270
271 ImGui::Indent();
272
273 // Pause updates checkbox
274 ImGui::Checkbox("Pause Updates", &debug_paused_);
275 ImGui::SameLine();
276 if (ImGui::Button("Snapshot")) {
277 // Force capture current values
278 debug_paused_ = true;
279 }
280 ImGui::SameLine();
281 ImGui::TextDisabled("(Freeze display to read values)");
282
283 // Capture current state (unless paused)
284 if (!debug_paused_) {
289
290 // Track statistics using wall-clock time for accuracy
292 auto now = std::chrono::steady_clock::now();
293
294 // Initialize on first call
295 if (last_stats_time_.time_since_epoch().count() == 0) {
296 last_stats_time_ = now;
299 }
300
301 auto elapsed = std::chrono::duration<double>(now - last_stats_time_).count();
302
303 // Update stats every 0.5 seconds
304 if (elapsed >= 0.5) {
305 uint64_t cycle_delta = cached_apu_.cycles - last_cycles_for_rate_;
306 int32_t queue_delta = static_cast<int32_t>(cached_audio_.queued_frames) -
307 static_cast<int32_t>(last_queued_for_rate_);
308
309 // Calculate actual rates based on elapsed wall-clock time
310 avg_cycle_rate_ = static_cast<uint64_t>(cycle_delta / elapsed);
311 avg_queue_delta_ = static_cast<int32_t>(queue_delta / elapsed);
312
313 // Reset for next measurement
314 last_stats_time_ = now;
317 }
318 } else {
319 // Reset when stopped
320 last_stats_time_ = std::chrono::steady_clock::time_point();
321 }
322 }
323
324 // === Quick Summary (always visible) ===
325 ImGui::Separator();
326 ImVec4 status_color = cached_audio_.is_playing
329 ImGui::TextColored(status_color, cached_audio_.is_playing ? "PLAYING" : "STOPPED");
330 ImGui::SameLine();
331 ImGui::Text("| Queue: %u frames", cached_audio_.queued_frames);
332 ImGui::SameLine();
333 ImGui::Text("| DSP: %u/2048", cached_dsp_.sample_offset);
334
335 // Queue trend indicator
336 ImGui::SameLine();
337 if (avg_queue_delta_ > 50) {
338 ImGui::TextColored(gui::GetErrorColor(),
339 ICON_MD_TRENDING_UP " GROWING (too fast!)");
340 } else if (avg_queue_delta_ < -50) {
341 ImGui::TextColored(gui::GetWarningColor(),
342 ICON_MD_TRENDING_DOWN " DRAINING");
343 } else {
344 ImGui::TextColored(gui::GetSuccessColor(),
345 ICON_MD_TRENDING_FLAT " STABLE");
346 }
347
348 // Cycle rate check (should be ~1,024,000/sec)
349 if (avg_cycle_rate_ > 0) {
350 float rate_ratio = avg_cycle_rate_ / 1024000.0f;
351 ImGui::Text("APU Rate: %.2fx expected", rate_ratio);
352 if (rate_ratio > 1.1f) {
353 ImGui::SameLine();
354 ImGui::TextColored(gui::GetErrorColor(),
355 "(APU running too fast!)");
356 }
357 }
358
359 ImGui::Separator();
360
361 // === DSP Buffer Status ===
362 if (ImGui::TreeNode("DSP Buffer")) {
363 auto& dsp = cached_dsp_;
364
365 ImGui::Text("Sample Offset: %u / 2048", dsp.sample_offset);
366 ImGui::Text("Frame Boundary: %u", dsp.frame_boundary);
367
368 // Buffer fill progress bar
369 float fill = dsp.sample_offset / 2048.0f;
370 char overlay[32];
371 snprintf(overlay, sizeof(overlay), "%.1f%%", fill * 100.0f);
372 ImGui::ProgressBar(fill, ImVec2(-1, 0), overlay);
373
374 // Drift indicator
375 int32_t drift = static_cast<int32_t>(dsp.sample_offset) -
376 static_cast<int32_t>(dsp.frame_boundary);
377 ImVec4 drift_color = (std::abs(drift) > 100)
380 ImGui::TextColored(drift_color, "Drift: %+d samples", drift);
381
382 ImGui::Text("Master Vol: L=%d R=%d", dsp.master_vol_l, dsp.master_vol_r);
383
384 // Status flags
385 if (dsp.mute) {
386 ImGui::TextColored(gui::GetWarningColor(), ICON_MD_VOLUME_OFF " MUTED");
387 ImGui::SameLine();
388 }
389 if (dsp.reset) {
390 ImGui::TextColored(gui::GetErrorColor(), ICON_MD_RESTART_ALT " RESET");
391 ImGui::SameLine();
392 }
393 if (dsp.echo_enabled) {
394 ImGui::TextColored(gui::GetInfoColor(),
395 ICON_MD_SURROUND_SOUND " Echo (delay=%u)", dsp.echo_delay);
396 }
397
398 ImGui::TreePop();
399 }
400
401 // === Audio Queue Status ===
402 if (ImGui::TreeNode("Audio Queue")) {
403 auto& audio = cached_audio_;
404
405 // Status indicator
406 if (audio.is_playing) {
407 ImGui::TextColored(gui::GetSuccessColor(),
408 ICON_MD_PLAY_CIRCLE " Playing");
409 } else {
410 ImGui::TextColored(gui::GetDisabledColor(),
411 ICON_MD_STOP_CIRCLE " Stopped");
412 }
413
414 ImGui::Text("Queued: %u frames (%u bytes)",
415 audio.queued_frames, audio.queued_bytes);
416 ImGui::Text("Sample Rate: %d Hz", audio.sample_rate);
417 ImGui::Text("Backend: %s", audio.backend_name.c_str());
418
419 // Underrun warning
420 if (audio.has_underrun) {
421 ImGui::TextColored(gui::GetErrorColor(),
422 ICON_MD_WARNING " UNDERRUN DETECTED");
423 }
424
425 // Queue level indicator
426 float queue_level = audio.queued_frames / 6000.0f; // ~100ms worth
427 queue_level = std::clamp(queue_level, 0.0f, 1.0f);
428 ImVec4 queue_color = (queue_level < 0.2f)
431 {
432 gui::StyleColorGuard queue_guard(ImGuiCol_PlotHistogram, queue_color);
433 ImGui::ProgressBar(queue_level, ImVec2(-1, 0), "Queue Level");
434 }
435
436 ImGui::TreePop();
437 }
438
439 // === APU Timing ===
440 if (ImGui::TreeNode("APU Timing")) {
441 auto& apu = cached_apu_;
442
443 ImGui::Text("Cycles: %llu", static_cast<unsigned long long>(apu.cycles));
444
445 // Timers in a table
446 if (ImGui::BeginTable("Timers", 4, ImGuiTableFlags_Borders)) {
447 ImGui::TableSetupColumn("Timer");
448 ImGui::TableSetupColumn("Enabled");
449 ImGui::TableSetupColumn("Counter");
450 ImGui::TableSetupColumn("Target");
451 ImGui::TableHeadersRow();
452
453 // Timer 0
454 ImGui::TableNextRow();
455 ImGui::TableNextColumn(); ImGui::Text("T0");
456 ImGui::TableNextColumn();
457 ImGui::TextColored(apu.timer0_enabled ? gui::GetSuccessColor()
459 apu.timer0_enabled ? "ON" : "off");
460 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer0_counter);
461 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer0_target);
462
463 // Timer 1
464 ImGui::TableNextRow();
465 ImGui::TableNextColumn(); ImGui::Text("T1");
466 ImGui::TableNextColumn();
467 ImGui::TextColored(apu.timer1_enabled ? gui::GetSuccessColor()
469 apu.timer1_enabled ? "ON" : "off");
470 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer1_counter);
471 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer1_target);
472
473 // Timer 2
474 ImGui::TableNextRow();
475 ImGui::TableNextColumn(); ImGui::Text("T2");
476 ImGui::TableNextColumn();
477 ImGui::TextColored(apu.timer2_enabled ? gui::GetSuccessColor()
479 apu.timer2_enabled ? "ON" : "off");
480 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer2_counter);
481 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer2_target);
482
483 ImGui::EndTable();
484 }
485
486 // Port state
487 ImGui::Text("Ports IN: [0]=%02X [1]=%02X", apu.port0_in, apu.port1_in);
488 ImGui::Text("Ports OUT: [0]=%02X [1]=%02X", apu.port0_out, apu.port1_out);
489
490 ImGui::TreePop();
491 }
492
493 // === Channel Overview ===
494 if (ImGui::TreeNode("Channels")) {
495 auto& channels = cached_channels_;
496
497 ImGui::Text("Key Status:");
498 ImGui::SameLine();
499 for (int i = 0; i < 8; i++) {
500 ImVec4 color = channels[i].key_on
503 ImGui::TextColored(color, "%d", i);
504 if (i < 7) ImGui::SameLine();
505 }
506
507 // Detailed channel info
508 if (ImGui::BeginTable("ChannelDetails", 6,
509 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
510 ImGui::TableSetupColumn("Ch", ImGuiTableColumnFlags_WidthFixed, 25);
511 ImGui::TableSetupColumn("Key");
512 ImGui::TableSetupColumn("Sample");
513 ImGui::TableSetupColumn("Pitch");
514 ImGui::TableSetupColumn("Vol L/R");
515 ImGui::TableSetupColumn("ADSR");
516 ImGui::TableHeadersRow();
517
518 const char* adsr_names[] = {"Atk", "Dec", "Sus", "Rel"};
519 for (int i = 0; i < 8; i++) {
520 ImGui::TableNextRow();
521 ImGui::TableNextColumn(); ImGui::Text("%d", i);
522 ImGui::TableNextColumn();
523 ImGui::TextColored(channels[i].key_on ? gui::GetSuccessColor()
525 channels[i].key_on ? "ON" : "--");
526 ImGui::TableNextColumn(); ImGui::Text("%02X", channels[i].sample_index);
527 ImGui::TableNextColumn(); ImGui::Text("%04X", channels[i].pitch);
528 ImGui::TableNextColumn();
529 ImGui::Text("%02X/%02X", channels[i].volume_l, channels[i].volume_r);
530 ImGui::TableNextColumn();
531 int state = channels[i].adsr_state & 0x03;
532 ImGui::Text("%s", adsr_names[state]);
533 }
534
535 ImGui::EndTable();
536 }
537
538 ImGui::TreePop();
539 }
540
541 // === Action Buttons ===
542 ImGui::Separator();
543 ImGui::Text("Actions:");
544
545 if (ImGui::Button(ICON_MD_CLEAR_ALL " Clear Queue")) {
547 }
548 if (ImGui::IsItemHovered())
549 ImGui::SetTooltip("Clear SDL audio queue immediately");
550
551 ImGui::SameLine();
552 if (ImGui::Button(ICON_MD_REFRESH " Reset DSP")) {
554 }
555 if (ImGui::IsItemHovered())
556 ImGui::SetTooltip("Reset DSP sample ring buffer");
557
558 ImGui::SameLine();
559 if (ImGui::Button(ICON_MD_SKIP_NEXT " NewFrame")) {
561 }
562 if (ImGui::IsItemHovered())
563 ImGui::SetTooltip("Force DSP NewFrame() call");
564
565 ImGui::SameLine();
566 if (ImGui::Button(ICON_MD_REPLAY " Reinit Audio")) {
568 }
569 if (ImGui::IsItemHovered())
570 ImGui::SetTooltip("Full audio system reinitialization");
571
572 ImGui::Unindent();
573 }
574
576 int* current_song_index_ = nullptr;
579
580 std::function<void(int)> on_open_song_;
581 std::function<void(int)> on_open_piano_roll_;
582
583 // Debug state
584 bool debug_paused_ = false;
588 std::array<music::ChannelState, 8> cached_channels_;
589 int32_t avg_queue_delta_ = 0;
590 uint64_t avg_cycle_rate_ = 0;
591
592 // Wall-clock timing for rate measurement
593 std::chrono::steady_clock::time_point last_stats_time_;
596};
597
598} // namespace editor
599} // namespace yaze
600
601#endif // YAZE_APP_EDITOR_MUSIC_PANELS_MUSIC_PLAYBACK_CONTROL_PANEL_H_
Base interface for all logical panel components.
EditorPanel for music playback controls and status display.
void SetOnOpenPianoRoll(std::function< void(int)> callback)
int GetPriority() const override
Get display priority for menu ordering.
std::string GetIcon() const override
Material Design icon for this panel.
std::string GetEditorCategory() const override
Editor category this panel belongs to.
void SetOnOpenSong(std::function< void(int)> callback)
void Draw(bool *p_open) override
Draw the panel content.
std::chrono::steady_clock::time_point last_stats_time_
std::string GetId() const override
Unique identifier for this panel.
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
MusicPlaybackControlPanel(zelda3::music::MusicBank *music_bank, int *current_song_index, music::MusicPlayer *music_player)
std::array< music::ChannelState, 8 > cached_channels_
Handles audio playback for the music editor using the SNES APU emulator.
ApuDebugStatus GetApuStatus() const
Get APU timing diagnostic status.
void Stop()
Stop playback completely.
void ReinitAudio()
Reinitialize the audio system.
void SetPlaybackSpeed(float speed)
Set the playback speed (0.25x to 2.0x).
void ForceNewFrame()
Force a DSP NewFrame() call.
void SetVolume(float volume)
Set the master volume (0.0 to 1.0).
void Pause()
Pause the current playback.
AudioQueueStatus GetAudioQueueStatus() const
Get audio queue diagnostic status.
std::array< ChannelState, 8 > GetChannelStates() const
void PlaySong(int song_index)
Start playing a song by index.
DspDebugStatus GetDspStatus() const
Get DSP buffer diagnostic status.
void Resume()
Resume paused playback.
bool IsAudioReady() const
Check if the audio system is ready for playback.
PlaybackState GetState() const
void ResetDspBuffer()
Reset the DSP sample buffer.
void ClearAudioQueue()
Clear the audio queue (stops sound immediately).
RAII guard for ImGui style colors.
Definition style_guard.h:27
Manages the collection of songs, instruments, and samples from a ROM.
Definition music_bank.h:27
MusicSong * GetSong(int index)
Get a song by index.
#define ICON_MD_PAUSE_CIRCLE
Definition icons.h:1390
#define ICON_MD_PAUSE
Definition icons.h:1389
#define ICON_MD_PIANO
Definition icons.h:1462
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_VOLUME_UP
Definition icons.h:2111
#define ICON_MD_TRENDING_DOWN
Definition icons.h:2013
#define ICON_MD_TRENDING_UP
Definition icons.h:2016
#define ICON_MD_PLAY_ARROW
Definition icons.h:1479
#define ICON_MD_REFRESH
Definition icons.h:1572
#define ICON_MD_STOP
Definition icons.h:1862
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_GRAPHIC_EQ
Definition icons.h:890
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_SPEED
Definition icons.h:1817
#define ICON_MD_REPLAY
Definition icons.h:1588
#define ICON_MD_STOP_CIRCLE
Definition icons.h:1863
#define ICON_MD_CLEAR_ALL
Definition icons.h:417
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_PLAY_CIRCLE
Definition icons.h:1480
#define ICON_MD_SKIP_NEXT
Definition icons.h:1773
#define ICON_MD_SURROUND_SOUND
Definition icons.h:1894
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_VOLUME_OFF
Definition icons.h:2110
#define ICON_MD_RESTART_ALT
Definition icons.h:1602
#define ICON_MD_TRENDING_FLAT
Definition icons.h:2014
bool SliderIntWheel(const char *label, int *v, int v_min, int v_max, const char *format, int wheel_step, ImGuiSliderFlags flags)
Definition input.cc:765
ImVec4 GetSuccessColor()
Definition ui_helpers.cc:48
bool SliderFloatWheel(const char *label, float *v, float v_min, float v_max, const char *format, float wheel_step, ImGuiSliderFlags flags)
Definition input.cc:749
ButtonColorSet GetSuccessButtonColors()
ImVec4 GetDisabledColor()
Definition ui_helpers.cc:73
ImVec4 GetErrorColor()
Definition ui_helpers.cc:58
ImVec4 GetWarningColor()
Definition ui_helpers.cc:53
ImVec4 GetInfoColor()
Definition ui_helpers.cc:63
APU timing diagnostic status for debug UI.
Audio queue diagnostic status for debug UI.
DSP buffer diagnostic status for debug UI.
Represents the current playback state of the music player.