summaryrefslogtreecommitdiff
path: root/src/factories/naudio/v1/SampleFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/factories/naudio/v1/SampleFactory.cpp')
-rw-r--r--src/factories/naudio/v1/SampleFactory.cpp117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/factories/naudio/v1/SampleFactory.cpp b/src/factories/naudio/v1/SampleFactory.cpp
index d72f79d..544c12b 100644
--- a/src/factories/naudio/v1/SampleFactory.cpp
+++ b/src/factories/naudio/v1/SampleFactory.cpp
@@ -221,3 +221,120 @@ std::optional<std::shared_ptr<IParsedData>> NSampleFactory::parse(std::vector<ui
return sample;
}
+
+#ifdef BUILD_UI
+#include <cmath>
+#include <unordered_map>
+#include "imgui.h"
+#include "SequencePlayerV1.h"
+#include "ui/BaseBackend.h"
+#include "ui/ExportUtils.h"
+#include "ui/Widgets.h"
+
+namespace {
+
+struct DecodedNSample {
+ std::string name;
+ std::vector<int16_t> pcm;
+ int rate = 0;
+};
+
+DecodedNSample sNDecoded; // last decoded sample (they can be large)
+std::string sNPlayingName;
+std::unordered_map<std::string, float> sNSampleSpeeds;
+
+bool DecodeNSample(const ParseResultData& item) {
+ if (sNDecoded.name == item.name) {
+ return !sNDecoded.pcm.empty();
+ }
+ sNDecoded = {};
+ sNDecoded.name = item.name;
+ if (!DecodeV1SampleToPcm(item, sNDecoded.pcm, sNDecoded.rate)) {
+ sNDecoded.pcm.clear();
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+float NSampleFactoryUI::GetItemHeight(const ParseResultData&) {
+ return ImGui::GetTextLineHeightWithSpacing() * 3.0f + ImGui::GetFrameHeightWithSpacing() * 2.0f +
+ ImGui::GetStyle().ItemSpacing.y * 4.0f;
+}
+
+void NSampleFactoryUI::DrawUI(const ParseResultData& item) {
+ UI::AssetHeader(item.name, item.type);
+ if (!item.data.has_value()) {
+ ImGui::TextDisabled("no data");
+ return;
+ }
+ const auto sample = std::static_pointer_cast<NSampleData>(item.data.value());
+ ImGui::TextDisabled("sample \xe2\x80\x94 %u bytes codec %u, bank %u, %u Hz, tuning %.3f", (uint32_t)sample->size,
+ (uint32_t)sample->codec, sample->sampleBankId, sample->sampleRate, sample->tuning);
+
+ auto speedIt = sNSampleSpeeds.emplace(item.name, 1.0f).first;
+ const bool playingThis = sNPlayingName == item.name && UI::GetBackend()->AudioProgress() >= 0.0f;
+ if (ImGui::Button(playingThis ? "Stop##nsample" : "Play##nsample")) {
+ if (playingThis) {
+ UI::GetBackend()->StopAudio();
+ sNPlayingName.clear();
+ } else if (DecodeNSample(item)) {
+ if (UI::GetBackend()->PlaySamples(sNDecoded.pcm.data(), sNDecoded.pcm.size(), sNDecoded.rate, 1)) {
+ sNPlayingName = item.name;
+ UI::GetBackend()->SetAudioSpeed(speedIt->second);
+ }
+ }
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("WAV##nsampleexp")) {
+ if (DecodeNSample(item)) {
+ const auto path = UI::ExportFilePath(item.name, "wav");
+ UI::NoteExport(item.name,
+ UI::WriteWavFile(path, sNDecoded.pcm.data(), sNDecoded.pcm.size(), 1, sNDecoded.rate)
+ ? path.string()
+ : "export failed");
+ } else {
+ UI::NoteExport(item.name, "decode failed");
+ }
+ }
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetTooltip("Export decoded sample to torch-exports/");
+ }
+ UI::DrawExportMarker(item.name);
+ ImGui::SameLine();
+ float volume = UI::GetBackend()->GetAudioVolume();
+ ImGui::SetNextItemWidth(140.0f);
+ if (ImGui::SliderFloat("##nvol", &volume, 0.0f, 1.0f, "vol %.2f")) {
+ UI::GetBackend()->SetAudioVolume(volume);
+ }
+ ImGui::SameLine();
+ float& speed = speedIt->second;
+ ImGui::SetNextItemWidth(140.0f);
+ if (ImGui::SliderFloat("##nspeed", &speed, 0.25f, 4.0f, "%.2fx", ImGuiSliderFlags_Logarithmic)) {
+ static const float kSnaps[] = { 0.5f, 1.0f, 2.0f };
+ for (const float snap : kSnaps) {
+ if (std::fabs(speed - snap) < 0.05f) {
+ speed = snap;
+ break;
+ }
+ }
+ if (playingThis) {
+ UI::GetBackend()->SetAudioSpeed(speed);
+ }
+ }
+ ImGui::SameLine();
+ if (sNDecoded.name == item.name && !sNDecoded.pcm.empty()) {
+ const float seconds = (float)sNDecoded.pcm.size() / (float)sNDecoded.rate;
+ ImGui::TextDisabled("%d Hz, mono, %.2fs", sNDecoded.rate, seconds);
+ } else {
+ ImGui::TextDisabled("press play to decode");
+ }
+
+ float progress = playingThis ? std::max(UI::GetBackend()->AudioProgress(), 0.0f) : 0.0f;
+ ImGui::SetNextItemWidth(std::min(ImGui::GetContentRegionAvail().x, 420.0f));
+ if (ImGui::SliderFloat("##nseek", &progress, 0.0f, 1.0f, "") && playingThis) {
+ UI::GetBackend()->SeekAudio(progress);
+ }
+}
+#endif