summaryrefslogtreecommitdiff
path: root/drumgizmo
diff options
context:
space:
mode:
authorGoran Mekić <meka@tilda.center>2017-05-12 11:47:07 +0200
committerGoran Mekić <meka@tilda.center>2017-05-14 21:43:18 +0200
commitba308173e6cbce1f54cfbe80c059641052681b72 (patch)
treed7dca8fd76503f8ab97b26d22eb5545a4458d114 /drumgizmo
parentb50c35be377c659cd4eeccd2148dfe1a27e4adbc (diff)
Use getoptpp for CLI argument parsing
Diffstat (limited to 'drumgizmo')
-rw-r--r--drumgizmo/Makefile.am3
-rw-r--r--drumgizmo/drumgizmoc.cc627
2 files changed, 281 insertions, 349 deletions
diff --git a/drumgizmo/Makefile.am b/drumgizmo/Makefile.am
index e41e72c..de5cad6 100644
--- a/drumgizmo/Makefile.am
+++ b/drumgizmo/Makefile.am
@@ -9,7 +9,7 @@ drumgizmo_LDADD = $(JACK_LIBS) $(top_srcdir)/src/libdg.la
drumgizmo_LDFLAGS =
drumgizmo_CXXFLAGS = \
- -I$(top_srcdir)/include -I$(top_srcdir)/src \
+ -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_srcdir)/getoptpp \
-I$(top_srcdir)/hugin -DWITH_HUG_MUTEX -DWITH_HUG_FILTER \
$(JACK_CFLAGS) $(SSEFLAGS)
@@ -86,6 +86,7 @@ EXTRA_DIST = \
drumgizmoc.h \
jackclient.h \
enginefactory.h \
+ getoptpp/getoptpp.hpp \
input/inputdummy.h \
input/test.h \
input/jackmidi.h \
diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc
index 6244125..6bb4d1a 100644
--- a/drumgizmo/drumgizmoc.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -27,11 +27,9 @@
#include <iostream>
#include <config.h>
-#include <getopt.h>
+#include <getoptpp.hpp>
#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sstream>
#include <chrono>
#include <thread>
@@ -46,398 +44,338 @@
#include "event.h"
-static const char version_str[] = "DrumGizmo v" VERSION "\n";
-
-static const char copyright_str[] =
- "Copyright (C) 2008-2011 Bent Bisballe Nyeng - Aasimon.org.\n"
- "This is free software. You may redistribute copies of it under the terms "
- "of\n"
- "the GNU Lesser General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n"
- "\n"
- "Written by Bent Bisballe Nyeng (deva@aasimon.org)\n";
-
-static const char usage_str[] =
- "Usage: %s [options] drumkitfile\n"
- "Options:\n"
- " -a, --async-load Load drumkit in the background and start the "
- "engine immediately.\n"
- " -i, --inputengine dummy|test|jackmidi|midifile Use said event "
- "input engine.\n"
- " -I, --inputparms parmlist Set input engine parameters.\n"
- " -o, --outputengine dummy|alsa|jackaudio|wavfile Use said audio "
- "output engine.\n"
- " -O, --outputparms parmlist Set output engine parameters.\n"
- " -e, --endpos Number of samples to process, -1: infinite.\n"
-#ifndef DISABLE_HUGIN
- " -D, --debug ddd Enable debug messages on 'ddd'; see hugin "
- "documentation for details\n"
-#endif /*DISABLE_HUGIN*/
- " -r, --no-resampling Disable resampling.\n"
- " -s, --streaming Enable streaming.\n"
- " -S, --streamingparms Streaming options.\n"
- " -v, --version Print version information and exit.\n"
- " -h, --help Print this message and exit.\n"
- "\n"
- "Input engine parameters:\n"
- " jackmidi: midimap=<midimapfile>\n"
- " midifile: file=<midifile>, speed=<tempo> (default 1.0),\n"
- " track=<miditrack> (default -1, all tracks)\n"
- " midimap=<midimapfile>, loop=<true|false>\n"
- " test: p=<hit_propability> (default 0.1)\n"
- " instr=<instrument> (default -1, random instrument)\n"
- " len=<seconds> (default -1, forever)\n"
- " dummy:\n"
- "\n"
- "Output engine parameters:\n"
- " alsa: dev=<device> (default 'default'), frames=<frames> (default "
- "32)\n"
- " srate=<samplerate> (default 441000)\n"
- " oss: dev=<device> (default '/dev/dsp'), srate=<samplerate>,\n"
- " max_fragments=<number> (default 4, see man page for more info),\n"
- " fragment_size=<selector> (default 8, see man page for more info)\n"
- " wavfile: file=<filename> (default 'output'), srate=<samplerate> "
- "(default 44100)\n"
- " jackaudio:\n"
- " dummy:\n"
- "\n"
- "Streaming parameters:\n"
- " limit: Limit the amount of preloaded drumkit data to the size\n"
- // " chunk_size: chunk size in k,M,G\n"
- "\n";
-
-int main(int argc, char* argv[])
+typedef struct parm_token
{
- int c;
- Settings settings;
- settings.disk_cache_enable = false;
- std::string hugin_filter;
- unsigned int hugin_flags = 0;
-#ifndef DISABLE_HUGIN
- hugin_flags = HUG_FLAG_DEFAULT;
-#endif /*DISABLE_HUGIN*/
+ std::string key;
+ std::string value;
+} parm_token_t;
- std::string outputengine;
- std::string inputengine;
- std::string iparms;
- std::string oparms;
- std::string sparms;
- bool async = false;
- int endpos = -1;
- EngineFactory factory;
+static std::string version()
+{
+ std::ostringstream output;
+ output << "DrumGizmo v" << VERSION << std::endl;
+ return output.str();
+}
- int option_index = 0;
- static struct option long_options[] = {
- {"async-load", no_argument, 0, 'a'},
- {"inputengine", required_argument, 0, 'i'},
- {"inputparms", required_argument, 0, 'I'},
- {"outputengine", required_argument, 0, 'o'},
- {"outputparms", required_argument, 0, 'O'},
- {"endpos", required_argument, 0, 'e'},
-#ifndef DISABLE_HUGIN
- {"debug", required_argument, 0, 'D'},
-#endif /*DISABLE_HUGIN*/
- {"streaming", no_argument, 0, 's'},
- {"streamingparams", required_argument, 0, 'S'},
- {"version", no_argument, 0, 'v'},
- {"help", no_argument, 0, 'h'},
- {"no-resample", no_argument, 0, 'r'},
- {0, 0, 0, 0}
- };
- while(1)
- {
- c = getopt_long(argc, argv, "hvpo:O:i:I:e:arsS:"
-#ifndef DISABLE_HUGIN
- "D:"
-#endif /*DISABLE_HUGIN*/
- , long_options, &option_index);
- if(c == -1)
- {
- break;
- }
+static std::string copyright()
+{
+ std::ostringstream output;
+ output << "Copyright (C) 2008-2011 Bent Bisballe Nyeng - Aasimon.org.\n";
+ output << "This is free software. You may redistribute copies of it under the terms ";
+ output << "of\n";
+ output << "the GNU Lesser General Public License <http://www.gnu.org/licenses/gpl.html>.\n";
+ output << "There is NO WARRANTY, to the extent permitted by law.\n";
+ output << "\n";
+ output << "Written by Bent Bisballe Nyeng (deva@aasimon.org)\n";
+ return output.str();
+}
- switch(c)
- {
- case 'i':
- inputengine = optarg;
- if(inputengine == "help")
- {
- std::cout << "Available Input Engines = { ";
- for(auto const& name : factory.getInputEngines())
- {
- std::cout << name << " ";
- }
- std::cout << "}\n";
- return 0;
- }
- break;
+static std::string usage(std::string name)
+{
+ std::ostringstream output;
+ output << "Usage: " << name << " [options] drumkitfile\n";
+ output << "Options:\n";
+ output << " -a, --async-load Load drumkit in the background and start the ";
+ output << "engine immediately.\n";
+ output << " -i, --inputengine dummy|test|jackmidi|midifile Use said event ";
+ output << "input engine.\n";
+ output << " -I, --inputparms parmlist Set input engine parameters.\n";
+ output << " -o, --outputengine dummy|alsa|jackaudio|wavfile Use said audio ";
+ output << "output engine.\n";
+ output << " -O, --outputparms parmlist Set output engine parameters.\n";
+ output << " -e, --endpos Number of samples to process, -1: infinite.\n";
#ifndef DISABLE_HUGIN
- case 'D':
- hugin_flags |= HUG_FLAG_USE_FILTER;
- hugin_filter = optarg;
- break;
+ output << " -D, --debug ddd Enable debug messages on 'ddd'; see hugin ";
+ output << "documentation for details\n";
#endif /*DISABLE_HUGIN*/
+ output << " -r, --no-resampling Disable resampling.\n";
+ output << " -s, --streaming Enable streaming.\n";
+ output << " -S, --streamingparms Streaming options.\n";
+ output << " -v, --version Print version information and exit.\n";
+ output << " -h, --help Print this message and exit.\n";
+ output << "\n";
+ output << "Input engine parameters:\n";
+ output << " jackmidi: midimap=<midimapfile>\n";
+ output << " midifile: file=<midifile>, speed=<tempo> (default 1.0),\n";
+ output << " track=<miditrack> (default -1, all tracks)\n";
+ output << " midimap=<midimapfile>, loop=<true|false>\n";
+ output << " test: p=<hit_propability> (default 0.1)\n";
+ output << " instr=<instrument> (default -1, random instrument)\n";
+ output << " len=<seconds> (default -1, forever)\n";
+ output << " dummy:\n";
+ output << "\n";
+ output << "Output engine parameters:\n";
+ output << " alsa: dev=<device> (default 'default'), frames=<frames> (default ";
+ output << "32)\n";
+ output << " srate=<samplerate> (default 441000)\n";
+ output << " oss: dev=<device> (default '/dev/dsp'), srate=<samplerate>,\n";
+ output << " max_fragments=<number> (default 4, see man page for more info),\n";
+ output << " fragment_size=<selector> (default 8, see man page for more info)\n";
+ output << " wavfile: file=<filename> (default 'output'), srate=<samplerate> ";
+ output << "(default 44100)\n";
+ output << " jackaudio:\n";
+ output << " dummy:\n";
+ output << "\n";
+ output << "Streaming parameters:\n";
+ output << " limit: Limit the amount of preloaded drumkit data to the size\n";
+ // output << " chunk_size: chunk size in k,M,G\n"
+ output << "\n";
+ return output.str();
+}
- case 'I':
- iparms = optarg;
- break;
- case 'o':
- outputengine = optarg;
- if(outputengine == "help")
+std::vector<parm_token_t> parse_parameters(std::string &parms)
+{
+ std::vector<parm_token_t> result;
+ std::string parm;
+ std::string val;
+ bool inval = false;
+ wordexp_t exp_result;
+ for(size_t i = 0; i < parms.size(); ++i)
+ {
+ if(parms[i] == ',')
+ {
+ int error = wordexp(val.data(), &exp_result, 0);
+ if(error)
{
- std::cout << "Available Output Engines = { ";
- for(auto const& name : factory.getOutputEngines())
- {
- std::cout << name << " ";
- }
- std::cout << "}\n";
- return 0;
+ std::cerr << "Wrong argument: ";
+ std::cerr << parm << " = " << val << std::endl;
+ exit(1);
}
- break;
-
- case 'O':
- oparms = optarg;
- break;
-
- case 'a':
- async = true;
- break;
-
- case 'e':
- endpos = atoi(optarg);
- break;
-
- case '?':
- case 'h':
- printf("%s", version_str);
- printf(usage_str, argv[0]);
- return 0;
-
- case 'v':
- printf("%s", version_str);
- printf("%s", copyright_str);
- return 0;
-
- case 'r':
- settings.enable_resampling = false;
- break;
-
- case 's':
- settings.disk_cache_enable = true;
- break;
+ result.push_back({parm, exp_result.we_wordv[0]});
+ parm = "";
+ val = "";
+ inval = false;
+ continue;
+ }
- case 'S':
- sparms = optarg;
- break;
+ if(parms[i] == '=')
+ {
+ inval = true;
+ continue;
+ }
- default:
- break;
+ if(inval)
+ {
+ val += parms[i];
+ }
+ else
+ {
+ parm += parms[i];
}
}
-
- hug_status_t status = hug_init(hugin_flags, HUG_OPTION_FILTER,
- hugin_filter.c_str(), HUG_OPTION_END);
- if(status != HUG_STATUS_OK)
+ if(parm != "")
{
- printf("Error: %d\n", status);
- return 1;
+ int error = wordexp(val.data(), &exp_result, 0);
+ if(error)
+ {
+ std::cerr << "Wrong argument: ";
+ std::cerr << parm << " = " << val << std::endl;
+ exit(1);
+ }
+ result.push_back({parm, exp_result.we_wordv[0]});
}
+ return result;
+}
- DEBUG(drumgizmo, "Debug enabled.");
-
- if(inputengine == "")
- {
- printf("Missing input engine\n");
- return 1;
- }
- auto ie = factory.createInput(inputengine);
+int main(int argc, char* argv[])
+{
+ EngineFactory factory;
+ Settings settings;
+ bool async = false;
+ dg::Options opt;
+ int endpos = -1;
+ std::string kitfile;
+ std::unique_ptr<AudioInputEngine> ie;
+ std::unique_ptr<AudioOutputEngine> oe;
+ std::string hugin_filter;
+ unsigned int hugin_flags = 0;
+#ifndef DISABLE_HUGIN
+ hugin_flags = HUG_FLAG_DEFAULT;
+#endif /*DISABLE_HUGIN*/
- if(ie == NULL)
- {
- printf("Invalid input engine: %s\n", inputengine.c_str());
- return 1;
- }
+ opt.add("async-load", no_argument, 'a', [&]() {
+ async = true;
+ });
- {
- std::string parm;
- std::string val;
- bool inval = false;
- wordexp_t exp_result;
- for(size_t i = 0; i < iparms.size(); ++i)
+ opt.add("inputengine", required_argument, 'i', [&]() {
+ std::string engine = optarg;
+ if(engine == "help")
{
- if(iparms[i] == ',')
+ std::cout << "Available Input Engines = { ";
+ for(auto const& name : factory.getInputEngines())
{
- int error = wordexp(val.data(), &exp_result, 0);
- if(error)
- {
- std::cerr << "Wrong argument: ";
- std::cerr << parm << " = " << val << std::endl;
- return 1;
- }
- ie->setParm(parm, exp_result.we_wordv[0]);
- parm = "";
- val = "";
- inval = false;
- continue;
+ std::cout << name << " ";
}
+ std::cout << "}\n";
+ exit(0);
+ }
+ if(engine == "")
+ {
+ std::cerr << "Missing input engine" << std::endl;;
+ exit(1);
+ }
+ ie = factory.createInput(engine);
+ if(ie == NULL)
+ {
+ std::cerr << "Invalid input engine: " << engine << std::endl;
+ exit(1);
+ }
+ });
- if(iparms[i] == '=')
- {
- inval = true;
- continue;
- }
+ opt.add("inputparms", required_argument, 'I', [&]() {
+ std::string parms = optarg;
+ auto tokens = parse_parameters(parms);
+ for(auto &token : tokens)
+ {
+ ie->setParm(token.key, token.value);
+ }
+ });
- if(inval)
- {
- val += iparms[i];
- }
- else
+ opt.add("outputengine", required_argument, 'o', [&]() {
+ std::string engine = optarg;
+ if(engine == "help")
+ {
+ std::cout << "Available Output Engines = { ";
+ for(auto const& name : factory.getOutputEngines())
{
- parm += iparms[i];
+ std::cout << name << " ";
}
+ std::cout << " }\n";
+ exit(0);
}
- if(parm != "")
+ if(engine == "")
{
- int error = wordexp(val.data(), &exp_result, 0);
- if(error)
- {
- std::cerr << "Wrong argument: ";
- std::cerr << parm << " = " << val << std::endl;
- return 1;
- }
- ie->setParm(parm, exp_result.we_wordv[0]);
+ std::cerr << "Missing output engine" << std::endl;
+ exit(1);
}
- }
+ oe = factory.createOutput(engine);
+ if(ie == NULL)
+ {
+ std::cerr << "Invalid output engine: " << engine << std::endl;;
+ exit(1);
+ }
+ });
- {
- if(sparms.size() != 0)
+ opt.add("outputparms", required_argument, 'O', [&]() {
+ std::string parms = optarg;
+ auto tokens = parse_parameters(parms);
+ for(auto &token : tokens)
{
- if(sparms[0] == ',' || sparms[sparms.size()-1] == ',')
+ oe->setParm(token.key, token.value);
+ }
+ });
+
+ opt.add("endpos", required_argument, 'e', [&]() {
+ try
{
- std::cerr << "Invalid streamparms" << std::endl;
- return 1;
+ endpos = std::stoi(optarg);
}
- std::string token;
- std::istringstream tokenstream(sparms);
- while(getline(tokenstream, token, ','))
+ catch(...)
{
- std::size_t index = token.find('=');
- if(index == std::string::npos || index == token.size()-1 || index == 0)
- {
- std::cerr << "Invalid streamparms" << std::endl;
- return 1;
- }
+ std::cerr << "Invalid endpos size " << optarg << std::endl;
+ }
+ });
- std::string parm = token.substr(0, index);
- std::string value = token.substr(index+1);
+#ifndef DISABLE_HUGIN
+ opt.add("debug", required_argument, 'D', [&]() {
+ hugin_flags |= HUG_FLAG_USE_FILTER;
+ hugin_filter = optarg;
+ });
+#endif /*DISABLE_HUGIN*/
- if(parm == "limit")
- {
- settings.disk_cache_upper_limit = byteSizeParser(value);
- if(settings.disk_cache_upper_limit == 0)
- {
- std::cerr << "Invalid argument for streamparms limit: " << value << std::endl;
- return 1;
- }
- }
- // else if(parm == "chunk_size")
- // {
- // settings.disk_cache_chunk_size = byteSizeParser(value);
- // if(settings.disk_cache_chunk_size == 0)
- // {
- // std::cerr << "Invalid argument for streamparms chunk_size: " << value << std::endl;
- // return 1;
- // }
- // }
- else
+ opt.add("no-resampling", no_argument, 'r', [&]() {
+ settings.enable_resampling = false;
+ });
+
+ opt.add("streaming", no_argument, 's', [&]() {
+ settings.disk_cache_enable = true;
+ });
+
+ opt.add("streamingparms", required_argument, 'S', [&]() {
+ std::string parms = optarg;
+ auto tokens = parse_parameters(parms);
+ for(auto &token : tokens)
+ {
+ if(token.key == "limit")
+ {
+ settings.disk_cache_upper_limit = byteSizeParser(token.value);
+ if(settings.disk_cache_upper_limit == 0)
{
- std::cerr << "Unknown streamingparms argument " << parm << std::endl;
- return 1;
+ std::cerr << "Invalid argument for streamparms limit: " << token.value << std::endl;
+ exit(1);
}
}
+ // else if(token.key == "chunk_size")
+ // {
+ // settings.disk_cache_chunk_size = byteSizeParser(token.value);
+ // if(settings.disk_cache_chunk_size == 0)
+ // {
+ // std::cerr << "Invalid argument for streamparms chunk_size: " << token.value << std::endl;
+ // exit(1);
+ // }
+ // }
+ else
+ {
+ std::cerr << "Unknown streamingparms argument " << token.key << std::endl;
+ exit(1);
+ }
}
- }
+ });
+
+ opt.add("version", no_argument, 'v', [&]() {
+ std::cout << version();
+ std::cout << copyright();
+ exit(0);
+ });
- if(outputengine == "")
+ opt.add("help", no_argument, 'h', [&]() {
+ std::cout << version();
+ std::cout << usage(argv[0]);
+ exit(0);
+ });
+
+ if(!opt.process(argc, argv))
{
- printf("Missing output engine\n");
return 1;
}
-
- auto oe = factory.createOutput(outputengine);
-
- if(oe == NULL)
+ hug_status_t status = hug_init(hugin_flags, HUG_OPTION_FILTER,
+ hugin_filter.data(), HUG_OPTION_END);
+ if(status != HUG_STATUS_OK)
{
- printf("Invalid output engine: %s\n", outputengine.c_str());
+ std::cerr << "Error: " << status << std::endl;
return 1;
}
+ DEBUG(drumgizmo, "Debug enabled.");
+ if(opt.arguments().empty())
{
- std::string parm;
- std::string val;
- bool inval = false;
- for(size_t i = 0; i < oparms.size(); ++i)
- {
- if(oparms[i] == ',')
- {
- oe->setParm(parm, val);
- parm = "";
- val = "";
- inval = false;
- continue;
- }
-
- if(oparms[i] == '=')
- {
- inval = true;
- continue;
- }
-
- if(inval)
- {
- val += oparms[i];
- }
- else
- {
- parm += oparms[i];
- }
- }
- if(parm != "")
- {
- oe->setParm(parm, val);
- }
+ std::cerr << "Missing kitfile." << std::endl;
+ std::cerr << usage(argv[0]) << std::endl;
+ return 1;
}
-
- std::string kitfile;
-
- if(option_index < argc)
+ else if(opt.arguments().size() > 1)
{
- while(optind < argc)
- {
- if(kitfile != "")
- {
- printf("Can only handle a single kitfile.\n");
- printf(usage_str, argv[0]);
- return 1;
- }
- kitfile = argv[optind++];
- }
- printf("\n");
+ std::cerr << "Can only handle a single kitfile." << std::endl;
+ std::cerr << usage(argv[0]) << std::endl;
+ return 1;
}
else
{
- printf("Missing kitfile.\n");
- printf(usage_str, argv[0]);
- return 1;
+ kitfile = opt.arguments()[0];
+ std::ifstream tmp_kit(kitfile);
+ if(!tmp_kit.good())
+ {
+ std::cerr << "Can not open " << kitfile << std::endl;
+ return 1;
+ }
}
-
- printf("Using kitfile: %s\n", kitfile.c_str());
+ std::cout << "Using kitfile: " << kitfile << std::endl;
DrumGizmo gizmo(settings, *oe.get(), *ie.get());
@@ -446,7 +384,7 @@ int main(int argc, char* argv[])
settings.drumkit_file.store(kitfile);
settings.reload_counter++;
- printf("Loading drumkit, this may take a while:\n");
+ std::cout << "Loading drumkit, this may take a while:" << std::endl;
if(!async)
{
@@ -457,12 +395,11 @@ int main(int argc, char* argv[])
int total = settings.number_of_files.load();
int loaded = settings.number_of_files_loaded.load();
- printf("\r%d of %d ", loaded, total);
- fflush(stdout);
+ std::cout << "\r" << loaded << " of " << total << std::flush;
if(settings.drumkit_load_status.load() == LoadStatus::Error)
{
- printf("\nFailed to load \"%s\".\n", kitfile.c_str());
+ std::cout << "\nFailed to load " << kitfile << std::endl;
return 1;
}
@@ -471,7 +408,7 @@ int main(int argc, char* argv[])
//break;
}
}
- printf("\ndone\n");
+ std::cout << "\ndone" << std::endl;
}
gizmo.setSamplerate(oe->getSamplerate());
@@ -479,11 +416,10 @@ int main(int argc, char* argv[])
if(!gizmo.init())
{
- printf("Failed init engine.\n");
+ std::cout << "Failed init engine." << std::endl;
return 1;
}
- // former drumgizmo run call
size_t pos = 0;
size_t nsamples = oe->getBufferSize();
sample_t *samples = (sample_t *)malloc(nsamples * sizeof(sample_t));
@@ -504,13 +440,8 @@ int main(int argc, char* argv[])
ie->stop();
oe->stop();
-
free(samples);
- // end former drumgizmo run call
-
- printf("Quit.\n");
- fflush(stdout);
-
+ std::cout << "Quit." << std::endl;
hug_close();
return 0;