ian@0
|
1 // Copyright 2011, Ian Hobson.
|
ian@0
|
2 //
|
ian@0
|
3 // This file is part of gpsynth.
|
ian@0
|
4 //
|
ian@0
|
5 // gpsynth is free software: you can redistribute it and/or modify
|
ian@0
|
6 // it under the terms of the GNU General Public License as published by
|
ian@0
|
7 // the Free Software Foundation, either version 3 of the License, or
|
ian@0
|
8 // (at your option) any later version.
|
ian@0
|
9 //
|
ian@0
|
10 // gpsynth is distributed in the hope that it will be useful,
|
ian@0
|
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
ian@0
|
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
ian@0
|
13 // GNU General Public License for more details.
|
ian@0
|
14 //
|
ian@0
|
15 // You should have received a copy of the GNU General Public License
|
ian@0
|
16 // along with gpsynth in the file COPYING.
|
ian@0
|
17 // If not, see http://www.gnu.org/licenses/.
|
ian@0
|
18
|
ian@0
|
19 #include "program_options.hpp"
|
ian@0
|
20
|
ian@0
|
21 #include "boost/filesystem.hpp"
|
ian@0
|
22 #include "boost/program_options.hpp"
|
ian@0
|
23
|
ian@0
|
24 #include <ctime>
|
ian@0
|
25
|
ian@0
|
26 namespace bf = boost::filesystem;
|
ian@0
|
27 namespace bo = boost::program_options;
|
ian@0
|
28
|
ian@0
|
29 namespace {
|
ian@0
|
30
|
ian@0
|
31 const std::string g_default_sc_app_path = "/Applications/SuperCollider";
|
ian@0
|
32
|
ian@0
|
33 void PrintHelpAndQuit(const bo::options_description& options,
|
ian@0
|
34 int exit_code = 0) {
|
ian@0
|
35 bo::arg = "value";
|
ian@0
|
36 std::cout << '\n' << options << std::endl;
|
ian@0
|
37 exit(exit_code);
|
ian@0
|
38 }
|
ian@0
|
39
|
ian@0
|
40 std::string GetTimeString() {
|
ian@0
|
41 std::time_t raw_time;
|
ian@0
|
42 time(&raw_time);
|
ian@0
|
43 tm* time_info = localtime(&raw_time);
|
ian@0
|
44 char buffer[20];
|
ian@0
|
45 strftime(buffer, 20, "%Y-%m-%d_%H:%M:%S", time_info);
|
ian@0
|
46 return buffer;
|
ian@0
|
47 }
|
ian@0
|
48
|
ian@0
|
49
|
ian@0
|
50 } // namespace
|
ian@0
|
51
|
ian@0
|
52
|
ian@0
|
53 void ParseCommandLine(int argument_count,
|
ian@0
|
54 const char* arguments[],
|
ian@0
|
55 ProgramOptions* options) {
|
ian@0
|
56 bo::options_description description;
|
ian@0
|
57 description.add_options()
|
ian@0
|
58 ("help,?", "Displays this message")
|
ian@0
|
59 ("target,t",
|
ian@0
|
60 bo::value<std::string>(&options->target_path_)->required(),
|
ian@0
|
61 "Target sound file path")
|
ian@0
|
62 ("grammar,g",
|
ian@0
|
63 bo::value<std::string>(&options->grammar_path_),
|
ian@0
|
64 "Grammar file path")
|
ian@0
|
65 ("scpath,s",
|
ian@0
|
66 bo::value<std::string>(&options->sc_app_path_),
|
ian@0
|
67 "Path to SuperCollider application folder")
|
ian@0
|
68 ("workfolder,w",
|
ian@0
|
69 bo::value<std::string>(&options->work_folder_),
|
ian@0
|
70 "Path of folder to place files in")
|
ian@0
|
71 ("population,p",
|
ian@0
|
72 bo::value<std::size_t>(&options->population_size_)->default_value(500),
|
ian@0
|
73 "Population size")
|
ian@0
|
74 ("generations,G",
|
ian@0
|
75 bo::value<std::size_t>(&options->generations_)->default_value(20),
|
ian@0
|
76 "Number of Generations")
|
ian@0
|
77 ("fitness,f",
|
ian@0
|
78 bo::value<double>(&options->fitness_threshold_)->default_value(0),
|
ian@0
|
79 "Fitness threshold")
|
ian@0
|
80 ("tournament,T",
|
ian@0
|
81 bo::value<std::size_t>(&options->tournament_size_)->default_value(7),
|
ian@0
|
82 "Tournament selection size")
|
ian@0
|
83 ("crossover,c",
|
ian@0
|
84 bo::value<double>(&options->crossover_rate_)->default_value(0.6, "0.6"),
|
ian@0
|
85 "Crossover rate")
|
ian@0
|
86 ("mutation,m",
|
ian@0
|
87 bo::value<double>(&options->mutation_rate_)->default_value(0.35, "0.35"),
|
ian@0
|
88 "Mutation rate")
|
ian@0
|
89 ("reproducebest,r",
|
ian@0
|
90 bo::value<bool>(&options->reproduce_best_individual_)->default_value(false),
|
ian@0
|
91 "Automatically reproduce best individual when populating next generation.")
|
ian@0
|
92 ("features,F",
|
ian@0
|
93 bo::value<std::string>(&options->fitness_features_),
|
ian@0
|
94 "Set of features that the fitness function will measure when comparing files."
|
ian@0
|
95 " Must be a comma separated list of feature names, which can be any of the following:"
|
ian@0
|
96 " pitch, energy, mfccs, dmfccs, ddmfccs, mag, logmag, centroid, spread, flux."
|
ian@0
|
97 " Default value is 'mfccs,dmfccs,ddmfccs'.")
|
ian@0
|
98 ("windowsize,w",
|
ian@0
|
99 bo::value<std::size_t>(&options->analysis_window_size_)->default_value(1024),
|
ian@0
|
100 "Analysis Window Size")
|
ian@0
|
101 ("hopsize,h",
|
ian@0
|
102 bo::value<std::size_t>(&options->analysis_hop_size_)->default_value(256),
|
ian@0
|
103 "Analysis Hop Size")
|
ian@0
|
104 ("maxtreedepth,M",
|
ian@0
|
105 bo::value<std::size_t>(&options->maximum_tree_depth_)->default_value(3),
|
ian@0
|
106 "Maximum generated tree depth (can grow bigger through mutation).")
|
ian@0
|
107 ("keepfolders,k",
|
ian@0
|
108 bo::value<bool>(&options->keep_temp_folders_)->default_value(false),
|
ian@0
|
109 "When set to 1 the temporary generation folders won't be deleted")
|
ian@0
|
110 ("corelimit,C",
|
ian@0
|
111 bo::value<std::size_t>(&options->core_limit_)->default_value(0),
|
ian@0
|
112 "Limits the number of cores gpsynth will use simultaneously, 0=unlimited.")
|
ian@0
|
113 ;
|
ian@0
|
114
|
ian@0
|
115 bo::command_line_parser parser(argument_count, arguments);
|
ian@0
|
116 parser.options(description);
|
ian@0
|
117 bo::variables_map config;
|
ian@0
|
118 try {
|
ian@0
|
119 bo::store(parser.run(), config);
|
ian@0
|
120 bo::notify(config);
|
ian@0
|
121 } catch (std::exception& e) {
|
ian@0
|
122 std::cout << "Error parsing options: " << e.what() << ".\n";
|
ian@0
|
123 PrintHelpAndQuit(description, -1);
|
ian@0
|
124 }
|
ian@0
|
125
|
ian@0
|
126 if (config.count("help")) {
|
ian@0
|
127 PrintHelpAndQuit(description);
|
ian@0
|
128 }
|
ian@0
|
129
|
ian@0
|
130 if (config.count("workfolder") == 0) {
|
ian@0
|
131 options->work_folder_ = bf::current_path().string();
|
ian@0
|
132 }
|
ian@0
|
133 // validate the work folder path
|
ian@0
|
134 if (!bf::is_directory(options->work_folder_)) {
|
ian@0
|
135 std::cout << "Work folder path '" << options->work_folder_
|
ian@0
|
136 << "' doesn't exist.\n";
|
ian@0
|
137 exit(-1);
|
ian@0
|
138 }
|
ian@0
|
139 options->work_folder_ += "/gpsynth_" + GetTimeString() + "/";
|
ian@0
|
140
|
ian@0
|
141 if (config.count("scpath") == 0) {
|
ian@0
|
142 options->sc_app_path_ = g_default_sc_app_path;
|
ian@0
|
143 }
|
ian@0
|
144 if (!bf::is_directory(options->sc_app_path_)) {
|
ian@0
|
145 std::cout << "SC App path '" << options->sc_app_path_
|
ian@0
|
146 << "' doesn't exist.\n";
|
ian@0
|
147 exit(-1);
|
ian@0
|
148 }
|
ian@0
|
149
|
ian@0
|
150 if (options->tournament_size_ < 1) {
|
ian@0
|
151 std::cout << "Tournament size must be greater than zero.\n";
|
ian@0
|
152 exit(-1);
|
ian@0
|
153 }
|
ian@0
|
154
|
ian@0
|
155 if (options->tournament_size_ > options->population_size_) {
|
ian@0
|
156 std::cout << "Tournament size can not be larger than population size.\n";
|
ian@0
|
157 exit(-1);
|
ian@0
|
158 }
|
ian@0
|
159
|
ian@0
|
160 if (options->crossover_rate_ < 0 || options->crossover_rate_ > 1) {
|
ian@0
|
161 std::cout << "The crossover rate should be between 0-1.\n";
|
ian@0
|
162 exit(-1);
|
ian@0
|
163 }
|
ian@0
|
164
|
ian@0
|
165 if (options->mutation_rate_ < 0 || options->mutation_rate_ > 1) {
|
ian@0
|
166 std::cout << "The mutation rate should be between 0-1.\n";
|
ian@0
|
167 exit(-1);
|
ian@0
|
168 }
|
ian@0
|
169
|
ian@0
|
170 if (options->maximum_tree_depth_ < 1) {
|
ian@0
|
171 std::cout << "Maximum tree depth must be greater than zero.\n";
|
ian@0
|
172 exit(-1);
|
ian@0
|
173 }
|
ian@0
|
174
|
ian@0
|
175 if (options->fitness_features_.empty()) {
|
ian@0
|
176 options->fitness_features_ = "mfccs,dmfccs,ddmfccs";
|
ian@0
|
177 }
|
ian@0
|
178 }
|
ian@0
|
179
|
ian@0
|
180
|