Browse Source

Merge branch 'v0.6' of github.com:VCVRack/Rack into v0.6

tags/v0.6.1
Andrew Belt 7 years ago
parent
commit
d7e7b04e23
14 changed files with 120 additions and 34 deletions
  1. +2
    -2
      CHANGELOG.md
  2. +2
    -1
      Makefile
  3. +1
    -1
      dep.mk
  4. +7
    -1
      dep/Makefile
  5. +3
    -1
      include/app.hpp
  6. +2
    -3
      include/settings.hpp
  7. +4
    -2
      include/util/request.hpp
  8. +41
    -12
      src/Core/MIDICCToCVInterface.cpp
  9. +12
    -0
      src/app/RackScene.cpp
  10. +28
    -2
      src/app/app.cpp
  11. +0
    -2
      src/engine.cpp
  12. +4
    -4
      src/main.cpp
  13. +11
    -3
      src/settings.cpp
  14. +3
    -0
      src/util/request.cpp

+ 2
- 2
CHANGELOG.md View File

@@ -1,12 +1,12 @@


### 0.6.1 (in development)
### 0.6.1 (2018-06-17)


- Added gamepad MIDI driver - Added gamepad MIDI driver
- Added computer keyboard MIDI driver - Added computer keyboard MIDI driver
- Added JACK support on Linux - Added JACK support on Linux
- Added velocity mode to MIDI-Trig - Added velocity mode to MIDI-Trig
- Added MIDI multiplexing so multiple MIDI modules can use the same MIDI device on Windows - Added MIDI multiplexing so multiple MIDI modules can use the same MIDI device on Windows
- Make Module Browser layout more compact
- Made Module Browser layout more compact
- Add power meter - Add power meter
- Add icons to toolbar - Add icons to toolbar
- [VCV Bridge](https://vcvrack.com/manual/Bridge.html) 0.6.1 - [VCV Bridge](https://vcvrack.com/manual/Bridge.html) 0.6.1


+ 2
- 1
Makefile View File

@@ -1,5 +1,5 @@
RACK_DIR ?= . RACK_DIR ?= .
VERSION = 0.6.1dev
VERSION = 0.6.1


FLAGS += \ FLAGS += \
-Iinclude \ -Iinclude \
@@ -13,6 +13,7 @@ STRIP ?= strip


SOURCES += dep/nanovg/src/nanovg.c SOURCES += dep/nanovg/src/nanovg.c
SOURCES += dep/osdialog/osdialog.c SOURCES += dep/osdialog/osdialog.c
SOURCES += $(wildcard dep/jpommier-pffft-*/pffft.c) $(wildcard dep/jpommier-pffft-*/fftpack.c)
SOURCES += $(wildcard src/*.cpp src/*/*.cpp) SOURCES += $(wildcard src/*.cpp src/*/*.cpp)


ifdef ARCH_MAC ifdef ARCH_MAC


+ 1
- 1
dep.mk View File

@@ -15,7 +15,7 @@ DEP_CXXFLAGS += $(DEP_FLAGS)
# Commands # Commands
WGET := wget -c WGET := wget -c
UNTAR := tar xf UNTAR := tar xf
UNZIP := unzip
UNZIP := unzip -o
CONFIGURE := ./configure --prefix="$(realpath $(DEP_LOCAL))" CONFIGURE := ./configure --prefix="$(realpath $(DEP_LOCAL))"
ifeq ($(ARCH), win) ifeq ($(ARCH), win)
CMAKE := cmake -G 'MSYS Makefiles' -DCMAKE_INSTALL_PREFIX="$(realpath $(DEP_LOCAL))" CMAKE := cmake -G 'MSYS Makefiles' -DCMAKE_INSTALL_PREFIX="$(realpath $(DEP_LOCAL))"


+ 7
- 1
dep/Makefile View File

@@ -49,8 +49,9 @@ nanovg = include/nanovg.h
nanosvg = include/nanosvg.h nanosvg = include/nanosvg.h
oui-blendish = include/blendish.h oui-blendish = include/blendish.h
osdialog = include/osdialog.h osdialog = include/osdialog.h
pffft = include/pffft.h


DEPS += $(glew) $(glfw) $(jansson) $(libspeexdsp) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) $(nanovg) $(nanosvg) $(oui-blendish) $(osdialog)
DEPS += $(glew) $(glfw) $(jansson) $(libspeexdsp) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) $(nanovg) $(nanosvg) $(oui-blendish) $(osdialog) $(pffft)
include $(RACK_DIR)/dep.mk include $(RACK_DIR)/dep.mk




