From d2da606eadcc7c02b6b74e60aa12e885fa051bfb Mon Sep 17 00:00:00 2001 From: Tobias Hienzsch Date: Mon, 13 Jun 2022 20:14:02 +0200 Subject: [PATCH] Convert to wav before bpm detection --- CMakeLists.txt | 1 + src/DSP/AudioFileConverter.hpp | 60 ++++++++++++++++++++++++++++++++++ src/DSP/BeatTrack.cpp | 10 +++++- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/DSP/AudioFileConverter.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c473b59..36b1879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ target_sources(StiggiDJ "src/Core/Array.hpp" + "src/DSP/AudioFileConverter.hpp" "src/DSP/BeatTrack.cpp" "src/DSP/BeatTrack.hpp" "src/DSP/DJPlayer.cpp" diff --git a/src/DSP/AudioFileConverter.hpp b/src/DSP/AudioFileConverter.hpp new file mode 100644 index 0000000..6e0428d --- /dev/null +++ b/src/DSP/AudioFileConverter.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +namespace ta +{ + +struct AudioFileConverterOptions +{ + juce::File source{}; + juce::File destination{}; +}; + +struct AudioFileConverterResult +{ + bool success{false}; + juce::String errorMessage{}; +}; + +struct AudioFileConverter +{ + using Options = AudioFileConverterOptions; + using Result = AudioFileConverterResult; + + AudioFileConverter(); + + template + auto convert(Options const& options) -> Result; + +private: + juce::AudioFormatManager _formatManager; +}; + +inline AudioFileConverter::AudioFileConverter() { _formatManager.registerBasicFormats(); } + +template +inline auto AudioFileConverter::convert(Options const& options) -> Result +{ + auto reader = std::unique_ptr(_formatManager.createReaderFor(options.source)); + if (reader == nullptr) { return Result{false, "Invalid file"}; } + + DestinationFormat format{}; + auto const sr = reader->sampleRate; + auto const ch = reader->numChannels; + auto const bits = reader->bitsPerSample; + + auto out = std::make_unique(options.destination); + auto writer = std::unique_ptr(format.createWriterFor(out.get(), sr, ch, bits, {}, 0)); + + if (writer == nullptr) { return Result{false, "Failed to convert to wav"}; } + out.release(); // writer took ownership + + writer->writeFromAudioReader(*reader, 0, reader->lengthInSamples); + writer->flush(); + + return Result{true, {}}; +} + +} // namespace ta diff --git a/src/DSP/BeatTrack.cpp b/src/DSP/BeatTrack.cpp index ace1628..5895675 100644 --- a/src/DSP/BeatTrack.cpp +++ b/src/DSP/BeatTrack.cpp @@ -1,15 +1,23 @@ #include "BeatTrack.hpp" +#include "DSP/AudioFileConverter.hpp" + namespace ta { auto beatTrack(juce::File const& audioFile) -> BeatTrackResult { + juce::TemporaryFile tmpFile{}; + AudioFileConverter converter{}; + auto const convertOptions = AudioFileConverterOptions{audioFile, tmpFile.getFile()}; + auto const convertResult = converter.convert(convertOptions); + if (!convertResult.success) { return BeatTrackResult{convertResult.errorMessage}; } + auto const* pythonPath = "/home/tobante/Developer/tobanteAudio/StiggiDJ/venv/bin/python3"; auto const scriptDir = juce::File{"/home/tobante/Developer/tobanteAudio/StiggiDJ/src/Scripts"}; auto const scriptPath = scriptDir.getChildFile("bpm_track.py"); juce::ChildProcess process{}; - auto processArgs = juce::StringArray{pythonPath, scriptPath.getFullPathName(), audioFile.getFullPathName()}; + auto processArgs = juce::StringArray{pythonPath, scriptPath.getFullPathName(), tmpFile.getFile().getFullPathName()}; if (!process.start(processArgs)) { return BeatTrackResult{"Failed to start"}; } if (!process.waitForProcessToFinish(10'000)) { return BeatTrackResult{"Timeout"}; }