Browse Source

Merge branch 'master' into ossia

# Conflicts:
#	include/engine.hpp
pull/574/head
Antoine Villeret 7 years ago
parent
commit
d19f17bd15
32 changed files with 450 additions and 318 deletions
  1. +8
    -5
      LICENSE-dist.txt
  2. +4
    -2
      Makefile
  3. +1
    -1
      README.md
  4. +1
    -1
      compile.mk
  5. +20
    -19
      dep/Makefile
  6. +30
    -24
      include/app.hpp
  7. +15
    -15
      include/components.hpp
  8. +21
    -20
      include/engine.hpp
  9. +3
    -0
      include/plugin.hpp
  10. +7
    -3
      include/rack.hpp
  11. +11
    -0
      include/util.hpp
  12. +1
    -0
      include/util/request.hpp
  13. +24
    -23
      src/app/AddModuleWindow.cpp
  14. +0
    -27
      src/app/ColorLightWidget.cpp
  15. +22
    -0
      src/app/ModuleLightWidget.cpp
  16. +24
    -0
      src/app/MultiLightWidget.cpp
  17. +34
    -5
      src/app/Port.cpp
  18. +2
    -2
      src/app/RackWidget.cpp
  19. +0
    -10
      src/app/Toolbar.cpp
  20. +15
    -24
      src/app/WireWidget.cpp
  21. +67
    -77
      src/core/AudioInterface.cpp
  22. +8
    -8
      src/core/MidiIO.cpp
  23. +19
    -7
      src/engine.cpp
  24. +14
    -9
      src/gui.cpp
  25. +17
    -3
      src/main.cpp
  26. +10
    -10
      src/plugin.cpp
  27. +3
    -12
      src/settings.cpp
  28. +53
    -6
      src/util.cpp
  29. +13
    -2
      src/util/request.cpp
  30. +2
    -1
      src/widgets/FramebufferWidget.cpp
  31. +1
    -1
      src/widgets/SpriteWidget.cpp
  32. +0
    -1
      src/widgets/TransformWidget.cpp

+ 8
- 5
LICENSE-dist.txt View File

