diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1e1e0ea --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmd/util"] + path = cmd/util + url = https://github.com/geraintluff/util.git diff --git a/cmd/main.cpp b/cmd/main.cpp index af3435b..1d306f2 100644 --- a/cmd/main.cpp +++ b/cmd/main.cpp @@ -2,233 +2,59 @@ #include #define LOG_EXPR(expr) std::cout << #expr << " = " << (expr) << "\n"; -#define PROFILE_PLOT_CHUNKS -#ifdef PROFILE_PLOT_CHUNKS -size_t activeStepIndex = 0; -void profileProcessStart(int, int); -void profileProcessEndStep(); -void profileProcessStep(size_t, size_t); -void profileProcessEnd(); -# define SIGNALSMITH_STRETCH_PROFILE_PROCESS_START profileProcessStart -# define SIGNALSMITH_STRETCH_PROFILE_PROCESS_STEP profileProcessStep -# define SIGNALSMITH_STRETCH_PROFILE_PROCESS_ENDSTEP profileProcessEndStep -# define SIGNALSMITH_STRETCH_PROFILE_PROCESS_END profileProcessEnd -#endif - #include "signalsmith-stretch/signalsmith-stretch.h" +using SignalsmithStretch = signalsmith::stretch::SignalsmithStretch; -#include "./util/stopwatch.h" -#include "./util/memory-tracker.hxx" #include "./util/simple-args.h" #include "./util/wav.h" -#ifdef PROFILE_PLOT_CHUNKS -#include "plot/plot.h" -std::vector processStopwatches; -signalsmith::Stopwatch processStopwatchStart, processStopwatchEnd; -bool started = false; -bool activeStep = false; -void profileProcessStart(int /*inputSamples*/, int /*outputSamples*/) { - activeStep = false; - started = true; - processStopwatchStart.startLap(); -} -void profileProcessEndStep() { - if (activeStep) { - activeStep = false; - processStopwatches[activeStepIndex].lap(); - } else if (started) { - started = false; - processStopwatchStart.lap(); - } - processStopwatchEnd.startLap(); -} -void profileProcessStep(size_t step, size_t count) { - profileProcessEndStep(); - activeStep = true; - activeStepIndex = step; - if (processStopwatches.size() < count) { - processStopwatches.resize(count); - } - processStopwatches[step].startLap(); -} -void profileProcessEnd() { - processStopwatchEnd.lap(); -} -#endif - int main(int argc, char* argv[]) { - signalsmith::stretch::SignalsmithStretch stretch; // optional cheaper RNG for performance comparison - -#ifdef PROFILE_PLOT_CHUNKS - processStopwatches.reserve(1000); -#endif - SimpleArgs args(argc, argv); if (args.hasFlag("v", "prints the version")) { - std::cout << stretch.version[0] << "." << stretch.version[1] << "." << stretch.version[2] << "\n"; + auto &version = SignalsmithStretch::version; + std::cout << version[0] << "." << version[1] << "." << version[2] << "\n"; return 0; } - + std::string inputWav = args.arg("input.wav", "16-bit WAV file"); std::string outputWav = args.arg("output.wav", "output WAV file"); - double semitones = args.flag("semitones", "pitch-shift amount", 0); double formants = args.flag("formant", "formant-shift amount (semitones)", 0); bool formantComp = args.hasFlag("formant-comp", "formant compensation"); - double formantBase = args.flag("formant-base", "formant base frequency (Hz, 0=auto)", 0); + double formantBase = args.flag("formant-base", "formant base frequency (Hz, 0=auto)", 100); double tonality = args.flag("tonality", "tonality limit (Hz)", 8000); double time = args.flag("time", "time-stretch factor", 1); - bool exactLength = args.hasFlag("exact", "trims the start/end so the output has the correct length"); bool splitComputation = args.hasFlag("split-computation", "distributes the computation more evenly (but higher latency)"); - args.errorExit(); - - std::cout << Console::Bright << inputWav << Console::Reset; - std::cout << " -> "; - std::cout << Console::Bright << outputWav << Console::Reset << "\n"; - std::cout << "\tsemitones: " << semitones << "\n\t time: " << time << "x" << (exactLength ? " (exact)" : "") << "\n\t tonality: " << tonality << "Hz\n"; + args.errorExit(); // exits on error, or with `--help` + + std::cout << inputWav << " -> " << outputWav << "\n"; Wav inWav; - std::cout << inputWav << " -> " << outputWav << "\n"; if (!inWav.read(inputWav).warn()) args.errorExit("failed to read WAV"); - size_t inputLength = inWav.samples.size()/inWav.channels; - Wav prevWav; // Used during development, to compare against known-good previous render - bool compareReference = (time <= 1.6); - if (compareReference && !prevWav.read(outputWav + "-reference.wav")) { - if (prevWav.read(outputWav)) { - prevWav.write(outputWav + "-reference.wav"); - } - } - + size_t inputLength = inWav.length(); + size_t outputLength = std::round(inputLength*time); + Wav outWav; outWav.channels = inWav.channels; outWav.sampleRate = inWav.sampleRate; - int outputLength = std::round(inputLength*time); + outWav.resize(outputLength); - signalsmith::MemoryTracker initMemory; - signalsmith::Stopwatch stopwatch; - - stopwatch.start(); + SignalsmithStretch stretch; stretch.presetDefault(int(inWav.channels), inWav.sampleRate, splitComputation); stretch.setTransposeSemitones(semitones, tonality/inWav.sampleRate); stretch.setFormantSemitones(formants, formantComp); stretch.setFormantBase(formantBase/inWav.sampleRate); - double initSeconds = stopwatch.lap(); - initMemory = initMemory.diff(); - std::cout << "Setup:\n\t" << initSeconds << "s\n"; - if (initMemory.implemented) { - std::cout << "\tallocated " << (initMemory.allocBytes/1000) << "kB, freed " << (initMemory.freeBytes/1000) << "kB\n"; - } - - signalsmith::MemoryTracker processMemory; - - if (exactLength) { - outWav.samples.resize(outputLength*outWav.channels); - stopwatch.start(); - processMemory = {}; - stretch.exact(inWav, int(inputLength), outWav, int(outputLength)); - } else { - // pad the input at the end, since we'll be reading slightly ahead - size_t paddedInputLength = inputLength + stretch.inputLatency(); - inWav.samples.resize(paddedInputLength*inWav.channels); - // pad the output at the end, since we have output latency as well - int tailSamples = exactLength ? stretch.outputLatency() : (stretch.outputLatency() + stretch.inputLatency()); // if we don't need exact length, add a bit more output to catch any wobbles past the end - int paddedOutputLength = outputLength + tailSamples; - outWav.samples.resize(paddedOutputLength*outWav.channels); - - stopwatch.start(); - // The simplest way to deal with input latency (when have access to the audio buffer) is to always be slightly ahead in the input - stretch.seek(inWav, stretch.inputLatency(), 1/time); - inWav.offset += stretch.inputLatency(); - // Process it all in one call, although it works just the same if we split into smaller blocks - processMemory = {}; - stretch.process(inWav, int(inputLength), outWav, int(outputLength)); - // Read the last bit of output without giving it any more input - outWav.offset += outputLength; - stretch.flush(outWav, tailSamples); - outWav.offset -= outputLength; - } - - double processSeconds = stopwatch.lap(); - double processRate = (inWav.length()/inWav.sampleRate)/processSeconds; - double processPercent = 100/processRate; - processMemory = processMemory.diff(); - std::cout << "Process:\n\t" << processSeconds << "s, " << processRate << "x realtime, " << processPercent << "% CPU\n"; - if (processMemory.implemented) { - std::cout << "\tallocated " << (processMemory.allocBytes/1000) << "kB, freed " << (processMemory.freeBytes/1000) << "kB\n"; - if (processMemory) args.errorExit("allocated during process()"); - } + /* Since the WAV helper allows sample access like `wav[c][index]`, we could just call: -#ifdef PROFILE_PLOT_CHUNKS - signalsmith::plot::Figure figure; - auto &plot = figure(0, 0).plot(400, 150); - plot.x.blank().label("step"); - plot.y.major(0, ""); - plot.title("computation time"); - auto &cumulativePlot = figure(1, 0).plot(150, 150); - cumulativePlot.x.major(processStopwatches.size(), ""); - cumulativePlot.y.major(0, ""); - cumulativePlot.title("cumulative"); - auto &line = plot.line().fillToY(0); - auto &extraLine = plot.line().fillToY(0); - auto &cumulativeLine = cumulativePlot.line(); - auto &flatLine = cumulativePlot.line(); - double cumulativeTime = 0; - line.add(0, 0); - cumulativeLine.add(0, 0); - for (size_t i = 0; i < processStopwatches.size(); ++i) { - double time = processStopwatches[i].total(); - if (i%5 == 0) { - plot.x.tick(i + 0.5, std::to_string(i)); - } else { - plot.x.tick(i + 0.5, ""); - } - line.add(i, time); - line.add(i + 1, time); + stretch.exact(inWav, int(inputLength), outWav, int(outputLength)); + + However, we'll do it in separate stages to demonstrate more of the API. + */ - cumulativeTime += time; - cumulativeLine.add(i, cumulativeTime); - cumulativeLine.add(i + 1, cumulativeTime); - } - line.add(processStopwatches.size(), 0); - extraLine.add(0, 0); - extraLine.add(0, processStopwatchStart.total()); - extraLine.add(1, processStopwatchStart.total()); - extraLine.add(1, 0); - extraLine.add(processStopwatches.size() - 1, 0); - extraLine.add(processStopwatches.size() - 1, processStopwatchEnd.total()); - extraLine.add(processStopwatches.size(), processStopwatchEnd.total()); - extraLine.add(processStopwatches.size(), 0); - flatLine.add(0, 0); - flatLine.add(processStopwatches.size(), cumulativeTime); - figure.write("profile.svg"); -#endif + stretch.exact(inWav, int(inputLength), outWav, int(outputLength)); if (!outWav.write(outputWav).warn()) args.errorExit("failed to write WAV"); - - if (compareReference && prevWav.result) { - outWav.read(outputWav); - if (prevWav.length() != outWav.length()) args.errorExit("lengths differ"); - double diff2 = 0; - for (size_t i = 0; i < prevWav.samples.size(); ++i) { - double diff = prevWav.samples[i] - outWav.samples[i]; - diff2 += diff*diff; - } - diff2 /= prevWav.samples.size(); - double diffDb = 10*std::log10(diff2); - std::cout << "Reference:\n\tdifference: "; - if (diff2 < 1e-6) { - std::cout << Console::Yellow; - } else if (diff2 < 1e-10) { - std::cout << Console::Green; - } else { - std::cout << Console::Red; - } - - std::cout << Console::Bright << diffDb << Console::Reset << " dB\n"; - if (diffDb > -60) args.errorExit("too much difference\n"); - } } diff --git a/cmd/util b/cmd/util new file mode 160000 index 0000000..aeb4e31 --- /dev/null +++ b/cmd/util @@ -0,0 +1 @@ +Subproject commit aeb4e31077a453566b58fff1c7e7e998ac824157 diff --git a/cmd/util/console-colours.h b/cmd/util/console-colours.h deleted file mode 100644 index 00b4319..0000000 --- a/cmd/util/console-colours.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#ifndef _CONSOLE_COLOURS_H -#define _CONSOLE_COLOURS_H - -#include - -namespace Console { - std::string Reset = "\x1b[0m"; - std::string Bright = "\x1b[1m"; - std::string Dim = "\x1b[2m"; - std::string Underscore = "\x1b[4m"; - std::string Blink = "\x1b[5m"; - std::string Reverse = "\x1b[7m"; - std::string Hidden = "\x1b[8m"; - - namespace Foreground { - std::string Black = "\x1b[30m"; - std::string Red = "\x1b[31m"; - std::string Green = "\x1b[32m"; - std::string Yellow = "\x1b[33m"; - std::string Blue = "\x1b[34m"; - std::string Magenta = "\x1b[35m"; - std::string Cyan = "\x1b[36m"; - std::string White = "\x1b[37m"; - } - - namespace Background { - std::string Black = "\x1b[40m"; - std::string Red = "\x1b[41m"; - std::string Green = "\x1b[42m"; - std::string Yellow = "\x1b[43m"; - std::string Blue = "\x1b[44m"; - std::string Magenta = "\x1b[45m"; - std::string Cyan = "\x1b[46m"; - std::string White = "\x1b[47m"; - } - - using namespace Foreground; -} - -#endif \ No newline at end of file diff --git a/cmd/util/memory-tracker.h b/cmd/util/memory-tracker.h deleted file mode 100644 index e246f5e..0000000 --- a/cmd/util/memory-tracker.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Currently only working/tested on Mac. You need to compile in `memory-tracker.cpp` as well, which does the actual stuff */ -#ifndef SIGNALSMITH_UTIL_MEMORY_TRACKER_H -#define SIGNALSMITH_UTIL_MEMORY_TRACKER_H - -#include - -namespace signalsmith { - -struct MemoryTracker { - static const bool implemented; // Whether the implementation actually tracks memory or not - - size_t allocBytes, freeBytes, currentBytes; - MemoryTracker(); - - MemoryTracker diff() const { - MemoryTracker now; - return {now.allocBytes - allocBytes, now.freeBytes - freeBytes}; - } - - // Is a `.diff()` result non-zero - operator bool() const { - return allocBytes > 0 || freeBytes > 0; - } -private: - MemoryTracker(size_t allocBytes, size_t freeBytes) : allocBytes(allocBytes), freeBytes(freeBytes), currentBytes(allocBytes - freeBytes) {} -}; - -} // namespace -#endif // include guard diff --git a/cmd/util/memory-tracker.hxx b/cmd/util/memory-tracker.hxx deleted file mode 100644 index 86c77b6..0000000 --- a/cmd/util/memory-tracker.hxx +++ /dev/null @@ -1,118 +0,0 @@ -#include "./memory-tracker.h" - -#if !defined(__has_include) || !__has_include() -// Fallback if we don't have , which we use to get the existing methods -signalsmith::MemoryTracker::MemoryTracker() : signalsmith::MemoryTracker::MemoryTracker(0, 0) {} -const bool signalsmith::MemoryTracker::implemented = false; -#else -const bool signalsmith::MemoryTracker::implemented = true; - -#include -#include -#include -#include -#include - -namespace signalsmith { - -namespace memory_tracker { - -static size_t memoryTrackerAllocCounter = 0; -static size_t memoryTrackerFreeCounter = 0; - -static void * (*originalCalloc)(size_t, size_t) = nullptr; -static void * (*originalMalloc)(size_t) = nullptr; -static void * (*originalRealloc)(void*, size_t) = nullptr; -static void (*originalFree)(void*) = nullptr; - -template -static void cacheOriginal(Fn& fn, const char *symbolName) { - if (!fn) { - fn = (Fn)dlsym(RTLD_NEXT, symbolName); - if (!fn) exit(1); - } -} - -template -auto callOriginal(Fn& fn, const char *symbolName, Args &&...args) - -> decltype(fn(std::forward(args)...)) { - cacheOriginal(fn, symbolName); - return fn(std::forward(args)...); -} - -static constexpr size_t extraInfoBytes = sizeof(std::max_align_t)*2; -void * storeAllocInfo(void *offsetPointer, void *originalPointer, size_t size) { - if (!originalPointer) return nullptr; - memoryTrackerAllocCounter += size; - - assert(!((size_t(offsetPointer))%sizeof(size_t))); // make sure it's aligned to size_t - size_t *sizePtr = (size_t *)offsetPointer; - sizePtr[-1] = size_t(originalPointer); - sizePtr[-2] = size; - return offsetPointer; -} -size_t getAllocSize(void *ptr) { - assert(!(size_t(ptr)%sizeof(size_t))); - size_t *sizePtr = (size_t *)ptr; - return sizePtr[-2]; -} -void * getAllocPointer(void *ptr) { - assert(!(size_t(ptr)%sizeof(size_t))); - size_t *sizePtr = (size_t *)ptr; - return (void *)sizePtr[-1]; -} - -}} // namespaces - -extern "C" { - void * malloc(size_t size) { - void *ptr = signalsmith::memory_tracker::callOriginal(signalsmith::memory_tracker::originalMalloc, "malloc", size + signalsmith::memory_tracker::extraInfoBytes); - return signalsmith::memory_tracker::storeAllocInfo((unsigned char *)ptr + signalsmith::memory_tracker::extraInfoBytes, ptr, size); - } - - void * calloc(size_t size, size_t count) { - size_t extraCount = (signalsmith::memory_tracker::extraInfoBytes + size - 1)/size; // enough extra items to store what we need - void *ptr = signalsmith::memory_tracker::callOriginal(signalsmith::memory_tracker::originalCalloc, "calloc", size, count + extraCount); - return signalsmith::memory_tracker::storeAllocInfo((unsigned char *)ptr + size*extraCount, ptr, size*count); - } - - void * realloc(void *ptr, size_t size) { - void *originalPtr = signalsmith::memory_tracker::getAllocPointer(ptr); - auto pointerOffset = (unsigned char *)ptr - (unsigned char *)originalPtr; - size_t originalSize = signalsmith::memory_tracker::getAllocSize(ptr); - signalsmith::memory_tracker::memoryTrackerFreeCounter += originalSize; - - ptr = signalsmith::memory_tracker::callOriginal(signalsmith::memory_tracker::originalRealloc, "realloc", originalPtr, size + pointerOffset); - return signalsmith::memory_tracker::storeAllocInfo((unsigned char *)ptr + pointerOffset, ptr, size); - } - - void free(void *ptr) { - void *originalPtr = signalsmith::memory_tracker::getAllocPointer(ptr); - size_t originalSize = signalsmith::memory_tracker::getAllocSize(ptr); - signalsmith::memory_tracker::memoryTrackerFreeCounter += originalSize; - - signalsmith::memory_tracker::callOriginal(signalsmith::memory_tracker::originalFree, "free", originalPtr); - } -} - -#include - -void * operator new(size_t size) { - return malloc(size); -} - -void * operator new[](size_t size) { - return malloc(size); -} - -void operator delete(void *ptr) noexcept { - free(ptr); -} - -void operator delete[](void *ptr) noexcept { - free(ptr); -} - -signalsmith::MemoryTracker::MemoryTracker() : signalsmith::MemoryTracker::MemoryTracker(signalsmith::memory_tracker::memoryTrackerAllocCounter, signalsmith::memory_tracker::memoryTrackerFreeCounter) {} - -#endif // check for diff --git a/cmd/util/simple-args.h b/cmd/util/simple-args.h deleted file mode 100644 index eb2d69a..0000000 --- a/cmd/util/simple-args.h +++ /dev/null @@ -1,322 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // exit() and codes - -#include "console-colours.h" - -/** Expected use: - - SimpleArgs args(argc, argv); - - // positional argument - std::string foo = args.arg("foo"); - // optional argument - std::string bar = args.arg("bar", "a string for Bar", "default"); - // --flag=value - double = args.flag("baz", "an optional flag", 5); - - // Exits if "foo" not supplied - args.errorExit(); - - If you have multiple commands, each with their own options: - - // Switches based on a command - if (args.command("bink", "Bink description")) { - // collect arguments for the command - } - // Exits with a help message (and list of commands) if no command matched - args.errorCommand(); - - By default, a flag of "-h" (or a command of "help", if any commands are used) prints a help message. To override: - SimpleArgs args(argc, argv); - args.helpFlag("h"); - args.helpCommand("help"); - -**/ -class SimpleArgs { - int argc; - const char* const* argv; - - template - T valueFromString(const char *arg); - - std::string parsedCommand; - struct Keywords { - std::string keyword; - std::string description; - bool isHelp; - }; - std::vector keywordOptions; - std::vector argDetails; - std::vector flagOptions; - std::set flagSet; - void clearKeywords() { - keywordOptions.resize(0); - flagSet.clear(); - flagOptions.clear(); - } - - bool helpMode = false; - bool checkedHelpCommand = false; - bool hasError = false; - std::string errorMessage; - void setError(std::string message) { - if (!hasError) { - hasError = true; - errorMessage = message; - } - } - - std::map flagMap; - void consumeFlags() { - while (index < argc && std::strlen(argv[index]) > 1 && argv[index][0] == '-') { - const char* arg = argv[index++]; - size_t length = strlen(arg); - - size_t keyStart = 1, keyEnd = keyStart + 1; - size_t valueStart = keyEnd; - // If it's "--long-arg" format - if (length > 1 && arg[1] == '-') { - keyStart++; - while (keyEnd < length && arg[keyEnd] != '=') { - keyEnd++; - } - valueStart = keyEnd; - if (keyEnd < length) valueStart++; - } - - std::string key = std::string(arg + keyStart, keyEnd - keyStart); - std::string value = std::string(arg + valueStart); - - if (key == "help") { - helpMode = true; - } - - flagMap[key] = value; - } - } - - int index = 1; -public: - SimpleArgs(int argc, const char* const argv[]) : argc(argc), argv(argv) { - std::string cmd = argv[0]; - size_t slashPos = cmd.find_last_of("\\/"); - if (slashPos != std::string::npos) cmd = cmd.substr(slashPos + 1); - parsedCommand = cmd; - } - - void help(std::ostream& out=std::cerr) const { - std::string parsedCommand = this->parsedCommand; - if (keywordOptions.size() > 0) { - parsedCommand += std::string(" "); - } - out << "Usage:\n\t" << parsedCommand << "\n\n"; - if (keywordOptions.size() > 0) { - out << "Commands:\n"; - for (unsigned int i = 0; i < keywordOptions.size(); i++) { - out << "\t" << keywordOptions[i].keyword; - if (keywordOptions[i].isHelp) out << " [command...]"; - if (keywordOptions[i].description.size()) out << " - " << keywordOptions[i].description; - out << "\n"; - } - out << "\n"; - } - if (argDetails.size() > 0) { - out << "Arguments:\n"; - for (Keywords const &arg : argDetails) { - out << "\t" << arg.keyword; - if (arg.description.size()) out << " - " << arg.description; - out << "\n"; - } - out << "\n"; - } - if (flagOptions.size() > 0) { - out << "Options: " << Console::Dim << "(--arg=value)" << Console::Reset << "\n"; - for (Keywords const &pair : flagOptions) { - out << "\t" << (pair.keyword.length() > 1 ? "--" : "-") << pair.keyword; - if (pair.description.size()) out << " - " << pair.description; - out << "\n"; - } - out << "\n"; - } - } - - bool isHelp() const { - return helpMode; - } - bool finished() const { - return index >= argc; - } - std::string peek() const { - return (index >= argc) ? "" : argv[index]; - } - - int errorExit(std::ostream& out=std::cerr) const { - if (hasError || helpMode) { - help(out); - if (!helpMode) { - out << Console::Red << errorMessage << Console::Reset << "\n"; - } - std::exit((!helpMode && hasError) ? EXIT_FAILURE : EXIT_SUCCESS); - } - return 0; - } - int errorExit(std::string forcedError, std::ostream& out=std::cerr) const { - if (hasError) return errorExit(out); // Argument errors take priority - out << Console::Red << forcedError << Console::Reset << "\n"; - std::exit(EXIT_FAILURE); - return 0; - } - int errorCommand(std::string message="", std::ostream& out=std::cerr) const { - if (keywordOptions.size()) { - // We expected a command, but didn't match on any - if (helpMode) return errorExit(out); - if (index >= argc) help(out); - if (message.length() == 0) { - message = (index < argc) ? std::string("Unknown command: ") + argv[index] : "Missing command"; - } - errorExit(message, out); - } - return 0; - } - - template - T arg(std::string name, std::string longName, T defaultValue) { - consumeFlags(); - if (index < argc) clearKeywords(); - parsedCommand += std::string(" [") + name + "]"; - argDetails.push_back(Keywords{name, longName, false}); - - if (index >= argc) return defaultValue; - return valueFromString(argv[index++]); - } - - template - T arg(std::string name, std::string longName="") { - consumeFlags(); - if (index < argc) clearKeywords(); - parsedCommand += std::string(" <") + name + ">"; - argDetails.push_back(Keywords{name, longName, false}); - - if (index >= argc) { - if (longName.length() > 0) { - setError("Missing " + longName + " <" + name + ">"); - } else { - setError("Missing argument <" + name + ">"); - } - return T(); - } - - return valueFromString(argv[index++]); - } - - bool command(std::string keyword, std::string description="", bool isHelp=false) { - consumeFlags(); - if (index == 1) { - helpCommand(); - } - if (index < argc && !keyword.compare(argv[index])) { - clearKeywords(); - index++; - if (!isHelp) parsedCommand += std::string(" ") + keyword; - return true; - } - keywordOptions.push_back(Keywords{keyword, description, isHelp}); - return false; - } - bool helpCommand(std::string keyword="help") { - if (!checkedHelpCommand && index == 1) { - keywordOptions.push_back(Keywords{keyword, "", true}); - if (index < argc && !keyword.compare(argv[index])) { - index++; - helpMode = true; - } - } - checkedHelpCommand = true; - return helpMode; - } - - template - T flag(std::string key, std::string description, T defaultValue) { - consumeFlags(); - if (!hasFlag(key, description)) return defaultValue; - - auto iterator = flagMap.find(key); - return valueFromString(iterator->second.c_str()); - } - template - T flag(std::string key, T defaultValue) { - consumeFlags(); - if (!hasFlag(key, "")) return defaultValue; - - auto iterator = flagMap.find(key); - return valueFromString(iterator->second.c_str()); - } - template - T flag(std::string key) { - return flag(key, T()); - } - bool hasFlag(std::string key, std::string description="") { - consumeFlags(); - auto iterator = flagSet.find(key); - if (iterator == flagSet.end()) { - flagSet.insert(key); - flagOptions.push_back(Keywords{key, description, false}); - } else if (description.length() > 0) { - bool found = false; - for (auto &option : flagOptions) { - if (option.keyword == key) { - option.description = description; - found = true; - break; - } - } - if (!found) { - flagOptions.push_back(Keywords{key, description, false}); - } - } - - auto mapIterator = flagMap.find(key); - return mapIterator != flagMap.end(); - } - bool helpFlag(std::string key, std::string description="shows this help") { - consumeFlags(); - hasFlag(key, description); - auto iterator = flagMap.find(key); - helpMode = (iterator != flagMap.end()); - return helpMode; - } -}; - -template<> -std::string SimpleArgs::valueFromString(const char *arg) { - return arg; -} -template<> -const char * SimpleArgs::valueFromString(const char *arg) { - return arg; -} -template<> -int SimpleArgs::valueFromString(const char *arg) { - return std::stoi(arg); -} -template<> -long SimpleArgs::valueFromString(const char *arg) { - return std::stol(arg); -} -template<> -unsigned long SimpleArgs::valueFromString(const char *arg) { - return std::stoul(arg); -} -template<> -float SimpleArgs::valueFromString(const char *arg) { - return std::stof(arg); -} -template<> -double SimpleArgs::valueFromString(const char *arg) { - return std::stod(arg); -} diff --git a/cmd/util/stop-denormals.h b/cmd/util/stop-denormals.h deleted file mode 100644 index c9a7bb5..0000000 --- a/cmd/util/stop-denormals.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#if defined(__SSE__) || defined(_M_X64) - class StopDenormals { - unsigned int controlStatusRegister; - public: - StopDenormals() : controlStatusRegister(_mm_getcsr()) { - _mm_setcsr(controlStatusRegister|0x8040); // Flush-to-Zero and Denormals-Are-Zero - } - ~StopDenormals() { - _mm_setcsr(controlStatusRegister); - } - }; -#elif (defined (__ARM_NEON) || defined (__ARM_NEON__)) - class StopDenormals { - uintptr_t status; - public: - StopDenormals() { - uintptr_t asmStatus; - asm volatile("mrs %0, fpcr" : "=r"(asmStatus)); - status = asmStatus = asmStatus|0x01000000U; // Flush to Zero - asm volatile("msr fpcr, %0" : : "ri"(asmStatus)); - } - ~StopDenormals() { - uintptr_t asmStatus = status; - asm volatile("msr fpcr, %0" : : "ri"(asmStatus)); - } - }; -#else -# if __cplusplus >= 202302L -# warning "The `StopDenormals` class doesn't do anything for this architecture" -# endif - class StopDenormals {}; // FIXME: add for other architectures -#endif diff --git a/cmd/util/stopwatch.h b/cmd/util/stopwatch.h deleted file mode 100644 index 72c4130..0000000 --- a/cmd/util/stopwatch.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef SIGNALSMITH_STOPWATCH_UTIL_H -#define SIGNALSMITH_STOPWATCH_UTIL_H - -#include -#include -#include -#include - -#ifdef WINDOWS // completely untested! -# include -namespace signalsmith { -class Stopwatch { - using Time = __int64; - using Duration = Time; - inline Time now() { - LARGE_INTEGER result; - QueryPerformanceCounter(&result); - return result.QuadPart; - } - static double toSeconds(Duration t) { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - return t/double(freq); - } -#else -# include -namespace signalsmith { -class Stopwatch { - using Clock = std::conditional::type; - using Time = Clock::time_point; - using Duration = std::chrono::duration; - - inline Time now() { - return Clock::now(); - } - static double toSeconds(Duration duration) { - return duration.count(); - } -#endif - - std::atomic