From ba308173e6cbce1f54cfbe80c059641052681b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Goran=20Meki=C4=87?= Date: Fri, 12 May 2017 11:47:07 +0200 Subject: Use getoptpp for CLI argument parsing --- drumgizmo/Makefile.am | 3 +- drumgizmo/drumgizmoc.cc | 627 +++++++++++++++++++++--------------------------- 2 files changed, 281 insertions(+), 349 deletions(-) (limited to 'drumgizmo') 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 #include -#include +#include #include -#include -#include #include #include #include @@ -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 .\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=\n" - " midifile: file=, speed= (default 1.0),\n" - " track= (default -1, all tracks)\n" - " midimap=, loop=\n" - " test: p= (default 0.1)\n" - " instr= (default -1, random instrument)\n" - " len= (default -1, forever)\n" - " dummy:\n" - "\n" - "Output engine parameters:\n" - " alsa: dev= (default 'default'), frames= (default " - "32)\n" - " srate= (default 441000)\n" - " oss: dev= (default '/dev/dsp'), srate=,\n" - " max_fragments= (default 4, see man page for more info),\n" - " fragment_size= (default 8, see man page for more info)\n" - " wavfile: file= (default 'output'), srate= " - "(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 .\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=\n"; + output << " midifile: file=, speed= (default 1.0),\n"; + output << " track= (default -1, all tracks)\n"; + output << " midimap=, loop=\n"; + output << " test: p= (default 0.1)\n"; + output << " instr= (default -1, random instrument)\n"; + output << " len= (default -1, forever)\n"; + output << " dummy:\n"; + output << "\n"; + output << "Output engine parameters:\n"; + output << " alsa: dev= (default 'default'), frames= (default "; + output << "32)\n"; + output << " srate= (default 441000)\n"; + output << " oss: dev= (default '/dev/dsp'), srate=,\n"; + output << " max_fragments= (default 4, see man page for more info),\n"; + output << " fragment_size= (default 8, see man page for more info)\n"; + output << " wavfile: file= (default 'output'), srate= "; + 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 parse_parameters(std::string &parms) +{ + std::vector 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 ie; + std::unique_ptr 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; -- cgit v1.2.3