7#include "absl/strings/str_format.h"
10#include "imgui/imgui.h"
19static void HelpMarker(
const char* desc) {
20 ImGui::TextDisabled(
"(?)");
21 if (ImGui::IsItemHovered()) {
22 ImGui::BeginTooltip();
23 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
24 ImGui::TextUnformatted(desc);
25 ImGui::PopTextWrapPos();
32 float total_w = ImGui::GetContentRegionAvail().x;
33 float list_w = std::max(150.0f, total_w * 0.2f);
34 float props_w = std::max(220.0f, total_w * 0.25f);
36 ImGui::BeginChild(
"SampleList", ImVec2(list_w, 0),
true);
42 ImGui::BeginChild(
"SampleProps", ImVec2(props_w, 0),
true);
47 ImGui::TextDisabled(tr(
"Select a sample"));
53 ImGui::BeginChild(
"SampleWaveform", ImVec2(0, 0),
true);
62 if (ImGui::Button(tr(
"Import WAV/BRR"))) {
77 std::string label = absl::StrFormat(
"%02X: %s", i, sample->name.c_str());
78 if (ImGui::Selectable(label.c_str(),
88 ImGui::Text(tr(
"Sample Properties"));
93 strncpy(name_buf, sample.
name.c_str(),
sizeof(name_buf));
94 if (ImGui::InputText(tr(
"Name"), name_buf,
sizeof(name_buf))) {
95 sample.
name = name_buf;
102 ImGui::Text(tr(
"BRR Size: %zu bytes"), sample.
brr_data.size());
103 int blocks =
static_cast<int>(sample.
brr_data.size() / 9);
104 ImGui::Text(tr(
"Blocks: %d"), blocks);
105 ImGui::Text(tr(
"Duration: %.3f s"), (blocks * 16) / 32040.0f);
109 ImGui::Text(tr(
"Loop Settings"));
112 "SNES samples can loop. The loop point is defined in BRR blocks (groups "
116 bool loops = sample.
loops;
117 if (ImGui::Checkbox(tr(
"Loop Enabled"), &loops)) {
118 sample.
loops = loops;
125 int max_block = std::max(0, blocks - 1);
128 if (ImGui::SliderInt(tr(
"Loop Start (Block)"), &loop_block, 0, max_block)) {
132 ImGui::TextDisabled(tr(
"Offset: $%04X bytes"), sample.
loop_point);
133 ImGui::TextDisabled(tr(
"Sample: %d"), loop_block * 16);
135 ImGui::BeginDisabled();
136 ImGui::SliderInt(tr(
"Loop Start (Block)"), &loop_block, 0, max_block);
137 ImGui::EndDisabled();
147 if (ImGui::IsItemHovered()) {
149 tr(
"Play this sample at default pitch (requires ROM loaded)"));
152 ImGui::BeginDisabled();
154 ImGui::EndDisabled();
155 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
156 ImGui::SetTooltip(tr(
"Preview not available - load a ROM first"));
170 ImGui::TextDisabled(tr(
"Empty sample (No PCM data)"));
171 ImGui::TextWrapped(tr(
"Import a WAV file or BRR sample to view waveform."));
185 step =
static_cast<int>(sample.
pcm_data.size()) / 4000;
189 for (
size_t i = 0; i < sample.
pcm_data.size(); i += step) {
190 plot_x_.push_back(
static_cast<float>(i));
194 if (ImPlot::BeginPlot(
"Waveform", ImVec2(-1, -1))) {
195 ImPlot::SetupAxes(
"Sample",
"Amplitude");
196 ImPlot::SetupAxesLimits(0, sample.
pcm_data.size(), -1.1, 1.1);
199 static_cast<int>(
plot_x_.size()));
203 double loop_sample = (sample.
loop_point / 9.0) * 16.0;
204 ImPlot::TagX(loop_sample, ImVec4(0, 1, 0, 1),
"Loop Start");
205 ImPlot::SetNextLineStyle(ImVec4(0, 1, 0, 0.5));
206 double loop_x[] = {loop_sample, loop_sample};
207 double loop_y[] = {-1.0, 1.0};
208 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