From b702fb5e8a1a95f5d8f961687b1ce1aa440c3fbe Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Tue, 14 Nov 2017 05:08:40 -0500 Subject: [PATCH 01/17] Hide metadata when mouse leaves ModelItem --- src/app/AddModuleWindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/AddModuleWindow.cpp b/src/app/AddModuleWindow.cpp index 5b2a22ac..523e9539 100644 --- a/src/app/AddModuleWindow.cpp +++ b/src/app/AddModuleWindow.cpp @@ -120,6 +120,10 @@ struct ModelItem : MenuItem { sModel = model; MenuItem::onMouseEnter(e); } + void onMouseLeave(EventMouseLeave &e) override { + sModel = NULL; + MenuItem::onMouseLeave(e); + } }; @@ -283,7 +287,6 @@ AddModuleWindow::AddModuleWindow() { // NVGcolor c = bndTransparent(nvgRGB(0, 0, 0)); NVGcolor c = bndGetTheme()->nodeTheme.nodeBackdropColor; - printf("%f %f %f %f\n", c.r, c.g, c.b, c.a); } From e76f3c8392d4f97b9c846ab3b2d5e7044e82d856 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Tue, 14 Nov 2017 07:50:48 -0500 Subject: [PATCH 02/17] Call onZoom event when DPI is changed --- src/gui.cpp | 7 ++++++- src/widgets/FramebufferWidget.cpp | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui.cpp b/src/gui.cpp index a5351fa2..0f2883d6 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -422,7 +422,12 @@ void guiRun() { glfwGetFramebufferSize(gWindow, &width, &height); int windowWidth, windowHeight; glfwGetWindowSize(gWindow, &windowWidth, &windowHeight); - gPixelRatio = (float)width / windowWidth; + float pixelRatio = (float)width / windowWidth; + if (pixelRatio != gPixelRatio) { + EventZoom eZoom; + gScene->onZoom(eZoom); + gPixelRatio = pixelRatio; + } // Step scene gScene->step(); diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index 651914dd..749940d1 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -122,6 +122,7 @@ int FramebufferWidget::getImageHandle() { void FramebufferWidget::onZoom(EventZoom &e) { dirty = true; + Widget::onZoom(e); } From 45f03be664c99398d180ca6222375af4747a9cf4 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 15 Nov 2017 01:12:16 -0500 Subject: [PATCH 03/17] Set manufacturer on click instead of on hover for AddModuleWindow --- src/app/AddModuleWindow.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app/AddModuleWindow.cpp b/src/app/AddModuleWindow.cpp index 523e9539..50e3c834 100644 --- a/src/app/AddModuleWindow.cpp +++ b/src/app/AddModuleWindow.cpp @@ -172,11 +172,8 @@ struct ModelMenu : ListMenu { struct ManufacturerItem : MenuItem { Model *model; void onAction(EventAction &e) override { - e.consumed = false; - } - void onMouseEnter(EventMouseEnter &e) override { sManufacturer = text; - MenuItem::onMouseEnter(e); + e.consumed = false; } }; From d24bed83e2f8904a8f403b80b578462adbdc32f2 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 01:00:47 -0500 Subject: [PATCH 04/17] Print version at boot --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 689e5da1..9948650a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,10 @@ using namespace rack; int main(int argc, char* argv[]) { randomSeedTime(); + if (!gApplicationVersion.empty()) { + printf("Rack v%s\n", gApplicationVersion.c_str()); + } + { char *cwd = getcwd(NULL, 0); printf("Current working directory: %s\n", cwd); From b10d1122bb9eba3be55b30ece1fec8709fdbf1b1 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 01:56:05 -0500 Subject: [PATCH 05/17] Added log() logger with INFO, WARN, and ERROR levels --- include/util.hpp | 14 ++++++++++ src/app/RackWidget.cpp | 4 +-- src/core/AudioInterface.cpp | 12 ++++----- src/core/MidiIO.cpp | 16 +++++------ src/gui.cpp | 16 +++++------ src/main.cpp | 18 ++++++++++--- src/plugin.cpp | 14 +++++----- src/settings.cpp | 6 ++--- src/util.cpp | 44 ++++++++++++++++++++++++++----- src/util/request.cpp | 5 ++-- src/widgets/FramebufferWidget.cpp | 2 +- src/widgets/SpriteWidget.cpp | 2 +- src/widgets/TransformWidget.cpp | 1 - 13 files changed, 105 insertions(+), 49 deletions(-) diff --git a/include/util.hpp b/include/util.hpp index 3b4a319f..63078c35 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -58,6 +58,7 @@ T *construct(F f, V v, Args... args) { // RNG //////////////////// +/** Seeds the RNG with the current time */ void randomSeedTime(); uint32_t randomu32(); uint64_t randomu64(); @@ -126,5 +127,18 @@ struct VIPLock { } }; +//////////////////// +// logger +//////////////////// + +enum LogLevel { + INFO, + WARN, + ERROR, +}; + +extern FILE *gLogFile; +void log(LogLevel level, const char *format, ...); + } // namespace rack diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 9d3c975a..9c6659e4 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -83,7 +83,7 @@ void RackWidget::saveAsDialog() { void RackWidget::savePatch(std::string path) { - printf("Saving patch %s\n", path.c_str()); + log(INFO, "Saving patch %s", path.c_str()); FILE *file = fopen(path.c_str(), "w"); if (!file) return; @@ -98,7 +98,7 @@ void RackWidget::savePatch(std::string path) { } void RackWidget::loadPatch(std::string path) { - printf("Loading patch %s\n", path.c_str()); + log(INFO, "Loading patch %s", path.c_str()); FILE *file = fopen(path.c_str(), "r"); if (!file) { // Exit silently diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 21e5c16e..e037c1ab 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -17,7 +17,7 @@ void audioInit() { PaError err = Pa_Initialize(); if (err) { - fprintf(stderr, "Failed to initialize PortAudio: %s\n", Pa_GetErrorText(err)); + log(WARN, "Failed to initialize PortAudio: %s", Pa_GetErrorText(err)); return; } initialized = true; @@ -244,7 +244,7 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { PaError err; const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId); if (!deviceInfo) { - fprintf(stderr, "Failed to query audio device\n"); + log(WARN, "Failed to query audio device"); return; } @@ -271,13 +271,13 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { numOutputs == 0 ? NULL : &outputParameters, sampleRate, blockSize, paNoFlag, paCallback, this); if (err) { - fprintf(stderr, "Failed to open audio stream: %s\n", Pa_GetErrorText(err)); + log(WARN, "Failed to open audio stream: %s", Pa_GetErrorText(err)); return; } err = Pa_StartStream(stream); if (err) { - fprintf(stderr, "Failed to start audio stream: %s\n", Pa_GetErrorText(err)); + log(WARN, "Failed to start audio stream: %s", Pa_GetErrorText(err)); return; } // This should go after Pa_StartStream because sometimes it will call the callback once synchronously, and that time it should return early @@ -299,12 +299,12 @@ void AudioInterface::closeDevice() { err = Pa_AbortStream(stream); // err = Pa_StopStream(stream); if (err) { - fprintf(stderr, "Failed to stop audio stream: %s\n", Pa_GetErrorText(err)); + log(WARN, "Failed to stop audio stream: %s", Pa_GetErrorText(err)); } err = Pa_CloseStream(stream); if (err) { - fprintf(stderr, "Failed to close audio stream: %s\n", Pa_GetErrorText(err)); + log(WARN, "Failed to close audio stream: %s", Pa_GetErrorText(err)); } } diff --git a/src/core/MidiIO.cpp b/src/core/MidiIO.cpp index 816e3110..d9e2f461 100644 --- a/src/core/MidiIO.cpp +++ b/src/core/MidiIO.cpp @@ -17,9 +17,9 @@ MidiIO::MidiIO(bool isOut) { channel = -1; this->isOut = isOut; - if (isOut) { - fprintf(stderr, "Midi Out is currently not supported (will be added soon)"); - } + // TODO + // Support MIDI out + assert(!isOut); }; void MidiIO::setChannel(int channel) { @@ -60,7 +60,7 @@ std::vector MidiIO::getDevices() { try { m = new RtMidiIn(); } catch (RtMidiError &error) { - fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); + log(WARN, "Failed to create RtMidiIn: %s", error.getMessage().c_str()); return names; } @@ -96,14 +96,14 @@ void MidiIO::openDevice(std::string deviceName) { } if (!mw->isPortOpen()) { - fprintf(stderr, "Failed to create RtMidiIn: No such device %s\n", deviceName.c_str()); + log(WARN, "Failed to create RtMidiIn: No such device %s", deviceName.c_str()); this->deviceName = ""; this->id = -1; return; } } catch (RtMidiError &error) { - fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); + log(WARN, "Failed to create RtMidiIn: %s", error.getMessage().c_str()); this->deviceName = ""; this->id = -1; return; @@ -144,7 +144,7 @@ double MidiIO::getMessage(std::vector *msg) { MidiInWrapper *mw = midiInMap[deviceName]; if (!mw) { - fprintf(stderr, "Device not opened!: %s\n", deviceName.c_str()); + log(WARN, "Device not opened!: %s", deviceName.c_str()); return 0; } @@ -176,7 +176,7 @@ void MidiIO::close() { MidiInWrapper *mw = midiInMap[deviceName]; if (!mw || id < 0) { - //fprintf(stderr, "Trying to close already closed device!\n"); + //log(WARN, "Trying to close already closed device!"); return; } diff --git a/src/gui.cpp b/src/gui.cpp index 0f2883d6..3407b5b2 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -279,7 +279,7 @@ void dropCallback(GLFWwindow *window, int count, const char **paths) { } void errorCallback(int error, const char *description) { - fprintf(stderr, "GLFW error %d: %s\n", error, description); + log(WARN, "GLFW error %d: %s", error, description); } void renderGui() { @@ -446,7 +446,7 @@ void guiRun() { std::this_thread::sleep_for(std::chrono::duration(minTime - frameTime)); } endTime = glfwGetTime(); - // printf("%lf fps\n", 1.0 / (endTime - startTime)); + // log(INFO, "%lf fps", 1.0 / (endTime - startTime)); } } @@ -519,10 +519,10 @@ bool guiIsMaximized() { Font::Font(const std::string &filename) { handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str()); if (handle >= 0) { - fprintf(stderr, "Loaded font %s\n", filename.c_str()); + log(INFO, "Loaded font %s", filename.c_str()); } else { - fprintf(stderr, "Failed to load font %s\n", filename.c_str()); + log(WARN, "Failed to load font %s", filename.c_str()); } } @@ -545,10 +545,10 @@ std::shared_ptr Font::load(const std::string &filename) { Image::Image(const std::string &filename) { handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); if (handle > 0) { - fprintf(stderr, "Loaded image %s\n", filename.c_str()); + log(INFO, "Loaded image %s", filename.c_str()); } else { - fprintf(stderr, "Failed to load image %s\n", filename.c_str()); + log(WARN, "Failed to load image %s", filename.c_str()); } } @@ -572,10 +572,10 @@ std::shared_ptr Image::load(const std::string &filename) { SVG::SVG(const std::string &filename) { handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI); if (handle) { - fprintf(stderr, "Loaded SVG %s\n", filename.c_str()); + log(INFO, "Loaded SVG %s", filename.c_str()); } else { - fprintf(stderr, "Failed to load SVG %s\n", filename.c_str()); + log(WARN, "Failed to load SVG %s", filename.c_str()); } } diff --git a/src/main.cpp b/src/main.cpp index 9948650a..50ba7cc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,18 +12,23 @@ using namespace rack; int main(int argc, char* argv[]) { randomSeedTime(); +#ifdef VERSION + std::string logFilename = assetLocal("log.txt"); + gLogFile = fopen(logFilename.c_str()); +#endif + if (!gApplicationVersion.empty()) { - printf("Rack v%s\n", gApplicationVersion.c_str()); + log(INFO, "Rack v%s", gApplicationVersion.c_str()); } { char *cwd = getcwd(NULL, 0); - printf("Current working directory: %s\n", cwd); + log(INFO, "Current working directory: %s", cwd); free(cwd); std::string globalDir = assetGlobal(""); std::string localDir = assetLocal(""); - printf("Global directory: %s\n", globalDir.c_str()); - printf("Local directory: %s\n", localDir.c_str()); + log(INFO, "Global directory: %s", globalDir.c_str()); + log(INFO, "Local directory: %s", localDir.c_str()); } pluginInit(); @@ -49,5 +54,10 @@ int main(int argc, char* argv[]) { guiDestroy(); engineDestroy(); pluginDestroy(); + +#ifdef VERSION + fclose(gLogFile); +#endif + return 0; } diff --git a/src/plugin.cpp b/src/plugin.cpp index c30f54de..dca0b639 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -112,13 +112,13 @@ static int loadPlugin(std::string path) { HINSTANCE handle = LoadLibrary(libraryFilename.c_str()); if (!handle) { int error = GetLastError(); - fprintf(stderr, "Failed to load library %s: %d\n", libraryFilename.c_str(), error); + log(WARN, "Failed to load library %s: %d", libraryFilename.c_str(), error); return -1; } #elif ARCH_LIN || ARCH_MAC void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW); if (!handle) { - fprintf(stderr, "Failed to load library %s: %s\n", libraryFilename.c_str(), dlerror()); + log(WARN, "Failed to load library %s: %s", libraryFilename.c_str(), dlerror()); return -1; } #endif @@ -132,7 +132,7 @@ static int loadPlugin(std::string path) { initCallback = (InitCallback) dlsym(handle, "init"); #endif if (!initCallback) { - fprintf(stderr, "Failed to read init() symbol in %s\n", libraryFilename.c_str()); + log(WARN, "Failed to read init() symbol in %s", libraryFilename.c_str()); return -2; } @@ -144,7 +144,7 @@ static int loadPlugin(std::string path) { // Add plugin to list gPlugins.push_back(plugin); - fprintf(stderr, "Loaded plugin %s\n", libraryFilename.c_str()); + log(INFO, "Loaded plugin %s", libraryFilename.c_str()); return 0; } @@ -277,14 +277,14 @@ void pluginInit() { // Load plugins from global directory std::string globalPlugins = assetGlobal("plugins"); - printf("Loading plugins from %s\n", globalPlugins.c_str()); + log(INFO, "Loading plugins from %s", globalPlugins.c_str()); loadPlugins(globalPlugins); // Load plugins from local directory std::string localPlugins = assetLocal("plugins"); if (globalPlugins != localPlugins) { mkdir(localPlugins.c_str(), 0755); - printf("Loading plugins from %s\n", localPlugins.c_str()); + log(INFO, "Loading plugins from %s", localPlugins.c_str()); loadPlugins(localPlugins); } } @@ -353,7 +353,7 @@ void pluginRefresh() { json_t *errorJ = json_object_get(resJ, "error"); if (errorJ) { const char *errorStr = json_string_value(errorJ); - fprintf(stderr, "Plugin refresh error: %s\n", errorStr); + log(WARN, "Plugin refresh error: %s", errorStr); } else { json_t *purchasesJ = json_object_get(resJ, "purchases"); diff --git a/src/settings.cpp b/src/settings.cpp index 86e2875a..cadad252 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -127,7 +127,7 @@ static void settingsFromJson(json_t *rootJ) { void settingsSave(std::string filename) { - printf("Saving settings %s\n", filename.c_str()); + log(INFO, "Saving settings %s", filename.c_str()); FILE *file = fopen(filename.c_str(), "w"); if (!file) return; @@ -142,7 +142,7 @@ void settingsSave(std::string filename) { } void settingsLoad(std::string filename) { - printf("Loading settings %s\n", filename.c_str()); + log(INFO, "Loading settings %s", filename.c_str()); FILE *file = fopen(filename.c_str(), "r"); if (!file) return; @@ -154,7 +154,7 @@ void settingsLoad(std::string filename) { json_decref(rootJ); } else { - printf("JSON parsing error at %s %d:%d %s\n", error.source, error.line, error.column, error.text); + log(WARN, "JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); } fclose(file); diff --git a/src/util.cpp b/src/util.cpp index c7af0887..74567237 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,5 +1,4 @@ #include "util.hpp" -#include #include #include #include @@ -15,6 +14,10 @@ namespace rack { +//////////////////// +// RNG +//////////////////// + // xoroshiro128+ // from http://xoroshiro.di.unimi.it/xoroshiro128plus.c @@ -36,11 +39,6 @@ static uint64_t xoroshiro128plus_next(void) { return result; } -static std::random_device rd; -static std::mt19937 rng(rd()); -static std::normal_distribution normalDist; - - void randomSeedTime() { struct timeval tv; gettimeofday(&tv, NULL); @@ -80,6 +78,9 @@ float randomNormal() { // return (sum - n / 2.f) / sqrtf(n / 12.f); } +//////////////////// +// String functions +//////////////////// std::string stringf(const char *format, ...) { va_list args; @@ -136,6 +137,10 @@ std::string extractExtension(std::string path) { return ext + 1; } +//////////////////// +// Operating system functions +//////////////////// + void openBrowser(std::string url) { #if ARCH_LIN std::string command = "xdg-open " + url; @@ -150,5 +155,32 @@ void openBrowser(std::string url) { #endif } +//////////////////// +// logger +//////////////////// + +FILE *gLogFile = stderr; + +void log(LogLevel level, const char *format, ...) { + va_list args; + va_start(args, format); + switch (level) { + case INFO: + fprintf(gLogFile, "[info] "); + break; + case WARN: + fprintf(gLogFile, "[warning] "); + break; + case ERROR: + fprintf(gLogFile, "[error] "); + break; + default: + break; + } + vfprintf(gLogFile, format, args); + fprintf(gLogFile, "\n"); + va_end(args); +} + } // namespace rack diff --git a/src/util/request.cpp b/src/util/request.cpp index 001eabf3..f620bdbc 100644 --- a/src/util/request.cpp +++ b/src/util/request.cpp @@ -1,4 +1,5 @@ #include "util/request.hpp" +#include "util.hpp" #include #include #include @@ -82,7 +83,7 @@ json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ) { curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resText); // Perform request - printf("Requesting %s\n", url.c_str()); + log(INFO, "Requesting %s", url.c_str()); // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); CURLcode res = curl_easy_perform(curl); @@ -130,7 +131,7 @@ bool requestDownload(std::string url, std::string filename, float *progress) { curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferInfoCallback); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, progress); - printf("Downloading %s\n", url.c_str()); + log(INFO, "Downloading %s", url.c_str()); CURLcode res = curl_easy_perform(curl); curl_easy_cleanup(curl); diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index 749940d1..52f9d0ac 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -64,7 +64,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { if (fbSize.isZero()) return; - // printf("rendering framebuffer %f %f\n", fbSize.x, fbSize.y); + // log(INFO, "rendering framebuffer %f %f", fbSize.x, fbSize.y); // Delete old one first to free up GPU memory internal->setFramebuffer(NULL); // Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context. diff --git a/src/widgets/SpriteWidget.cpp b/src/widgets/SpriteWidget.cpp index 9d1367b5..aafd3b55 100644 --- a/src/widgets/SpriteWidget.cpp +++ b/src/widgets/SpriteWidget.cpp @@ -8,7 +8,7 @@ void SpriteWidget::draw(NVGcontext *vg) { nvgImageSize(vg, spriteImage->handle, &width, &height); int stride = width / spriteSize.x; if (stride == 0) { - printf("Size of SpriteWidget is %d, %d but spriteSize is %f, %f\n", width, height, spriteSize.x, spriteSize.y); + log(WARN, "Size of SpriteWidget is %d, %d but spriteSize is %f, %f", width, height, spriteSize.x, spriteSize.y); return; } Vec offset = Vec((index % stride) * spriteSize.x, (index / stride) * spriteSize.y); diff --git a/src/widgets/TransformWidget.cpp b/src/widgets/TransformWidget.cpp index 87b3c5c0..269514a8 100644 --- a/src/widgets/TransformWidget.cpp +++ b/src/widgets/TransformWidget.cpp @@ -14,7 +14,6 @@ Rect TransformWidget::getChildrenBoundingBox() { Vec bottomRight = bound.getBottomRight(); nvgTransformPoint(&topLeft.x, &topLeft.y, transform, topLeft.x, topLeft.y); nvgTransformPoint(&bottomRight.x, &bottomRight.y, transform, bottomRight.x, bottomRight.y); - printf("%f\n", 42.1); return Rect(topLeft, bottomRight.minus(topLeft)); } From acb1eb60924319008fc76905897c0c846a3bc2a2 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 03:09:02 -0500 Subject: [PATCH 06/17] Add file mode to log.txt file --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 50ba7cc2..4ccf6ed7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ int main(int argc, char* argv[]) { #ifdef VERSION std::string logFilename = assetLocal("log.txt"); - gLogFile = fopen(logFilename.c_str()); + gLogFile = fopen(logFilename.c_str(), "w"); #endif if (!gApplicationVersion.empty()) { From 85c75eef3322daa96ee4dd73d7407ea486d7e050 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 04:05:02 -0500 Subject: [PATCH 07/17] Changed log() to info(), warn(), and fatal() --- include/util.hpp | 10 +++------ src/app/RackWidget.cpp | 4 ++-- src/core/AudioInterface.cpp | 12 +++++------ src/core/MidiIO.cpp | 10 ++++----- src/gui.cpp | 16 +++++++-------- src/main.cpp | 8 ++++---- src/plugin.cpp | 14 ++++++------- src/settings.cpp | 6 +++--- src/util.cpp | 34 ++++++++++++++++++------------- src/util/request.cpp | 4 ++-- src/widgets/FramebufferWidget.cpp | 2 +- src/widgets/SpriteWidget.cpp | 2 +- 12 files changed, 62 insertions(+), 60 deletions(-) diff --git a/include/util.hpp b/include/util.hpp index 63078c35..cb6dc007 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -131,14 +131,10 @@ struct VIPLock { // logger //////////////////// -enum LogLevel { - INFO, - WARN, - ERROR, -}; - extern FILE *gLogFile; -void log(LogLevel level, const char *format, ...); +void info(const char *format, ...); +void warn(const char *format, ...); +void fatal(const char *format, ...); } // namespace rack diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 9c6659e4..f8301de5 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -83,7 +83,7 @@ void RackWidget::saveAsDialog() { void RackWidget::savePatch(std::string path) { - log(INFO, "Saving patch %s", path.c_str()); + info("Saving patch %s", path.c_str()); FILE *file = fopen(path.c_str(), "w"); if (!file) return; @@ -98,7 +98,7 @@ void RackWidget::savePatch(std::string path) { } void RackWidget::loadPatch(std::string path) { - log(INFO, "Loading patch %s", path.c_str()); + info("Loading patch %s", path.c_str()); FILE *file = fopen(path.c_str(), "r"); if (!file) { // Exit silently diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index e037c1ab..7860d82a 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -17,7 +17,7 @@ void audioInit() { PaError err = Pa_Initialize(); if (err) { - log(WARN, "Failed to initialize PortAudio: %s", Pa_GetErrorText(err)); + warn("Failed to initialize PortAudio: %s", Pa_GetErrorText(err)); return; } initialized = true; @@ -244,7 +244,7 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { PaError err; const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId); if (!deviceInfo) { - log(WARN, "Failed to query audio device"); + warn("Failed to query audio device"); return; } @@ -271,13 +271,13 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { numOutputs == 0 ? NULL : &outputParameters, sampleRate, blockSize, paNoFlag, paCallback, this); if (err) { - log(WARN, "Failed to open audio stream: %s", Pa_GetErrorText(err)); + warn("Failed to open audio stream: %s", Pa_GetErrorText(err)); return; } err = Pa_StartStream(stream); if (err) { - log(WARN, "Failed to start audio stream: %s", Pa_GetErrorText(err)); + warn("Failed to start audio stream: %s", Pa_GetErrorText(err)); return; } // This should go after Pa_StartStream because sometimes it will call the callback once synchronously, and that time it should return early @@ -299,12 +299,12 @@ void AudioInterface::closeDevice() { err = Pa_AbortStream(stream); // err = Pa_StopStream(stream); if (err) { - log(WARN, "Failed to stop audio stream: %s", Pa_GetErrorText(err)); + warn("Failed to stop audio stream: %s", Pa_GetErrorText(err)); } err = Pa_CloseStream(stream); if (err) { - log(WARN, "Failed to close audio stream: %s", Pa_GetErrorText(err)); + warn("Failed to close audio stream: %s", Pa_GetErrorText(err)); } } diff --git a/src/core/MidiIO.cpp b/src/core/MidiIO.cpp index d9e2f461..2ca166ee 100644 --- a/src/core/MidiIO.cpp +++ b/src/core/MidiIO.cpp @@ -60,7 +60,7 @@ std::vector MidiIO::getDevices() { try { m = new RtMidiIn(); } catch (RtMidiError &error) { - log(WARN, "Failed to create RtMidiIn: %s", error.getMessage().c_str()); + warn("Failed to create RtMidiIn: %s", error.getMessage().c_str()); return names; } @@ -96,14 +96,14 @@ void MidiIO::openDevice(std::string deviceName) { } if (!mw->isPortOpen()) { - log(WARN, "Failed to create RtMidiIn: No such device %s", deviceName.c_str()); + warn("Failed to create RtMidiIn: No such device %s", deviceName.c_str()); this->deviceName = ""; this->id = -1; return; } } catch (RtMidiError &error) { - log(WARN, "Failed to create RtMidiIn: %s", error.getMessage().c_str()); + warn("Failed to create RtMidiIn: %s", error.getMessage().c_str()); this->deviceName = ""; this->id = -1; return; @@ -144,7 +144,7 @@ double MidiIO::getMessage(std::vector *msg) { MidiInWrapper *mw = midiInMap[deviceName]; if (!mw) { - log(WARN, "Device not opened!: %s", deviceName.c_str()); + warn("Device not opened!: %s", deviceName.c_str()); return 0; } @@ -176,7 +176,7 @@ void MidiIO::close() { MidiInWrapper *mw = midiInMap[deviceName]; if (!mw || id < 0) { - //log(WARN, "Trying to close already closed device!"); + //warn("Trying to close already closed device!"); return; } diff --git a/src/gui.cpp b/src/gui.cpp index 3407b5b2..af9632fd 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -279,7 +279,7 @@ void dropCallback(GLFWwindow *window, int count, const char **paths) { } void errorCallback(int error, const char *description) { - log(WARN, "GLFW error %d: %s", error, description); + warn("GLFW error %d: %s", error, description); } void renderGui() { @@ -446,7 +446,7 @@ void guiRun() { std::this_thread::sleep_for(std::chrono::duration(minTime - frameTime)); } endTime = glfwGetTime(); - // log(INFO, "%lf fps", 1.0 / (endTime - startTime)); + // info("%lf fps", 1.0 / (endTime - startTime)); } } @@ -519,10 +519,10 @@ bool guiIsMaximized() { Font::Font(const std::string &filename) { handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str()); if (handle >= 0) { - log(INFO, "Loaded font %s", filename.c_str()); + info("Loaded font %s", filename.c_str()); } else { - log(WARN, "Failed to load font %s", filename.c_str()); + warn("Failed to load font %s", filename.c_str()); } } @@ -545,10 +545,10 @@ std::shared_ptr Font::load(const std::string &filename) { Image::Image(const std::string &filename) { handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); if (handle > 0) { - log(INFO, "Loaded image %s", filename.c_str()); + info("Loaded image %s", filename.c_str()); } else { - log(WARN, "Failed to load image %s", filename.c_str()); + warn("Failed to load image %s", filename.c_str()); } } @@ -572,10 +572,10 @@ std::shared_ptr Image::load(const std::string &filename) { SVG::SVG(const std::string &filename) { handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI); if (handle) { - log(INFO, "Loaded SVG %s", filename.c_str()); + info("Loaded SVG %s", filename.c_str()); } else { - log(WARN, "Failed to load SVG %s", filename.c_str()); + warn("Failed to load SVG %s", filename.c_str()); } } diff --git a/src/main.cpp b/src/main.cpp index 4ccf6ed7..d8a45214 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,17 +18,17 @@ int main(int argc, char* argv[]) { #endif if (!gApplicationVersion.empty()) { - log(INFO, "Rack v%s", gApplicationVersion.c_str()); + info("Rack v%s", gApplicationVersion.c_str()); } { char *cwd = getcwd(NULL, 0); - log(INFO, "Current working directory: %s", cwd); + info("Current working directory: %s", cwd); free(cwd); std::string globalDir = assetGlobal(""); std::string localDir = assetLocal(""); - log(INFO, "Global directory: %s", globalDir.c_str()); - log(INFO, "Local directory: %s", localDir.c_str()); + info("Global directory: %s", globalDir.c_str()); + info("Local directory: %s", localDir.c_str()); } pluginInit(); diff --git a/src/plugin.cpp b/src/plugin.cpp index dca0b639..1c1a56f4 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -112,13 +112,13 @@ static int loadPlugin(std::string path) { HINSTANCE handle = LoadLibrary(libraryFilename.c_str()); if (!handle) { int error = GetLastError(); - log(WARN, "Failed to load library %s: %d", libraryFilename.c_str(), error); + warn("Failed to load library %s: %d", libraryFilename.c_str(), error); return -1; } #elif ARCH_LIN || ARCH_MAC void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW); if (!handle) { - log(WARN, "Failed to load library %s: %s", libraryFilename.c_str(), dlerror()); + warn("Failed to load library %s: %s", libraryFilename.c_str(), dlerror()); return -1; } #endif @@ -132,7 +132,7 @@ static int loadPlugin(std::string path) { initCallback = (InitCallback) dlsym(handle, "init"); #endif if (!initCallback) { - log(WARN, "Failed to read init() symbol in %s", libraryFilename.c_str()); + warn("Failed to read init() symbol in %s", libraryFilename.c_str()); return -2; } @@ -144,7 +144,7 @@ static int loadPlugin(std::string path) { // Add plugin to list gPlugins.push_back(plugin); - log(INFO, "Loaded plugin %s", libraryFilename.c_str()); + info("Loaded plugin %s", libraryFilename.c_str()); return 0; } @@ -277,14 +277,14 @@ void pluginInit() { // Load plugins from global directory std::string globalPlugins = assetGlobal("plugins"); - log(INFO, "Loading plugins from %s", globalPlugins.c_str()); + info("Loading plugins from %s", globalPlugins.c_str()); loadPlugins(globalPlugins); // Load plugins from local directory std::string localPlugins = assetLocal("plugins"); if (globalPlugins != localPlugins) { mkdir(localPlugins.c_str(), 0755); - log(INFO, "Loading plugins from %s", localPlugins.c_str()); + info("Loading plugins from %s", localPlugins.c_str()); loadPlugins(localPlugins); } } @@ -353,7 +353,7 @@ void pluginRefresh() { json_t *errorJ = json_object_get(resJ, "error"); if (errorJ) { const char *errorStr = json_string_value(errorJ); - log(WARN, "Plugin refresh error: %s", errorStr); + warn("Plugin refresh error: %s", errorStr); } else { json_t *purchasesJ = json_object_get(resJ, "purchases"); diff --git a/src/settings.cpp b/src/settings.cpp index cadad252..4425e076 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -127,7 +127,7 @@ static void settingsFromJson(json_t *rootJ) { void settingsSave(std::string filename) { - log(INFO, "Saving settings %s", filename.c_str()); + info("Saving settings %s", filename.c_str()); FILE *file = fopen(filename.c_str(), "w"); if (!file) return; @@ -142,7 +142,7 @@ void settingsSave(std::string filename) { } void settingsLoad(std::string filename) { - log(INFO, "Loading settings %s", filename.c_str()); + info("Loading settings %s", filename.c_str()); FILE *file = fopen(filename.c_str(), "r"); if (!file) return; @@ -154,7 +154,7 @@ void settingsLoad(std::string filename) { json_decref(rootJ); } else { - log(WARN, "JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); + warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); } fclose(file); diff --git a/src/util.cpp b/src/util.cpp index 74567237..8412b3d8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -161,22 +161,28 @@ void openBrowser(std::string url) { FILE *gLogFile = stderr; -void log(LogLevel level, const char *format, ...) { +void info(const char *format, ...) { va_list args; va_start(args, format); - switch (level) { - case INFO: - fprintf(gLogFile, "[info] "); - break; - case WARN: - fprintf(gLogFile, "[warning] "); - break; - case ERROR: - fprintf(gLogFile, "[error] "); - break; - default: - break; - } + fprintf(gLogFile, "[info] "); + vfprintf(gLogFile, format, args); + fprintf(gLogFile, "\n"); + va_end(args); +} + +void warn(const char *format, ...) { + va_list args; + va_start(args, format); + fprintf(gLogFile, "[warn] "); + vfprintf(gLogFile, format, args); + fprintf(gLogFile, "\n"); + va_end(args); +} + +void fatal(const char *format, ...) { + va_list args; + va_start(args, format); + fprintf(gLogFile, "[fatal] "); vfprintf(gLogFile, format, args); fprintf(gLogFile, "\n"); va_end(args); diff --git a/src/util/request.cpp b/src/util/request.cpp index f620bdbc..1bb0e507 100644 --- a/src/util/request.cpp +++ b/src/util/request.cpp @@ -83,7 +83,7 @@ json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ) { curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resText); // Perform request - log(INFO, "Requesting %s", url.c_str()); + info("Requesting %s", url.c_str()); // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); CURLcode res = curl_easy_perform(curl); @@ -131,7 +131,7 @@ bool requestDownload(std::string url, std::string filename, float *progress) { curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferInfoCallback); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, progress); - log(INFO, "Downloading %s", url.c_str()); + info("Downloading %s", url.c_str()); CURLcode res = curl_easy_perform(curl); curl_easy_cleanup(curl); diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index 52f9d0ac..72a6930e 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -64,7 +64,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { if (fbSize.isZero()) return; - // log(INFO, "rendering framebuffer %f %f", fbSize.x, fbSize.y); + // info("rendering framebuffer %f %f", fbSize.x, fbSize.y); // Delete old one first to free up GPU memory internal->setFramebuffer(NULL); // Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context. diff --git a/src/widgets/SpriteWidget.cpp b/src/widgets/SpriteWidget.cpp index aafd3b55..c0cfc02e 100644 --- a/src/widgets/SpriteWidget.cpp +++ b/src/widgets/SpriteWidget.cpp @@ -8,7 +8,7 @@ void SpriteWidget::draw(NVGcontext *vg) { nvgImageSize(vg, spriteImage->handle, &width, &height); int stride = width / spriteSize.x; if (stride == 0) { - log(WARN, "Size of SpriteWidget is %d, %d but spriteSize is %f, %f", width, height, spriteSize.x, spriteSize.y); + warn("Size of SpriteWidget is %d, %d but spriteSize is %f, %f", width, height, spriteSize.x, spriteSize.y); return; } Vec offset = Vec((index % stride) * spriteSize.x, (index / stride) * spriteSize.y); From 7b697b1487bcc95533fac2d76eaa888151b4986b Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 04:33:36 -0500 Subject: [PATCH 08/17] Update dist license for new libraries --- LICENSE-dist.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/LICENSE-dist.txt b/LICENSE-dist.txt index 5769d523..62b28280 100644 --- a/LICENSE-dist.txt +++ b/LICENSE-dist.txt @@ -193,13 +193,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# portmidi +# RtMidi -Copyright (c) 1999-2000 Ross Bencina and Phil Burk -Copyright (c) 2001-2009 Roger B. Dannenberg +RtMidi: realtime MIDI i/o C++ classes +Copyright (c) 2003-2017 Gary P. Scavone -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, @@ -209,6 +209,9 @@ subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +Any person wishing to distribute modifications to the Software is asked to send the modifications to the original developer so that they can be incorporated into the canonical version. This is, +however, not a binding provision of this license. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. From e5ba0db78af3c1f04359509eec251d80d76d99f8 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 04:34:29 -0500 Subject: [PATCH 09/17] Escape download link --- include/util/request.hpp | 1 + src/plugin.cpp | 4 ++-- src/util/request.cpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/util/request.hpp b/include/util/request.hpp index 2626cdda..d0405155 100644 --- a/include/util/request.hpp +++ b/include/util/request.hpp @@ -18,5 +18,6 @@ enum RequestMethod { json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ); /** Returns the filename, blank if unsuccessful */ bool requestDownload(std::string url, std::string filename, float *progress); +std::string requestEscape(std::string s); } // namespace rack diff --git a/src/plugin.cpp b/src/plugin.cpp index 1c1a56f4..a2be13bf 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -237,9 +237,9 @@ static void refreshPurchase(json_t *pluginJ) { url += "?product="; url += slug; url += "&version="; - url += gApplicationVersion; + url += requestEscape(gApplicationVersion); url += "&token="; - url += gToken; + url += requestEscape(gToken); // If plugin is not loaded, download the zip file to /plugins downloadName = name; diff --git a/src/util/request.cpp b/src/util/request.cpp index 1bb0e507..c046bbb7 100644 --- a/src/util/request.cpp +++ b/src/util/request.cpp @@ -143,5 +143,15 @@ bool requestDownload(std::string url, std::string filename, float *progress) { return res == CURLE_OK; } +std::string requestEscape(std::string s) { + CURL *curl = curl_easy_init(); + assert(curl); + char *escaped = curl_easy_escape(curl, s.c_str(), s.size()); + std::string ret = escaped; + curl_free(escaped); + curl_easy_cleanup(curl); + return ret; +} + } // namespace rack From 4d10ad6c32340f6e46f352516f8a2bc2a8dc0ee3 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 04:48:08 -0500 Subject: [PATCH 10/17] Add debug() to the logger --- include/util.hpp | 1 + src/util.cpp | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/util.hpp b/include/util.hpp index cb6dc007..f7e4732a 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -132,6 +132,7 @@ struct VIPLock { //////////////////// extern FILE *gLogFile; +void debug(const char *format, ...); void info(const char *format, ...); void warn(const char *format, ...); void fatal(const char *format, ...); diff --git a/src/util.cpp b/src/util.cpp index 8412b3d8..e01c10a9 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -161,6 +161,15 @@ void openBrowser(std::string url) { FILE *gLogFile = stderr; +void debug(const char *format, ...) { + va_list args; + va_start(args, format); + fprintf(gLogFile, "[debug] "); + vfprintf(gLogFile, format, args); + fprintf(gLogFile, "\n"); + va_end(args); +} + void info(const char *format, ...) { va_list args; va_start(args, format); @@ -173,7 +182,7 @@ void info(const char *format, ...) { void warn(const char *format, ...) { va_list args; va_start(args, format); - fprintf(gLogFile, "[warn] "); + fprintf(gLogFile, "[warning] "); vfprintf(gLogFile, format, args); fprintf(gLogFile, "\n"); va_end(args); From 33e8973bf17ff35f014118dae1bd158a7785956f Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 04:54:35 -0500 Subject: [PATCH 11/17] Ignore mkdir() error when directory already exists --- src/plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin.cpp b/src/plugin.cpp index a2be13bf..ad7a868c 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -179,7 +179,7 @@ static int extractZipHandle(zip_t *za, const char *dir) { if (zs.name[nameLen - 1] == '/') { err = mkdir(path, 0755); - if (err) + if (err && errno != EEXIST) return err; } else { From 3c7043fbb5fc614e35d3ebac079121149ba1230c Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 17:34:38 -0500 Subject: [PATCH 12/17] Made git checkout instructions more clear --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f77abe1..ddcaaf42 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ With your distro's package manager, make sure you have installed `gcc`, `make`, *If the build fails for you, please report the issue with a detailed error message to help the portability of Rack.* -Clone this repository and `cd` into it. +Clone this repository with `git clone https://github.com/VCVRack/Rack.git` and `cd Rack`. If you would like to build a previous version of Rack instead of the master branch, check out the desired tag with `git checkout v0.4.0` for example. Clone submodules. From cbc9a523ff8ebcf43ba1a075c3489c918cb15c73 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 17:50:52 -0500 Subject: [PATCH 13/17] Add manufacturer label in model list --- src/app/AddModuleWindow.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/app/AddModuleWindow.cpp b/src/app/AddModuleWindow.cpp index 50e3c834..5e6bf541 100644 --- a/src/app/AddModuleWindow.cpp +++ b/src/app/AddModuleWindow.cpp @@ -48,37 +48,37 @@ struct MetadataMenu : ListMenu { void step() override { if (model != sModel) { + model = sModel; clearChildren(); - if (sModel) { + if (model) { // Tag list - if (!sModel->tags.empty()) { - for (ModelTag tag : sModel->tags) { + if (!model->tags.empty()) { + for (ModelTag tag : model->tags) { addChild(construct(&MenuEntry::text, gTagNames[tag])); } addChild(construct()); } // Plugin name - std::string pluginName = sModel->plugin->slug; - if (!sModel->plugin->version.empty()) { + std::string pluginName = model->plugin->slug; + if (!model->plugin->version.empty()) { pluginName += " v"; - pluginName += sModel->plugin->version; + pluginName += model->plugin->version; } addChild(construct(&MenuEntry::text, pluginName)); // Plugin metadata - if (!sModel->plugin->website.empty()) { - addChild(construct(&MenuEntry::text, "Website", &UrlItem::url, sModel->plugin->path)); + if (!model->plugin->website.empty()) { + addChild(construct(&MenuEntry::text, "Website", &UrlItem::url, model->plugin->path)); } - if (!sModel->plugin->manual.empty()) { - addChild(construct(&MenuEntry::text, "Manual", &UrlItem::url, sModel->plugin->manual)); + if (!model->plugin->manual.empty()) { + addChild(construct(&MenuEntry::text, "Manual", &UrlItem::url, model->plugin->manual)); } - if (!sModel->plugin->path.empty()) { - addChild(construct(&MenuEntry::text, "Browse directory", &UrlItem::url, sModel->plugin->path)); + if (!model->plugin->path.empty()) { + addChild(construct(&MenuEntry::text, "Browse directory", &UrlItem::url, model->plugin->path)); } } - model = sModel; } ListMenu::step(); @@ -133,20 +133,22 @@ struct ModelMenu : ListMenu { void step() override { if (manufacturer != sManufacturer) { + manufacturer = sManufacturer; + filter = ""; clearChildren(); + addChild(construct(&MenuLabel::text, manufacturer)); // Add models for the selected manufacturer for (Plugin *plugin : gPlugins) { for (Model *model : plugin->models) { - if (model->manufacturer == sManufacturer) { + if (model->manufacturer == manufacturer) { addChild(construct(&MenuEntry::text, model->name, &ModelItem::model, model)); } } } - manufacturer = sManufacturer; - filter = ""; } if (filter != sFilter) { + filter = sFilter; // Make all children invisible for (Widget *child : children) { child->visible = false; @@ -157,11 +159,10 @@ struct ModelMenu : ListMenu { if (!item) continue; - if (isModelMatch(item->model, sFilter)) { + if (isModelMatch(item->model, filter)) { item->visible = true; } } - filter = sFilter; } ListMenu::step(); From 70bb8c7759438b097536cccee28b0ded41828a95 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 20:45:32 -0500 Subject: [PATCH 14/17] Add plug lights, remove plug light toggling --- include/app.hpp | 54 +++++++++++++++++++---------------- include/components.hpp | 30 +++++++++---------- include/engine.hpp | 24 +++++++++------- include/rack.hpp | 4 +-- src/app/ColorLightWidget.cpp | 27 ------------------ src/app/ModuleLightWidget.cpp | 22 ++++++++++++++ src/app/MultiLightWidget.cpp | 24 ++++++++++++++++ src/app/Port.cpp | 32 +++++++++++++++++++++ src/app/Toolbar.cpp | 10 ------- src/app/WireWidget.cpp | 39 ++++++++++--------------- src/engine.cpp | 19 +++++++++++- src/settings.cpp | 9 ------ 12 files changed, 171 insertions(+), 123 deletions(-) delete mode 100644 src/app/ColorLightWidget.cpp create mode 100644 src/app/ModuleLightWidget.cpp create mode 100644 src/app/MultiLightWidget.cpp diff --git a/include/app.hpp b/include/app.hpp index 0790a2d3..5acb6bef 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -277,6 +277,33 @@ struct MomentarySwitch : virtual Switch { } }; +//////////////////// +// lights +//////////////////// + +struct LightWidget : TransparentWidget { + NVGcolor bgColor = nvgRGBf(0, 0, 0); + NVGcolor color = nvgRGBf(1, 1, 1); + void draw(NVGcontext *vg) override; +}; + +/** Mixes a list of colors based on a list of brightness values */ +struct MultiLightWidget : LightWidget { + std::vector baseColors; + void addBaseColor(NVGcolor baseColor); + /** Sets the color to a linear combination of the baseColors with the given weights */ + void setValues(const std::vector &values); +}; + +/** A MultiLightWidget that points to a module's Light or a range of lights +Will access firstLightId, firstLightId + 1, etc. for each added color +*/ +struct ModuleLightWidget : MultiLightWidget { + Module *module = NULL; + int firstLightId; + void step() override; +}; + //////////////////// // ports //////////////////// @@ -290,8 +317,11 @@ struct Port : OpaqueWidget { Module *module = NULL; PortType type = INPUT; int portId; + MultiLightWidget *plugLight; + Port(); ~Port(); + void step() override; void draw(NVGcontext *vg) override; void onMouseDown(EventMouseDown &e) override; void onDragStart(EventDragStart &e) override; @@ -315,29 +345,6 @@ struct SVGScrew : FramebufferWidget { SVGScrew(); }; -//////////////////// -// lights -//////////////////// - -struct LightWidget : TransparentWidget { - NVGcolor bgColor = nvgRGBf(0, 0, 0); - NVGcolor color = nvgRGBf(1, 1, 1); - void draw(NVGcontext *vg) override; -}; - -/** A LightWidget that points to a module's Light or a range of lights */ -struct ModuleLightWidget : LightWidget { - Module *module = NULL; - int lightId; -}; - -/** Mixes colors based on the brightness of the module light at lightId, lightId + 1, etc */ -struct ColorLightWidget : ModuleLightWidget { - std::vector colors; - void addColor(NVGcolor c); - void step() override; -}; - //////////////////// // scene //////////////////// @@ -347,7 +354,6 @@ struct Toolbar : OpaqueWidget { Slider *wireTensionSlider; Slider *zoomSlider; RadioButton *cpuUsageButton; - RadioButton *plugLightButton; Toolbar(); void draw(NVGcontext *vg) override; diff --git a/include/components.hpp b/include/components.hpp index 40849dff..c300e44b 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -368,43 +368,43 @@ struct CL1362Port : SVGPort { // Lights //////////////////// -struct RedLight : ColorLightWidget { +struct RedLight : ModuleLightWidget { RedLight() { - addColor(COLOR_RED); + addBaseColor(COLOR_RED); } }; -struct GreenLight : ColorLightWidget { +struct GreenLight : ModuleLightWidget { GreenLight() { - addColor(COLOR_GREEN); + addBaseColor(COLOR_GREEN); } }; -struct YellowLight : ColorLightWidget { +struct YellowLight : ModuleLightWidget { YellowLight() { - addColor(COLOR_YELLOW); + addBaseColor(COLOR_YELLOW); } }; -struct BlueLight : ColorLightWidget { +struct BlueLight : ModuleLightWidget { BlueLight() { - addColor(COLOR_BLUE); + addBaseColor(COLOR_BLUE); } }; /** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */ -struct GreenRedLight : ColorLightWidget { +struct GreenRedLight : ModuleLightWidget { GreenRedLight() { - addColor(COLOR_GREEN); - addColor(COLOR_RED); + addBaseColor(COLOR_GREEN); + addBaseColor(COLOR_RED); } }; -struct RedGreenBlueLight : ColorLightWidget { +struct RedGreenBlueLight : ModuleLightWidget { RedGreenBlueLight() { - addColor(COLOR_RED); - addColor(COLOR_GREEN); - addColor(COLOR_BLUE); + addBaseColor(COLOR_RED); + addBaseColor(COLOR_GREEN); + addBaseColor(COLOR_BLUE); } }; diff --git a/include/engine.hpp b/include/engine.hpp index 2f0bc546..ad3cf9e5 100644 --- a/include/engine.hpp +++ b/include/engine.hpp @@ -11,11 +11,22 @@ struct Param { float value = 0.0; }; +struct Light { + /** The square of the brightness value */ + float value = 0.0; + float getBrightness(); + void setBrightness(float brightness) { + value = brightness * brightness; + } + void setBrightnessSmooth(float brightness); +}; + struct Input { /** Voltage of the port, zero if not plugged in. Read-only by Module */ float value = 0.0; /** Whether a wire is plugged in */ bool active = false; + Light plugLights[2]; /** Returns the value if a wire is plugged in, otherwise returns the given default value */ float normalize(float normalValue) { return active ? value : normalValue; @@ -27,16 +38,7 @@ struct Output { float value = 0.0; /** Whether a wire is plugged in */ bool active = false; -}; - -struct Light { - /** The square of the brightness value */ - float value = 0.0; - float getBrightness(); - void setBrightness(float brightness) { - value = brightness * brightness; - } - void setBrightnessSmooth(float brightness); + Light plugLights[2]; }; @@ -49,7 +51,7 @@ struct Module { float cpuTime = 0.0; /** Deprecated, use constructor below this one */ - Module() {} + Module() DEPRECATED {} /** Constructs Module with a fixed number of params, inputs, and outputs */ Module(int numParams, int numInputs, int numOutputs, int numLights = 0) { params.resize(numParams); diff --git a/include/rack.hpp b/include/rack.hpp index 5d45a5e5..b4371009 100644 --- a/include/rack.hpp +++ b/include/rack.hpp @@ -74,11 +74,11 @@ Port *createOutput(Vec pos, Module *module, int outputId) { } template -ModuleLightWidget *createLight(Vec pos, Module *module, int lightId) { +ModuleLightWidget *createLight(Vec pos, Module *module, int firstLightId) { ModuleLightWidget *light = new TModuleLightWidget(); light->box.pos = pos; light->module = module; - light->lightId = lightId; + light->firstLightId = firstLightId; return light; } diff --git a/src/app/ColorLightWidget.cpp b/src/app/ColorLightWidget.cpp deleted file mode 100644 index 125373b2..00000000 --- a/src/app/ColorLightWidget.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "app.hpp" -#include "engine.hpp" - - -namespace rack { - - -void ColorLightWidget::addColor(NVGcolor c) { - colors.push_back(c); -} - -void ColorLightWidget::step() { - assert(module); - assert(module->lights.size() >= lightId + colors.size()); - color = nvgRGBf(0, 0, 0); - for (int i = 0; i < (int)colors.size(); i++) { - NVGcolor c = colors[i]; - float brightness = module->lights[lightId + i].getBrightness(); - brightness = clampf(brightness, 0.0, 1.0); - color.r += c.r * brightness; - color.g += c.g * brightness; - color.b += c.b * brightness; - } -} - - -} // namespace rack diff --git a/src/app/ModuleLightWidget.cpp b/src/app/ModuleLightWidget.cpp new file mode 100644 index 00000000..02296a0d --- /dev/null +++ b/src/app/ModuleLightWidget.cpp @@ -0,0 +1,22 @@ +#include "app.hpp" +#include "engine.hpp" + + +namespace rack { + + +void ModuleLightWidget::step() { + assert(module); + assert(module->lights.size() >= firstLightId + baseColors.size()); + std::vector values(baseColors.size()); + + for (size_t i = 0; i < baseColors.size(); i++) { + float value = module->lights[firstLightId + i].getBrightness(); + value = clampf(value, 0.0, 1.0); + values[i] = value; + } + setValues(values); +} + + +} // namespace rack diff --git a/src/app/MultiLightWidget.cpp b/src/app/MultiLightWidget.cpp new file mode 100644 index 00000000..eb9ceb1f --- /dev/null +++ b/src/app/MultiLightWidget.cpp @@ -0,0 +1,24 @@ +#include "app.hpp" + + +namespace rack { + + +void MultiLightWidget::addBaseColor(NVGcolor baseColor) { + baseColors.push_back(baseColor); +} + +void MultiLightWidget::setValues(const std::vector &values) { + assert(values.size() == baseColors.size()); + color = nvgRGBf(0, 0, 0); + for (size_t i = 0; i < baseColors.size(); i++) { + NVGcolor c = baseColors[i]; + float value = values[i]; + color.r += c.r * value; + color.g += c.g * value; + color.b += c.b * value; + } +} + + +} // namespace rack diff --git a/src/app/Port.cpp b/src/app/Port.cpp index 0f1e5ae0..af1cdb43 100644 --- a/src/app/Port.cpp +++ b/src/app/Port.cpp @@ -1,13 +1,45 @@ #include "app.hpp" #include "gui.hpp" +#include "components.hpp" +#include "engine.hpp" namespace rack { + +struct PlugLight : MultiLightWidget { + PlugLight() { + addBaseColor(COLOR_GREEN); + addBaseColor(COLOR_RED); + box.size = Vec(8, 8); + bgColor = COLOR_BLACK_TRANSPARENT; + } +}; + + +Port::Port() { + plugLight = new PlugLight(); +} + Port::~Port() { + // plugLight is not a child and is thus owned by the Port, so we need to delete it here + delete plugLight; gRackWidget->wireContainer->removeAllWires(this); } +void Port::step() { + std::vector values(2); + if (type == INPUT) { + values[0] = module->inputs[portId].plugLights[0].getBrightness(); + values[1] = module->inputs[portId].plugLights[1].getBrightness(); + } + else { + values[0] = module->outputs[portId].plugLights[0].getBrightness(); + values[1] = module->outputs[portId].plugLights[1].getBrightness(); + } + plugLight->setValues(values); +} + void Port::draw(NVGcontext *vg) { WireWidget *activeWire = gRackWidget->wireContainer->activeWire; if (activeWire) { diff --git a/src/app/Toolbar.cpp b/src/app/Toolbar.cpp index 15138ea3..cde1221b 100644 --- a/src/app/Toolbar.cpp +++ b/src/app/Toolbar.cpp @@ -166,16 +166,6 @@ Toolbar::Toolbar() { } xPos += margin; - { - plugLightButton = new RadioButton(); - plugLightButton->box.pos = Vec(xPos, margin); - plugLightButton->box.size.x = 100; - plugLightButton->label = "Plug lights"; - addChild(plugLightButton); - xPos += plugLightButton->box.size.x; - } - xPos += margin; - /* { cpuUsageButton = new RadioButton(); diff --git a/src/app/WireWidget.cpp b/src/app/WireWidget.cpp index 1908f5ac..07d16226 100644 --- a/src/app/WireWidget.cpp +++ b/src/app/WireWidget.cpp @@ -155,7 +155,9 @@ void WireWidget::draw(NVGcontext *vg) { if (!(inputPort && outputPort)) opacity = 1.0; - drawWire(vg, getOutputPos(), getInputPos(), color, tension, opacity); + Vec outputPos = getOutputPos(); + Vec inputPos = getInputPos(); + drawWire(vg, outputPos, inputPos, color, tension, opacity); } void WireWidget::drawPlugs(NVGcontext *vg) { @@ -166,31 +168,20 @@ void WireWidget::drawPlugs(NVGcontext *vg) { drawPlug(vg, inputPos, color); // Draw plug light - /* - if (gToolbar->plugLightButton->value > 0.0) { - if (wire) { - Output &output = wire->outputModule->outputs[wire->outputId]; - float value = output.value / 8.0; - outputLight->box.size = Vec(10, 10); - inputLight->box.size = Vec(10, 10); - outputLight->box.pos = outputPos.minus(Vec(5, 5)); - inputLight->box.pos = inputPos.minus(Vec(5, 5)); - outputLight->setValue(value); - inputLight->setValue(value); - } - else { - outputLight->setValue(0.0); - inputLight->setValue(0.0); - } - outputLight->visible = true; - inputLight->visible = true; + // TODO + // Only draw this when light is on top of the plug stack + if (outputPort) { + nvgSave(vg); + nvgTranslate(vg, outputPos.x - 4, outputPos.y - 4); + outputPort->plugLight->draw(vg); + nvgRestore(vg); } - else { - outputLight->visible = false; - inputLight->visible = false; + if (inputPort) { + nvgSave(vg); + nvgTranslate(vg, inputPos.x - 4, inputPos.y - 4); + inputPort->plugLight->draw(vg); + nvgRestore(vg); } - */ - Widget::draw(vg); } diff --git a/src/engine.cpp b/src/engine.cpp index 2e8f984e..d7097e4b 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -39,7 +39,7 @@ float Light::getBrightness() { } void Light::setBrightnessSmooth(float brightness) { - float v = brightness * brightness; + float v = (brightness > 0.0) ? brightness * brightness : 0.0; if (v < value) { // Fade out light with lambda = 2 * framerate value += (v - value) * sampleTime * (60.0 * 2.0); @@ -87,6 +87,23 @@ static void engineStep() { // Step modules for (Module *module : modules) { module->step(); + + // TODO skip this step when plug lights are disabled + // Step ports + for (Input &input : module->inputs) { + if (input.active) { + float value = input.value / 10.0; + input.plugLights[0].setBrightnessSmooth(value); + input.plugLights[1].setBrightnessSmooth(-value); + } + } + for (Output &output : module->outputs) { + if (output.active) { + float value = output.value / 10.0; + output.plugLights[0].setBrightnessSmooth(value); + output.plugLights[1].setBrightnessSmooth(-value); + } + } } // Step cables by moving their output values to inputs diff --git a/src/settings.cpp b/src/settings.cpp index 4425e076..1020f192 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -52,10 +52,6 @@ static json_t *settingsToJson() { json_t *sampleRateJ = json_real(engineGetSampleRate()); json_object_set_new(rootJ, "sampleRate", sampleRateJ); - // plugLight - json_t *plugLightJ = json_boolean(gToolbar->plugLightButton->value > 0.0); - json_object_set_new(rootJ, "plugLight", plugLightJ); - // lastPath json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str()); json_object_set_new(rootJ, "lastPath", lastPathJ); @@ -114,11 +110,6 @@ static void settingsFromJson(json_t *rootJ) { engineSetSampleRate(sampleRate); } - // plugLight - json_t *plugLightJ = json_object_get(rootJ, "plugLight"); - if (plugLightJ) - gToolbar->plugLightButton->setValue(json_is_true(plugLightJ) ? 1.0 : 0.0); - // lastPath json_t *lastPathJ = json_object_get(rootJ, "lastPath"); if (lastPathJ) From 215f9675954e02162ae35a8f429c84adace33ac7 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 16 Nov 2017 20:52:24 -0500 Subject: [PATCH 15/17] Allow Ctrl-dragging input, although it doesn't do anything different from normal dragging --- src/app/Port.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/app/Port.cpp b/src/app/Port.cpp index af1cdb43..8d7b3cbb 100644 --- a/src/app/Port.cpp +++ b/src/app/Port.cpp @@ -65,11 +65,8 @@ void Port::onMouseDown(EventMouseDown &e) { void Port::onDragStart(EventDragStart &e) { // Try to grab wire on top of stack WireWidget *wire = gRackWidget->wireContainer->getTopWire(this); - if (guiIsModPressed()) { - if (type == INPUT) - return; - else - wire = NULL; + if (type == OUTPUT && guiIsModPressed()) { + wire = NULL; } if (wire) { From e4f18e7c0cc42556caca708577585b60db860b26 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 17 Nov 2017 06:14:54 -0500 Subject: [PATCH 16/17] Migrate to RtAudio from portaudio --- Makefile | 2 +- dep/Makefile | 27 ++----- src/core/AudioInterface.cpp | 143 +++++++++++++++++------------------- 3 files changed, 75 insertions(+), 97 deletions(-) diff --git a/Makefile b/Makefile index 73cd890b..1e991132 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ ifeq ($(ARCH), lin) LDFLAGS += -rdynamic \ -lpthread -lGL -ldl \ $(shell pkg-config --libs gtk+-2.0) \ - -Ldep/lib -lGLEW -lglfw -ljansson -lsamplerate -lcurl -lzip -lportaudio -lrtmidi + -Ldep/lib -lGLEW -lglfw -ljansson -lsamplerate -lcurl -lzip -lrtaudio -lrtmidi TARGET = Rack endif diff --git a/dep/Makefile b/dep/Makefile index 184d29e3..ce4c9286 100755 --- a/dep/Makefile +++ b/dep/Makefile @@ -30,7 +30,7 @@ ifeq ($(ARCH),lin) libcurl = lib/libcurl.so libzip = lib/libzip.so rtmidi = lib/librtmidi.so - portaudio = lib/libportaudio.so + rtaudio = lib/librtaudio.so endif ifeq ($(ARCH),mac) @@ -41,7 +41,6 @@ ifeq ($(ARCH),mac) libcurl = lib/libcurl.dylib libzip = lib/libzip.dylib rtmidi = lib/librtmidi.dylib - portaudio = lib/libportaudio.dylib endif ifeq ($(ARCH),win) @@ -52,13 +51,12 @@ ifeq ($(ARCH),win) libcurl = bin/libcurl-4.dll libzip = bin/libzip-5.dll rtmidi = bin/librtmidi-4.dll - portaudio = bin/portaudio_x64.dll endif .NOTPARALLEL: -all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(portaudio) +all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) @echo "" @echo "#######################################" @echo "# Built all dependencies successfully #" @@ -122,21 +120,12 @@ $(rtmidi): $(MAKE) -C rtmidi-3.0.0 $(MAKE) -C rtmidi-3.0.0 install -$(portaudio): -ifeq ($(ARCH),win) - $(WGET) https://github.com/adfernandes/precompiled-portaudio-windows/raw/master/portaudio-r1891-build.zip - $(UNZIP) portaudio-r1891-build.zip - mv portaudio-r1891-build portaudio - cp portaudio/lib/x64/ReleaseMinDependency/portaudio_x64.lib "$(LOCAL)/lib" - cp portaudio/lib/x64/ReleaseMinDependency/portaudio_x64.dll "$(LOCAL)/bin" - cp portaudio/include/*.h "$(LOCAL)/include" -else - $(WGET) http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz - $(UNTAR) pa_stable_v190600_20161030.tgz - cd portaudio && ./configure --prefix="$(LOCAL)" --disable-debug --disable-dependency-tracking --enable-mac-universal=no - $(MAKE) -C portaudio - $(MAKE) -C portaudio install -endif +$(rtaudio): + $(WGET) http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-5.0.0.tar.gz + $(UNTAR) rtaudio-5.0.0.tar.gz + cd rtaudio-5.0.0 && ./configure --prefix="$(LOCAL)" + $(MAKE) -C rtaudio-5.0.0 + $(MAKE) -C rtaudio-5.0.0 install clean: git clean -ffdxi diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 7860d82a..81c0e5a7 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -1,27 +1,18 @@ #include #include #include -#include #include "core.hpp" #include "dsp/samplerate.hpp" #include "dsp/ringbuffer.hpp" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsuggest-override" +#include +#pragma GCC diagnostic pop -using namespace rack; - -static bool initialized = false; -void audioInit() { - if (initialized) - return; - PaError err = Pa_Initialize(); - if (err) { - warn("Failed to initialize PortAudio: %s", Pa_GetErrorText(err)); - return; - } - initialized = true; -} +using namespace rack; struct AudioInterface : Module { @@ -37,7 +28,7 @@ struct AudioInterface : Module { NUM_OUTPUTS = AUDIO1_OUTPUT + 8 }; - PaStream *stream = NULL; + RtAudio stream; // Stream properties int deviceId = -1; float sampleRate = 44100.0; @@ -58,9 +49,7 @@ struct AudioInterface : Module { // in device's sample rate DoubleRingBuffer, (1<<15)> inputSrcBuffer; - AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { - audioInit(); - } + AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} ~AudioInterface() { closeDevice(); } @@ -125,9 +114,6 @@ struct AudioInterface : Module { void AudioInterface::step() { - if (!stream) - return; - // Read/write stream if we have enough input, OR the output buffer is empty if we have no input if (numOutputs > 0) { while (inputSrcBuffer.size() >= blockSize && streamRunning) { @@ -215,21 +201,28 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames } int AudioInterface::getDeviceCount() { - return Pa_GetDeviceCount(); + return stream.getDeviceCount(); } std::string AudioInterface::getDeviceName(int deviceId) { - const PaDeviceInfo *info = Pa_GetDeviceInfo(deviceId); - if (!info) + if (deviceId < 0) return ""; - const PaHostApiInfo *apiInfo = Pa_GetHostApiInfo(info->hostApi); - return stringf("%s: %s (%d in, %d out)", apiInfo->name, info->name, info->maxInputChannels, info->maxOutputChannels); + + try { + RtAudio::DeviceInfo deviceInfo = stream.getDeviceInfo(deviceId); + return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels); + } + catch (RtAudioError &e) { + warn("Failed to query audio device: %s", e.what()); + return ""; + } } -static int paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { - AudioInterface *p = (AudioInterface *) userData; - p->stepStream((const float *) inputBuffer, (float *) outputBuffer, framesPerBuffer); - return paContinue; +static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) { + AudioInterface *audioInterface = (AudioInterface *) userData; + assert(audioInterface); + audioInterface->stepStream((const float *) inputBuffer, (float *) outputBuffer, nFrames); + return 0; } void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { @@ -241,51 +234,52 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { // Open new device if (deviceId >= 0) { - PaError err; - const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId); - if (!deviceInfo) { - warn("Failed to query audio device"); + RtAudio::DeviceInfo deviceInfo; + try { + deviceInfo = stream.getDeviceInfo(deviceId); + } + catch (RtAudioError &e) { + warn("Failed to query audio device: %s", e.what()); return; } - numOutputs = mini(deviceInfo->maxOutputChannels, 8); - numInputs = mini(deviceInfo->maxInputChannels, 8); - - PaStreamParameters outputParameters; - outputParameters.device = deviceId; - outputParameters.channelCount = numOutputs; - outputParameters.sampleFormat = paFloat32; - outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - - PaStreamParameters inputParameters; - inputParameters.device = deviceId; - inputParameters.channelCount = numInputs; - inputParameters.sampleFormat = paFloat32; - inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency; - inputParameters.hostApiSpecificStreamInfo = NULL; - - // Don't use stream parameters if 0 input or output channels - err = Pa_OpenStream(&stream, - numInputs == 0 ? NULL : &inputParameters, - numOutputs == 0 ? NULL : &outputParameters, - sampleRate, blockSize, paNoFlag, paCallback, this); - if (err) { - warn("Failed to open audio stream: %s", Pa_GetErrorText(err)); + numOutputs = mini(deviceInfo.outputChannels, 8); + numInputs = mini(deviceInfo.inputChannels, 8); + + RtAudio::StreamParameters outParameters; + outParameters.deviceId = deviceId; + outParameters.nChannels = numOutputs; + + RtAudio::StreamParameters inParameters; + inParameters.deviceId = deviceId; + inParameters.nChannels = numInputs; + + RtAudio::StreamOptions options; + options.flags |= RTAUDIO_MINIMIZE_LATENCY; + + try { + // Don't use stream parameters if 0 input or output channels + stream.openStream( + numOutputs == 0 ? NULL : &outParameters, + numInputs == 0 ? NULL : &inParameters, + RTAUDIO_FLOAT32, sampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL); + } + catch (RtAudioError &e) { + warn("Failed to open audio stream: %s", e.what()); return; } - err = Pa_StartStream(stream); - if (err) { - warn("Failed to start audio stream: %s", Pa_GetErrorText(err)); + try { + stream.startStream(); + } + catch (RtAudioError &e) { + warn("Failed to start audio stream: %s", e.what()); return; } - // This should go after Pa_StartStream because sometimes it will call the callback once synchronously, and that time it should return early + streamRunning = true; - // Correct sample rate - const PaStreamInfo *streamInfo = Pa_GetStreamInfo(stream); - this->sampleRate = streamInfo->sampleRate; + this->sampleRate = stream.getStreamSampleRate(); this->deviceId = deviceId; } } @@ -293,23 +287,19 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { void AudioInterface::closeDevice() { std::lock_guard lock(bufferMutex); - if (stream) { - PaError err; + if (stream.isStreamOpen()) { streamRunning = false; - err = Pa_AbortStream(stream); - // err = Pa_StopStream(stream); - if (err) { - warn("Failed to stop audio stream: %s", Pa_GetErrorText(err)); + try { + stream.abortStream(); + stream.closeStream(); } - - err = Pa_CloseStream(stream); - if (err) { - warn("Failed to close audio stream: %s", Pa_GetErrorText(err)); + catch (RtAudioError &e) { + warn("Failed to abort stream %s", e.what()); + return; } } // Reset stream settings - stream = NULL; deviceId = -1; numOutputs = 0; numInputs = 0; @@ -427,7 +417,6 @@ AudioInterfaceWidget::AudioInterfaceWidget() { AudioInterface *module = new AudioInterface(); setModule(module); box.size = Vec(15*12, 380); - { Panel *panel = new LightPanel(); panel->box.size = box.size; From f33220aa9b1d6a4788de345b2da052c1e34ea860 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 17 Nov 2017 06:20:07 -0500 Subject: [PATCH 17/17] Add mutex to AudioInterface::getDeviceName --- src/core/AudioInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 81c0e5a7..6fcfd373 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -208,6 +208,7 @@ std::string AudioInterface::getDeviceName(int deviceId) { if (deviceId < 0) return ""; + std::lock_guard lock(bufferMutex); try { RtAudio::DeviceInfo deviceInfo = stream.getDeviceInfo(deviceId); return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels);