From 5aba10efb7c5d6043bbe11ecbdaeca4ce0a50c9b Mon Sep 17 00:00:00 2001 From: Sam Perry Date: Mon, 4 Jul 2016 16:45:04 +0100 Subject: [PATCH 1/9] In the process of creating unit tests/cmake files. --- CMakeLists.txt | 72 +++++++++++++++++++++++++----- external/CMakeLists.txt | 0 tests/CMakeLists.txt | 0 tests/Concatenator_Basic_Tests.cpp | 2 + 4 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 external/CMakeLists.txt create mode 100644 tests/CMakeLists.txt create mode 100644 tests/Concatenator_Basic_Tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d00662..95de6d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,28 +3,78 @@ set(CMAKE_CXX_STANDARD 11) # Set the project name project (concatenator) -set(Boost_USE_STATIC_LIBS OFF) -set(Boost_USE_MULTITHREADED ON) -set(Boost_USE_STATIC_RUNTIME OFF) -find_package(Boost 1.60.0 COMPONENTS program_options log log_setup thread date_time filesystem system) +############################################################################### +### Boost Settings +find_package(Boost 1.60.0 COMPONENTS program_options log log_setup thread date_time filesystem system REQUIRED) if (NOT FO_BOOST_STATIC_LINK) add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) endif() +set(Boost_USE_STATIC_LIBS OFF) +set(Boost_USE_MULTITHREADED ON) +set(Boost_USE_STATIC_RUNTIME OFF) +############################################################################### + # Set build flags set(CMAKE_CXX_FLAGS "-g -Wall ") # Set cmake to output executable to the bin directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +# Find all included header files. include_directories(include) - -# Find all the source fies in the src directory -file(GLOB SOURCES "src/*.cpp") +include_directories(${Boost_INCLUDE_DIRS}) +add_subdirectory(external) # Build the executable from the source files found -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - add_executable(concatenator ${SOURCES}) - target_link_libraries(concatenator ${Boost_LIBRARIES}) + + +set(CONCATENATOR_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src) +set(CONCATENATOR_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) +set(CONCATENATOR_TEST_DIR ${PROJECT_SOURCE_DIR}/tests) + +set(CONCATENATOR_SOURCE_FILES + ${CONCATENATOR_SOURCE_DIR}/Concatenator.cpp +) +set(CONCATENATOR_HEADER_FILES + ${CONCATENATOR_INCLUDE_DIR}/config.hpp +) +set(CONCATENATOR_TEST_SOURCES + ${CONCATENATOR_TEST_DIR}/Concatenator_Basic_Tests.cpp +) + +add_executable(concatenator ${CONCATENATOR_SOURCE_DIR}/concatenator.cpp) + +target_link_libraries(concatenator ${Boost_LIBRARIES}) +# Test build options (this code adapted from: https://github.com/ComicSansMS/GhulbusBase/blob/master/CMakeLists.txt) +option(BUILD_TESTS "Determines whether to build tests." ON) +if(BUILD_TESTS) + enable_testing() + + if(NOT TARGET Catch) + include(ExternalProject) + if(WIN32) + set(FETCH_EXTERNAL_CATCH + URL https://github.com/philsquared/Catch/archive/v1.2.1-develop.12.zip + URL_HASH MD5=cda228922a1c9248364c99a3ff9cd9fa) + else() + set(FETCH_EXTERNAL_CATCH + URL https://github.com/philsquared/Catch/archive/v1.2.1-develop.12.tar.gz + URL_HASH MD5=a8dfb7be899a6e7fb30bd55d53426122) + endif() + ExternalProject_Add(Catch-External + PREFIX ${CMAKE_BINARY_DIR}/external/Catch + ${FETCH_EXTERNAL_CATCH} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/external/Catch/src/Catch-External/single_include/catch.hpp + ${CMAKE_BINARY_DIR}/external/Catch/include/catch.hpp + ) + add_library(Catch INTERFACE) + add_dependencies(Catch Catch-External) + target_include_directories(Catch INTERFACE ${CMAKE_BINARY_DIR}/external/Catch/include) + endif() + + add_executable(Concatenator_Base_Test ${CONCATENATOR_TEST_SOURCES}) + add_test(NAME TestBase COMMAND Concatenator_Base_Test) endif() diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/Concatenator_Basic_Tests.cpp b/tests/Concatenator_Basic_Tests.cpp new file mode 100644 index 0000000..e6d1d56 --- /dev/null +++ b/tests/Concatenator_Basic_Tests.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" From f76fbd50da45c74f2266294d318d03153b478e23 Mon Sep 17 00:00:00 2001 From: Sam Perry Date: Mon, 4 Jul 2016 18:26:57 +0100 Subject: [PATCH 2/9] CMake is now working - Empty test suite is created and built alongside the main concatenator executable --- CMakeLists.txt | 26 ++++++++++++++++++-------- src/ArgumentParser.cpp | 2 ++ src/concatenator.cpp | 2 +- tests/Concatenator_Basic_Tests.cpp | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95de6d2..4248d85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,12 +21,7 @@ set(CMAKE_CXX_FLAGS "-g -Wall ") # Set cmake to output executable to the bin directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -# Find all included header files. -include_directories(include) -include_directories(${Boost_INCLUDE_DIRS}) -add_subdirectory(external) -# Build the executable from the source files found set(CONCATENATOR_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src) @@ -35,15 +30,26 @@ set(CONCATENATOR_TEST_DIR ${PROJECT_SOURCE_DIR}/tests) set(CONCATENATOR_SOURCE_FILES ${CONCATENATOR_SOURCE_DIR}/Concatenator.cpp + ${CONCATENATOR_SOURCE_DIR}/AudioDatabase.cpp + ${CONCATENATOR_SOURCE_DIR}/AudioFile.cpp + ${CONCATENATOR_SOURCE_DIR}/Logger.cpp + ${CONCATENATOR_SOURCE_DIR}/ArgumentParser.cpp ) set(CONCATENATOR_HEADER_FILES - ${CONCATENATOR_INCLUDE_DIR}/config.hpp + ${CONCATENATOR_INCLUDE_DIR}/ArgumentParser.h + ${CONCATENATOR_INCLUDE_DIR}/AudioDatabase.h + ${CONCATENATOR_INCLUDE_DIR}/AudioFile.h + ${CONCATENATOR_INCLUDE_DIR}/Logger.h ) set(CONCATENATOR_TEST_SOURCES ${CONCATENATOR_TEST_DIR}/Concatenator_Basic_Tests.cpp ) -add_executable(concatenator ${CONCATENATOR_SOURCE_DIR}/concatenator.cpp) +include_directories(${CONCATENATOR_INCLUDE_DIR}) +include_directories(${Boost_INCLUDE_DIRS}) +add_subdirectory(external) + +add_executable(concatenator ${CONCATENATOR_SOURCE_FILES} ${CONCATENATOR_HEADER_FILES}) target_link_libraries(concatenator ${Boost_LIBRARIES}) # Test build options (this code adapted from: https://github.com/ComicSansMS/GhulbusBase/blob/master/CMakeLists.txt) @@ -72,9 +78,13 @@ if(BUILD_TESTS) ) add_library(Catch INTERFACE) add_dependencies(Catch Catch-External) + target_include_directories(Catch INTERFACE ${CMAKE_BINARY_DIR}/external/Catch/include) endif() - add_executable(Concatenator_Base_Test ${CONCATENATOR_TEST_SOURCES}) + + add_executable(Concatenator_Basic_Tests ${CONCATENATOR_TEST_SOURCES}) + target_link_libraries(Concatenator_Basic_Tests Catch) add_test(NAME TestBase COMMAND Concatenator_Base_Test) endif() + diff --git a/src/ArgumentParser.cpp b/src/ArgumentParser.cpp index 70110f3..da2d17a 100644 --- a/src/ArgumentParser.cpp +++ b/src/ArgumentParser.cpp @@ -16,6 +16,7 @@ ArgumentParser::ArgumentParser() : desc("Allowed options") { ; } +/* int ArgumentParser::parseargs(int argc, char** argv) { po::store(po::command_line_parser(argc, argv).options(desc).positional(positionalOptions).run(), vm); po::notify(vm); @@ -27,3 +28,4 @@ int ArgumentParser::parseargs(int argc, char** argv) { } return 0; } +*/ diff --git a/src/concatenator.cpp b/src/concatenator.cpp index d307d82..5cc29b3 100644 --- a/src/concatenator.cpp +++ b/src/concatenator.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) { Logger log = Logger(); ArgumentParser argparse = ArgumentParser(); - argparse.parseargs(argc, argv); + //argparse.parseargs(argc, argv); log.error("My pretty little error!"); return 0; } diff --git a/tests/Concatenator_Basic_Tests.cpp b/tests/Concatenator_Basic_Tests.cpp index e6d1d56..3c3c6f2 100644 --- a/tests/Concatenator_Basic_Tests.cpp +++ b/tests/Concatenator_Basic_Tests.cpp @@ -1,2 +1,2 @@ #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "catch.hpp" +#include From d886cb8772a4e22eaee6676263081f3c24f0e8d2 Mon Sep 17 00:00:00 2001 From: Sam Perry Date: Mon, 4 Jul 2016 19:28:21 +0100 Subject: [PATCH 3/9] renamed test files/folder. Added basic tests file for creating initial tests --- .clang | 2 +- CMakeLists.txt | 11 ++++++----- test/Basic_Tests.cpp | 1 + .../Concatenator_Test.cpp | 2 ++ tests/CMakeLists.txt | 0 5 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 test/Basic_Tests.cpp rename tests/Concatenator_Basic_Tests.cpp => test/Concatenator_Test.cpp (98%) delete mode 100644 tests/CMakeLists.txt diff --git a/.clang b/.clang index 8b5eec8..579743b 100644 --- a/.clang +++ b/.clang @@ -1 +1 @@ --I ./include -std=c++11 +-I ./include -I ./external/Catch/include/ -std=c++11 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4248d85..5c7fd80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CONCATENATOR_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src) set(CONCATENATOR_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) -set(CONCATENATOR_TEST_DIR ${PROJECT_SOURCE_DIR}/tests) +set(CONCATENATOR_TEST_DIR ${PROJECT_SOURCE_DIR}/test) set(CONCATENATOR_SOURCE_FILES ${CONCATENATOR_SOURCE_DIR}/Concatenator.cpp @@ -42,7 +42,8 @@ set(CONCATENATOR_HEADER_FILES ${CONCATENATOR_INCLUDE_DIR}/Logger.h ) set(CONCATENATOR_TEST_SOURCES - ${CONCATENATOR_TEST_DIR}/Concatenator_Basic_Tests.cpp + ${CONCATENATOR_TEST_DIR}/Concatenator_Test.cpp + ${CONCATENATOR_TEST_DIR}/Basic_Tests.cpp ) include_directories(${CONCATENATOR_INCLUDE_DIR}) @@ -83,8 +84,8 @@ if(BUILD_TESTS) endif() - add_executable(Concatenator_Basic_Tests ${CONCATENATOR_TEST_SOURCES}) - target_link_libraries(Concatenator_Basic_Tests Catch) - add_test(NAME TestBase COMMAND Concatenator_Base_Test) + add_executable(Concatenator_Test ${CONCATENATOR_TEST_SOURCES}) + target_link_libraries(Concatenator_Test Catch) + add_test(NAME TestBase COMMAND Concatenator_Test) endif() diff --git a/test/Basic_Tests.cpp b/test/Basic_Tests.cpp new file mode 100644 index 0000000..fc502ef --- /dev/null +++ b/test/Basic_Tests.cpp @@ -0,0 +1 @@ +#include "catch.hpp" diff --git a/tests/Concatenator_Basic_Tests.cpp b/test/Concatenator_Test.cpp similarity index 98% rename from tests/Concatenator_Basic_Tests.cpp rename to test/Concatenator_Test.cpp index 3c3c6f2..2926188 100644 --- a/tests/Concatenator_Basic_Tests.cpp +++ b/test/Concatenator_Test.cpp @@ -1,2 +1,4 @@ #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file #include + + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index e69de29..0000000 From 7f56ede91676a0cf88a3af5349de5a2f59e63af1 Mon Sep 17 00:00:00 2001 From: Sam Perry Date: Mon, 4 Jul 2016 22:47:37 +0100 Subject: [PATCH 4/9] Added check for libsndfile library to cmake --- CMakeLists.txt | 4 ++++ cmake/Modules/FindLibSndFile.cmake | 34 ++++++++++++++++++++++++++++++ include/AudioFile.h | 21 ++++++++++++++++++ src/AudioFile.cpp | 30 +++++++++++++++++--------- 4 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 cmake/Modules/FindLibSndFile.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c7fd80..81c61c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,12 @@ set(CMAKE_CXX_STANDARD 11) # Set the project name project (concatenator) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") + ############################################################################### ### Boost Settings find_package(Boost 1.60.0 COMPONENTS program_options log log_setup thread date_time filesystem system REQUIRED) +find_package(LibSndFile REQUIRED) if (NOT FO_BOOST_STATIC_LINK) add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) @@ -48,6 +51,7 @@ set(CONCATENATOR_TEST_SOURCES include_directories(${CONCATENATOR_INCLUDE_DIR}) include_directories(${Boost_INCLUDE_DIRS}) +include_directories(${LIBSNDFILE_INCLUDE_DIR}) add_subdirectory(external) add_executable(concatenator ${CONCATENATOR_SOURCE_FILES} ${CONCATENATOR_HEADER_FILES}) diff --git a/cmake/Modules/FindLibSndFile.cmake b/cmake/Modules/FindLibSndFile.cmake new file mode 100644 index 0000000..0d4e5dc --- /dev/null +++ b/cmake/Modules/FindLibSndFile.cmake @@ -0,0 +1,34 @@ +# - Try to find libsndfile +# Once done, this will define +# +# LIBSNDFILE_FOUND - system has libsndfile +# LIBSNDFILE_INCLUDE_DIRS - the libsndfile include directories +# LIBSNDFILE_LIBRARIES - link these to use libsndfile + +# Use pkg-config to get hints about paths +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_check_modules(LIBSNDFILE_PKGCONF sndfile) +endif(PKG_CONFIG_FOUND) + +# Include dir +find_path(LIBSNDFILE_INCLUDE_DIR + NAMES sndfile.h + PATHS ${LIBSNDFILE_PKGCONF_INCLUDE_DIRS} +) + +# Library +find_library(LIBSNDFILE_LIBRARY + NAMES sndfile libsndfile-1 + PATHS ${LIBSNDFILE_PKGCONF_LIBRARY_DIRS} +) + +find_package(PackageHandleStandardArgs) +find_package_handle_standard_args(LibSndFile DEFAULT_MSG LIBSNDFILE_LIBRARY LIBSNDFILE_INCLUDE_DIR) + +if(LIBSNDFILE_FOUND) + set(LIBSNDFILE_LIBRARIES ${LIBSNDFILE_LIBRARY}) + set(LIBSNDFILE_INCLUDE_DIRS ${LIBSNDFILE_INCLUDE_DIR}) +endif(LIBSNDFILE_FOUND) + +mark_as_advanced(LIBSNDFILE_LIBRARY LIBSNDFILE_LIBRARIES LIBSNDFILE_INCLUDE_DIR LIBSNDFILE_INCLUDE_DIRS) diff --git a/include/AudioFile.h b/include/AudioFile.h index e69de29..1397e02 100644 --- a/include/AudioFile.h +++ b/include/AudioFile.h @@ -0,0 +1,21 @@ +#include +#include + +class AudioFile { + public: + AudioFile(const char * fname, bool open=true); + AudioFile(const char * fname, int format, int channels, int samplerate); + ~AudioFile(); + void swap_mode(std::string m); + bool is_open() { return open; }; + private: + std::string mode; + std::string name; + bool open; + SndfileHandle file; +}; + +class AnalysedAudioFile : public AudioFile { + public: + private: +}; diff --git a/src/AudioFile.cpp b/src/AudioFile.cpp index 20348cb..209db12 100644 --- a/src/AudioFile.cpp +++ b/src/AudioFile.cpp @@ -1,12 +1,22 @@ -#include +#include "AudioFile.h" +#include +using namespace std; -class AudioFile { - public: - private: - SndfileHandle file; -}; +AudioFile::AudioFile(const char * fname, bool open) +{ + if(open) { + file = SndfileHandle(fname); + } + name = fname; +} + +AudioFile::AudioFile(const char * fname, const int format, const int channels, const int samplerate) +{ + +} + +void AudioFile::swap_mode(string m) +{ + +} -class AnalysedAudioFile : public AudioFile { - public: - private: -}; From 6cb48863cf50042afc8f4854d0d0780baa68aa75 Mon Sep 17 00:00:00 2001 From: Pezz89 Date: Mon, 11 Jul 2016 20:59:54 +0100 Subject: [PATCH 5/9] Begun creation of audio database class. Rethought AudioFile class design (removed mode switching approach) --- CMakeLists.txt | 5 ++++- include/AudioDatabase.h | 45 +++++++++++++++++++++++++++++++++++++++++ include/AudioFile.h | 16 +++++++-------- src/AudioDatabase.cpp | 1 + src/AudioFile.cpp | 29 +++++++++++++------------- src/concatenator.cpp | 7 +++++-- 6 files changed, 77 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81c61c3..1dd458e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(Boost_USE_STATIC_RUNTIME OFF) ############################################################################### # Set build flags -set(CMAKE_CXX_FLAGS "-g -Wall ") +set(CMAKE_CXX_FLAGS "-g -Wall") # Set cmake to output executable to the bin directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) @@ -56,7 +56,10 @@ add_subdirectory(external) add_executable(concatenator ${CONCATENATOR_SOURCE_FILES} ${CONCATENATOR_HEADER_FILES}) +# Link to external libraries target_link_libraries(concatenator ${Boost_LIBRARIES}) +target_link_libraries(concatenator ${LIBSNDFILE_LIBRARIES}) + # Test build options (this code adapted from: https://github.com/ComicSansMS/GhulbusBase/blob/master/CMakeLists.txt) option(BUILD_TESTS "Determines whether to build tests." ON) if(BUILD_TESTS) diff --git a/include/AudioDatabase.h b/include/AudioDatabase.h index e69de29..10082fb 100644 --- a/include/AudioDatabase.h +++ b/include/AudioDatabase.h @@ -0,0 +1,45 @@ +#include +#include +#include + +using std::string; +using std::cout; +using std::endl; + +class AudioDatabase { + public: + template + AudioDatabase(std::string audio_dir, std::string database_dir, Iter it, Iter end); + private: + std::string database_dir = ""; + std::string audio_dir = ""; +}; + +template +bool in_array(const string &value, const container &array) +{ + cout <<"Test: " << value << endl; + return std::find(array.begin(), array.end(), value) != array.end(); +} + +template +bool check_analyses_valid(Iter iterator, Iter end) +{ + static std::list valid_analyses = {"f0", "RMS"}; + + while(iterator != end) + { + if(!in_array(*iterator, valid_analyses)) { + cout << "Nope!" << endl; + return false; + } + ++iterator; + } + return true; +} + +template +AudioDatabase::AudioDatabase(string audio_dir, string database_dir, Iter it, Iter end) { + cout << "HELLO?!?" << endl; + check_analyses_valid(it, end); +} diff --git a/include/AudioFile.h b/include/AudioFile.h index 1397e02..a2548c1 100644 --- a/include/AudioFile.h +++ b/include/AudioFile.h @@ -3,19 +3,17 @@ class AudioFile { public: - AudioFile(const char * fname, bool open=true); - AudioFile(const char * fname, int format, int channels, int samplerate); - ~AudioFile(); - void swap_mode(std::string m); - bool is_open() { return open; }; - private: - std::string mode; - std::string name; - bool open; + AudioFile(const char * &name, const int &mode=SFM_RDWR, const int &format=0, const int &channels=0, const int &samplerate=0); + int open(const int &mode=SFM_READ, const int &format=0, const int &channels=0, const int &samplerate=0); + protected: SndfileHandle file; + SF_INFO* file_info; + private: + std::string name; }; class AnalysedAudioFile : public AudioFile { public: private: }; + diff --git a/src/AudioDatabase.cpp b/src/AudioDatabase.cpp index e69de29..8b13789 100644 --- a/src/AudioDatabase.cpp +++ b/src/AudioDatabase.cpp @@ -0,0 +1 @@ + diff --git a/src/AudioFile.cpp b/src/AudioFile.cpp index 209db12..e2af864 100644 --- a/src/AudioFile.cpp +++ b/src/AudioFile.cpp @@ -1,22 +1,23 @@ #include "AudioFile.h" #include +#include +#include using namespace std; -AudioFile::AudioFile(const char * fname, bool open) +AudioFile::AudioFile(const char * &name, const int &mode, const int &format, const int &channels, const int &samplerate) { - if(open) { - file = SndfileHandle(fname); + this->name = name; + open(mode, format, channels, samplerate); +} + +int AudioFile::open(const int &mode, const int &format, const int &channels, const int &samplerate) +{ + switch(mode){ + case SFM_READ: file = SndfileHandle(name); + case SFM_WRITE: file = SndfileHandle(name, SFM_WRITE, format, channels, samplerate); + case SFM_RDWR: file = SndfileHandle(name, SFM_RDWR, format, channels, samplerate); } - name = fname; -} - -AudioFile::AudioFile(const char * fname, const int format, const int channels, const int samplerate) -{ - -} - -void AudioFile::swap_mode(string m) -{ - + + return 0; } diff --git a/src/concatenator.cpp b/src/concatenator.cpp index 5cc29b3..09b6e45 100644 --- a/src/concatenator.cpp +++ b/src/concatenator.cpp @@ -1,15 +1,18 @@ #include -#include "Logger.h" +#include "logger.h" #include "ArgumentParser.h" #include "AudioDatabase.h" +#include using namespace std; int main(int argc, char** argv) { Logger log = Logger(); - ArgumentParser argparse = ArgumentParser(); //argparse.parseargs(argc, argv); log.error("My pretty little error!"); + + vector analyses = {"BLARGH"}; + AudioDatabase db = AudioDatabase("./", "./", analyses.begin(), analyses.end()); return 0; } From 1fd2a35c4b0d329a99df94e56cdd2c71a7987f40 Mon Sep 17 00:00:00 2001 From: Pezz89 Date: Mon, 11 Jul 2016 22:07:49 +0100 Subject: [PATCH 6/9] Added logging to AudioDatabase. Also implemented analysis string checking. Added logger pointer member to AudioDatabase class Fixed logger flush on error issue. Implemented analysis string checking in AudioDatabase constructor. Added std exception handeling and logging in main. --- include/AudioDatabase.h | 59 ++++++++++++++++++++++++++++++----------- include/logger.h | 3 +++ src/ArgumentParser.cpp | 2 -- src/AudioDatabase.cpp | 29 ++++++++++++++++++++ src/concatenator.cpp | 47 +++++++++++++++++++++++++------- src/logger.cpp | 4 +++ 6 files changed, 117 insertions(+), 27 deletions(-) diff --git a/include/AudioDatabase.h b/include/AudioDatabase.h index 10082fb..dbf5869 100644 --- a/include/AudioDatabase.h +++ b/include/AudioDatabase.h @@ -1,45 +1,74 @@ #include #include #include +#include +#include +#include "logger.h" using std::string; using std::cout; using std::endl; +using std::list; + +/*! + * A class that encapsulates a collection of AudioFile objects in order to + * perform analysis and synthesis operations on batches of audio files. +*/ class AudioDatabase { public: - template - AudioDatabase(std::string audio_dir, std::string database_dir, Iter it, Iter end); + AudioDatabase(const std::string audio_dir, const std::string database_dir, list& analyses, Logger* log); private: std::string database_dir = ""; std::string audio_dir = ""; + // Define a set that stores the locations of audiofiles in the database. + std::set audio_file_set; + Logger* log; + }; + +/*! A function that determines whether a string value is found in the container. +*/ template -bool in_array(const string &value, const container &array) +bool in_array(string &value, const container &array) { - cout <<"Test: " << value << endl; + boost::algorithm::to_upper(value); return std::find(array.begin(), array.end(), value) != array.end(); } +/*! Check that analysis strings provided are supported by the database object + + \param iterator - An iterator pointing to where to begin checking strings are valid. + \param end - An iterator pointing to the point at which to stop analysing strings. +*/ template -bool check_analyses_valid(Iter iterator, Iter end) +Iter check_analyses_valid(Iter iterator, Iter end) { - static std::list valid_analyses = {"f0", "RMS"}; + static std::list valid_analyses = { + "RMS", + "ZEROX", + "FFT", + "SPCCNTR", + "SPCSPRD", + "SPCFLUX", + "SPCCF", + "SPCFLATNESS", + "F0", + "PEAK", + "CENTROID", + "VARIANCE", + "KURTOSIS", + "SKEWNESS", + "HARM_RATIO" + }; while(iterator != end) { if(!in_array(*iterator, valid_analyses)) { - cout << "Nope!" << endl; - return false; + return iterator; } ++iterator; } - return true; -} - -template -AudioDatabase::AudioDatabase(string audio_dir, string database_dir, Iter it, Iter end) { - cout << "HELLO?!?" << endl; - check_analyses_valid(it, end); + return iterator; } diff --git a/include/logger.h b/include/logger.h index 91774f8..ebf6717 100644 --- a/include/logger.h +++ b/include/logger.h @@ -1,3 +1,5 @@ +#ifndef LOGGER_H +#define LOGGER_H #include #include #include @@ -31,3 +33,4 @@ class Logger { //Define a logger boost::log::sources::severity_logger< boost::log::trivial::severity_level > lg; }; +#endif diff --git a/src/ArgumentParser.cpp b/src/ArgumentParser.cpp index da2d17a..70110f3 100644 --- a/src/ArgumentParser.cpp +++ b/src/ArgumentParser.cpp @@ -16,7 +16,6 @@ ArgumentParser::ArgumentParser() : desc("Allowed options") { ; } -/* int ArgumentParser::parseargs(int argc, char** argv) { po::store(po::command_line_parser(argc, argv).options(desc).positional(positionalOptions).run(), vm); po::notify(vm); @@ -28,4 +27,3 @@ int ArgumentParser::parseargs(int argc, char** argv) { } return 0; } -*/ diff --git a/src/AudioDatabase.cpp b/src/AudioDatabase.cpp index 8b13789..0dcc380 100644 --- a/src/AudioDatabase.cpp +++ b/src/AudioDatabase.cpp @@ -1 +1,30 @@ +#include +#include +#include "AudioDatabase.h" +#include +#include +using namespace std; + +AudioDatabase::AudioDatabase( + const string audio_dir, + const string database_dir, + list& analyses, + Logger* log + ) +{ + this->log = log; + + // Remove duplicate strings from list of analyses. + analyses.unique(); + + // Check that all analysis strings supplied refer to valid analyses. + list::const_iterator valid = check_analyses_valid(analyses.begin(), analyses.end()); + if(valid != analyses.end()) { + string err = "The analysis string supplied to the AudioDatabase constructor is not valid: " + *valid; + throw std::runtime_error(err); + } + + this->database_dir = database_dir; + this->audio_dir = audio_dir; +} diff --git a/src/concatenator.cpp b/src/concatenator.cpp index 09b6e45..3acca8c 100644 --- a/src/concatenator.cpp +++ b/src/concatenator.cpp @@ -2,17 +2,44 @@ #include "logger.h" #include "ArgumentParser.h" #include "AudioDatabase.h" -#include +#include +#include using namespace std; -int main(int argc, char** argv) { - Logger log = Logger(); - ArgumentParser argparse = ArgumentParser(); - //argparse.parseargs(argc, argv); - log.error("My pretty little error!"); - - vector analyses = {"BLARGH"}; - AudioDatabase db = AudioDatabase("./", "./", analyses.begin(), analyses.end()); - return 0; +namespace +{ + const size_t ERROR_IN_COMMAND_LINE = 1; + const size_t SUCCESS = 0; + const size_t ERROR_UNHANDLED_EXCEPTION = 2; + +} + +int main(int argc, char** argv) { + // Initialize a logger object to be used for message handeling throughout + // the program + Logger log = Logger(); + try + { + // Initialize object to parse arguments supplied by user from command + // line + ArgumentParser argparse = ArgumentParser(); + // Parse arguments and exit program if specified (through use of --help + // or -h flag) + if(argparse.parseargs(argc, argv)) { + return ERROR_IN_COMMAND_LINE; + } + + list analyses = {"BLARGH"}; + AudioDatabase db = AudioDatabase("./", "./", analyses, &log); + } + catch(std::exception& e) + { + string error("Unhandled Exception reached the top of main:\n"); + error.append(e.what()); + + log.error(error); + return ERROR_UNHANDLED_EXCEPTION; + } + return SUCCESS; } diff --git a/src/logger.cpp b/src/logger.cpp index 9abf143..742eff0 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -87,8 +87,12 @@ void Logger::warning(std::string str) { void Logger::error(std::string str) { BOOST_LOG_SEV(lg, logging::trivial::error) << str; + Logger::console_sink->flush(); + Logger::file_sink->flush(); } void Logger::fatal(std::string str) { BOOST_LOG_SEV(lg, logging::trivial::fatal) << str; + Logger::console_sink->flush(); + Logger::file_sink->flush(); } From a6b663128924baf253d1457278b4443ebc6ba369 Mon Sep 17 00:00:00 2001 From: Pezz89 Date: Mon, 18 Jul 2016 14:54:59 +0100 Subject: [PATCH 7/9] Improved command line interface. Added [] overloaded operator for accessing ArgumentParser option values. Implemented analysis program option and added checks for lack of arguments. Added arguments for specifying seperate audio and database directories. Implemented automatic setting of database directory as the same as the audio directory if no value is provided on the command line. --- include/ArgumentParser.h | 21 +++++++++++++++++++-- include/AudioDatabase.h | 3 ++- include/logger.h | 2 +- src/ArgumentParser.cpp | 34 +++++++++++++++++++++++++++++----- src/AudioDatabase.cpp | 19 ++++++++++++------- src/concatenator.cpp | 28 ++++++++++++++++++++++++---- src/logger.cpp | 4 ++++ 7 files changed, 91 insertions(+), 20 deletions(-) diff --git a/include/ArgumentParser.h b/include/ArgumentParser.h index a48653c..b4f4823 100644 --- a/include/ArgumentParser.h +++ b/include/ArgumentParser.h @@ -1,6 +1,10 @@ #include +#include +#include #include "boost/program_options.hpp" +using std::vector; +using std::string; namespace po = boost::program_options; class ArgumentParser { @@ -10,12 +14,25 @@ class ArgumentParser { ArgumentParser(const ArgumentParser&); ArgumentParser& operator=(const ArgumentParser&); int parseargs(int argc, char** argv); + po::variables_map::size_type count(char const *ref); + + const po::variable_value& operator [](char const *b) const; + //std::string& operator [](char const *b); private: + // Stores values for arguments parsed from the command line + po::variables_map vm; //Create a positional options object for parsing input, output etc //positional arguments from command line. po::positional_options_description positionalOptions; - // - po::variables_map vm; po::options_description desc; }; + +class ConcatenatorArgParse : public ArgumentParser { + public: + vector get_analyses() { return (*this)["analyses"].as>(); } + string get_source_db() { return (*this)["source"].as(); } + string get_target_db() { return (*this)["target"].as(); } + string get_tar_audio_dir() { return ((*this)["tar_db"].empty() ? (*this)["target"].as() : (*this)["tar_db"].as()); } + string get_src_audio_dir() { return ((*this)["src_db"].empty() ? (*this)["source"].as() : (*this)["src_db"].as()); } +}; diff --git a/include/AudioDatabase.h b/include/AudioDatabase.h index dbf5869..5b660d4 100644 --- a/include/AudioDatabase.h +++ b/include/AudioDatabase.h @@ -9,6 +9,7 @@ using std::string; using std::cout; using std::endl; using std::list; +using std::vector; /*! * A class that encapsulates a collection of AudioFile objects in order to @@ -17,7 +18,7 @@ using std::list; class AudioDatabase { public: - AudioDatabase(const std::string audio_dir, const std::string database_dir, list& analyses, Logger* log); + AudioDatabase(const std::string database_dir, vector& analyses, Logger* log, const std::string audio_dir=""); private: std::string database_dir = ""; std::string audio_dir = ""; diff --git a/include/logger.h b/include/logger.h index ebf6717..2cac6ba 100644 --- a/include/logger.h +++ b/include/logger.h @@ -10,7 +10,7 @@ class Logger { public: Logger(); - ~Logger() {}; + ~Logger(); void trace(std::string str); void debug(std::string str); void info(std::string str); diff --git a/src/ArgumentParser.cpp b/src/ArgumentParser.cpp index 70110f3..6cb4820 100644 --- a/src/ArgumentParser.cpp +++ b/src/ArgumentParser.cpp @@ -1,29 +1,53 @@ #include "ArgumentParser.h" +#include #include using namespace std; ArgumentParser::ArgumentParser() : desc("Allowed options") { // Add positional arguments to specify source, target and output database locations. - positionalOptions.add("source_db", 1); - positionalOptions.add("target_db", 1); - positionalOptions.add("output_db", 1); + positionalOptions.add("source", 1); + positionalOptions.add("target", 1); + positionalOptions.add("output", 1); // Add optional arguments to allow control over application settings from the command line. desc.add_options() ("help,h", "produce help message") - ("compression", po::value(), "set compression level") + ("source", po::value()->required(), "Source location") + ("target", po::value()->required(), "Target location") + ("output", po::value()->required(), "Output location") + ("analyses,a", po::value>()->multitoken(), "Analysis " + "strings specifying analyses to use for database comparison.") + ("tar_db", po::value(), "Specifies the " + "directory to create the target database and store analyses in. If " + "not specified then the target directory will be used directly.") + ("src_db", po::value(), "Specifies the " + "directory to create the source database and store analyses in. If " + "not specified then the " "source directory will be used directly.") ; } int ArgumentParser::parseargs(int argc, char** argv) { po::store(po::command_line_parser(argc, argv).options(desc).positional(positionalOptions).run(), vm); - po::notify(vm); // If help option is specified then output help message if (vm.count("help")) { cout << desc << "\n"; return 1; } + + po::notify(vm); + + if (vm["analyses"].empty()) { + throw runtime_error("No analysis strings provided as arguments."); + } return 0; } + +const po::variable_value& ArgumentParser::operator [](char const *b) const { + return vm[b]; +} + +po::variables_map::size_type ArgumentParser::count(char const *ref) { + return vm.count(ref); +} diff --git a/src/AudioDatabase.cpp b/src/AudioDatabase.cpp index 0dcc380..f46f956 100644 --- a/src/AudioDatabase.cpp +++ b/src/AudioDatabase.cpp @@ -1,25 +1,30 @@ #include -#include +#include #include "AudioDatabase.h" #include #include +#include using namespace std; AudioDatabase::AudioDatabase( - const string audio_dir, const string database_dir, - list& analyses, - Logger* log + vector& analyses, + Logger* log, + const string audio_dir ) { this->log = log; - // Remove duplicate strings from list of analyses. - analyses.unique(); + log->info("Database directory: " + database_dir); + log->info("Audio directory: " + audio_dir); + // Remove duplicate strings from vector of analyses. + std::vector::iterator it; + it = std::unique (analyses.begin(), analyses.end()); // 10 20 30 20 10 ? ? ? ? + analyses.resize(std::distance(analyses.begin(),it)); // Check that all analysis strings supplied refer to valid analyses. - list::const_iterator valid = check_analyses_valid(analyses.begin(), analyses.end()); + vector::const_iterator valid = check_analyses_valid(analyses.begin(), analyses.end()); if(valid != analyses.end()) { string err = "The analysis string supplied to the AudioDatabase constructor is not valid: " + *valid; throw std::runtime_error(err); diff --git a/src/concatenator.cpp b/src/concatenator.cpp index 3acca8c..0852d70 100644 --- a/src/concatenator.cpp +++ b/src/concatenator.cpp @@ -19,19 +19,38 @@ int main(int argc, char** argv) { // Initialize a logger object to be used for message handeling throughout // the program Logger log = Logger(); + /* try { + */ // Initialize object to parse arguments supplied by user from command // line - ArgumentParser argparse = ArgumentParser(); + ConcatenatorArgParse argparse = ConcatenatorArgParse(); // Parse arguments and exit program if specified (through use of --help // or -h flag) if(argparse.parseargs(argc, argv)) { - return ERROR_IN_COMMAND_LINE; + return SUCCESS; } + + vector analyses = argparse.get_analyses(); - list analyses = {"BLARGH"}; - AudioDatabase db = AudioDatabase("./", "./", analyses, &log); + // Initialize the source audio database object with arguments provided from the command line. + AudioDatabase source_db = AudioDatabase( + argparse.get_source_db(), + analyses, + &log, + argparse.get_src_audio_dir() + ); + + // Initialize the target audio database object with arguments provided from the command line. + AudioDatabase target_db = AudioDatabase( + argparse.get_target_db(), + analyses, + &log, + argparse.get_tar_audio_dir() + ); + + /* } catch(std::exception& e) { @@ -41,5 +60,6 @@ int main(int argc, char** argv) { log.error(error); return ERROR_UNHANDLED_EXCEPTION; } + */ return SUCCESS; } diff --git a/src/logger.cpp b/src/logger.cpp index 742eff0..7242a55 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -69,6 +69,10 @@ Logger::Logger() { }; +Logger::~Logger() { + Logger::console_sink->flush(); + Logger::file_sink->flush(); +} void Logger::trace(std::string str) { BOOST_LOG_SEV(lg, logging::trivial::trace) << str; } From 729df10465822426c173707608e8ef40a4ed47ea Mon Sep 17 00:00:00 2001 From: Pezz89 Date: Tue, 19 Jul 2016 13:48:24 +0100 Subject: [PATCH 8/9] Improved exception raised from invalid analysis strings. Now all invalid strings are reported. Also swapped asynchronous logging sink for synchronous. --- include/AudioDatabase.h | 7 ++++--- include/logger.h | 4 ++-- src/AudioDatabase.cpp | 13 ++++++++----- src/logger.cpp | 6 +++--- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/AudioDatabase.h b/include/AudioDatabase.h index 5b660d4..1b3cd91 100644 --- a/include/AudioDatabase.h +++ b/include/AudioDatabase.h @@ -44,7 +44,7 @@ bool in_array(string &value, const container &array) \param end - An iterator pointing to the point at which to stop analysing strings. */ template -Iter check_analyses_valid(Iter iterator, Iter end) +std::list check_analyses_valid(Iter iterator, Iter end) { static std::list valid_analyses = { "RMS", @@ -63,13 +63,14 @@ Iter check_analyses_valid(Iter iterator, Iter end) "SKEWNESS", "HARM_RATIO" }; + std::list invalid; while(iterator != end) { if(!in_array(*iterator, valid_analyses)) { - return iterator; + invalid.push_back(*iterator); } ++iterator; } - return iterator; + return invalid; } diff --git a/include/logger.h b/include/logger.h index 2cac6ba..32abf25 100644 --- a/include/logger.h +++ b/include/logger.h @@ -23,8 +23,8 @@ class Logger { static void log_formatter(boost::log::record_view const& rec, boost::log::formatting_ostream& strm); // Define types for logging backends - typedef boost::log::sinks::asynchronous_sink console_backend; - typedef boost::log::sinks::asynchronous_sink file_backend; + typedef boost::log::sinks::synchronous_sink console_backend; + typedef boost::log::sinks::synchronous_sink file_backend; // Define a sink for console output and for log file output boost::shared_ptr console_sink; diff --git a/src/AudioDatabase.cpp b/src/AudioDatabase.cpp index f46f956..2069931 100644 --- a/src/AudioDatabase.cpp +++ b/src/AudioDatabase.cpp @@ -1,9 +1,11 @@ #include #include +#include #include "AudioDatabase.h" #include #include #include +#include using namespace std; @@ -20,14 +22,15 @@ AudioDatabase::AudioDatabase( log->info("Audio directory: " + audio_dir); // Remove duplicate strings from vector of analyses. std::vector::iterator it; - it = std::unique (analyses.begin(), analyses.end()); // 10 20 30 20 10 ? ? ? ? + it = std::unique (analyses.begin(), analyses.end()); analyses.resize(std::distance(analyses.begin(),it)); // Check that all analysis strings supplied refer to valid analyses. - vector::const_iterator valid = check_analyses_valid(analyses.begin(), analyses.end()); - if(valid != analyses.end()) { - string err = "The analysis string supplied to the AudioDatabase constructor is not valid: " + *valid; - throw std::runtime_error(err); + list invalid = check_analyses_valid(analyses.begin(), analyses.end()); + if(!invalid.empty()) { + string err = "The following analysis string(s) supplied to the AudioDatabase constructor are not valid: "; + string invalid_strings = boost::algorithm::join(invalid, " "); + throw std::runtime_error(err + invalid_strings); } this->database_dir = database_dir; diff --git a/src/logger.cpp b/src/logger.cpp index 7242a55..a401ed3 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -70,8 +70,8 @@ Logger::Logger() { }; Logger::~Logger() { - Logger::console_sink->flush(); Logger::file_sink->flush(); + Logger::console_sink->flush(); } void Logger::trace(std::string str) { BOOST_LOG_SEV(lg, logging::trivial::trace) << str; @@ -91,12 +91,12 @@ void Logger::warning(std::string str) { void Logger::error(std::string str) { BOOST_LOG_SEV(lg, logging::trivial::error) << str; - Logger::console_sink->flush(); Logger::file_sink->flush(); + Logger::console_sink->flush(); } void Logger::fatal(std::string str) { BOOST_LOG_SEV(lg, logging::trivial::fatal) << str; - Logger::console_sink->flush(); Logger::file_sink->flush(); + Logger::console_sink->flush(); } From bc64642d8c524d91cdb141025dfd776b1b4e5d6c Mon Sep 17 00:00:00 2001 From: Pezz89 Date: Tue, 19 Jul 2016 15:13:37 +0100 Subject: [PATCH 9/9] Implemented database creation/loading logic. Implemented AudioDatabase subdirectory creation logic. Begun audio organizing/symlinking function Created symlinking functionality for organising audio databases Added copying logic to audio organisation function in AudioDatabase Implemented basic audio file management for AudioDatabase initialisation/loading. Stopped database from searching it's own audio directory when searching for new source files. --- include/ArgumentParser.h | 8 +- include/AudioDatabase.h | 22 +++-- src/ArgumentParser.cpp | 8 +- src/AudioDatabase.cpp | 174 +++++++++++++++++++++++++++++++++++++-- src/concatenator.cpp | 53 ++++++------ 5 files changed, 223 insertions(+), 42 deletions(-) diff --git a/include/ArgumentParser.h b/include/ArgumentParser.h index b4f4823..5ca9074 100644 --- a/include/ArgumentParser.h +++ b/include/ArgumentParser.h @@ -1,11 +1,13 @@ #include #include #include -#include "boost/program_options.hpp" +#include +#include using std::vector; using std::string; namespace po = boost::program_options; +namespace fs = boost::filesystem; class ArgumentParser { public: @@ -33,6 +35,6 @@ class ConcatenatorArgParse : public ArgumentParser { vector get_analyses() { return (*this)["analyses"].as>(); } string get_source_db() { return (*this)["source"].as(); } string get_target_db() { return (*this)["target"].as(); } - string get_tar_audio_dir() { return ((*this)["tar_db"].empty() ? (*this)["target"].as() : (*this)["tar_db"].as()); } - string get_src_audio_dir() { return ((*this)["src_db"].empty() ? (*this)["source"].as() : (*this)["src_db"].as()); } + fs::path get_tar_audio_dir() { return ((*this)["tar_audio"].empty() ? fs::path("") : fs::path((*this)["tar_audio"].as())); } + fs::path get_src_audio_dir() { return ((*this)["src_audio"].empty() ? fs::path("") : fs::path((*this)["src_audio"].as())); } }; diff --git a/include/AudioDatabase.h b/include/AudioDatabase.h index 1b3cd91..0ba6e3c 100644 --- a/include/AudioDatabase.h +++ b/include/AudioDatabase.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "logger.h" using std::string; @@ -18,17 +19,28 @@ using std::vector; class AudioDatabase { public: - AudioDatabase(const std::string database_dir, vector& analyses, Logger* log, const std::string audio_dir=""); + AudioDatabase( + const std::string database_dir, + vector& analyses, + Logger* log + ); + void load_database(boost::filesystem::path source_dir, bool reanalyse=false); + private: - std::string database_dir = ""; - std::string audio_dir = ""; + boost::filesystem::path database_dir; + boost::filesystem::path audio_dir; // Define a set that stores the locations of audiofiles in the database. - std::set audio_file_set; + std::set audio_file_set; + std::map database_dirs; Logger* log; + void validate_analysis_list(); + bool validate_filetype(const boost::filesystem::path& filepath); + void create_subdirs(); + void organise_audio(boost::filesystem::path source_dir, bool symlink=true); + void register_audio(); }; - /*! A function that determines whether a string value is found in the container. */ template diff --git a/src/ArgumentParser.cpp b/src/ArgumentParser.cpp index 6cb4820..24eefeb 100644 --- a/src/ArgumentParser.cpp +++ b/src/ArgumentParser.cpp @@ -18,12 +18,12 @@ ArgumentParser::ArgumentParser() : desc("Allowed options") { ("output", po::value()->required(), "Output location") ("analyses,a", po::value>()->multitoken(), "Analysis " "strings specifying analyses to use for database comparison.") - ("tar_db", po::value(), "Specifies the " - "directory to create the target database and store analyses in. If " - "not specified then the target directory will be used directly.") - ("src_db", po::value(), "Specifies the " + ("src_audio", po::value(), "Specifies the " "directory to create the source database and store analyses in. If " "not specified then the " "source directory will be used directly.") + ("tar_audio", po::value(), "Specifies the " + "directory to create the target database and store analyses in. If " + "not specified then the target directory will be used directly.") ; } diff --git a/src/AudioDatabase.cpp b/src/AudioDatabase.cpp index 2069931..60cc7db 100644 --- a/src/AudioDatabase.cpp +++ b/src/AudioDatabase.cpp @@ -6,20 +6,23 @@ #include #include #include +#include +#include + +namespace fs = boost::filesystem; using namespace std; AudioDatabase::AudioDatabase( const string database_dir, vector& analyses, - Logger* log, - const string audio_dir + Logger* log ) { this->log = log; log->info("Database directory: " + database_dir); - log->info("Audio directory: " + audio_dir); + // Remove duplicate strings from vector of analyses. std::vector::iterator it; it = std::unique (analyses.begin(), analyses.end()); @@ -33,6 +36,167 @@ AudioDatabase::AudioDatabase( throw std::runtime_error(err + invalid_strings); } - this->database_dir = database_dir; - this->audio_dir = audio_dir; + database_dirs.insert({"root", fs::path(database_dir)}); + this->audio_dir = fs::path(audio_dir); +} + +void AudioDatabase::validate_analysis_list() +{ +} + +void AudioDatabase::load_database(fs::path source_dir, bool reanalyse) +{ + // Make sure the database root directory exists. + try + { + if(create_directory(database_dirs["root"])) + { + log->debug("Database directory created: " + database_dir.string()); + } + else if(exists(database_dirs["root"])) + { + log->debug("Database directory already exists: " + database_dir.string()); + } + } + catch(boost::filesystem::filesystem_error &e) + { + throw std::runtime_error("Database directory could not be created: " + database_dir.string()); + } + + + // Create a folder hierachy used to store audio and analysis data used by the database. + create_subdirs(); + + if(source_dir.empty()) { + source_dir = database_dirs["audio"]; + log->debug("Source directory not provided. Setting to:" + source_dir.string()); + } + + if(!exists(source_dir)) { + throw std::runtime_error("Source audio directory does not exist: " + source_dir.string()); + } + + // Only organise audio if new audio is to be added from a new location. + if(source_dir != database_dirs["audio"]) { + // Copy/create links to audio files that are to be used as part of the database. + organise_audio(source_dir); + } + + // Find all audio in the database and store references for use later... + register_audio(); + +} + +void AudioDatabase::create_subdirs() +{ + array directory_names = {{ + fs::path("audio"), + fs::path("data") + }}; + + for(const auto& name : directory_names) { + fs::path subdir = database_dirs["root"]/name; + try + { + if(create_directory(subdir)) { + log->info("Subdirectory created: " + subdir.string()); + } + else if(exists(database_dirs["root"])) + { + log->info("Subdirectory already exists: " + subdir.string()); + } + } + catch(boost::filesystem::filesystem_error &e) + { + throw std::runtime_error("Subdirectory could not be created: " + database_dirs["root"].string()); + } + database_dirs.insert({name.string(), subdir}); + } +} + +bool AudioDatabase::validate_filetype(const fs::path& filepath) +{ + // Define patterns to validate files found based on their file extensions. + static array valid_filetypes = {{ + ".wav", + ".aif", + ".aiff", + ".flac" + }}; + + for(const auto& filetype : valid_filetypes) + { + // compare file extension with valid extension strings to find match. + bool valid = (filetype.compare(filepath.extension().string()) == 0); + if(valid) { + return true; + } + } + return false; +} + +void AudioDatabase::organise_audio(fs::path source_dir, bool symlink) +{ + + log->info("Organising audio directory at: " + database_dirs["audio"].string()); + // Define the destination for copying/linking all valid audio files found. + for(fs::recursive_directory_iterator iter(source_dir), end; iter != end; ++iter) + { + // Don't search the audio directory of the database if this is a subdirectory of the source directory provided. + if (iter->path() == database_dirs["audio"]) + { + iter.disable_recursion_pending(); + } + + if(!validate_filetype(iter->path())) { + log->debug("File: " + iter->path().string() + " isn't a supported audiofile. Skipping..."); + continue; + } + + + fs::path destination_file = database_dirs["audio"]/iter->path().filename(); + + if(symlink) { + // Try to symlink the file to the audio directory of the database. + try { + fs::create_symlink(iter->path(), destination_file); + log->debug("Linked: " + iter->path().string() + " to: " + destination_file.string()); + } + catch(boost::filesystem::filesystem_error &e){ + // If symbolic linking fails then the file probably already exists at the location. + log->debug("Failed to link: " + iter->path().string() + " to " + destination_file.string() + " File may already exists."); + } + } + else { + // If it is in the database as a symlink, but a full copy is required + if(fs::exists(destination_file) && !fs::is_symlink(destination_file)) { + log->debug("File already exists: " + iter->path().string()); + continue; + } + + // Copy file, overwriting any previously created symbolic links. + try { + fs::remove(destination_file); + fs::copy_file(iter->path(), destination_file, fs::copy_option::overwrite_if_exists); + log->debug("Copied: " + iter->path().string() + " to: " + destination_file.string()); + } + catch(boost::filesystem::filesystem_error &e){ + // If symbolic linking fails then the file probably already exists at the location. + log->debug("Failed to copy source file to: " + destination_file.string() + " File may already exists."); + } + } + } +} + +void AudioDatabase::register_audio() +{ + // Clear any previous entries from set. + audio_file_set.clear(); + for(auto& entry : boost::make_iterator_range(fs::directory_iterator(database_dirs["audio"]), {})) + { + if(validate_filetype(entry.path())) { + log->info("Registered audio file: " + entry.path().string()); + audio_file_set.insert(entry.path()); + } + } } diff --git a/src/concatenator.cpp b/src/concatenator.cpp index 0852d70..a770858 100644 --- a/src/concatenator.cpp +++ b/src/concatenator.cpp @@ -23,32 +23,35 @@ int main(int argc, char** argv) { try { */ - // Initialize object to parse arguments supplied by user from command - // line - ConcatenatorArgParse argparse = ConcatenatorArgParse(); - // Parse arguments and exit program if specified (through use of --help - // or -h flag) - if(argparse.parseargs(argc, argv)) { - return SUCCESS; - } - - vector analyses = argparse.get_analyses(); - // Initialize the source audio database object with arguments provided from the command line. - AudioDatabase source_db = AudioDatabase( - argparse.get_source_db(), - analyses, - &log, - argparse.get_src_audio_dir() - ); + // Initialize object to parse arguments supplied by user from command + // line + ConcatenatorArgParse argparse = ConcatenatorArgParse(); + // Parse arguments and exit program if specified (through use of --help + // or -h flag) + if(argparse.parseargs(argc, argv)) { + return SUCCESS; + } + + vector analyses = argparse.get_analyses(); - // Initialize the target audio database object with arguments provided from the command line. - AudioDatabase target_db = AudioDatabase( - argparse.get_target_db(), - analyses, - &log, - argparse.get_tar_audio_dir() - ); + // Initialize the source audio database object with arguments provided from the command line. + AudioDatabase source_db = AudioDatabase( + argparse.get_source_db(), + analyses, + &log + ); + source_db.load_database(argparse.get_src_audio_dir()); + + /* + // Initialize the target audio database object with arguments provided from the command line. + AudioDatabase target_db = AudioDatabase( + argparse.get_target_db(), + analyses, + &log + ); + target_db.load_database(argparse.get_tar_audio_dir()); + */ /* } @@ -58,7 +61,7 @@ int main(int argc, char** argv) { error.append(e.what()); log.error(error); - return ERROR_UNHANDLED_EXCEPTION; + throw; } */ return SUCCESS;