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:
2016-07-19 15:13:37 +01:00
committed by Sam Perry
parent 729df10465
commit bc64642d8c
5 changed files with 223 additions and 42 deletions
+5 -3
View File
@@ -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
View File
@@ -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>
+4 -4
View File
@@ -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
View File
@@ -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());
}
}
}
+28 -25
View File
@@ -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 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<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;