From 80827ea3955cc1912053442d16a0b975aea01291 Mon Sep 17 00:00:00 2001 From: George Olson Date: Tue, 22 Oct 2024 14:43:16 -0700 Subject: [PATCH] Feature: Add DeepFilterCommandBuilder to MediaProcessor (#42) Initial implementation of DeepFilterCommandBuilder --------- Co-authored-by: George Olson Co-authored-by: omeryusufyagci --- MediaProcessor/CMakeLists.txt | 1 - MediaProcessor/cmake/src.cmake | 1 + MediaProcessor/src/AudioProcessor.cpp | 1 + MediaProcessor/src/ConfigManager.cpp | 4 +- .../src/DeepFilterCommandBuilder.cpp | 58 +++++++++++++++ MediaProcessor/src/DeepFilterCommandBuilder.h | 72 +++++++++++++++++++ MediaProcessor/src/Utils.cpp | 4 -- MediaProcessor/src/Utils.h | 17 +++-- 8 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 MediaProcessor/src/DeepFilterCommandBuilder.cpp create mode 100644 MediaProcessor/src/DeepFilterCommandBuilder.h diff --git a/MediaProcessor/CMakeLists.txt b/MediaProcessor/CMakeLists.txt index 656c935..436760a 100644 --- a/MediaProcessor/CMakeLists.txt +++ b/MediaProcessor/CMakeLists.txt @@ -18,7 +18,6 @@ option(BUILD_TESTING "Test Build" OFF) # Set include directories include(CTest) include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_SOURCE_DIR}/third_party/nlohmann) # Threads is required set(THREADS_PREFER_PTHREAD_FLAG ON) diff --git a/MediaProcessor/cmake/src.cmake b/MediaProcessor/cmake/src.cmake index 45978a5..0e77903 100644 --- a/MediaProcessor/cmake/src.cmake +++ b/MediaProcessor/cmake/src.cmake @@ -9,6 +9,7 @@ add_executable(MediaProcessor ${CMAKE_SOURCE_DIR}/src/CommandBuilder.cpp ${CMAKE_SOURCE_DIR}/src/HardwareUtils.cpp ${CMAKE_SOURCE_DIR}/src/FFmpegSettingsManager.cpp + ${CMAKE_SOURCE_DIR}/src/DeepFilterCommandBuilder.cpp ) target_link_libraries(MediaProcessor PRIVATE Threads::Threads) diff --git a/MediaProcessor/src/AudioProcessor.cpp b/MediaProcessor/src/AudioProcessor.cpp index 9fd87c4..374202a 100644 --- a/MediaProcessor/src/AudioProcessor.cpp +++ b/MediaProcessor/src/AudioProcessor.cpp @@ -148,6 +148,7 @@ bool AudioProcessor::invokeDeepFilter(fs::path chunkPath) { const fs::path deepFilterPath = configManager.getDeepFilterPath(); const fs::path deepFilterTarballPath = configManager.getDeepFilterTarballPath(); + // TODO: implement with DeepFilterCommandBuilder once base class is updated (#51) // `--compensate-delay` ensures the audio remains in sync after filtering CommandBuilder cmd; cmd.addArgument(deepFilterPath.string()); diff --git a/MediaProcessor/src/ConfigManager.cpp b/MediaProcessor/src/ConfigManager.cpp index e292457..e9c325d 100644 --- a/MediaProcessor/src/ConfigManager.cpp +++ b/MediaProcessor/src/ConfigManager.cpp @@ -63,7 +63,7 @@ unsigned int ConfigManager::getNumThreadsValue() { unsigned int ConfigManager::determineNumThreads(unsigned int configNumThreads, unsigned int hardwareNumThreads) { - return Utils::isWithinRange(configNumThreads, 1, hardwareNumThreads) ? configNumThreads - : hardwareNumThreads; + return Utils::isWithinRange(configNumThreads, 1u, hardwareNumThreads) ? configNumThreads + : hardwareNumThreads; } } // namespace MediaProcessor diff --git a/MediaProcessor/src/DeepFilterCommandBuilder.cpp b/MediaProcessor/src/DeepFilterCommandBuilder.cpp new file mode 100644 index 0000000..369e2d7 --- /dev/null +++ b/MediaProcessor/src/DeepFilterCommandBuilder.cpp @@ -0,0 +1,58 @@ +#include "DeepFilterCommandBuilder.h" + +#include +#include + +#include "Utils.h" + +namespace MediaProcessor { + +DeepFilterCommandBuilder& DeepFilterCommandBuilder::setInputFile( + const std::string& inputAudioPath) { + /** + * FIXME: Find a solution to ensure flexibility in calling `setInputFile()`. + * See the header for more details on the problem. + */ + + m_inputAudioPath = inputAudioPath; + addArgument(inputAudioPath); + + return *this; +} + +DeepFilterCommandBuilder& DeepFilterCommandBuilder::setOutputFile( + const std::string& outputAudioPath) { + m_outputAudioPath = outputAudioPath; + addFlag("--output-dir", outputAudioPath); + + return *this; +} + +DeepFilterCommandBuilder& DeepFilterCommandBuilder::setNoiseReductionLevel(double level) { + if (!Utils::isWithinRange(level, 0.0, 1.0)) { + throw std::invalid_argument("Noise reduction level must be between 0.0 and 1.0"); + } + m_noiseReductionLevel = level; + addFlag("--noise-reduction", std::to_string(level)); + + return *this; +} + +DeepFilterCommandBuilder& DeepFilterCommandBuilder::enableDelayCompensation() { + addFlag("--compensate-delay"); + + return *this; +} + +std::string DeepFilterCommandBuilder::build() const { + if (m_inputAudioPath.empty()) { + throw std::runtime_error("Input audio path must be specified."); + } + if (m_outputAudioPath.empty()) { + throw std::runtime_error("Output audio path must be specified."); + } + + return CommandBuilder::build(); +} + +} // namespace MediaProcessor \ No newline at end of file diff --git a/MediaProcessor/src/DeepFilterCommandBuilder.h b/MediaProcessor/src/DeepFilterCommandBuilder.h new file mode 100644 index 0000000..eca544c --- /dev/null +++ b/MediaProcessor/src/DeepFilterCommandBuilder.h @@ -0,0 +1,72 @@ +#ifndef DEEPFILTERCOMMANDBUILDER_H +#define DEEPFILTERCOMMANDBUILDER_H + +#include "CommandBuilder.h" + +namespace MediaProcessor { + +/** + * @brief A builder class for constructing DeepFilter commands. + */ +class DeepFilterCommandBuilder : public CommandBuilder { + public: + /** + * @brief Sets the input audio file for the DeepFilter command. + * + * @note + * To ensure the correct behavior, please call `setInputFile()` as the first + * method when configuring this builder. This guarantees that the input file + * is added in the proper order before other optional parameters. + * + * DeepFilter not providing an input file flag poses challenges to implement + * this without breaking the builder pattern or sacrificing const-correctness. + * We'll try to find a good solution for this ASAP. + * + * @return A reference to the updated object for method chaining. + */ + DeepFilterCommandBuilder& setInputFile(const std::string& inputAudioPath); + + /** + * @brief Sets the output audio file for the DeepFilter command. + * + * @return A reference to the updated object for method chaining. + */ + DeepFilterCommandBuilder& setOutputFile(const std::string& outputAudioPath); + + /** + * @brief Sets the noise reduction level for the DeepFilter command. + * + * @param level The noise reduction level: from 0.0 (no reduction) to 1.0 (max reduction). + * @return A reference to the updated DeepFilterCommandBuilder instance. + * + * @throws std::invalid_argument if the level is not within the range [0.0, 1.0]. + */ + DeepFilterCommandBuilder& setNoiseReductionLevel(double level); + + /** + * @brief Enabled filtering delay compensation for the DeepFilter command. + * + * @return A reference to the updated DeepFilterCommandBuilder instance. + */ + DeepFilterCommandBuilder& enableDelayCompensation(); + + /** + * @brief Builds the final DeepFilter command string. + * + * Constructs the command string using the provided parameters and options. + * + * @return The constructed command string. + * + * @throws std::runtime_error if required parameters (input or output file) are missing. + */ + std::string build() const override; + + private: + std::string m_inputAudioPath; + std::string m_outputAudioPath; + double m_noiseReductionLevel = 0.5; +}; + +} // namespace MediaProcessor + +#endif \ No newline at end of file diff --git a/MediaProcessor/src/Utils.cpp b/MediaProcessor/src/Utils.cpp index e9ada9d..10ca652 100644 --- a/MediaProcessor/src/Utils.cpp +++ b/MediaProcessor/src/Utils.cpp @@ -69,10 +69,6 @@ bool containsWhitespace(const std::string &str) { return str.find(' ') != std::string::npos; } -bool isWithinRange(unsigned int value, unsigned int lowerBound, unsigned int upperBound) { - return value >= lowerBound && value <= upperBound; -} - std::string trimTrailingSpace(const std::string &str) { if (str.empty() || str.back() != ' ') { return str; diff --git a/MediaProcessor/src/Utils.h b/MediaProcessor/src/Utils.h index 21303ab..a2fee59 100644 --- a/MediaProcessor/src/Utils.h +++ b/MediaProcessor/src/Utils.h @@ -37,13 +37,6 @@ bool removeFileIfExists(const fs::path &filePath); */ bool containsWhitespace(const std::string &str); -/** - * @brief Checks if a value is within a specified range (inclusive). - * - * @return true if the value is within the range, false otherwise. - */ -bool isWithinRange(unsigned int value, unsigned int lowerBound, unsigned int upperBound); - /** * @brief Prepares the output paths for audio and video processing. * @@ -65,6 +58,16 @@ std::string trimTrailingSpace(const std::string &str); */ double getMediaDuration(const fs::path &mediaPath); +/** + * @brief Checks if a value is within a specified range (inclusive). + * + * @return true if the value is within the range, false otherwise. + */ +template +bool isWithinRange(T value, T lowerBound, T upperBound) { + return value >= lowerBound && value <= upperBound; +} + } // namespace MediaProcessor::Utils #endif // UTILS_H