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")) {
75 std::string label = absl::StrFormat(
"%02X: %s", i, sample->name.c_str());
85 ImGui::Text(
"Sample Properties");
90 strncpy(name_buf, sample.
name.c_str(),
sizeof(name_buf));
91 if (ImGui::InputText(
"Name", name_buf,
sizeof(name_buf))) {
92 sample.
name = name_buf;
99 ImGui::Text(
"BRR Size: %zu bytes", sample.
brr_data.size());
100 int blocks =
static_cast<int>(sample.
brr_data.size() / 9);
101 ImGui::Text(
"Blocks: %d", blocks);
102 ImGui::Text(
"Duration: %.3f s", (blocks * 16) / 32040.0f);
106 ImGui::Text(
"Loop Settings");
108 HelpMarker(
"SNES samples can loop. The loop point is defined in BRR blocks (groups of 16 samples).");
111 bool loops = sample.
loops;
112 if (ImGui::Checkbox(
"Loop Enabled", &loops)) {
113 sample.
loops = loops;
120 int max_block = std::max(0, blocks - 1);
123 if (ImGui::SliderInt(
"Loop Start (Block)", &loop_block, 0, max_block)) {
127 ImGui::TextDisabled(
"Offset: $%04X bytes", sample.
loop_point);
128 ImGui::TextDisabled(
"Sample: %d", loop_block * 16);
130 ImGui::BeginDisabled();
131 ImGui::SliderInt(
"Loop Start (Block)", &loop_block, 0, max_block);
132 ImGui::EndDisabled();
142 if (ImGui::IsItemHovered()) {
143 ImGui::SetTooltip(
"Play this sample at default pitch (requires ROM loaded)");
146 ImGui::BeginDisabled();
148 ImGui::EndDisabled();
149 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
150 ImGui::SetTooltip(
"Preview not available - load a ROM first");
164 ImGui::TextDisabled(
"Empty sample (No PCM data)");
165 ImGui::TextWrapped(
"Import a WAV file or BRR sample to view waveform.");
178 if (sample.
pcm_data.size() > 4000) step =
static_cast<int>(sample.
pcm_data.size()) / 4000;
179 if (step < 1) step = 1;
181 for (
size_t i = 0; i < sample.
pcm_data.size(); i += step) {
182 plot_x_.push_back(
static_cast<float>(i));
186 if (ImPlot::BeginPlot(
"Waveform", ImVec2(-1, -1))) {
187 ImPlot::SetupAxes(
"Sample",
"Amplitude");
188 ImPlot::SetupAxesLimits(0, sample.
pcm_data.size(), -1.1, 1.1);
194 double loop_sample = (sample.
loop_point / 9.0) * 16.0;
195 ImPlot::TagX(loop_sample, ImVec4(0, 1, 0, 1),
"Loop Start");
196 ImPlot::SetNextLineStyle(ImVec4(0, 1, 0, 0.5));
197 double loop_x[] = {loop_sample, loop_sample};
198 double loop_y[] = {-1.0, 1.0};
199 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