#include #include #include #include "appInfo.h" #include "NiceCmdLineOutput.h" #include "ProgressBar.h" #include "logging.h" #include #include "Exporter.h" #include "ContinuousTimeline.h" #include #include "stringTools.h" #include #include #include "parallel.h" #include "exceptions.h" #include "textFiles.h" #include "rhubarbLib.h" #include "ExportFormat.h" #include "TsvExporter.h" #include "XmlExporter.h" #include "JsonExporter.h" using std::exception; using std::string; using std::u32string; using std::vector; using std::unique_ptr; using std::make_unique; using std::shared_ptr; using std::make_shared; using std::map; using std::chrono::duration; using std::chrono::duration_cast; using boost::filesystem::path; using boost::adaptors::transformed; namespace tclap = TCLAP; // Tell TCLAP how to handle our types namespace TCLAP { template<> struct ArgTraits { typedef ValueLike ValueCategory; }; template<> struct ArgTraits { typedef ValueLike ValueCategory; }; } shared_ptr addPausableStdErrSink(logging::Level minLevel) { auto stdErrSink = make_shared(make_shared()); auto pausableSink = make_shared(stdErrSink); auto levelFilter = make_shared(pausableSink, minLevel); logging::addSink(levelFilter); return pausableSink; } void addFileSink(path path, logging::Level minLevel) { auto file = make_shared(); file->exceptions(std::ifstream::failbit | std::ifstream::badbit); file->open(path); auto FileSink = make_shared(file, make_shared()); auto levelFilter = make_shared(FileSink, minLevel); logging::addSink(levelFilter); } unique_ptr createExporter(ExportFormat exportFormat) { switch (exportFormat) { case ExportFormat::Tsv: return make_unique(); case ExportFormat::Xml: return make_unique(); case ExportFormat::Json: return make_unique(); default: throw std::runtime_error("Unknown export format."); } } int main(int argc, char *argv[]) { #ifdef _DEBUG auto pausableStderrSink = addPausableStdErrSink(logging::Level::Warn); pausableStderrSink->pause(); #endif // Define command-line parameters const char argumentValueSeparator = ' '; tclap::CmdLine cmd(appName, argumentValueSeparator, appVersion); cmd.setExceptionHandling(false); cmd.setOutput(new NiceCmdLineOutput()); auto logLevels = vector(logging::LevelConverter::get().getValues()); tclap::ValuesConstraint logLevelConstraint(logLevels); tclap::ValueArg logLevel("", "logLevel", "The minimum log level to log", false, logging::Level::Debug, &logLevelConstraint, cmd); tclap::ValueArg logFileName("", "logFile", "The log file path.", false, string(), "string", cmd); tclap::ValueArg maxThreadCount("", "threads", "The maximum number of worker threads to use.", false, getProcessorCoreCount(), "number", cmd); tclap::ValueArg dialogFile("d", "dialogFile", "A file containing the text of the dialog.", false, string(), "string", cmd); auto exportFormats = vector(ExportFormatConverter::get().getValues()); tclap::ValuesConstraint exportFormatConstraint(exportFormats); tclap::ValueArg exportFormat("f", "exportFormat", "The export format.", false, ExportFormat::Tsv, &exportFormatConstraint, cmd); tclap::UnlabeledValueArg inputFileName("inputFile", "The input file. Must be a sound file in WAVE format.", true, "", "string", cmd); try { auto resumeLogging = gsl::finally([&]() { std::cerr << std::endl << std::endl; #ifdef _DEBUG pausableStderrSink->resume(); #endif std::cerr << std::endl; }); // Parse command line cmd.parse(argc, argv); if (maxThreadCount.getValue() < 1) { throw std::runtime_error("Thread count must be 1 or higher."); } // Set up log file if (logFileName.isSet()) { addFileSink(path(logFileName.getValue()), logLevel.getValue()); } logging::infoFormat("Application startup. Command line: {}", join( vector(argv, argv + argc) | transformed([](char* arg) { return fmt::format("\"{}\"", arg); }), " ")); std::cerr << "Processing input file. "; JoiningContinuousTimeline animation(TimeRange::zero(), Shape::X); { ProgressBar progressBar; // Animate the recording animation = animateWaveFile( inputFileName.getValue(), dialogFile.isSet() ? readUtf8File(path(dialogFile.getValue())) : boost::optional(), maxThreadCount.getValue(), progressBar); } std::cerr << "Done." << std::endl << std::endl; // Export animation unique_ptr exporter = createExporter(exportFormat.getValue()); exporter->exportShapes(path(inputFileName.getValue()), animation, std::cout); logging::info("Exiting application normally."); return 0; } catch (tclap::ArgException& e) { // Error parsing command-line args. cmd.getOutput()->failure(cmd, e); std::cerr << std::endl; logging::error("Invalid command line. Exiting application with error code."); return 1; } catch (tclap::ExitException&) { // A built-in TCLAP command (like --help) has finished. Exit application. std::cerr << std::endl; logging::info("Exiting application after help-like command."); return 0; } catch (const exception& e) { // Generic error string message = getMessage(e); std::cerr << "An error occurred.\n" << message << std::endl; logging::errorFormat("Exiting application with error: {}", message); return 1; } }