3#include "absl/strings/str_format.h"
9#include "imgui/imgui.h"
19 return absl::OkStatus();
25 ImGui::TableSetupColumn(
"Assembly");
26 ImGui::TableSetupColumn(
"Composition");
27 ImGui::TableHeadersRow();
28 ImGui::TableNextRow();
30 ImGui::TableNextColumn();
33 ImGui::TableNextColumn();
36 ImGui::Text(
"Music channels coming soon...");
41 return absl::OkStatus();
44static const int NUM_KEYS = 25;
45static bool keys[NUM_KEYS];
47static void DrawPianoStaff() {
48 if (ImGuiID child_id = ImGui::GetID((
void*)(intptr_t)9);
49 ImGui::BeginChild(child_id, ImVec2(0, 170),
false)) {
50 const int NUM_LINES = 5;
51 const int LINE_THICKNESS = 2;
52 const int LINE_SPACING = 40;
55 ImDrawList* draw_list = ImGui::GetWindowDrawList();
59 ImVec2(ImGui::GetCursorScreenPos().x, ImGui::GetCursorScreenPos().y);
60 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + ImGui::GetContentRegionAvail().x,
61 canvas_p0.y + ImGui::GetContentRegionAvail().y);
62 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(32, 32, 32, 255));
63 for (
int i = 0; i < NUM_LINES; i++) {
64 auto line_start = ImVec2(canvas_p0.x, canvas_p0.y + i * LINE_SPACING);
65 auto line_end = ImVec2(canvas_p1.x + ImGui::GetContentRegionAvail().x,
66 canvas_p0.y + i * LINE_SPACING);
67 draw_list->AddLine(line_start, line_end, IM_COL32(200, 200, 200, 255),
72 const int NUM_LEDGER_LINES = 3;
73 for (
int i = -NUM_LEDGER_LINES; i <= NUM_LINES + NUM_LEDGER_LINES; i++) {
74 if (i % 2 == 0)
continue;
75 auto line_start = ImVec2(canvas_p0.x, canvas_p0.y + i * LINE_SPACING / 2);
76 auto line_end = ImVec2(canvas_p1.x + ImGui::GetContentRegionAvail().x,
77 canvas_p0.y + i * LINE_SPACING / 2);
78 draw_list->AddLine(line_start, line_end, IM_COL32(150, 150, 150, 255),
85static void DrawPianoRoll() {
87 float key_width = ImGui::GetContentRegionAvail().x / NUM_KEYS;
88 float white_key_height = ImGui::GetContentRegionAvail().y * 0.8f;
89 float black_key_height = ImGui::GetContentRegionAvail().y * 0.5f;
90 ImGui::Text(
"Piano Roll");
92 ImDrawList* draw_list = ImGui::GetWindowDrawList();
96 ImVec2(ImGui::GetCursorScreenPos().x, ImGui::GetCursorScreenPos().y);
97 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + ImGui::GetContentRegionAvail().x,
98 canvas_p0.y + ImGui::GetContentRegionAvail().y);
99 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(200, 200, 200, 255));
101 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4.f, 0.f));
102 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.f);
103 for (
int i = 0; i < NUM_KEYS; i++) {
105 ImVec2 key_pos = ImVec2(i * key_width, 0.0f);
109 if (i % 12 == 1 || i % 12 == 3 || i % 12 == 6 || i % 12 == 8 ||
112 key_size = ImVec2(key_width * 0.6f, black_key_height);
113 key_color = ImVec4(0, 0, 0, 255);
114 text_color = ImVec4(255, 255, 255, 255);
117 key_size = ImVec2(key_width, white_key_height);
118 key_color = ImVec4(255, 255, 255, 255);
119 text_color = ImVec4(0, 0, 0, 255);
123 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 0.f));
124 ImGui::PushStyleColor(ImGuiCol_Button, key_color);
125 ImGui::PushStyleColor(ImGuiCol_Text, text_color);
126 if (ImGui::Button(kSongNotes[i].data(), key_size)) {
129 ImGui::PopStyleColor();
130 ImGui::PopStyleColor();
131 ImGui::PopStyleVar();
133 ImVec2 button_pos = ImGui::GetItemRectMin();
134 ImVec2 button_size = ImGui::GetItemRectSize();
137 dest.x = button_pos.x + button_size.x;
138 dest.y = button_pos.y + button_size.y;
139 ImGui::GetWindowDrawList()->AddRectFilled(button_pos, dest,
140 IM_COL32(200, 200, 255, 200));
145 ImGui::PopStyleVar();
146 ImGui::PopStyleVar();
150 static bool is_playing =
false;
151 static int selected_option = 0;
152 static int current_volume = 0;
153 static bool has_loaded_song =
false;
154 const int MAX_VOLUME = 100;
156 if (is_playing && !has_loaded_song) {
157 has_loaded_song =
true;
160 gui::ItemLabel(
"Select a song to edit: ", gui::ItemLabelFlags::Left);
161 ImGui::Combo(
"#songs_in_game", &selected_option, kGameSongs, 30);
165 ImGui::TableSetupColumn(
"#play");
166 ImGui::TableSetupColumn(
"#rewind");
167 ImGui::TableSetupColumn(
"#fastforward");
168 ImGui::TableSetupColumn(
"#volume");
169 ImGui::TableSetupColumn(
"#debug");
171 ImGui::TableSetupColumn(
"#slider");
173 ImGui::TableNextColumn();
176 has_loaded_song =
false;
178 is_playing = !is_playing;
181 ImGui::TableNextColumn();
186 ImGui::TableNextColumn();
191 ImGui::TableNextColumn();
199 ImGui::TableNextColumn();
200 ImGui::SliderInt(
"Volume", ¤t_volume, 0, 100);
204 const int SONG_DURATION = 120;
205 static int current_time = 0;
209 ImGui::Text(
"%d:%02d", current_time / 60, current_time % 60);
212 ImGui::ProgressBar((
float)current_time / SONG_DURATION);
221 LOG_WARN(
"MusicEditor",
"No emulator instance - cannot play song");
226 LOG_WARN(
"MusicEditor",
"Emulator not running - cannot play song");
233 emulator_->
snes().Write(0x7E012C,
static_cast<uint8_t
>(song_id));
234 LOG_INFO(
"MusicEditor",
"Requested song %d (%s)", song_id,
235 song_id < 30 ? kGameSongs[song_id] :
"Unknown");
239 auto status = audio->GetStatus();
240 if (!status.is_playing) {
242 LOG_INFO(
"MusicEditor",
"Started audio backend playback");
247 }
catch (
const std::exception& e) {
248 LOG_ERROR(
"MusicEditor",
"Failed to play song: %s", e.what());
258 LOG_INFO(
"MusicEditor",
"Stopped music playback");
266 }
catch (
const std::exception& e) {
267 LOG_ERROR(
"MusicEditor",
"Failed to stop song: %s", e.what());
275 volume = std::clamp(volume, 0.0f, 1.0f);
278 audio->SetVolume(volume);
279 LOG_DEBUG(
"MusicEditor",
"Set volume to %.2f", volume);
281 LOG_WARN(
"MusicEditor",
"No audio backend available");
zelda3::music::Tracker music_tracker_
emu::Emulator * emulator_
void SetVolume(float volume)
void Initialize() override
absl::Status Load() override
absl::Status Update() override
ImGuiTableFlags music_editor_flags_
void PlaySong(int song_id)
ImGuiTableFlags toolset_table_flags_
AssemblyEditor assembly_editor_
audio::IAudioBackend * audio_backend()
RAII timer for automatic timing management.
void LoadSongs(Rom &rom)
High-level function to load all song data from the ROM. (Currently commented out, but this would be t...
#define ICON_MD_VOLUME_UP
#define ICON_MD_FAST_FORWARD
#define ICON_MD_PLAY_ARROW
#define ICON_MD_FAST_REWIND
#define ICON_MD_ACCESS_TIME
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
#define LOG_INFO(category, format,...)
void ItemLabel(absl::string_view title, ItemLabelFlags flags)
Main namespace for the application.