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.


# 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.


+ 4
- 2
Makefile View File

@@ -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 -lossia
TARGET = Rack
endif

@@ -154,11 +154,13 @@ ifeq ($(ARCH), lin)
cp dep/lib/libglfw.so.3 dist/Rack/
cp dep/lib/libcurl.so.4 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 /usr/local/lib/libossia.so dist/Rack/
mkdir -p dist/Rack/plugins
# Make ZIP
cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/
cp -R plugins/Tutorial/dist/Template dist/Rack/plugins/
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.*

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.


+ 1
- 1
compile.mk View File

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


ifeq ($(ARCH), lin)


+ 20
- 19
dep/Makefile View File

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

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

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


.NOTPARALLEL:

all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(portaudio)
all: $(glew) $(glfw) $(jansson) $(libsamplerate) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) $(ossia)
@echo ""
@echo "#######################################"
@echo "# Built all dependencies successfully #"
@@ -122,21 +123,21 @@ $(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
$(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:
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
////////////////////
@@ -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<NVGcolor> 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;


+ 15
- 15
include/components.hpp View File

@@ -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);
}
};



+ 21
- 20
include/engine.hpp View File

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

namespace rack {


struct Param {
float value = 0.0;
std::string name = "param.1";
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 {
/** 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;
@@ -30,16 +42,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];
};

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

/** 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);
~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 */
virtual void step() {}


+ 3
- 0
include/plugin.hpp View File

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

#include <ossia/network/network.hpp>

namespace rack {

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

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

void pluginInit();


+ 7
- 3
include/rack.hpp View File

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

namespace rack {

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

template<class TModuleLightWidget>
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;
}



+ 11
- 0
include/util.hpp View File

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

+ 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);
/** Returns the filename, blank if unsuccessful */
bool requestDownload(std::string url, std::string filename, float *progress);
std::string requestEscape(std::string s);

} // namespace rack

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

@@ -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<MenuLabel>(&MenuEntry::text, gTagNames[tag]));
}
addChild(construct<MenuEntry>());
}

// 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<MenuLabel>(&MenuEntry::text, pluginName));

// 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();
@@ -120,6 +120,10 @@ struct ModelItem : MenuItem {
sModel = model;
MenuItem::onMouseEnter(e);
}
void onMouseLeave(EventMouseLeave &e) override {
sModel = NULL;
MenuItem::onMouseLeave(e);
}
};


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

void step() override {
if (manufacturer != sManufacturer) {
manufacturer = sManufacturer;
filter = "";
clearChildren();
addChild(construct<MenuLabel>(&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<ModelItem>(&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;
@@ -153,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();
@@ -168,11 +173,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;
}
};

@@ -283,7 +285,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);
}




+ 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 "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<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) {
WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
if (activeWire) {
@@ -33,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) {


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

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


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");
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());
info("Loading patch %s", path.c_str());
FILE *file = fopen(path.c_str(), "r");
if (!file) {
// Exit silently


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

@@ -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();


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

@@ -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);
}




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

@@ -1,27 +1,18 @@
#include <assert.h>
#include <mutex>
#include <thread>
#include <portaudio.h>
#include "core.hpp"
#include "dsp/samplerate.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 {
@@ -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<Frame<8>, (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,29 @@ 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 "";

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 "";
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) {
@@ -241,51 +235,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) {
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;
}

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;
}

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;
}
// 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 +288,19 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
void AudioInterface::closeDevice() {
std::lock_guard<std::mutex> lock(bufferMutex);

if (stream) {
PaError err;
if (stream.isStreamOpen()) {
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
stream = NULL;
deviceId = -1;
numOutputs = 0;
numInputs = 0;
@@ -427,7 +418,6 @@ AudioInterfaceWidget::AudioInterfaceWidget() {
AudioInterface *module = new AudioInterface();
setModule(module);
box.size = Vec(15*12, 380);

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


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

@@ -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<std::string> MidiIO::getDevices() {
try {
m = new RtMidiIn();
} 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;
}

@@ -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());
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());
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<unsigned char> *msg) {
MidiInWrapper *mw = midiInMap[deviceName];

if (!mw) {
fprintf(stderr, "Device not opened!: %s\n", 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) {
//fprintf(stderr, "Trying to close already closed device!\n");
//warn("Trying to close already closed device!");
return;
}



+ 19
- 7
src/engine.cpp View File

@@ -37,7 +37,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
@@ -259,18 +276,13 @@ float engineGetSampleTime() {
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) {
params.resize(numParams);
inputs.resize(numInputs);
outputs.resize(numOutputs);
lights.resize(numLights);
std::cout << "create node" << std::endl;
node = &ossia::net::create_node(rack::root_dev(),"module");
}

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) {
fprintf(stderr, "GLFW error %d: %s\n", error, description);
warn("GLFW error %d: %s", error, description);
}

void renderGui() {
@@ -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();
@@ -441,7 +446,7 @@ void guiRun() {
std::this_thread::sleep_for(std::chrono::duration<double>(minTime - frameTime));
}
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) {
handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str());
if (handle >= 0) {
fprintf(stderr, "Loaded font %s\n", filename.c_str());
info("Loaded font %s", filename.c_str());
}
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) {
handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (handle > 0) {
fprintf(stderr, "Loaded image %s\n", filename.c_str());
info("Loaded image %s", filename.c_str());
}
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) {
handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI);
if (handle) {
fprintf(stderr, "Loaded SVG %s\n", filename.c_str());
info("Loaded SVG %s", filename.c_str());
}
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[]) {
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);
printf("Current working directory: %s\n", cwd);
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());
info("Global directory: %s", globalDir.c_str());
info("Local directory: %s", localDir.c_str());
}

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

#ifdef VERSION
fclose(gLogFile);
#endif

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());
if (!handle) {
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;
}
#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());
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());
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());
info("Loaded plugin %s", libraryFilename.c_str());
return 0;
}

@@ -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 {
@@ -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;
@@ -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());
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());
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);
warn("Plugin refresh error: %s", errorStr);
}
else {
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_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)
@@ -127,7 +118,7 @@ static void settingsFromJson(json_t *rootJ) {


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");
if (!file)
return;
@@ -142,7 +133,7 @@ void settingsSave(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");
if (!file)
return;
@@ -154,7 +145,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);
warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
}

fclose(file);


+ 53
- 6
src/util.cpp View File

@@ -1,5 +1,4 @@
#include "util.hpp"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <random>
@@ -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<float> 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,47 @@ void openBrowser(std::string url) {
#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

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

@@ -1,4 +1,5 @@
#include "util/request.hpp"
#include "util.hpp"
#include <assert.h>
#include <stdio.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);

// Perform request
printf("Requesting %s\n", url.c_str());
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());
info("Downloading %s", url.c_str());
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);

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

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

@@ -64,7 +64,7 @@ void FramebufferWidget::draw(NVGcontext *vg) {
if (fbSize.isZero())
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
internal->setFramebuffer(NULL);
// 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) {
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);
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);
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);


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

@@ -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));
}



Loading…
Cancel
Save