Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add DeepFilterCommandBuilder to MediaProcessor #42

Merged
1 change: 0 additions & 1 deletion MediaProcessor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions MediaProcessor/cmake/src.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions MediaProcessor/src/AudioProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions MediaProcessor/src/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
58 changes: 58 additions & 0 deletions MediaProcessor/src/DeepFilterCommandBuilder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "DeepFilterCommandBuilder.h"

#include <sstream>
#include <stdexcept>

#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
72 changes: 72 additions & 0 deletions MediaProcessor/src/DeepFilterCommandBuilder.h
Original file line number Diff line number Diff line change
@@ -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
4 changes: 0 additions & 4 deletions MediaProcessor/src/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 10 additions & 7 deletions MediaProcessor/src/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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 <typename T>
bool isWithinRange(T value, T lowerBound, T upperBound) {
return value >= lowerBound && value <= upperBound;
}

} // namespace MediaProcessor::Utils

#endif // UTILS_H
Loading