@@ -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. 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, (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, 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 The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.


+ 4
- 2
Makefile View File

@@ -14,7 +14,7 @@ ifeq ($(ARCH), lin)
LDFLAGS += -rdynamic \ LDFLAGS += -rdynamic \
-lpthread -lGL -ldl \ -lpthread -lGL -ldl \
$(shell pkg-config --libs gtk+-2.0) \ $(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 -lossia
TARGET = Rack TARGET = Rack
endif endif


@@ -154,11 +154,13 @@ ifeq ($(ARCH), lin)
cp dep/lib/libglfw.so.3 dist/Rack/ cp dep/lib/libglfw.so.3 dist/Rack/
cp dep/lib/libcurl.so.4 dist/Rack/ cp dep/lib/libcurl.so.4 dist/Rack/
cp dep/lib/libzip.so.5 dist/Rack/ cp dep/lib/libzip.so.5 dist/Rack/
cp dep/lib/libportaudio.so.2 dist/Rack/
cp dep/lib/librtaudio.so.6 dist/Rack/
cp dep/lib/librtmidi.so.4 dist/Rack/ cp dep/lib/librtmidi.so.4 dist/Rack/
cp /usr/local/lib/libossia.so dist/Rack/
mkdir -p dist/Rack/plugins mkdir -p dist/Rack/plugins
# Make ZIP # Make ZIP
cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/
cp -R plugins/Tutorial/dist/Template dist/Rack/plugins/
endif endif






+ 1
- 1
README.md View File

@@ -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.* *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. 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. Clone submodules.


+ 1
- 1
compile.mk View File

@@ -11,7 +11,7 @@ FLAGS += -Wall -Wextra -Wno-unused-parameter
ifneq ($(ARCH), mac) ifneq ($(ARCH), mac)
CXXFLAGS += -Wsuggest-override CXXFLAGS += -Wsuggest-override
endif endif
CXXFLAGS += -std=c++11
CXXFLAGS += -std=c++14




ifeq ($(ARCH), lin) ifeq ($(ARCH), lin)


+ 20
- 19
dep/Makefile View File

@@ -30,7 +30,8 @@ ifeq ($(ARCH),lin)
libcurl = lib/libcurl.so libcurl = lib/libcurl.so
libzip = lib/libzip.so libzip = lib/libzip.so
rtmidi = lib/librtmidi.so rtmidi = lib/librtmidi.so
portaudio = lib/libportaudio.so
rtaudio = lib/librtaudio.so
ossia = lib/libossia.so
endif endif


ifeq ($(ARCH),mac) ifeq ($(ARCH),mac)
@@ -41,7 +42,7 @@ ifeq ($(ARCH),mac)
libcurl = lib/libcurl.dylib libcurl = lib/libcurl.dylib
libzip = lib/libzip.dylib libzip = lib/libzip.dylib
rtmidi = lib/librtmidi.dylib rtmidi = lib/librtmidi.dylib
portaudio = lib/libportaudio.dylib
ossia = lib/libossia.so
endif endif


ifeq ($(ARCH),win) ifeq ($(ARCH),win)
@@ -52,13 +53,13 @@ ifeq ($(ARCH),win)
libcurl = bin/libcurl-4.dll libcurl = bin/libcurl-4.dll
libzip = bin/libzip-5.dll libzip = bin/libzip-5.dll
rtmidi = bin/librtmidi-4.dll rtmidi = bin/librtmidi-4.dll
portaudio = bin/portaudio_x64.dll
ossia = lib/libossia.dll
endif endif




.NOTPARALLEL: .NOTPARALLEL:


all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(portaudio)
all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) $(ossia)
@echo "" @echo ""
@echo "#######################################" @echo "#######################################"
@echo "# Built all dependencies successfully #" @echo "# Built all dependencies successfully #"
@@ -122,21 +123,21 @@ $(rtmidi):
$(MAKE) -C rtmidi-3.0.0 $(MAKE) -C rtmidi-3.0.0
$(MAKE) -C rtmidi-3.0.0 install $(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
$(ossia):
# TODO use release tarball instead of building it locally
git clone https://github.com/OSSIA/libossia --recursive
cd libossia && $(CMAKE) . \
-DCMAKE_INSTALL_PREFIX="$(LOCAL)" -DOSSIA_PD=OFF \
-DOSSIA_COTIRE=OFF -DOSSIA_PROTOCOL_MIDI=OFF .
$(MAKE) -j4
$(MAKE) install


clean: clean:
git clean -ffdxi git clean -ffdxi

+ 30
- 24
include/app.hpp View File

@@ -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<NVGcolor> baseColors;
void addBaseColor(NVGcolor baseColor);
/** Sets the color to a linear combination of the baseColors with the given weights */
void setValues(const std::vector<float> &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 // ports
//////////////////// ////////////////////
@@ -290,8 +317,11 @@ struct Port : OpaqueWidget {
Module *module = NULL; Module *module = NULL;
PortType type = INPUT; PortType type = INPUT;
int portId; int portId;
MultiLightWidget *plugLight;


Port();
~Port(); ~Port();
void step() override;
void draw(NVGcontext *vg) override; void draw(NVGcontext *vg) override;
void onMouseDown(EventMouseDown &e) override; void onMouseDown(EventMouseDown &e) override;
void onDragStart(EventDragStart &e) override; void onDragStart(EventDragStart &e) override;
@@ -315,29 +345,6 @@ struct SVGScrew : FramebufferWidget {
SVGScrew(); 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<NVGcolor> colors;
void addColor(NVGcolor c);
void step() override;
};

//////////////////// ////////////////////
// scene // scene
//////////////////// ////////////////////
@@ -347,7 +354,6 @@ struct Toolbar : OpaqueWidget {
Slider *wireTensionSlider; Slider *wireTensionSlider;
Slider *zoomSlider; Slider *zoomSlider;
RadioButton *cpuUsageButton; RadioButton *cpuUsageButton;
RadioButton *plugLightButton;


Toolbar(); Toolbar();
void draw(NVGcontext *vg) override; void draw(NVGcontext *vg) override;


+ 15
- 15
include/components.hpp View File

@@ -368,43 +368,43 @@ struct CL1362Port : SVGPort {
// Lights // Lights
//////////////////// ////////////////////


struct RedLight : ColorLightWidget {
struct RedLight : ModuleLightWidget {
RedLight() { RedLight() {
addColor(COLOR_RED);
addBaseColor(COLOR_RED);
} }
}; };


struct GreenLight : ColorLightWidget {
struct GreenLight : ModuleLightWidget {
GreenLight() { GreenLight() {
addColor(COLOR_GREEN);
addBaseColor(COLOR_GREEN);
} }
}; };


struct YellowLight : ColorLightWidget {
struct YellowLight : ModuleLightWidget {
YellowLight() { YellowLight() {
addColor(COLOR_YELLOW);
addBaseColor(COLOR_YELLOW);
} }
}; };


struct BlueLight : ColorLightWidget {
struct BlueLight : ModuleLightWidget {
BlueLight() { BlueLight() {
addColor(COLOR_BLUE);
addBaseColor(COLOR_BLUE);
} }
}; };


/** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */ /** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */
struct GreenRedLight : ColorLightWidget {
struct GreenRedLight : ModuleLightWidget {
GreenRedLight() { GreenRedLight() {
addColor(COLOR_GREEN);
addColor(COLOR_RED);
addBaseColor(COLOR_GREEN);
addBaseColor(COLOR_RED);
} }
}; };


struct RedGreenBlueLight : ColorLightWidget {
struct RedGreenBlueLight : ModuleLightWidget {
RedGreenBlueLight() { RedGreenBlueLight() {
addColor(COLOR_RED);
addColor(COLOR_GREEN);
addColor(COLOR_BLUE);
addBaseColor(COLOR_RED);
addBaseColor(COLOR_GREEN);
addBaseColor(COLOR_BLUE);
} }
}; };




+ 21
- 20
include/engine.hpp View File

@@ -8,17 +8,29 @@


namespace rack { namespace rack {



struct Param { struct Param {
float value = 0.0; float value = 0.0;
std::string name = "param.1"; std::string name = "param.1";
ossia::net::parameter_base* ossia_param; ossia::net::parameter_base* ossia_param;
}; };


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 { struct Input {
/** Voltage of the port, zero if not plugged in. Read-only by Module */ /** Voltage of the port, zero if not plugged in. Read-only by Module */
float value = 0.0; float value = 0.0;
/** Whether a wire is plugged in */ /** Whether a wire is plugged in */
bool active = false; bool active = false;
Light plugLights[2];
/** Returns the value if a wire is plugged in, otherwise returns the given default value */ /** Returns the value if a wire is plugged in, otherwise returns the given default value */
float normalize(float normalValue) { float normalize(float normalValue) {
return active ? value : normalValue; return active ? value : normalValue;
@@ -30,16 +42,7 @@ struct Output {
float value = 0.0; float value = 0.0;
/** Whether a wire is plugged in */ /** Whether a wire is plugged in */
bool active = false; 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];
}; };


static ossia::net::generic_device& root_dev(); static ossia::net::generic_device& root_dev();
@@ -51,19 +54,17 @@ struct Module {
std::vector<Light> lights; std::vector<Light> lights;
/** For CPU usage meter */ /** For CPU usage meter */
float cpuTime = 0.0; float cpuTime = 0.0;
ossia::net::node_base* node{};


/** Deprecated, use constructor below this one */ /** Deprecated, use constructor below this one */
Module();
Module() DEPRECATED {}
/** Constructs Module with a fixed number of params, inputs, and outputs */ /** Constructs Module with a fixed number of params, inputs, and outputs */
Module(int numParams, int numInputs, int numOutputs, int numLights = 0);
~Module()
{
if (node)
node->get_parent()->remove_child(*node);
}
Module(int numParams, int numInputs, int numOutputs, int numLights = 0) {
params.resize(numParams);
inputs.resize(numInputs);
outputs.resize(numOutputs);
lights.resize(numLights);
}
virtual ~Module() {}


/** Advances the module by 1 audio frame with duration 1.0 / gSampleRate */ /** Advances the module by 1 audio frame with duration 1.0 / gSampleRate */
virtual void step() {} virtual void step() {}


+ 3
- 0
include/plugin.hpp View File

@@ -2,6 +2,7 @@
#include <string> #include <string>
#include <list> #include <list>


#include <ossia/network/network.hpp>


namespace rack { namespace rack {


@@ -101,6 +102,8 @@ struct Model {


virtual ~Model() {} virtual ~Model() {}
virtual ModuleWidget *createModuleWidget() { return NULL; } virtual ModuleWidget *createModuleWidget() { return NULL; }
ossia::net::node_base* node;
}; };


void pluginInit(); void pluginInit();


+ 7
- 3
include/rack.hpp View File

@@ -8,7 +8,7 @@
#include "gui.hpp" #include "gui.hpp"
#include "app.hpp" #include "app.hpp"
#include "components.hpp" #include "components.hpp"
#include <iostream>


namespace rack { namespace rack {


@@ -24,6 +24,10 @@ Model *createModel(std::string manufacturer, std::string slug, std::string name,
ModuleWidget *createModuleWidget() override { ModuleWidget *createModuleWidget() override {
ModuleWidget *moduleWidget = new TModuleWidget(); ModuleWidget *moduleWidget = new TModuleWidget();
moduleWidget->model = this; moduleWidget->model = this;
// TODO move node creation here
node = &ossia::net::create_node(rack::root_dev(),name);
return moduleWidget; return moduleWidget;
} }
}; };
@@ -92,11 +96,11 @@ Port *createOutput(Vec pos, Module *module, int outputId) {
} }


template<class TModuleLightWidget> template<class TModuleLightWidget>
ModuleLightWidget *createLight(Vec pos, Module *module, int lightId) {
ModuleLightWidget *createLight(Vec pos, Module *module, int firstLightId) {
ModuleLightWidget *light = new TModuleLightWidget(); ModuleLightWidget *light = new TModuleLightWidget();
light->box.pos = pos; light->box.pos = pos;
light->module = module; light->module = module;
light->lightId = lightId;
light->firstLightId = firstLightId;
return light; return light;
} }




+ 11
- 0
include/util.hpp View File

@@ -58,6 +58,7 @@ T *construct(F f, V v, Args... args) {
// RNG // RNG
//////////////////// ////////////////////


/** Seeds the RNG with the current time */
void randomSeedTime(); void randomSeedTime();
uint32_t randomu32(); uint32_t randomu32();
uint64_t randomu64(); uint64_t randomu64();
@@ -126,5 +127,15 @@ struct VIPLock {
} }
}; };


////////////////////
// logger
////////////////////

extern FILE *gLogFile;
void debug(const char *format, ...);
void info(const char *format, ...);
void warn(const char *format, ...);
void fatal(const char *format, ...);



} // namespace rack } // namespace rack

+ 1
- 0
include/util/request.hpp View File

@@ -18,5 +18,6 @@ enum RequestMethod {
json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ); json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ);
/** Returns the filename, blank if unsuccessful */ /** Returns the filename, blank if unsuccessful */
bool requestDownload(std::string url, std::string filename, float *progress); bool requestDownload(std::string url, std::string filename, float *progress);
std::string requestEscape(std::string s);


} // namespace rack } // namespace rack

+ 24
- 23
src/app/AddModuleWindow.cpp View File

@@ -48,37 +48,37 @@ struct MetadataMenu : ListMenu {


void step() override { void step() override {
if (model != sModel) { if (model != sModel) {
model = sModel;
clearChildren(); clearChildren();


if (sModel) {
if (model) {
// Tag list // Tag list
if (!sModel->tags.empty()) {
for (ModelTag tag : sModel->tags) {
if (!model->tags.empty()) {
for (ModelTag tag : model->tags) {
addChild(construct<MenuLabel>(&MenuEntry::text, gTagNames[tag])); addChild(construct<MenuLabel>(&MenuEntry::text, gTagNames[tag]));
} }
addChild(construct<MenuEntry>()); addChild(construct<MenuEntry>());
} }


// Plugin name // 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 += " v";
pluginName += sModel->plugin->version;
pluginName += model->plugin->version;
} }
addChild(construct<MenuLabel>(&MenuEntry::text, pluginName)); addChild(construct<MenuLabel>(&MenuEntry::text, pluginName));


// Plugin metadata // Plugin metadata
if (!sModel->plugin->website.empty()) {
addChild(construct<UrlItem>(&MenuEntry::text, "Website", &UrlItem::url, sModel->plugin->path));
if (!model->plugin->website.empty()) {
addChild(construct<UrlItem>(&MenuEntry::text, "Website", &UrlItem::url, model->plugin->path));
} }
if (!sModel->plugin->manual.empty()) {
addChild(construct<UrlItem>(&MenuEntry::text, "Manual", &UrlItem::url, sModel->plugin->manual));
if (!model->plugin->manual.empty()) {
addChild(construct<UrlItem>(&MenuEntry::text, "Manual", &UrlItem::url, model->plugin->manual));
} }
if (!sModel->plugin->path.empty()) {
addChild(construct<UrlItem>(&MenuEntry::text, "Browse directory", &UrlItem::url, sModel->plugin->path));
if (!model->plugin->path.empty()) {
addChild(construct<UrlItem>(&MenuEntry::text, "Browse directory", &UrlItem::url, model->plugin->path));
} }
} }
model = sModel;
} }


ListMenu::step(); ListMenu::step();
@@ -120,6 +120,10 @@ struct ModelItem : MenuItem {
sModel = model; sModel = model;
MenuItem::onMouseEnter(e); MenuItem::onMouseEnter(e);
} }
void onMouseLeave(EventMouseLeave &e) override {
sModel = NULL;
MenuItem::onMouseLeave(e);
}
}; };




@@ -129,20 +133,22 @@ struct ModelMenu : ListMenu {


void step() override { void step() override {
if (manufacturer != sManufacturer) { if (manufacturer != sManufacturer) {
manufacturer = sManufacturer;
filter = "";
clearChildren(); clearChildren();
addChild(construct<MenuLabel>(&MenuLabel::text, manufacturer));
// Add models for the selected manufacturer // Add models for the selected manufacturer
for (Plugin *plugin : gPlugins) { for (Plugin *plugin : gPlugins) {
for (Model *model : plugin->models) { for (Model *model : plugin->models) {
if (model->manufacturer == sManufacturer) {
if (model->manufacturer == manufacturer) {
addChild(construct<ModelItem>(&MenuEntry::text, model->name, &ModelItem::model, model)); addChild(construct<ModelItem>(&MenuEntry::text, model->name, &ModelItem::model, model));
} }
} }
} }
manufacturer = sManufacturer;
filter = "";
} }


if (filter != sFilter) { if (filter != sFilter) {
filter = sFilter;
// Make all children invisible // Make all children invisible
for (Widget *child : children) { for (Widget *child : children) {
child->visible = false; child->visible = false;
@@ -153,11 +159,10 @@ struct ModelMenu : ListMenu {
if (!item) if (!item)
continue; continue;


if (isModelMatch(item->model, sFilter)) {
if (isModelMatch(item->model, filter)) {
item->visible = true; item->visible = true;
} }
} }
filter = sFilter;
} }


ListMenu::step(); ListMenu::step();
@@ -168,11 +173,8 @@ struct ModelMenu : ListMenu {
struct ManufacturerItem : MenuItem { struct ManufacturerItem : MenuItem {
Model *model; Model *model;
void onAction(EventAction &e) override { void onAction(EventAction &e) override {
e.consumed = false;
}
void onMouseEnter(EventMouseEnter &e) override {
sManufacturer = text; sManufacturer = text;
MenuItem::onMouseEnter(e);
e.consumed = false;
} }
}; };


@@ -283,7 +285,6 @@ AddModuleWindow::AddModuleWindow() {


// NVGcolor c = bndTransparent(nvgRGB(0, 0, 0)); // NVGcolor c = bndTransparent(nvgRGB(0, 0, 0));
NVGcolor c = bndGetTheme()->nodeTheme.nodeBackdropColor; NVGcolor c = bndGetTheme()->nodeTheme.nodeBackdropColor;
printf("%f %f %f %f\n", c.r, c.g, c.b, c.a);
} }






+ 0
- 27
src/app/ColorLightWidget.cpp View File

@@ -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

+ 22
- 0
src/app/ModuleLightWidget.cpp View File

@@ -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<float> 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

+ 24
- 0
src/app/MultiLightWidget.cpp View File

@@ -0,0 +1,24 @@
#include "app.hpp"


namespace rack {


void MultiLightWidget::addBaseColor(NVGcolor baseColor) {
baseColors.push_back(baseColor);
}

void MultiLightWidget::setValues(const std::vector<float> &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

+ 34
- 5
src/app/Port.cpp View File

@@ -1,13 +1,45 @@
#include "app.hpp" #include "app.hpp"
#include "gui.hpp" #include "gui.hpp"
#include "components.hpp"
#include "engine.hpp"




namespace rack { 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() { 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); gRackWidget->wireContainer->removeAllWires(this);
} }


void Port::step() {
std::vector<float> 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) { void Port::draw(NVGcontext *vg) {
WireWidget *activeWire = gRackWidget->wireContainer->activeWire; WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
if (activeWire) { if (activeWire) {
@@ -33,11 +65,8 @@ void Port::onMouseDown(EventMouseDown &e) {
void Port::onDragStart(EventDragStart &e) { void Port::onDragStart(EventDragStart &e) {
// Try to grab wire on top of stack // Try to grab wire on top of stack
WireWidget *wire = gRackWidget->wireContainer->getTopWire(this); WireWidget *wire = gRackWidget->wireContainer->getTopWire(this);
if (guiIsModPressed()) {
if (type == INPUT)
return;
else
wire = NULL;
if (type == OUTPUT && guiIsModPressed()) {
wire = NULL;
} }


if (wire) { if (wire) {


+ 2
- 2
src/app/RackWidget.cpp View File

@@ -83,7 +83,7 @@ void RackWidget::saveAsDialog() {




void RackWidget::savePatch(std::string path) { void RackWidget::savePatch(std::string path) {
printf("Saving patch %s\n", path.c_str());
info("Saving patch %s", path.c_str());
FILE *file = fopen(path.c_str(), "w"); FILE *file = fopen(path.c_str(), "w");
if (!file) if (!file)
return; return;
@@ -98,7 +98,7 @@ void RackWidget::savePatch(std::string path) {
} }


void RackWidget::loadPatch(std::string path) { void RackWidget::loadPatch(std::string path) {
printf("Loading patch %s\n", path.c_str());
info("Loading patch %s", path.c_str());
FILE *file = fopen(path.c_str(), "r"); FILE *file = fopen(path.c_str(), "r");
if (!file) { if (!file) {
// Exit silently // Exit silently


+ 0
- 10
src/app/Toolbar.cpp View File

@@ -166,16 +166,6 @@ Toolbar::Toolbar() {
} }
xPos += margin; 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(); cpuUsageButton = new RadioButton();


+ 15
- 24
src/app/WireWidget.cpp View File

@@ -155,7 +155,9 @@ void WireWidget::draw(NVGcontext *vg) {
if (!(inputPort && outputPort)) if (!(inputPort && outputPort))
opacity = 1.0; 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) { void WireWidget::drawPlugs(NVGcontext *vg) {
@@ -166,31 +168,20 @@ void WireWidget::drawPlugs(NVGcontext *vg) {
drawPlug(vg, inputPos, color); drawPlug(vg, inputPos, color);


// Draw plug light // 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);
} }






+ 67
- 77
src/core/AudioInterface.cpp View File

@@ -1,27 +1,18 @@
#include <assert.h> #include <assert.h>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <portaudio.h>
#include "core.hpp" #include "core.hpp"
#include "dsp/samplerate.hpp" #include "dsp/samplerate.hpp"
#include "dsp/ringbuffer.hpp" #include "dsp/ringbuffer.hpp"


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-override"
#include <rtaudio/RtAudio.h>
#pragma GCC diagnostic pop


using namespace rack;

static bool initialized = false;


void audioInit() {
if (initialized)
return;


PaError err = Pa_Initialize();
if (err) {
fprintf(stderr, "Failed to initialize PortAudio: %s\n", Pa_GetErrorText(err));
return;
}
initialized = true;
}
using namespace rack;




struct AudioInterface : Module { struct AudioInterface : Module {
@@ -37,7 +28,7 @@ struct AudioInterface : Module {
NUM_OUTPUTS = AUDIO1_OUTPUT + 8 NUM_OUTPUTS = AUDIO1_OUTPUT + 8
}; };


PaStream *stream = NULL;
RtAudio stream;
// Stream properties // Stream properties
int deviceId = -1; int deviceId = -1;
float sampleRate = 44100.0; float sampleRate = 44100.0;
@@ -58,9 +49,7 @@ struct AudioInterface : Module {
// in device's sample rate // in device's sample rate
DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer; DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer;


AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
audioInit();
}
AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
~AudioInterface() { ~AudioInterface() {
closeDevice(); closeDevice();
} }
@@ -125,9 +114,6 @@ struct AudioInterface : Module {




void AudioInterface::step() { 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 // Read/write stream if we have enough input, OR the output buffer is empty if we have no input
if (numOutputs > 0) { if (numOutputs > 0) {
while (inputSrcBuffer.size() >= blockSize && streamRunning) { while (inputSrcBuffer.size() >= blockSize && streamRunning) {
@@ -215,21 +201,29 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames
} }


int AudioInterface::getDeviceCount() { int AudioInterface::getDeviceCount() {
return Pa_GetDeviceCount();
return stream.getDeviceCount();
} }


std::string AudioInterface::getDeviceName(int deviceId) { std::string AudioInterface::getDeviceName(int deviceId) {
const PaDeviceInfo *info = Pa_GetDeviceInfo(deviceId);
if (!info)
if (deviceId < 0)
return "";

std::lock_guard<std::mutex> lock(bufferMutex);
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 ""; return "";
const PaHostApiInfo *apiInfo = Pa_GetHostApiInfo(info->hostApi);
return stringf("%s: %s (%d in, %d out)", apiInfo->name, info->name, info->maxInputChannels, info->maxOutputChannels);
}
} }


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) { void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
@@ -241,51 +235,52 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {


// Open new device // Open new device
if (deviceId >= 0) { if (deviceId >= 0) {
PaError err;
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId);
if (!deviceInfo) {
fprintf(stderr, "Failed to query audio device\n");
RtAudio::DeviceInfo deviceInfo;
try {
deviceInfo = stream.getDeviceInfo(deviceId);
}
catch (RtAudioError &e) {
warn("Failed to query audio device: %s", e.what());
return; 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) {
fprintf(stderr, "Failed to open audio stream: %s\n", 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; return;
} }


err = Pa_StartStream(stream);
if (err) {
fprintf(stderr, "Failed to start audio stream: %s\n", Pa_GetErrorText(err));
try {
stream.startStream();
}
catch (RtAudioError &e) {
warn("Failed to start audio stream: %s", e.what());
return; 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; streamRunning = true;


// Correct sample rate
const PaStreamInfo *streamInfo = Pa_GetStreamInfo(stream);
this->sampleRate = streamInfo->sampleRate;
this->sampleRate = stream.getStreamSampleRate();
this->deviceId = deviceId; this->deviceId = deviceId;
} }
} }
@@ -293,23 +288,19 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
void AudioInterface::closeDevice() { void AudioInterface::closeDevice() {
std::lock_guard<std::mutex> lock(bufferMutex); std::lock_guard<std::mutex> lock(bufferMutex);


if (stream) {
PaError err;
if (stream.isStreamOpen()) {
streamRunning = false; streamRunning = false;
err = Pa_AbortStream(stream);
// err = Pa_StopStream(stream);
if (err) {
fprintf(stderr, "Failed to stop audio stream: %s\n", Pa_GetErrorText(err));
try {
stream.abortStream();
stream.closeStream();
} }

err = Pa_CloseStream(stream);
if (err) {
fprintf(stderr, "Failed to close audio stream: %s\n", Pa_GetErrorText(err));
catch (RtAudioError &e) {
warn("Failed to abort stream %s", e.what());
return;
} }
} }


// Reset stream settings // Reset stream settings
stream = NULL;
deviceId = -1; deviceId = -1;
numOutputs = 0; numOutputs = 0;
numInputs = 0; numInputs = 0;
@@ -427,7 +418,6 @@ AudioInterfaceWidget::AudioInterfaceWidget() {
AudioInterface *module = new AudioInterface(); AudioInterface *module = new AudioInterface();
setModule(module); setModule(module);
box.size = Vec(15*12, 380); box.size = Vec(15*12, 380);

{ {
Panel *panel = new LightPanel(); Panel *panel = new LightPanel();
panel->box.size = box.size; panel->box.size = box.size;


+ 8
- 8
src/core/MidiIO.cpp View File

@@ -17,9 +17,9 @@ MidiIO::MidiIO(bool isOut) {
channel = -1; channel = -1;
this->isOut = isOut; 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) { void MidiIO::setChannel(int channel) {
@@ -60,7 +60,7 @@ std::vector<std::string> MidiIO::getDevices() {
try { try {
m = new RtMidiIn(); m = new RtMidiIn();
} catch (RtMidiError &error) { } catch (RtMidiError &error) {
fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str());
warn("Failed to create RtMidiIn: %s", error.getMessage().c_str());
return names; return names;
} }


@@ -96,14 +96,14 @@ void MidiIO::openDevice(std::string deviceName) {
} }


if (!mw->isPortOpen()) { if (!mw->isPortOpen()) {
fprintf(stderr, "Failed to create RtMidiIn: No such device %s\n", deviceName.c_str());
warn("Failed to create RtMidiIn: No such device %s", deviceName.c_str());
this->deviceName = ""; this->deviceName = "";
this->id = -1; this->id = -1;
return; return;
} }
} }
catch (RtMidiError &error) { catch (RtMidiError &error) {
fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str());
warn("Failed to create RtMidiIn: %s", error.getMessage().c_str());
this->deviceName = ""; this->deviceName = "";
this->id = -1; this->id = -1;
return; return;
@@ -144,7 +144,7 @@ double MidiIO::getMessage(std::vector<unsigned char> *msg) {
MidiInWrapper *mw = midiInMap[deviceName]; MidiInWrapper *mw = midiInMap[deviceName];


if (!mw) { if (!mw) {
fprintf(stderr, "Device not opened!: %s\n", deviceName.c_str());
warn("Device not opened!: %s", deviceName.c_str());
return 0; return 0;
} }


@@ -176,7 +176,7 @@ void MidiIO::close() {
MidiInWrapper *mw = midiInMap[deviceName]; MidiInWrapper *mw = midiInMap[deviceName];


if (!mw || id < 0) { if (!mw || id < 0) {
//fprintf(stderr, "Trying to close already closed device!\n");
//warn("Trying to close already closed device!");
return; return;
} }




+ 19
- 7
src/engine.cpp View File

@@ -37,7 +37,7 @@ float Light::getBrightness() {
} }


void Light::setBrightnessSmooth(float brightness) { void Light::setBrightnessSmooth(float brightness) {
float v = brightness * brightness;
float v = (brightness > 0.0) ? brightness * brightness : 0.0;
if (v < value) { if (v < value) {
// Fade out light with lambda = 2 * framerate // Fade out light with lambda = 2 * framerate
value += (v - value) * sampleTime * (60.0 * 2.0); value += (v - value) * sampleTime * (60.0 * 2.0);
@@ -87,6 +87,23 @@ static void engineStep() {
// Step modules // Step modules
for (Module *module : modules) { for (Module *module : modules) {
module->step(); 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 // Step cables by moving their output values to inputs
@@ -259,18 +276,13 @@ float engineGetSampleTime() {
return sampleTime; return sampleTime;
} }


Module::Module(){
node = &ossia::net::create_node(rack::root_dev(),"module");
}
Module::Module(){}


Module::Module(int numParams, int numInputs, int numOutputs, int numLights) { Module::Module(int numParams, int numInputs, int numOutputs, int numLights) {
params.resize(numParams); params.resize(numParams);
inputs.resize(numInputs); inputs.resize(numInputs);
outputs.resize(numOutputs); outputs.resize(numOutputs);
lights.resize(numLights); lights.resize(numLights);
std::cout << "create node" << std::endl;
node = &ossia::net::create_node(rack::root_dev(),"module");
} }


ossia::net::generic_device& root_dev(){ ossia::net::generic_device& root_dev(){


+ 14
- 9
src/gui.cpp View File

@@ -279,7 +279,7 @@ void dropCallback(GLFWwindow *window, int count, const char **paths) {
} }


void errorCallback(int error, const char *description) { void errorCallback(int error, const char *description) {
fprintf(stderr, "GLFW error %d: %s\n", error, description);
warn("GLFW error %d: %s", error, description);
} }


void renderGui() { void renderGui() {
@@ -422,7 +422,12 @@ void guiRun() {
glfwGetFramebufferSize(gWindow, &width, &height); glfwGetFramebufferSize(gWindow, &width, &height);
int windowWidth, windowHeight; int windowWidth, windowHeight;
glfwGetWindowSize(gWindow, &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 // Step scene
gScene->step(); gScene->step();
@@ -441,7 +446,7 @@ void guiRun() {
std::this_thread::sleep_for(std::chrono::duration<double>(minTime - frameTime)); std::this_thread::sleep_for(std::chrono::duration<double>(minTime - frameTime));
} }
endTime = glfwGetTime(); endTime = glfwGetTime();
// printf("%lf fps\n", 1.0 / (endTime - startTime));
// info("%lf fps", 1.0 / (endTime - startTime));
} }
} }


@@ -514,10 +519,10 @@ bool guiIsMaximized() {
Font::Font(const std::string &filename) { Font::Font(const std::string &filename) {
handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str()); handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str());
if (handle >= 0) { if (handle >= 0) {
fprintf(stderr, "Loaded font %s\n", filename.c_str());
info("Loaded font %s", filename.c_str());
} }
else { else {
fprintf(stderr, "Failed to load font %s\n", filename.c_str());
warn("Failed to load font %s", filename.c_str());
} }
} }


@@ -540,10 +545,10 @@ std::shared_ptr<Font> Font::load(const std::string &filename) {
Image::Image(const std::string &filename) { Image::Image(const std::string &filename) {
handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (handle > 0) { if (handle > 0) {
fprintf(stderr, "Loaded image %s\n", filename.c_str());
info("Loaded image %s", filename.c_str());
} }
else { else {
fprintf(stderr, "Failed to load image %s\n", filename.c_str());
warn("Failed to load image %s", filename.c_str());
} }
} }


@@ -567,10 +572,10 @@ std::shared_ptr<Image> Image::load(const std::string &filename) {
SVG::SVG(const std::string &filename) { SVG::SVG(const std::string &filename) {
handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI); handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI);
if (handle) { if (handle) {
fprintf(stderr, "Loaded SVG %s\n", filename.c_str());
info("Loaded SVG %s", filename.c_str());
} }
else { else {
fprintf(stderr, "Failed to load SVG %s\n", filename.c_str());
warn("Failed to load SVG %s", filename.c_str());
} }
} }




+ 17
- 3
src/main.cpp View File

@@ -12,14 +12,23 @@ using namespace rack;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
randomSeedTime(); randomSeedTime();


#ifdef VERSION
std::string logFilename = assetLocal("log.txt");
gLogFile = fopen(logFilename.c_str(), "w");
#endif

if (!gApplicationVersion.empty()) {
info("Rack v%s", gApplicationVersion.c_str());
}

{ {
char *cwd = getcwd(NULL, 0); char *cwd = getcwd(NULL, 0);
printf("Current working directory: %s\n", cwd);
info("Current working directory: %s", cwd);
free(cwd); free(cwd);
std::string globalDir = assetGlobal(""); std::string globalDir = assetGlobal("");
std::string localDir = assetLocal(""); std::string localDir = assetLocal("");
printf("Global directory: %s\n", globalDir.c_str());
printf("Local directory: %s\n", localDir.c_str());
info("Global directory: %s", globalDir.c_str());
info("Local directory: %s", localDir.c_str());
} }


pluginInit(); pluginInit();
@@ -45,5 +54,10 @@ int main(int argc, char* argv[]) {
guiDestroy(); guiDestroy();
engineDestroy(); engineDestroy();
pluginDestroy(); pluginDestroy();

#ifdef VERSION
fclose(gLogFile);
#endif

return 0; return 0;
} }

+ 10
- 10
src/plugin.cpp View File

@@ -112,13 +112,13 @@ static int loadPlugin(std::string path) {
HINSTANCE handle = LoadLibrary(libraryFilename.c_str()); HINSTANCE handle = LoadLibrary(libraryFilename.c_str());
if (!handle) { if (!handle) {
int error = GetLastError(); int error = GetLastError();
fprintf(stderr, "Failed to load library %s: %d\n", libraryFilename.c_str(), error);
warn("Failed to load library %s: %d", libraryFilename.c_str(), error);
return -1; return -1;
} }
#elif ARCH_LIN || ARCH_MAC #elif ARCH_LIN || ARCH_MAC
void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW); void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW);
if (!handle) { if (!handle) {
fprintf(stderr, "Failed to load library %s: %s\n", libraryFilename.c_str(), dlerror());
warn("Failed to load library %s: %s", libraryFilename.c_str(), dlerror());
return -1; return -1;
} }
#endif #endif
@@ -132,7 +132,7 @@ static int loadPlugin(std::string path) {
initCallback = (InitCallback) dlsym(handle, "init"); initCallback = (InitCallback) dlsym(handle, "init");
#endif #endif
if (!initCallback) { if (!initCallback) {
fprintf(stderr, "Failed to read init() symbol in %s\n", libraryFilename.c_str());
warn("Failed to read init() symbol in %s", libraryFilename.c_str());
return -2; return -2;
} }


@@ -144,7 +144,7 @@ static int loadPlugin(std::string path) {


// Add plugin to list // Add plugin to list
gPlugins.push_back(plugin); gPlugins.push_back(plugin);
fprintf(stderr, "Loaded plugin %s\n", libraryFilename.c_str());
info("Loaded plugin %s", libraryFilename.c_str());
return 0; return 0;
} }


@@ -179,7 +179,7 @@ static int extractZipHandle(zip_t *za, const char *dir) {


if (zs.name[nameLen - 1] == '/') { if (zs.name[nameLen - 1] == '/') {
err = mkdir(path, 0755); err = mkdir(path, 0755);
if (err)
if (err && errno != EEXIST)
return err; return err;
} }
else { else {
@@ -237,9 +237,9 @@ static void refreshPurchase(json_t *pluginJ) {
url += "?product="; url += "?product=";
url += slug; url += slug;
url += "&version="; url += "&version=";
url += gApplicationVersion;
url += requestEscape(gApplicationVersion);
url += "&token="; url += "&token=";
url += gToken;
url += requestEscape(gToken);


// If plugin is not loaded, download the zip file to /plugins // If plugin is not loaded, download the zip file to /plugins
downloadName = name; downloadName = name;
@@ -277,14 +277,14 @@ void pluginInit() {


// Load plugins from global directory // Load plugins from global directory
std::string globalPlugins = assetGlobal("plugins"); std::string globalPlugins = assetGlobal("plugins");
printf("Loading plugins from %s\n", globalPlugins.c_str());
info("Loading plugins from %s", globalPlugins.c_str());
loadPlugins(globalPlugins); loadPlugins(globalPlugins);


// Load plugins from local directory // Load plugins from local directory
std::string localPlugins = assetLocal("plugins"); std::string localPlugins = assetLocal("plugins");
if (globalPlugins != localPlugins) { if (globalPlugins != localPlugins) {
mkdir(localPlugins.c_str(), 0755); mkdir(localPlugins.c_str(), 0755);
printf("Loading plugins from %s\n", localPlugins.c_str());
info("Loading plugins from %s", localPlugins.c_str());
loadPlugins(localPlugins); loadPlugins(localPlugins);
} }
} }
@@ -353,7 +353,7 @@ void pluginRefresh() {
json_t *errorJ = json_object_get(resJ, "error"); json_t *errorJ = json_object_get(resJ, "error");
if (errorJ) { if (errorJ) {
const char *errorStr = json_string_value(errorJ); const char *errorStr = json_string_value(errorJ);
fprintf(stderr, "Plugin refresh error: %s\n", errorStr);
warn("Plugin refresh error: %s", errorStr);
} }
else { else {
json_t *purchasesJ = json_object_get(resJ, "purchases"); json_t *purchasesJ = json_object_get(resJ, "purchases");


+ 3
- 12
src/settings.cpp View File

@@ -52,10 +52,6 @@ static json_t *settingsToJson() {
json_t *sampleRateJ = json_real(engineGetSampleRate()); json_t *sampleRateJ = json_real(engineGetSampleRate());
json_object_set_new(rootJ, "sampleRate", sampleRateJ); 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 // lastPath
json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str()); json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str());
json_object_set_new(rootJ, "lastPath", lastPathJ); json_object_set_new(rootJ, "lastPath", lastPathJ);
@@ -114,11 +110,6 @@ static void settingsFromJson(json_t *rootJ) {
engineSetSampleRate(sampleRate); 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 // lastPath
json_t *lastPathJ = json_object_get(rootJ, "lastPath"); json_t *lastPathJ = json_object_get(rootJ, "lastPath");
if (lastPathJ) if (lastPathJ)
@@ -127,7 +118,7 @@ static void settingsFromJson(json_t *rootJ) {




void settingsSave(std::string filename) { void settingsSave(std::string filename) {
printf("Saving settings %s\n", filename.c_str());
info("Saving settings %s", filename.c_str());
FILE *file = fopen(filename.c_str(), "w"); FILE *file = fopen(filename.c_str(), "w");
if (!file) if (!file)
return; return;
@@ -142,7 +133,7 @@ void settingsSave(std::string filename) {
} }


void settingsLoad(std::string filename) { void settingsLoad(std::string filename) {
printf("Loading settings %s\n", filename.c_str());
info("Loading settings %s", filename.c_str());
FILE *file = fopen(filename.c_str(), "r"); FILE *file = fopen(filename.c_str(), "r");
if (!file) if (!file)
return; return;
@@ -154,7 +145,7 @@ void settingsLoad(std::string filename) {
json_decref(rootJ); json_decref(rootJ);
} }
else { else {
printf("JSON parsing error at %s %d:%d %s\n", 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); fclose(file);


+ 53
- 6
src/util.cpp View File

@@ -1,5 +1,4 @@
#include "util.hpp" #include "util.hpp"
#include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <random> #include <random>
@@ -15,6 +14,10 @@
namespace rack { namespace rack {




////////////////////
// RNG
////////////////////

// xoroshiro128+ // xoroshiro128+
// from http://xoroshiro.di.unimi.it/xoroshiro128plus.c // from http://xoroshiro.di.unimi.it/xoroshiro128plus.c


@@ -36,11 +39,6 @@ static uint64_t xoroshiro128plus_next(void) {
return result; return result;
} }


static std::random_device rd;
static std::mt19937 rng(rd());
static std::normal_distribution<float> normalDist;


void randomSeedTime() { void randomSeedTime() {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
@@ -80,6 +78,9 @@ float randomNormal() {
// return (sum - n / 2.f) / sqrtf(n / 12.f); // return (sum - n / 2.f) / sqrtf(n / 12.f);
} }


////////////////////
// String functions
////////////////////


std::string stringf(const char *format, ...) { std::string stringf(const char *format, ...) {
va_list args; va_list args;
@@ -136,6 +137,10 @@ std::string extractExtension(std::string path) {
return ext + 1; return ext + 1;
} }


////////////////////
// Operating system functions
////////////////////

void openBrowser(std::string url) { void openBrowser(std::string url) {
#if ARCH_LIN #if ARCH_LIN
std::string command = "xdg-open " + url; std::string command = "xdg-open " + url;
@@ -150,5 +155,47 @@ void openBrowser(std::string url) {
#endif #endif
} }


////////////////////
// logger
////////////////////

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);
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, "[warning] ");
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);
}



} // namespace rack } // namespace rack

+ 13
- 2
src/util/request.cpp View File

@@ -1,4 +1,5 @@
#include "util/request.hpp" #include "util/request.hpp"
#include "util.hpp"
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -82,7 +83,7 @@ json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ) {
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resText); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resText);


// Perform request // Perform request
printf("Requesting %s\n", url.c_str());
info("Requesting %s", url.c_str());
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
CURLcode res = curl_easy_perform(curl); 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_XFERINFOFUNCTION, xferInfoCallback);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, progress); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, progress);


printf("Downloading %s\n", url.c_str());
info("Downloading %s", url.c_str());
CURLcode res = curl_easy_perform(curl); CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl); curl_easy_cleanup(curl);


@@ -142,5 +143,15 @@ bool requestDownload(std::string url, std::string filename, float *progress) {
return res == CURLE_OK; 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 } // namespace rack

+ 2
- 1
src/widgets/FramebufferWidget.cpp View File

@@ -64,7 +64,7 @@ void FramebufferWidget::draw(NVGcontext *vg) {
if (fbSize.isZero()) if (fbSize.isZero())
return; return;


// printf("rendering framebuffer %f %f\n", fbSize.x, fbSize.y);
// info("rendering framebuffer %f %f", fbSize.x, fbSize.y);
// Delete old one first to free up GPU memory // Delete old one first to free up GPU memory
internal->setFramebuffer(NULL); internal->setFramebuffer(NULL);
// Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context. // Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context.
@@ -122,6 +122,7 @@ int FramebufferWidget::getImageHandle() {


void FramebufferWidget::onZoom(EventZoom &e) { void FramebufferWidget::onZoom(EventZoom &e) {
dirty = true; dirty = true;
Widget::onZoom(e);
} }






+ 1
- 1
src/widgets/SpriteWidget.cpp View File

@@ -8,7 +8,7 @@ void SpriteWidget::draw(NVGcontext *vg) {
nvgImageSize(vg, spriteImage->handle, &width, &height); nvgImageSize(vg, spriteImage->handle, &width, &height);
int stride = width / spriteSize.x; int stride = width / spriteSize.x;
if (stride == 0) { if (stride == 0) {
printf("Size of SpriteWidget is %d, %d but spriteSize is %f, %f\n", 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; return;
} }
Vec offset = Vec((index % stride) * spriteSize.x, (index / stride) * spriteSize.y); Vec offset = Vec((index % stride) * spriteSize.x, (index / stride) * spriteSize.y);


+ 0
- 1
src/widgets/TransformWidget.cpp View File

@@ -14,7 +14,6 @@ Rect TransformWidget::getChildrenBoundingBox() {
Vec bottomRight = bound.getBottomRight(); Vec bottomRight = bound.getBottomRight();
nvgTransformPoint(&topLeft.x, &topLeft.y, transform, topLeft.x, topLeft.y); nvgTransformPoint(&topLeft.x, &topLeft.y, transform, topLeft.x, topLeft.y);
nvgTransformPoint(&bottomRight.x, &bottomRight.y, transform, bottomRight.x, bottomRight.y); nvgTransformPoint(&bottomRight.x, &bottomRight.y, transform, bottomRight.x, bottomRight.y);
printf("%f\n", 42.1);
return Rect(topLeft, bottomRight.minus(topLeft)); return Rect(topLeft, bottomRight.minus(topLeft));
} }




Loading…
Cancel
Save