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"
17#include "imgui/imgui.h"
19
20namespace yaze {
21namespace editor {
22
28 public:
30 int* current_song_index,
31 music::MusicPlayer* music_player)
32 : music_bank_(music_bank),
33 current_song_index_(current_song_index),
34 music_player_(music_player) {}
35
36 // ==========================================================================
37 // EditorPanel Identity
38 // ==========================================================================
39
40 std::string GetId() const override { return "music.tracker"; }
41 std::string GetDisplayName() const override { return "Playback Control"; }
42 std::string GetIcon() const override { return ICON_MD_PLAY_CIRCLE; }
43 std::string GetEditorCategory() const override { return "Music"; }
44 int GetPriority() const override { return 10; }
45
46 // ==========================================================================
47 // Callback Setters
48 // ==========================================================================
49
50 void SetOnOpenSong(std::function<void(int)> callback) {
51 on_open_song_ = callback;
52 }
53
54 void SetOnOpenPianoRoll(std::function<void(int)> callback) {
55 on_open_piano_roll_ = callback;
56 }
57
58 // ==========================================================================
59 // EditorPanel Drawing
60 // ==========================================================================
61
62 void Draw(bool* p_open) override {
64 ImGui::TextDisabled("Music system not initialized");
65 return;
66 }
67
69 ImGui::Separator();
73
74 // Debug controls (collapsed by default)
76
77 // Help section (collapsed by default)
78 if (ImGui::CollapsingHeader(ICON_MD_KEYBOARD " Keyboard Shortcuts")) {
79 ImGui::BulletText("Space: Play/Pause toggle");
80 ImGui::BulletText("Escape: Stop playback");
81 ImGui::BulletText("+/-: Increase/decrease speed");
82 ImGui::BulletText("Arrow keys: Navigate in tracker/piano roll");
83 ImGui::BulletText("Z,S,X,D,C,V,G,B,H,N,J,M: Piano keyboard (C to B)");
84 ImGui::BulletText("Ctrl+Wheel: Zoom (Piano Roll)");
85 }
86 }
87
88 private:
89 void DrawToolset() {
90 auto state =
92 bool can_play = music_player_ && music_player_->IsAudioReady();
94
95 if (!can_play) ImGui::BeginDisabled();
96
97 // Transport controls
98 if (state.is_playing && !state.is_paused) {
99 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.5f, 0.2f, 1.0f));
100 if (ImGui::Button(ICON_MD_PAUSE "##Pause")) music_player_->Pause();
101 ImGui::PopStyleColor();
102 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Pause (Space)");
103 } else if (state.is_paused) {
104 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.5f, 0.4f, 0.1f, 1.0f));
105 if (ImGui::Button(ICON_MD_PLAY_ARROW "##Resume")) music_player_->Resume();
106 ImGui::PopStyleColor();
107 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Resume (Space)");
108 } else {
109 if (ImGui::Button(ICON_MD_PLAY_ARROW "##Play"))
111 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Play (Space)");
112 }
113
114 ImGui::SameLine();
115 if (ImGui::Button(ICON_MD_STOP "##Stop")) music_player_->Stop();
116 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Stop (Escape)");
117
118 if (!can_play) ImGui::EndDisabled();
119
120 // Song label with playing indicator
121 ImGui::SameLine();
122 if (song) {
123 if (state.is_playing && !state.is_paused) {
124 float t = static_cast<float>(ImGui::GetTime() * 3.0);
125 float alpha = 0.5f + 0.5f * std::sin(t);
126 ImGui::TextColored(ImVec4(0.4f, 0.9f, 0.4f, alpha), ICON_MD_GRAPHIC_EQ);
127 ImGui::SameLine();
128 } else if (state.is_paused) {
129 ImGui::TextColored(ImVec4(0.9f, 0.7f, 0.2f, 1.0f),
131 ImGui::SameLine();
132 }
133 ImGui::Text("%s", song->name.c_str());
134 if (song->modified) {
135 ImGui::SameLine();
136 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), ICON_MD_EDIT);
137 }
138 } else {
139 ImGui::TextDisabled("No song selected");
140 }
141
142 // Time display
143 if (state.is_playing || state.is_paused) {
144 ImGui::SameLine();
145 float seconds = state.ticks_per_second > 0
146 ? state.current_tick / state.ticks_per_second
147 : 0.0f;
148 int mins = static_cast<int>(seconds) / 60;
149 int secs = static_cast<int>(seconds) % 60;
150 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.8f, 1.0f), " %d:%02d", mins,
151 secs);
152 }
153
154 // Right-aligned controls
155 float right_offset = ImGui::GetWindowWidth() - 200;
156 if (right_offset > 200) {
157 ImGui::SameLine(right_offset);
158
159 ImGui::Text(ICON_MD_SPEED);
160 ImGui::SameLine();
161 ImGui::SetNextItemWidth(70);
162 float speed = state.playback_speed;
163 if (gui::SliderFloatWheel("##Speed", &speed, 0.25f, 2.0f, "%.2fx",
164 0.1f)) {
166 }
167 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Playback speed (+/- keys)");
168
169 ImGui::SameLine();
170 ImGui::Text(ICON_MD_VOLUME_UP);
171 ImGui::SameLine();
172 ImGui::SetNextItemWidth(60);
173 if (gui::SliderIntWheel("##Vol", &current_volume_, 0, 100, "%d%%", 5)) {
175 }
176 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Volume");
177 }
178 }
179
182
183 if (song) {
184 ImGui::Text("Selected Song:");
185 ImGui::SameLine();
186 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "[%02X] %s",
187 *current_song_index_ + 1, song->name.c_str());
188
189 ImGui::SameLine();
190 ImGui::TextDisabled("| %zu segments", song->segments.size());
191 if (song->modified) {
192 ImGui::SameLine();
193 ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.2f, 1.0f),
194 ICON_MD_EDIT " Modified");
195 }
196 }
197 }
198
200 auto state =
203
204 if (state.is_playing || state.is_paused) {
205 ImGui::Separator();
206
207 // Timeline progress
208 if (song && !song->segments.empty()) {
209 uint32_t total_duration = 0;
210 for (const auto& seg : song->segments) {
211 total_duration += seg.GetDuration();
212 }
213
214 float progress = (total_duration > 0)
215 ? static_cast<float>(state.current_tick) /
216 total_duration
217 : 0.0f;
218 progress = std::clamp(progress, 0.0f, 1.0f);
219
220 float current_seconds =
221 state.ticks_per_second > 0
222 ? state.current_tick / state.ticks_per_second
223 : 0.0f;
224 float total_seconds = state.ticks_per_second > 0
225 ? total_duration / state.ticks_per_second
226 : 0.0f;
227
228 int cur_min = static_cast<int>(current_seconds) / 60;
229 int cur_sec = static_cast<int>(current_seconds) % 60;
230 int tot_min = static_cast<int>(total_seconds) / 60;
231 int tot_sec = static_cast<int>(total_seconds) % 60;
232
233 ImGui::Text("%d:%02d / %d:%02d", cur_min, cur_sec, tot_min, tot_sec);
234 ImGui::SameLine();
235 ImGui::ProgressBar(progress, ImVec2(-1, 0), "");
236 }
237
238 ImGui::Text("Segment: %d | Tick: %u", state.current_segment_index + 1,
239 state.current_tick);
240 ImGui::SameLine();
241 ImGui::TextDisabled("| %.1f ticks/sec | %.2fx speed",
242 state.ticks_per_second, state.playback_speed);
243 }
244 }
245
247 ImGui::Separator();
248
249 if (ImGui::Button(ICON_MD_OPEN_IN_NEW " Open Tracker")) {
251 }
252 if (ImGui::IsItemHovered())
253 ImGui::SetTooltip("Open song in dedicated tracker window");
254
255 ImGui::SameLine();
256 if (ImGui::Button(ICON_MD_PIANO " Open Piano Roll")) {
258 }
259 if (ImGui::IsItemHovered())
260 ImGui::SetTooltip("Open piano roll view for this song");
261 }
262
264 if (!music_player_) return;
265
266 if (!ImGui::CollapsingHeader(ICON_MD_BUG_REPORT " Debug Controls")) return;
267
268 ImGui::Indent();
269
270 // Pause updates checkbox
271 ImGui::Checkbox("Pause Updates", &debug_paused_);
272 ImGui::SameLine();
273 if (ImGui::Button("Snapshot")) {
274 // Force capture current values
275 debug_paused_ = true;
276 }
277 ImGui::SameLine();
278 ImGui::TextDisabled("(Freeze display to read values)");
279
280 // Capture current state (unless paused)
281 if (!debug_paused_) {
286
287 // Track statistics using wall-clock time for accuracy
289 auto now = std::chrono::steady_clock::now();
290
291 // Initialize on first call
292 if (last_stats_time_.time_since_epoch().count() == 0) {
293 last_stats_time_ = now;
296 }
297
298 auto elapsed = std::chrono::duration<double>(now - last_stats_time_).count();
299
300 // Update stats every 0.5 seconds
301 if (elapsed >= 0.5) {
302 uint64_t cycle_delta = cached_apu_.cycles - last_cycles_for_rate_;
303 int32_t queue_delta = static_cast<int32_t>(cached_audio_.queued_frames) -
304 static_cast<int32_t>(last_queued_for_rate_);
305
306 // Calculate actual rates based on elapsed wall-clock time
307 avg_cycle_rate_ = static_cast<uint64_t>(cycle_delta / elapsed);
308 avg_queue_delta_ = static_cast<int32_t>(queue_delta / elapsed);
309
310 // Reset for next measurement
311 last_stats_time_ = now;
314 }
315 } else {
316 // Reset when stopped
317 last_stats_time_ = std::chrono::steady_clock::time_point();
318 }
319 }
320
321 // === Quick Summary (always visible) ===
322 ImGui::Separator();
323 ImVec4 status_color = cached_audio_.is_playing
324 ? ImVec4(0.3f, 0.9f, 0.3f, 1.0f)
325 : ImVec4(0.6f, 0.6f, 0.6f, 1.0f);
326 ImGui::TextColored(status_color, cached_audio_.is_playing ? "PLAYING" : "STOPPED");
327 ImGui::SameLine();
328 ImGui::Text("| Queue: %u frames", cached_audio_.queued_frames);
329 ImGui::SameLine();
330 ImGui::Text("| DSP: %u/2048", cached_dsp_.sample_offset);
331
332 // Queue trend indicator
333 ImGui::SameLine();
334 if (avg_queue_delta_ > 50) {
335 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
336 ICON_MD_TRENDING_UP " GROWING (too fast!)");
337 } else if (avg_queue_delta_ < -50) {
338 ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f),
339 ICON_MD_TRENDING_DOWN " DRAINING");
340 } else {
341 ImGui::TextColored(ImVec4(0.5f, 0.8f, 0.5f, 1.0f),
342 ICON_MD_TRENDING_FLAT " STABLE");
343 }
344
345 // Cycle rate check (should be ~1,024,000/sec)
346 if (avg_cycle_rate_ > 0) {
347 float rate_ratio = avg_cycle_rate_ / 1024000.0f;
348 ImGui::Text("APU Rate: %.2fx expected", rate_ratio);
349 if (rate_ratio > 1.1f) {
350 ImGui::SameLine();
351 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
352 "(APU running too fast!)");
353 }
354 }
355
356 ImGui::Separator();
357
358 // === DSP Buffer Status ===
359 if (ImGui::TreeNode("DSP Buffer")) {
360 auto& dsp = cached_dsp_;
361
362 ImGui::Text("Sample Offset: %u / 2048", dsp.sample_offset);
363 ImGui::Text("Frame Boundary: %u", dsp.frame_boundary);
364
365 // Buffer fill progress bar
366 float fill = dsp.sample_offset / 2048.0f;
367 char overlay[32];
368 snprintf(overlay, sizeof(overlay), "%.1f%%", fill * 100.0f);
369 ImGui::ProgressBar(fill, ImVec2(-1, 0), overlay);
370
371 // Drift indicator
372 int32_t drift = static_cast<int32_t>(dsp.sample_offset) -
373 static_cast<int32_t>(dsp.frame_boundary);
374 ImVec4 drift_color = (std::abs(drift) > 100)
375 ? ImVec4(1.0f, 0.3f, 0.3f, 1.0f)
376 : ImVec4(0.5f, 0.8f, 0.5f, 1.0f);
377 ImGui::TextColored(drift_color, "Drift: %+d samples", drift);
378
379 ImGui::Text("Master Vol: L=%d R=%d", dsp.master_vol_l, dsp.master_vol_r);
380
381 // Status flags
382 if (dsp.mute) {
383 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), ICON_MD_VOLUME_OFF " MUTED");
384 ImGui::SameLine();
385 }
386 if (dsp.reset) {
387 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), ICON_MD_RESTART_ALT " RESET");
388 ImGui::SameLine();
389 }
390 if (dsp.echo_enabled) {
391 ImGui::TextColored(ImVec4(0.5f, 0.8f, 1.0f, 1.0f),
392 ICON_MD_SURROUND_SOUND " Echo (delay=%u)", dsp.echo_delay);
393 }
394
395 ImGui::TreePop();
396 }
397
398 // === Audio Queue Status ===
399 if (ImGui::TreeNode("Audio Queue")) {
400 auto& audio = cached_audio_;
401
402 // Status indicator
403 if (audio.is_playing) {
404 ImGui::TextColored(ImVec4(0.3f, 0.9f, 0.3f, 1.0f),
405 ICON_MD_PLAY_CIRCLE " Playing");
406 } else {
407 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
408 ICON_MD_STOP_CIRCLE " Stopped");
409 }
410
411 ImGui::Text("Queued: %u frames (%u bytes)",
412 audio.queued_frames, audio.queued_bytes);
413 ImGui::Text("Sample Rate: %d Hz", audio.sample_rate);
414 ImGui::Text("Backend: %s", audio.backend_name.c_str());
415
416 // Underrun warning
417 if (audio.has_underrun) {
418 ImGui::TextColored(ImVec4(1.0f, 0.2f, 0.2f, 1.0f),
419 ICON_MD_WARNING " UNDERRUN DETECTED");
420 }
421
422 // Queue level indicator
423 float queue_level = audio.queued_frames / 6000.0f; // ~100ms worth
424 queue_level = std::clamp(queue_level, 0.0f, 1.0f);
425 ImVec4 queue_color = (queue_level < 0.2f)
426 ? ImVec4(1.0f, 0.3f, 0.3f, 1.0f)
427 : ImVec4(0.3f, 0.8f, 0.3f, 1.0f);
428 ImGui::PushStyleColor(ImGuiCol_PlotHistogram, queue_color);
429 ImGui::ProgressBar(queue_level, ImVec2(-1, 0), "Queue Level");
430 ImGui::PopStyleColor();
431
432 ImGui::TreePop();
433 }
434
435 // === APU Timing ===
436 if (ImGui::TreeNode("APU Timing")) {
437 auto& apu = cached_apu_;
438
439 ImGui::Text("Cycles: %llu", static_cast<unsigned long long>(apu.cycles));
440
441 // Timers in a table
442 if (ImGui::BeginTable("Timers", 4, ImGuiTableFlags_Borders)) {
443 ImGui::TableSetupColumn("Timer");
444 ImGui::TableSetupColumn("Enabled");
445 ImGui::TableSetupColumn("Counter");
446 ImGui::TableSetupColumn("Target");
447 ImGui::TableHeadersRow();
448
449 // Timer 0
450 ImGui::TableNextRow();
451 ImGui::TableNextColumn(); ImGui::Text("T0");
452 ImGui::TableNextColumn();
453 ImGui::TextColored(apu.timer0_enabled ? ImVec4(0.3f, 0.9f, 0.3f, 1.0f)
454 : ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
455 apu.timer0_enabled ? "ON" : "off");
456 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer0_counter);
457 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer0_target);
458
459 // Timer 1
460 ImGui::TableNextRow();
461 ImGui::TableNextColumn(); ImGui::Text("T1");
462 ImGui::TableNextColumn();
463 ImGui::TextColored(apu.timer1_enabled ? ImVec4(0.3f, 0.9f, 0.3f, 1.0f)
464 : ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
465 apu.timer1_enabled ? "ON" : "off");
466 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer1_counter);
467 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer1_target);
468
469 // Timer 2
470 ImGui::TableNextRow();
471 ImGui::TableNextColumn(); ImGui::Text("T2");
472 ImGui::TableNextColumn();
473 ImGui::TextColored(apu.timer2_enabled ? ImVec4(0.3f, 0.9f, 0.3f, 1.0f)
474 : ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
475 apu.timer2_enabled ? "ON" : "off");
476 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer2_counter);
477 ImGui::TableNextColumn(); ImGui::Text("%u", apu.timer2_target);
478
479 ImGui::EndTable();
480 }
481
482 // Port state
483 ImGui::Text("Ports IN: [0]=%02X [1]=%02X", apu.port0_in, apu.port1_in);
484 ImGui::Text("Ports OUT: [0]=%02X [1]=%02X", apu.port0_out, apu.port1_out);
485
486 ImGui::TreePop();
487 }
488
489 // === Channel Overview ===
490 if (ImGui::TreeNode("Channels")) {
491 auto& channels = cached_channels_;
492
493 ImGui::Text("Key Status:");
494 ImGui::SameLine();
495 for (int i = 0; i < 8; i++) {
496 ImVec4 color = channels[i].key_on
497 ? ImVec4(0.2f, 0.9f, 0.2f, 1.0f)
498 : ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
499 ImGui::TextColored(color, "%d", i);
500 if (i < 7) ImGui::SameLine();
501 }
502
503 // Detailed channel info
504 if (ImGui::BeginTable("ChannelDetails", 6,
505 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
506 ImGui::TableSetupColumn("Ch", ImGuiTableColumnFlags_WidthFixed, 25);
507 ImGui::TableSetupColumn("Key");
508 ImGui::TableSetupColumn("Sample");
509 ImGui::TableSetupColumn("Pitch");
510 ImGui::TableSetupColumn("Vol L/R");
511 ImGui::TableSetupColumn("ADSR");
512 ImGui::TableHeadersRow();
513
514 const char* adsr_names[] = {"Atk", "Dec", "Sus", "Rel"};
515 for (int i = 0; i < 8; i++) {
516 ImGui::TableNextRow();
517 ImGui::TableNextColumn(); ImGui::Text("%d", i);
518 ImGui::TableNextColumn();
519 ImGui::TextColored(channels[i].key_on ? ImVec4(0.2f, 0.9f, 0.2f, 1.0f)
520 : ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
521 channels[i].key_on ? "ON" : "--");
522 ImGui::TableNextColumn(); ImGui::Text("%02X", channels[i].sample_index);
523 ImGui::TableNextColumn(); ImGui::Text("%04X", channels[i].pitch);
524 ImGui::TableNextColumn();
525 ImGui::Text("%02X/%02X", channels[i].volume_l, channels[i].volume_r);
526 ImGui::TableNextColumn();
527 int state = channels[i].adsr_state & 0x03;
528 ImGui::Text("%s", adsr_names[state]);
529 }
530
531 ImGui::EndTable();
532 }
533
534 ImGui::TreePop();
535 }
536
537 // === Action Buttons ===
538 ImGui::Separator();
539 ImGui::Text("Actions:");
540
541 if (ImGui::Button(ICON_MD_CLEAR_ALL " Clear Queue")) {
543 }
544 if (ImGui::IsItemHovered())
545 ImGui::SetTooltip("Clear SDL audio queue immediately");
546
547 ImGui::SameLine();
548 if (ImGui::Button(ICON_MD_REFRESH " Reset DSP")) {
550 }
551 if (ImGui::IsItemHovered())
552 ImGui::SetTooltip("Reset DSP sample ring buffer");
553
554 ImGui::SameLine();
555 if (ImGui::Button(ICON_MD_SKIP_NEXT " NewFrame")) {
557 }
558 if (ImGui::IsItemHovered())
559 ImGui::SetTooltip("Force DSP NewFrame() call");
560
561 ImGui::SameLine();
562 if (ImGui::Button(ICON_MD_REPLAY " Reinit Audio")) {
564 }
565 if (ImGui::IsItemHovered())
566 ImGui::SetTooltip("Full audio system reinitialization");
567
568 ImGui::Unindent();
569 }
570
572 int* current_song_index_ = nullptr;
575
576 std::function<void(int)> on_open_song_;
577 std::function<void(int)> on_open_piano_roll_;
578
579 // Debug state
580 bool debug_paused_ = false;
584 std::array<music::ChannelState, 8> cached_channels_;
585 int32_t avg_queue_delta_ = 0;
586 uint64_t avg_cycle_rate_ = 0;
587
588 // Wall-clock timing for rate measurement
589 std::chrono::steady_clock::time_point last_stats_time_;
592};
593
594} // namespace editor
595} // namespace yaze
596
597#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).
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
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
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.