diff --git a/.idea/LipSync.iml b/.idea/LipSync.iml index e9eb483..540160f 100644 --- a/.idea/LipSync.iml +++ b/.idea/LipSync.iml @@ -145,6 +145,8 @@ + + diff --git a/CMakeLists.txt b/CMakeLists.txt index d0ac8f5..dbc9835 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.3) project(LipSync) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") @@ -14,7 +14,7 @@ set(Boost_USE_STATIC_RUNTIME ON) # Use static C++ runtime find_package(Boost REQUIRED COMPONENTS filesystem locale system) include_directories(${Boost_INCLUDE_DIRS}) -set(SOURCE_FILES src/main.cpp src/audio_input/WaveFileReader.cpp src/audio_input/WaveFileReader.h src/audio_input/ChannelDownmixer.cpp src/audio_input/ChannelDownmixer.h src/audio_input/AudioStream.h src/audio_input/SampleRateConverter.cpp src/audio_input/SampleRateConverter.h src/audio_input/wave_file_writing.cpp src/audio_input/wave_file_writing.h src/audio_input/io_tools.h src/platform_tools.h src/phone_extraction.cpp src/phone_extraction.h src/Phone.cpp src/Phone.h src/centiseconds.cpp src/centiseconds.h) +set(SOURCE_FILES src/main.cpp src/audio_input/WaveFileReader.cpp src/audio_input/WaveFileReader.h src/audio_input/ChannelDownmixer.cpp src/audio_input/ChannelDownmixer.h src/audio_input/AudioStream.h src/audio_input/SampleRateConverter.cpp src/audio_input/SampleRateConverter.h src/audio_input/wave_file_writing.cpp src/audio_input/wave_file_writing.h src/audio_input/io_tools.h src/platform_tools.h src/phone_extraction.cpp src/phone_extraction.h src/Phone.cpp src/Phone.h src/centiseconds.cpp src/centiseconds.h src/tools.cpp src/tools.h) if(WIN32) set(SOURCE_FILES "${SOURCE_FILES};src/platform_tools_win.cpp") else() diff --git a/src/audio_input/WaveFileReader.cpp b/src/audio_input/WaveFileReader.cpp index bcb6322..616d281 100644 --- a/src/audio_input/WaveFileReader.cpp +++ b/src/audio_input/WaveFileReader.cpp @@ -24,10 +24,10 @@ enum class Codec { Float = 0x03 }; -WaveFileReader::WaveFileReader(std::string fileName) { +WaveFileReader::WaveFileReader(boost::filesystem::path filePath) { // Open file file.exceptions(std::ifstream::failbit | std::ifstream::badbit); - file.open(fileName, std::ios::binary); + file.open(filePath, std::ios::binary); // Read header uint32_t rootChunkId = read(file); diff --git a/src/audio_input/WaveFileReader.h b/src/audio_input/WaveFileReader.h index 520f6f1..1eaeadf 100644 --- a/src/audio_input/WaveFileReader.h +++ b/src/audio_input/WaveFileReader.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "AudioStream.h" enum class SampleFormat { @@ -15,14 +17,14 @@ enum class SampleFormat { class WaveFileReader : public AudioStream { public: - WaveFileReader(std::string fileName); + WaveFileReader(boost::filesystem::path filePath); virtual int getFrameRate() override ; virtual int getFrameCount() override; virtual int getChannelCount() override; virtual bool getNextSample(float &sample) override; private: - std::ifstream file; + boost::filesystem::ifstream file; SampleFormat sampleFormat; int frameRate; int frameCount; diff --git a/src/main.cpp b/src/main.cpp index b4511eb..33a1db1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,11 @@ #include #include "audio_input/WaveFileReader.h" #include "phone_extraction.h" +#include "platform_tools.h" using std::exception; using std::string; +using std::wstring; using std::unique_ptr; string getMessage(const exception& e) { @@ -17,9 +19,9 @@ string getMessage(const exception& e) { return result; } -unique_ptr createAudioStream(string fileName) { +unique_ptr createAudioStream(boost::filesystem::path filePath) { try { - return unique_ptr(new WaveFileReader(fileName)); + return unique_ptr(new WaveFileReader(filePath)); } catch (...) { std::throw_with_nested(std::runtime_error("Could not open sound file.") ); } @@ -27,8 +29,17 @@ unique_ptr createAudioStream(string fileName) { int main(int argc, char *argv[]) { try { - unique_ptr audioStream = createAudioStream(R"(C:\Users\Daniel\Desktop\audio-test\test 16000Hz 1ch 16bit.wav)"); + // Get sound file name + std::vector commandLineArgs = getCommandLineArgs(argc, argv); + if (commandLineArgs.size() != 2) { + throw std::runtime_error("Invalid command line arguments. Call with sound file name as sole argument."); + } + wstring soundFileName = commandLineArgs[1]; + // Create audio streams + unique_ptr audioStream = createAudioStream(soundFileName); + + // Detect phones std::map phones = detectPhones(std::move(audioStream)); for (auto &pair : phones) { diff --git a/src/phone_extraction.cpp b/src/phone_extraction.cpp index 7a95925..32459e3 100644 --- a/src/phone_extraction.cpp +++ b/src/phone_extraction.cpp @@ -5,6 +5,8 @@ #include "audio_input/SampleRateConverter.h" #include "audio_input/ChannelDownmixer.h" #include "platform_tools.h" +#include "tools.h" + using std::runtime_error; using std::unique_ptr; using std::shared_ptr; @@ -12,9 +14,6 @@ using std::string; using std::map; using boost::filesystem::path; -template -using lambda_unique_ptr = std::unique_ptr>; - unique_ptr to16kHzMono(unique_ptr stream) { // Downmix, if required if (stream->getChannelCount() != 1) { diff --git a/src/platform_tools.h b/src/platform_tools.h index 55d27ea..30e925f 100644 --- a/src/platform_tools.h +++ b/src/platform_tools.h @@ -3,6 +3,8 @@ #include +std::vector getCommandLineArgs(int argc, char *argv[]); + boost::filesystem::path getBinDirectory(); #endif //LIPSYNC_PLATFORM_TOOLS_H diff --git a/src/platform_tools_win.cpp b/src/platform_tools_win.cpp index d500b2a..07cd813 100644 --- a/src/platform_tools_win.cpp +++ b/src/platform_tools_win.cpp @@ -1,9 +1,31 @@ +#include +#include "tools.h" #include "platform_tools.h" -#include +std::vector getCommandLineArgs(int argc, char **argv) { + UNUSED(argv); + + // Get command line as single Unicode string + LPWSTR commandLine = GetCommandLineW(); + + // Split into individual args + int argumentCount; + LPWSTR* arguments = CommandLineToArgvW(commandLine, &argumentCount); + if (!arguments) throw std::runtime_error("Could not determine command line arguments."); + auto _ = finally([&arguments](){ LocalFree(arguments); }); + assert(argumentCount == argc); + + // Convert to vector + std::vector result; + for (int i = 0; i < argumentCount; i++) { + result.push_back(arguments[i]); + } + + return result; +} boost::filesystem::path getBinDirectory() { - std::vector executablePath(MAX_PATH); + std::vector executablePath(MAX_PATH); // Try to get the executable path with a buffer of MAX_PATH characters. DWORD result = GetModuleFileNameW(0, executablePath.data(), executablePath.size()); diff --git a/src/tools.cpp b/src/tools.cpp new file mode 100644 index 0000000..2fa7e97 --- /dev/null +++ b/src/tools.cpp @@ -0,0 +1 @@ +#include "tools.h" diff --git a/src/tools.h b/src/tools.h new file mode 100644 index 0000000..87e77f9 --- /dev/null +++ b/src/tools.h @@ -0,0 +1,39 @@ +#ifndef LIPSYNC_TOOLS_H +#define LIPSYNC_TOOLS_H + +#include +#include + +#define UNUSED(x) ((void)(x)) + +template +using lambda_unique_ptr = std::unique_ptr>; + +// The following definitions are taken from https://github.com/Microsoft/GSL. + +// final_act allows you to ensure something gets run at the end of a scope +template +class final_act +{ +public: + explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {} + + final_act(final_act&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_) { other.invoke_ = false; } + final_act(const final_act&) = delete; + final_act& operator=(const final_act&) = delete; + + ~final_act() noexcept { if (invoke_) f_(); } + +private: + F f_; + bool invoke_; +}; + +// finally() - convenience function to generate a final_act +template +final_act finally(const F &f) noexcept { return final_act(f); } + +template +final_act finally(F &&f) noexcept { return final_act(std::forward(f)); } + +#endif //LIPSYNC_TOOLS_H