6#include "absl/strings/str_format.h"
9#include "imgui/imgui.h"
18static void HelpMarker(
const char* desc) {
19 ImGui::TextDisabled(
"(?)");
20 if (ImGui::IsItemHovered()) {
21 ImGui::BeginTooltip();
22 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
23 ImGui::TextUnformatted(desc);
24 ImGui::PopTextWrapPos();
31 float total_w = ImGui::GetContentRegionAvail().x;
32 float list_w = std::max(150.0f, total_w * 0.2f);
33 float props_w = std::max(220.0f, total_w * 0.25f);
35 ImGui::BeginChild(
"SampleList", ImVec2(list_w, 0),
true);
41 ImGui::BeginChild(
"SampleProps", ImVec2(props_w, 0),
true);
46 ImGui::TextDisabled(
"Select a sample");
52 ImGui::BeginChild(
"SampleWaveform", ImVec2(0, 0),
true);
61 if (ImGui::Button(
"Import WAV/BRR")) {
76 std::string label = absl::StrFormat(
"%02X: %s", i, sample->name.c_str());
77 if (ImGui::Selectable(label.c_str(),
87 ImGui::Text(
"Sample Properties");
92 strncpy(name_buf, sample.
name.c_str(),
sizeof(name_buf));
93 if (ImGui::InputText(
"Name", name_buf,
sizeof(name_buf))) {
94 sample.
name = name_buf;
101 ImGui::Text(
"BRR Size: %zu bytes", sample.
brr_data.size());
102 int blocks =
static_cast<int>(sample.
brr_data.size() / 9);
103 ImGui::Text(
"Blocks: %d", blocks);
104 ImGui::Text(
"Duration: %.3f s", (blocks * 16) / 32040.0f);
108 ImGui::Text(
"Loop Settings");
111 "SNES samples can loop. The loop point is defined in BRR blocks (groups "
115 bool loops = sample.
loops;
116 if (ImGui::Checkbox(
"Loop Enabled", &loops)) {
117 sample.
loops = loops;
124 int max_block = std::max(0, blocks - 1);
127 if (ImGui::SliderInt(
"Loop Start (Block)", &loop_block, 0, max_block)) {
131 ImGui::TextDisabled(
"Offset: $%04X bytes", sample.
loop_point);
132 ImGui::TextDisabled(
"Sample: %d", loop_block * 16);
134 ImGui::BeginDisabled();
135 ImGui::SliderInt(
"Loop Start (Block)", &loop_block, 0, max_block);
136 ImGui::EndDisabled();
146 if (ImGui::IsItemHovered()) {
148 "Play this sample at default pitch (requires ROM loaded)");
151 ImGui::BeginDisabled();
153 ImGui::EndDisabled();
154 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
155 ImGui::SetTooltip(
"Preview not available - load a ROM first");
169 ImGui::TextDisabled(
"Empty sample (No PCM data)");
170 ImGui::TextWrapped(
"Import a WAV file or BRR sample to view waveform.");
184 step =
static_cast<int>(sample.
pcm_data.size()) / 4000;
188 for (
size_t i = 0; i < sample.
pcm_data.size(); i += step) {
189 plot_x_.push_back(
static_cast<float>(i));
193 if (ImPlot::BeginPlot(
"Waveform", ImVec2(-1, -1))) {
194 ImPlot::SetupAxes(
"Sample",
"Amplitude");
195 ImPlot::SetupAxesLimits(0, sample.
pcm_data.size(), -1.1, 1.1);
198 static_cast<int>(
plot_x_.size()));
202 double loop_sample = (sample.
loop_point / 9.0) * 16.0;
203 ImPlot::TagX(loop_sample, ImVec4(0, 1, 0, 1),
"Loop Start");
204 ImPlot::SetNextLineStyle(ImVec4(0, 1, 0, 0.5));
205 double loop_x[] = {loop_sample, loop_sample};
206 double loop_y[] = {-1.0, 1.0};
207 ImPlot::PlotLine(
"Loop", loop_x, loop_y, 2);
int selected_sample_index_
void DrawProperties(MusicSample &sample)
void DrawWaveform(const MusicSample &sample)
void DrawSampleList(MusicBank &bank)
std::vector< float > plot_y_
std::function< void(int)> on_preview_
void Draw(MusicBank &bank)
Draw the sample editor.
std::function< void()> on_edit_
std::vector< float > plot_x_
Manages the collection of songs, instruments, and samples from a ROM.
size_t GetSampleCount() const
Get the number of samples.
MusicSample * GetSample(int index)
Get a sample by index.
absl::StatusOr< int > ImportSampleFromWav(const std::string &filepath, const std::string &name)
Import a WAV file as a new sample.
#define ICON_MD_PLAY_ARROW
void EnsureImPlotContext()
Contains classes and functions for handling music data in Zelda 3.
A BRR-encoded audio sample.
std::vector< uint8_t > brr_data
std::vector< int16_t > pcm_data