@@ -158,6 +159,11 @@ $(oui-blendish): $(wildcard oui-blendish/*.h)
$(osdialog): $(wildcard osdialog/*.h) $(osdialog): $(wildcard osdialog/*.h)
cp $^ include/ cp $^ include/


$(pffft):
$(WGET) "https://bitbucket.org/jpommier/pffft/get/29e4f76ac53b.zip"
$(UNZIP) 29e4f76ac53b.zip
cp jpommier-pffft-29e4f76ac53b/*.h include/

clean: clean:
git clean -fdx git clean -fdx
git submodule foreach git clean -fdx git submodule foreach git clean -fdx

+ 3
- 1
include/app.hpp View File

@@ -534,13 +534,15 @@ struct RackScene : Scene {
extern std::string gApplicationName; extern std::string gApplicationName;
extern std::string gApplicationVersion; extern std::string gApplicationVersion;
extern std::string gApiHost; extern std::string gApiHost;
extern std::string gLatestVersion;
extern bool gCheckVersion;


// Easy access to "singleton" widgets // Easy access to "singleton" widgets
extern RackScene *gRackScene; extern RackScene *gRackScene;
extern RackWidget *gRackWidget; extern RackWidget *gRackWidget;
extern Toolbar *gToolbar; extern Toolbar *gToolbar;


void appInit();
void appInit(bool devMode);
void appDestroy(); void appDestroy();
void appModuleBrowserCreate(); void appModuleBrowserCreate();
json_t *appModuleBrowserToJson(); json_t *appModuleBrowserToJson();


+ 2
- 3
include/settings.hpp View File

@@ -6,11 +6,10 @@
namespace rack { namespace rack {




extern bool gSkipAutosaveOnLaunch;

void settingsSave(std::string filename); void settingsSave(std::string filename);
void settingsLoad(std::string filename); void settingsLoad(std::string filename);




extern bool skipAutosaveOnLaunch;


} // namespace rack } // namespace rack

+ 4
- 2
include/util/request.hpp View File

@@ -13,9 +13,11 @@ enum RequestMethod {
METHOD_DELETE, METHOD_DELETE,
}; };


/** Requests a JSON API URL over HTTP(S), using the data as the query (GET) or the body (POST, etc) */
/** Requests a JSON API URL over HTTP(S), using the data as the query (GET) or the body (POST, etc)
Caller must json_decref().
*/
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 true if downloaded successfully */
bool requestDownload(std::string url, std::string filename, float *progress); bool requestDownload(std::string url, std::string filename, float *progress);
/** URL-encodes `s` */ /** URL-encodes `s` */
std::string requestEscape(std::string s); std::string requestEscape(std::string s);


+ 41
- 12
src/Core/MIDICCToCVInterface.cpp View File

@@ -1,6 +1,7 @@
#include "Core.hpp" #include "Core.hpp"
#include "midi.hpp" #include "midi.hpp"
#include "dsp/filter.hpp" #include "dsp/filter.hpp"
#include "window.hpp"




struct MIDICCToCVInterface : Module { struct MIDICCToCVInterface : Module {
@@ -19,19 +20,21 @@ struct MIDICCToCVInterface : Module {
}; };


MidiInputQueue midiInput; MidiInputQueue midiInput;
int8_t cvs[16];
int8_t ccs[128];
ExponentialFilter ccFilters[16]; ExponentialFilter ccFilters[16];


int learningId = -1; int learningId = -1;
uint8_t learnedCcs[16] = {};
int learnedCcs[16] = {};


MIDICCToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { MIDICCToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
onReset(); onReset();
} }


void onReset() override { void onReset() override {
for (int i = 0; i < 128; i++) {
ccs[i] = 0;
}
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
cvs[i] = 0;
learnedCcs[i] = i; learnedCcs[i] = i;
} }
learningId = -1; learningId = -1;
@@ -45,7 +48,8 @@ struct MIDICCToCVInterface : Module {


float lambda = 100.f * engineGetSampleTime(); float lambda = 100.f * engineGetSampleTime();
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
float value = rescale(cvs[i], 0, 127, 0.f, 10.f);
int learnedCc = learnedCcs[i];
float value = rescale(clamp(ccs[learnedCc], -127, 127), 0, 127, 0.f, 10.f);
ccFilters[i].lambda = lambda; ccFilters[i].lambda = lambda;
outputs[CC_OUTPUT + i].value = ccFilters[i].process(value); outputs[CC_OUTPUT + i].value = ccFilters[i].process(value);
} }
@@ -57,17 +61,13 @@ struct MIDICCToCVInterface : Module {
case 0xb: { case 0xb: {
uint8_t cc = msg.note(); uint8_t cc = msg.note();
// Learn // Learn
if (learningId >= 0) {
if (learningId >= 0 && ccs[cc] != msg.data2) {
learnedCcs[learningId] = cc; learnedCcs[learningId] = cc;
learningId = -1; learningId = -1;
} }
// Set CV // Set CV
for (int i = 0; i < 16; i++) {
if (learnedCcs[i] == cc) {
// Allow CC to be negative if the 8th bit is set
cvs[i] = msg.data2;
}
}
// Allow CC to be negative if the 8th bit is set
ccs[cc] = msg.data2;
} break; } break;
default: break; default: break;
} }
@@ -107,6 +107,7 @@ struct MIDICCToCVInterface : Module {
struct MidiCcChoice : GridChoice { struct MidiCcChoice : GridChoice {
MIDICCToCVInterface *module; MIDICCToCVInterface *module;
int id; int id;
int focusCc;


MidiCcChoice() { MidiCcChoice() {
box.size.y = mm2px(6.666); box.size.y = mm2px(6.666);
@@ -119,7 +120,10 @@ struct MidiCcChoice : GridChoice {


void step() override { void step() override {
if (module->learningId == id) { if (module->learningId == id) {
text = "LRN";
if (0 <= focusCc)
text = stringf("%d", focusCc);
else
text = "LRN";
color.a = 0.5; color.a = 0.5;
} }
else { else {
@@ -133,11 +137,36 @@ struct MidiCcChoice : GridChoice {
void onFocus(EventFocus &e) override { void onFocus(EventFocus &e) override {
e.consumed = true; e.consumed = true;
module->learningId = id; module->learningId = id;
focusCc = -1;
} }


void onDefocus(EventDefocus &e) override { void onDefocus(EventDefocus &e) override {
if (0 <= focusCc && focusCc < 128) {
module->learnedCcs[id] = focusCc;
}
module->learningId = -1; module->learningId = -1;
} }

void onText(EventText &e) override {
char c = e.codepoint;
if ('0' <= c && c <= '9') {
if (focusCc < 0)
focusCc = 0;
focusCc = focusCc * 10 + (c - '0');
}
e.consumed = true;
}

void onKey(EventKey &e) override {
if (gFocusedWidget == this) {
if (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) {
EventDefocus eDefocus;
onDefocus(eDefocus);
gFocusedWidget = NULL;
e.consumed = true;
}
}
}
}; };






+ 12
- 0
src/app/RackScene.cpp View File

@@ -1,6 +1,7 @@
#include "app.hpp" #include "app.hpp"
#include "window.hpp" #include "window.hpp"
#include "util/request.hpp" #include "util/request.hpp"
#include "osdialog.h"
#include <string.h> #include <string.h>
#include <thread> #include <thread>


@@ -40,6 +41,17 @@ void RackScene::step() {
Scene::step(); Scene::step();


zoomWidget->box.size = gRackWidget->box.size.mult(zoomWidget->zoom); zoomWidget->box.size = gRackWidget->box.size.mult(zoomWidget->zoom);

// Version popup message
if (!gLatestVersion.empty()) {
std::string versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nClose Rack and download new version on the website?", gLatestVersion.c_str(), gApplicationVersion.c_str());
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, versionMessage.c_str())) {
std::thread t(systemOpenBrowser, "https://vcvrack.com/");
t.detach();
windowClose();
}
gLatestVersion = "";
}
} }


void RackScene::draw(NVGcontext *vg) { void RackScene::draw(NVGcontext *vg) {


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

@@ -1,23 +1,49 @@
#include "app.hpp" #include "app.hpp"
#include "util/request.hpp"
#include <thread>




namespace rack { namespace rack {




bool gDev = false;
std::string gApplicationName = "VCV Rack"; std::string gApplicationName = "VCV Rack";
std::string gApplicationVersion = TOSTRING(VERSION); std::string gApplicationVersion = TOSTRING(VERSION);
std::string gApiHost = "https://api.vcvrack.com"; std::string gApiHost = "https://api.vcvrack.com";
// std::string gApiHost = "http://localhost:8081"; // std::string gApiHost = "http://localhost:8081";
std::string gLatestVersion;
bool gCheckVersion = true;



RackWidget *gRackWidget = NULL; RackWidget *gRackWidget = NULL;
Toolbar *gToolbar = NULL; Toolbar *gToolbar = NULL;
RackScene *gRackScene = NULL; RackScene *gRackScene = NULL;




void appInit() {
static void checkVersion() {
json_t *resJ = requestJson(METHOD_GET, gApiHost + "/version", NULL);

if (resJ) {
json_t *versionJ = json_object_get(resJ, "version");
if (versionJ) {
const char *version = json_string_value(versionJ);
if (version && version != gApplicationVersion) {
gLatestVersion = version;
}
}
json_decref(resJ);
}
}


void appInit(bool devMode) {
gRackScene = new RackScene(); gRackScene = new RackScene();
gScene = gRackScene; gScene = gRackScene;

// Request latest version from server
if (!devMode && gCheckVersion) {
std::thread t(checkVersion);
t.detach();
}
} }


void appDestroy() { void appDestroy() {


+ 0
- 2
src/engine.cpp View File

@@ -54,8 +54,6 @@ void Light::setBrightnessSmooth(float brightness, float frames) {


void Wire::step() { void Wire::step() {
float value = outputModule->outputs[outputId].value; float value = outputModule->outputs[outputId].value;
// Assume a +/-12V power supply (like Eurorack), and prevent voltages outside the power range.
value = clamp(value, -12.f, 12.f);
inputModule->inputs[inputId].value = value; inputModule->inputs[inputId].value = value;
} }




+ 4
- 4
src/main.cpp View File

@@ -58,16 +58,16 @@ int main(int argc, char* argv[]) {
keyboardInit(); keyboardInit();
gamepadInit(); gamepadInit();
windowInit(); windowInit();
appInit();
appInit(devMode);
settingsLoad(assetLocal("settings.json")); settingsLoad(assetLocal("settings.json"));


if (patchFile.empty()) { if (patchFile.empty()) {
std::string oldLastPath = gRackWidget->lastPath; std::string oldLastPath = gRackWidget->lastPath;
// To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded. // To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded.
bool oldSkipAutosaveOnLaunch = skipAutosaveOnLaunch;
skipAutosaveOnLaunch = true;
bool oldSkipAutosaveOnLaunch = gSkipAutosaveOnLaunch;
gSkipAutosaveOnLaunch = true;
settingsSave(assetLocal("settings.json")); settingsSave(assetLocal("settings.json"));
skipAutosaveOnLaunch = false;
gSkipAutosaveOnLaunch = false;
if (oldSkipAutosaveOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Would you like to clear your patch and start over?")) { if (oldSkipAutosaveOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Would you like to clear your patch and start over?")) {
// Do nothing. Empty patch is already loaded. // Do nothing. Empty patch is already loaded.
} }


+ 11
- 3
src/settings.cpp View File

@@ -9,7 +9,7 @@
namespace rack { namespace rack {




bool skipAutosaveOnLaunch = false;
bool gSkipAutosaveOnLaunch = false;




static json_t *settingsToJson() { static json_t *settingsToJson() {
@@ -60,7 +60,7 @@ static json_t *settingsToJson() {
json_object_set_new(rootJ, "lastPath", lastPathJ); json_object_set_new(rootJ, "lastPath", lastPathJ);


// skipAutosaveOnLaunch // skipAutosaveOnLaunch
if (skipAutosaveOnLaunch) {
if (gSkipAutosaveOnLaunch) {
json_object_set_new(rootJ, "skipAutosaveOnLaunch", json_true()); json_object_set_new(rootJ, "skipAutosaveOnLaunch", json_true());
} }


@@ -70,6 +70,9 @@ static json_t *settingsToJson() {
// powerMeter // powerMeter
json_object_set_new(rootJ, "powerMeter", json_boolean(gPowerMeter)); json_object_set_new(rootJ, "powerMeter", json_boolean(gPowerMeter));


// checkVersion
json_object_set_new(rootJ, "checkVersion", json_boolean(gCheckVersion));

return rootJ; return rootJ;
} }


@@ -132,7 +135,7 @@ static void settingsFromJson(json_t *rootJ) {
// skipAutosaveOnLaunch // skipAutosaveOnLaunch
json_t *skipAutosaveOnLaunchJ = json_object_get(rootJ, "skipAutosaveOnLaunch"); json_t *skipAutosaveOnLaunchJ = json_object_get(rootJ, "skipAutosaveOnLaunch");
if (skipAutosaveOnLaunchJ) if (skipAutosaveOnLaunchJ)
skipAutosaveOnLaunch = json_boolean_value(skipAutosaveOnLaunchJ);
gSkipAutosaveOnLaunch = json_boolean_value(skipAutosaveOnLaunchJ);


// moduleBrowser // moduleBrowser
json_t *moduleBrowserJ = json_object_get(rootJ, "moduleBrowser"); json_t *moduleBrowserJ = json_object_get(rootJ, "moduleBrowser");
@@ -143,6 +146,11 @@ static void settingsFromJson(json_t *rootJ) {
json_t *powerMeterJ = json_object_get(rootJ, "powerMeter"); json_t *powerMeterJ = json_object_get(rootJ, "powerMeter");
if (powerMeterJ) if (powerMeterJ)
gPowerMeter = json_boolean_value(powerMeterJ); gPowerMeter = json_boolean_value(powerMeterJ);

// checkVersion
json_t *checkVersionJ = json_object_get(rootJ, "checkVersion");
if (checkVersionJ)
gCheckVersion = json_boolean_value(checkVersionJ);
} }






+ 3
- 0
src/util/request.cpp View File

@@ -115,6 +115,9 @@ static int xferInfoCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
} }


bool requestDownload(std::string url, std::string filename, float *progress) { bool requestDownload(std::string url, std::string filename, float *progress) {
if (progress)
*progress = 0.f;

CURL *curl = curl_easy_init(); CURL *curl = curl_easy_init();
if (!curl) if (!curl)
return false; return false;


Loading…
Cancel
Save