ian@0: // Copyright 2011, Ian Hobson. ian@0: // ian@0: // This file is part of gpsynth. ian@0: // ian@0: // gpsynth is free software: you can redistribute it and/or modify ian@0: // it under the terms of the GNU General Public License as published by ian@0: // the Free Software Foundation, either version 3 of the License, or ian@0: // (at your option) any later version. ian@0: // ian@0: // gpsynth is distributed in the hope that it will be useful, ian@0: // but WITHOUT ANY WARRANTY; without even the implied warranty of ian@0: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ian@0: // GNU General Public License for more details. ian@0: // ian@0: // You should have received a copy of the GNU General Public License ian@0: // along with gpsynth in the file COPYING. ian@0: // If not, see http://www.gnu.org/licenses/. ian@0: ian@0: #include "program_options.hpp" ian@0: ian@0: #include "boost/filesystem.hpp" ian@0: #include "boost/program_options.hpp" ian@0: ian@0: #include ian@0: ian@0: namespace bf = boost::filesystem; ian@0: namespace bo = boost::program_options; ian@0: ian@0: namespace { ian@0: ian@0: const std::string g_default_sc_app_path = "/Applications/SuperCollider"; ian@0: ian@0: void PrintHelpAndQuit(const bo::options_description& options, ian@0: int exit_code = 0) { ian@0: bo::arg = "value"; ian@0: std::cout << '\n' << options << std::endl; ian@0: exit(exit_code); ian@0: } ian@0: ian@0: std::string GetTimeString() { ian@0: std::time_t raw_time; ian@0: time(&raw_time); ian@0: tm* time_info = localtime(&raw_time); ian@0: char buffer[20]; ian@0: strftime(buffer, 20, "%Y-%m-%d_%H:%M:%S", time_info); ian@0: return buffer; ian@0: } ian@0: ian@0: ian@0: } // namespace ian@0: ian@0: ian@0: void ParseCommandLine(int argument_count, ian@0: const char* arguments[], ian@0: ProgramOptions* options) { ian@0: bo::options_description description; ian@0: description.add_options() ian@0: ("help,?", "Displays this message") ian@0: ("target,t", ian@0: bo::value(&options->target_path_)->required(), ian@0: "Target sound file path") ian@0: ("grammar,g", ian@0: bo::value(&options->grammar_path_), ian@0: "Grammar file path") ian@0: ("scpath,s", ian@0: bo::value(&options->sc_app_path_), ian@0: "Path to SuperCollider application folder") ian@0: ("workfolder,w", ian@0: bo::value(&options->work_folder_), ian@0: "Path of folder to place files in") ian@0: ("population,p", ian@0: bo::value(&options->population_size_)->default_value(500), ian@0: "Population size") ian@0: ("generations,G", ian@0: bo::value(&options->generations_)->default_value(20), ian@0: "Number of Generations") ian@0: ("fitness,f", ian@0: bo::value(&options->fitness_threshold_)->default_value(0), ian@0: "Fitness threshold") ian@0: ("tournament,T", ian@0: bo::value(&options->tournament_size_)->default_value(7), ian@0: "Tournament selection size") ian@0: ("crossover,c", ian@0: bo::value(&options->crossover_rate_)->default_value(0.6, "0.6"), ian@0: "Crossover rate") ian@0: ("mutation,m", ian@0: bo::value(&options->mutation_rate_)->default_value(0.35, "0.35"), ian@0: "Mutation rate") ian@0: ("reproducebest,r", ian@0: bo::value(&options->reproduce_best_individual_)->default_value(false), ian@0: "Automatically reproduce best individual when populating next generation.") ian@0: ("features,F", ian@0: bo::value(&options->fitness_features_), ian@0: "Set of features that the fitness function will measure when comparing files." ian@0: " Must be a comma separated list of feature names, which can be any of the following:" ian@0: " pitch, energy, mfccs, dmfccs, ddmfccs, mag, logmag, centroid, spread, flux." ian@0: " Default value is 'mfccs,dmfccs,ddmfccs'.") ian@0: ("windowsize,w", ian@0: bo::value(&options->analysis_window_size_)->default_value(1024), ian@0: "Analysis Window Size") ian@0: ("hopsize,h", ian@0: bo::value(&options->analysis_hop_size_)->default_value(256), ian@0: "Analysis Hop Size") ian@0: ("maxtreedepth,M", ian@0: bo::value(&options->maximum_tree_depth_)->default_value(3), ian@0: "Maximum generated tree depth (can grow bigger through mutation).") ian@0: ("keepfolders,k", ian@0: bo::value(&options->keep_temp_folders_)->default_value(false), ian@0: "When set to 1 the temporary generation folders won't be deleted") ian@0: ("corelimit,C", ian@0: bo::value(&options->core_limit_)->default_value(0), ian@0: "Limits the number of cores gpsynth will use simultaneously, 0=unlimited.") ian@0: ; ian@0: ian@0: bo::command_line_parser parser(argument_count, arguments); ian@0: parser.options(description); ian@0: bo::variables_map config; ian@0: try { ian@0: bo::store(parser.run(), config); ian@0: bo::notify(config); ian@0: } catch (std::exception& e) { ian@0: std::cout << "Error parsing options: " << e.what() << ".\n"; ian@0: PrintHelpAndQuit(description, -1); ian@0: } ian@0: ian@0: if (config.count("help")) { ian@0: PrintHelpAndQuit(description); ian@0: } ian@0: ian@0: if (config.count("workfolder") == 0) { ian@0: options->work_folder_ = bf::current_path().string(); ian@0: } ian@0: // validate the work folder path ian@0: if (!bf::is_directory(options->work_folder_)) { ian@0: std::cout << "Work folder path '" << options->work_folder_ ian@0: << "' doesn't exist.\n"; ian@0: exit(-1); ian@0: } ian@0: options->work_folder_ += "/gpsynth_" + GetTimeString() + "/"; ian@0: ian@0: if (config.count("scpath") == 0) { ian@0: options->sc_app_path_ = g_default_sc_app_path; ian@0: } ian@0: if (!bf::is_directory(options->sc_app_path_)) { ian@0: std::cout << "SC App path '" << options->sc_app_path_ ian@0: << "' doesn't exist.\n"; ian@0: exit(-1); ian@0: } ian@0: ian@0: if (options->tournament_size_ < 1) { ian@0: std::cout << "Tournament size must be greater than zero.\n"; ian@0: exit(-1); ian@0: } ian@0: ian@0: if (options->tournament_size_ > options->population_size_) { ian@0: std::cout << "Tournament size can not be larger than population size.\n"; ian@0: exit(-1); ian@0: } ian@0: ian@0: if (options->crossover_rate_ < 0 || options->crossover_rate_ > 1) { ian@0: std::cout << "The crossover rate should be between 0-1.\n"; ian@0: exit(-1); ian@0: } ian@0: ian@0: if (options->mutation_rate_ < 0 || options->mutation_rate_ > 1) { ian@0: std::cout << "The mutation rate should be between 0-1.\n"; ian@0: exit(-1); ian@0: } ian@0: ian@0: if (options->maximum_tree_depth_ < 1) { ian@0: std::cout << "Maximum tree depth must be greater than zero.\n"; ian@0: exit(-1); ian@0: } ian@0: ian@0: if (options->fitness_features_.empty()) { ian@0: options->fitness_features_ = "mfccs,dmfccs,ddmfccs"; ian@0: } ian@0: } ian@0: ian@0: