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.
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "boost/program_options.hpp"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
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<string> get_analyses() { return (*this)["analyses"].as<vector<string>>(); }
|
||||
string get_source_db() { return (*this)["source"].as<string>(); }
|
||||
string get_target_db() { return (*this)["target"].as<string>(); }
|
||||
string get_tar_audio_dir() { return ((*this)["tar_db"].empty() ? (*this)["target"].as<string>() : (*this)["tar_db"].as<string>()); }
|
||||
string get_src_audio_dir() { return ((*this)["src_db"].empty() ? (*this)["source"].as<string>() : (*this)["src_db"].as<string>()); }
|
||||
fs::path get_tar_audio_dir() { return ((*this)["tar_audio"].empty() ? fs::path("") : fs::path((*this)["tar_audio"].as<string>())); }
|
||||
fs::path get_src_audio_dir() { return ((*this)["src_audio"].empty() ? fs::path("") : fs::path((*this)["src_audio"].as<string>())); }
|
||||
};
|
||||
|
||||
+17
-5
@@ -3,6 +3,7 @@
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "logger.h"
|
||||
|
||||
using std::string;
|
||||
@@ -18,17 +19,28 @@ using std::vector;
|
||||
|
||||
class AudioDatabase {
|
||||
public:
|
||||
AudioDatabase(const std::string database_dir, vector<string>& analyses, Logger* log, const std::string audio_dir="");
|
||||
AudioDatabase(
|
||||
const std::string database_dir,
|
||||
vector<string>& 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<string> audio_file_set;
|
||||
std::set<boost::filesystem::path> audio_file_set;
|
||||
std::map<string, boost::filesystem::path> 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<typename container>
|
||||
|
||||
@@ -18,12 +18,12 @@ ArgumentParser::ArgumentParser() : desc("Allowed options") {
|
||||
("output", po::value<string>()->required(), "Output location")
|
||||
("analyses,a", po::value<vector<string>>()->multitoken(), "Analysis "
|
||||
"strings specifying analyses to use for database comparison.")
|
||||
("tar_db", po::value<string>(), "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<string>(), "Specifies the "
|
||||
("src_audio", po::value<string>(), "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<string>(), "Specifies the "
|
||||
"directory to create the target database and store analyses in. If "
|
||||
"not specified then the target directory will be used directly.")
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
+169
-5
@@ -6,20 +6,23 @@
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
using namespace std;
|
||||
|
||||
AudioDatabase::AudioDatabase(
|
||||
const string database_dir,
|
||||
vector<string>& 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<string>::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<fs::path, 2> 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<string, 4> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-24
@@ -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<string> analyses = argparse.get_analyses();
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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()
|
||||
);
|
||||
vector<string> 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;
|
||||
|
||||
Reference in New Issue
Block a user