Browse Source

Use RELEASE=1 to build release version. VERSION is automatically set in the Makefile now.

Add detection code for legacy1 mode for patch files.
Initialize patch on launch if the last launch crashed after 15 seconds.
tags/v0.6.0
Andrew Belt 6 years ago
parent
commit
575e4df2fd
17 changed files with 110 additions and 83 deletions
  1. +6
    -3
      Makefile
  2. +13
    -2
      include/engine.hpp
  3. +3
    -0
      include/settings.hpp
  4. +3
    -2
      include/util.hpp
  5. +1
    -6
      src/app.cpp
  6. +2
    -2
      src/app/AddModuleWindow.cpp
  7. +5
    -5
      src/app/RackScene.cpp
  8. +12
    -6
      src/app/RackWidget.cpp
  9. +1
    -1
      src/app/Toolbar.cpp
  10. +6
    -6
      src/asset.cpp
  11. +5
    -12
      src/core/MidiToCV.cpp
  12. +1
    -1
      src/core/core.cpp
  13. +16
    -18
      src/core/core.hpp
  14. +1
    -4
      src/gui.cpp
  15. +12
    -7
      src/main.cpp
  16. +17
    -6
      src/settings.cpp
  17. +6
    -2
      src/util.cpp

+ 6
- 3
Makefile View File

@@ -1,7 +1,13 @@
VERSION = 0.6.0dev

FLAGS += \ FLAGS += \
-Iinclude \ -Iinclude \
-Idep/include -Idep/lib/libzip/include -Idep/include -Idep/lib/libzip/include


ifdef RELEASE
FLAGS += -DRELEASE=$(RELEASE)
endif

SOURCES = $(wildcard src/*.cpp src/*/*.cpp) \ SOURCES = $(wildcard src/*.cpp src/*/*.cpp) \
ext/nanovg/src/nanovg.c ext/nanovg/src/nanovg.c


@@ -87,9 +93,6 @@ include compile.mk




dist: all dist: all
ifndef VERSION
$(error VERSION must be defined when making distributables)
endif
rm -rf dist rm -rf dist
$(MAKE) -C plugins/Fundamental dist $(MAKE) -C plugins/Fundamental dist




+ 13
- 2
include/engine.hpp View File

@@ -70,13 +70,24 @@ struct Module {
/** Called when user explicitly deletes the module, not when Rack is closed or a new patch is loaded */ /** Called when user explicitly deletes the module, not when Rack is closed or a new patch is loaded */
virtual void onDelete() {} virtual void onDelete() {}
/** Called when user clicks Initialize in the module context menu */ /** Called when user clicks Initialize in the module context menu */
virtual void onReset() {}
virtual void onReset() {
// Call deprecated method
reset();
}
/** Called when user clicks Randomize in the module context menu */ /** Called when user clicks Randomize in the module context menu */
virtual void onRandomize() {}
virtual void onRandomize() {
// Call deprecated method
randomize();
}


/** Override these to store extra internal data in the "data" property */ /** Override these to store extra internal data in the "data" property */
virtual json_t *toJson() { return NULL; } virtual json_t *toJson() { return NULL; }
virtual void fromJson(json_t *root) {} virtual void fromJson(json_t *root) {}

/** Deprecated */
virtual void reset() {}
/** Deprecated */
virtual void randomize() {}
}; };


struct Wire { struct Wire {


+ 3
- 0
include/settings.hpp View File

@@ -10,4 +10,7 @@ void settingsSave(std::string filename);
void settingsLoad(std::string filename); void settingsLoad(std::string filename);




extern bool skipAutosaveOnLaunch;


} // namespace rack } // namespace rack

+ 3
- 2
include/util.hpp View File

@@ -83,11 +83,12 @@ float randomNormal();


/** Converts a printf format string and optional arguments into a std::string */ /** Converts a printf format string and optional arguments into a std::string */
std::string stringf(const char *format, ...); std::string stringf(const char *format, ...);
std::string tolower(std::string s);
std::string toupper(std::string s);
std::string lowercase(std::string s);
std::string uppercase(std::string s);


/** Truncates and adds "..." to a string, not exceeding `len` characters */ /** Truncates and adds "..." to a string, not exceeding `len` characters */
std::string ellipsize(std::string s, size_t len); std::string ellipsize(std::string s, size_t len);
bool startsWith(std::string str, std::string prefix);


std::string extractDirectory(std::string path); std::string extractDirectory(std::string path);
std::string extractFilename(std::string path); std::string extractFilename(std::string path);


+ 1
- 6
src/app.cpp View File

@@ -4,12 +4,7 @@
namespace rack { namespace rack {


std::string gApplicationName = "VCV Rack"; std::string gApplicationName = "VCV Rack";
std::string gApplicationVersion =
#ifdef VERSION
TOSTRING(VERSION);
#else
"";
#endif
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";




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

@@ -98,8 +98,8 @@ static bool isModelMatch(Model *model, std::string search) {
str += " "; str += " ";
str += gTagNames[tag]; str += gTagNames[tag];
} }
str = tolower(str);
search = tolower(search);
str = lowercase(str);
search = lowercase(search);
return (str.find(search) != std::string::npos); return (str.find(search) != std::string::npos);
} }




+ 5
- 5
src/app/RackScene.cpp View File

@@ -45,10 +45,10 @@ RackScene::RackScene() {
scrollWidget->box.pos.y = gToolbar->box.size.y; scrollWidget->box.pos.y = gToolbar->box.size.y;


// Check for new version // Check for new version
if (!gApplicationVersion.empty()) {
std::thread versionThread(checkVersion);
versionThread.detach();
}
#if defined(RELEASE)
std::thread versionThread(checkVersion);
versionThread.detach();
#endif
} }


void RackScene::step() { void RackScene::step() {
@@ -68,7 +68,7 @@ void RackScene::step() {


// Version popup message // Version popup message
if (!newVersion.empty()) { if (!newVersion.empty()) {
std::string versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nWould you like to download the new version on the website?", newVersion.c_str(), gApplicationVersion.c_str());
std::string versionMessage = stringf("Rack v%s is available.\n\nYou have Rack v%s.\n\nWould you like to download the new version on the website?", newVersion.c_str(), gApplicationVersion.c_str());
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, versionMessage.c_str())) { if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, versionMessage.c_str())) {
std::thread t(openBrowser, "https://vcvrack.com/"); std::thread t(openBrowser, "https://vcvrack.com/");
t.detach(); t.detach();


+ 12
- 6
src/app/RackWidget.cpp View File

@@ -145,10 +145,8 @@ json_t *RackWidget::toJson() {
json_t *rootJ = json_object(); json_t *rootJ = json_object();


// version // version
if (!gApplicationVersion.empty()) {
json_t *versionJ = json_string(gApplicationVersion.c_str());
json_object_set_new(rootJ, "version", versionJ);
}
json_t *versionJ = json_string(gApplicationVersion.c_str());
json_object_set_new(rootJ, "version", versionJ);


// modules // modules
json_t *modulesJ = json_array(); json_t *modulesJ = json_array();
@@ -210,11 +208,19 @@ void RackWidget::fromJson(json_t *rootJ) {
std::string message; std::string message;


// version // version
std::string version;
json_t *versionJ = json_object_get(rootJ, "version"); json_t *versionJ = json_object_get(rootJ, "version");
if (versionJ) { if (versionJ) {
std::string version = json_string_value(versionJ);
version = json_string_value(versionJ);
if (!version.empty() && gApplicationVersion != version) if (!version.empty() && gApplicationVersion != version)
message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version.c_str(), gApplicationVersion.empty() ? "dev" : gApplicationVersion.c_str());
message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version.c_str(), gApplicationVersion.c_str());
}

// Detect old patches with ModuleWidget::params/inputs/outputs indices.
// (We now use Module::params/inputs/outputs indices.)
bool legacy1 = (startsWith(version, "0.3.") || startsWith(version, "0.4.") || startsWith(version, "0.5.") || version == "" || version == "dev");
if (legacy1) {
info("Converting patch using legacy1 loader");
} }


// modules // modules


+ 1
- 1
src/app/Toolbar.cpp View File

@@ -178,7 +178,7 @@ Toolbar::Toolbar() {
xPos += margin; xPos += margin;
*/ */


#ifdef VERSION
#if defined(RELEASE)
{ {
Widget *pluginManager = new PluginManagerWidget(); Widget *pluginManager = new PluginManagerWidget();
pluginManager->box.pos = Vec(xPos, margin); pluginManager->box.pos = Vec(xPos, margin);


+ 6
- 6
src/asset.cpp View File

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


std::string assetGlobal(std::string filename) { std::string assetGlobal(std::string filename) {
std::string dir; std::string dir;
#ifdef VERSION
#if defined(RELEASE)
#if ARCH_MAC #if ARCH_MAC
CFBundleRef bundle = CFBundleGetMainBundle(); CFBundleRef bundle = CFBundleGetMainBundle();
assert(bundle); assert(bundle);
@@ -45,16 +45,16 @@ std::string assetGlobal(std::string filename) {
// TODO For now, users should launch Rack from their terminal in the global directory // TODO For now, users should launch Rack from their terminal in the global directory
dir = "."; dir = ".";
#endif #endif
#else // VERSION
#else // RELEASE
dir = "."; dir = ".";
#endif // VERSION
#endif // RELEASE
return dir + "/" + filename; return dir + "/" + filename;
} }




std::string assetLocal(std::string filename) { std::string assetLocal(std::string filename) {
std::string dir; std::string dir;
#ifdef VERSION
#if defined(RELEASE)
#if ARCH_MAC #if ARCH_MAC
// Get home directory // Get home directory
struct passwd *pw = getpwuid(getuid()); struct passwd *pw = getpwuid(getuid());
@@ -83,9 +83,9 @@ std::string assetLocal(std::string filename) {
dir += "/.Rack"; dir += "/.Rack";
mkdir(dir.c_str(), 0755); mkdir(dir.c_str(), 0755);
#endif #endif
#else // VERSION
#else // RELEASE
dir = "."; dir = ".";
#endif // VERSION
#endif // RELEASE
return dir + "/" + filename; return dir + "/" + filename;
} }




+ 5
- 12
src/core/MidiToCV.cpp View File

@@ -2,7 +2,7 @@
#include <list> #include <list>
#include <algorithm> #include <algorithm>
#include "core.hpp" #include "core.hpp"
#include "MidiIO.hpp"
#include "midi.hpp"
#include "dsp/digital.hpp" #include "dsp/digital.hpp"




@@ -16,7 +16,7 @@ struct MidiValue {
bool changed = false; // Value has been changed by midi message (only if it is in sync!) bool changed = false; // Value has been changed by midi message (only if it is in sync!)
}; };


struct MIDIToCVInterface : MidiIO, Module {
struct MIDIToCVInterface : Module {
enum ParamIds { enum ParamIds {
RESET_PARAM, RESET_PARAM,
NUM_PARAMS NUM_PARAMS
@@ -49,7 +49,7 @@ struct MIDIToCVInterface : MidiIO, Module {


SchmittTrigger resetTrigger; SchmittTrigger resetTrigger;


MIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
MIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
pitchWheel.val = 64; pitchWheel.val = 64;
pitchWheel.tSmooth.set(0, 0); pitchWheel.tSmooth.set(0, 0);
} }
@@ -253,8 +253,7 @@ MidiToCVWidget::MidiToCVWidget() {
} }


addParam(createParam<LEDButton>(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0)); addParam(createParam<LEDButton>(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0));
addChild(createLight<SmallLight<RedLight>>(Vec(7 * 15 + 5, labelHeight + 5), module,
MIDIToCVInterface::RESET_LIGHT));
addChild(createLight<SmallLight<RedLight>>(Vec(7 * 15 + 5, labelHeight + 5), module, MIDIToCVInterface::RESET_LIGHT));
{ {
Label *label = new Label(); Label *label = new Label();
label->box.pos = Vec(margin, yPos); label->box.pos = Vec(margin, yPos);
@@ -285,8 +284,7 @@ MidiToCVWidget::MidiToCVWidget() {
yPos += channelChoice->box.size.y + margin + 15; yPos += channelChoice->box.size.y + margin + 15;
} }


std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel",
"Aftertouch"};
std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel", "Aftertouch"};


for (int i = 0; i < MIDIToCVInterface::NUM_OUTPUTS; i++) { for (int i = 0; i < MIDIToCVInterface::NUM_OUTPUTS; i++) {
Label *label = new Label(); Label *label = new Label();
@@ -299,9 +297,4 @@ MidiToCVWidget::MidiToCVWidget() {
yPos += yGap + margin; yPos += yGap + margin;
} }
} }

void MidiToCVWidget::step() {

ModuleWidget::step();
}
#endif #endif

+ 1
- 1
src/core/core.cpp View File

@@ -8,8 +8,8 @@ void init(rack::Plugin *p) {
#endif #endif


p->addModel(createModel<AudioInterfaceWidget>("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); p->addModel(createModel<AudioInterfaceWidget>("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG));
// p->addModel(createModel<MidiToCVWidget>("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG));


// p->addModel(createModel<MidiToCVWidget>("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG));
// p->addModel(createModel<MIDICCToCVWidget>("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); // p->addModel(createModel<MIDICCToCVWidget>("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG));
// p->addModel(createModel<MIDIClockToCVWidget>("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); // p->addModel(createModel<MIDIClockToCVWidget>("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG));
// p->addModel(createModel<MIDITriggerToCVWidget>("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); // p->addModel(createModel<MIDITriggerToCVWidget>("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG));


+ 16
- 18
src/core/core.hpp View File

@@ -14,29 +14,27 @@ struct AudioInterfaceWidget : ModuleWidget {


struct MidiToCVWidget : ModuleWidget { struct MidiToCVWidget : ModuleWidget {
MidiToCVWidget(); MidiToCVWidget();
void step() override;
}; };


struct MIDICCToCVWidget : ModuleWidget {
MIDICCToCVWidget();
void step() override;
};

struct MIDIClockToCVWidget : ModuleWidget {
MIDIClockToCVWidget();
void step() override;
};
// struct MIDICCToCVWidget : ModuleWidget {
// MIDICCToCVWidget();
// void step() override;
// };


struct MIDITriggerToCVWidget : ModuleWidget {
MIDITriggerToCVWidget();
void step() override;
};
// struct MIDIClockToCVWidget : ModuleWidget {
// MIDIClockToCVWidget();
// void step() override;
// };


struct QuadMidiToCVWidget : ModuleWidget {
QuadMidiToCVWidget();
void step() override;
};
// struct MIDITriggerToCVWidget : ModuleWidget {
// MIDITriggerToCVWidget();
// void step() override;
// };


// struct QuadMidiToCVWidget : ModuleWidget {
// QuadMidiToCVWidget();
// void step() override;
// };


struct BridgeWidget : ModuleWidget { struct BridgeWidget : ModuleWidget {
BridgeWidget(); BridgeWidget();


+ 1
- 4
src/gui.cpp View File

@@ -432,10 +432,7 @@ void guiRun() {
mouseButtonStickyPop(); mouseButtonStickyPop();


// Set window title // Set window title
std::string windowTitle = gApplicationName;
if (!gApplicationVersion.empty()) {
windowTitle += " v" + gApplicationVersion;
}
std::string windowTitle = gApplicationName + " v" + gApplicationVersion;
if (!gRackWidget->lastPath.empty()) { if (!gRackWidget->lastPath.empty()) {
windowTitle += " - "; windowTitle += " - ";
windowTitle += extractFilename(gRackWidget->lastPath); windowTitle += extractFilename(gRackWidget->lastPath);


+ 12
- 7
src/main.cpp View File

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


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


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


{ {
char *cwd = getcwd(NULL, 0); char *cwd = getcwd(NULL, 0);
@@ -35,21 +33,28 @@ int main(int argc, char* argv[]) {
engineInit(); engineInit();
guiInit(); guiInit();
sceneInit(); sceneInit();
gRackWidget->loadPatch(assetLocal("autosave.vcv"));
settingsLoad(assetLocal("settings.json")); settingsLoad(assetLocal("settings.json"));


// 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;
settingsSave(assetLocal("settings.json"));
skipAutosaveOnLaunch = false;
if (!oldSkipAutosaveOnLaunch)
gRackWidget->loadPatch(assetLocal("autosave.vcv"));

engineStart(); engineStart();
guiRun(); guiRun();
engineStop(); engineStop();


settingsSave(assetLocal("settings.json"));
gRackWidget->savePatch(assetLocal("autosave.vcv")); gRackWidget->savePatch(assetLocal("autosave.vcv"));
settingsSave(assetLocal("settings.json"));
sceneDestroy(); sceneDestroy();
guiDestroy(); guiDestroy();
engineDestroy(); engineDestroy();
pluginDestroy(); pluginDestroy();


#ifdef VERSION
#ifdef RELEASE
fclose(gLogFile); fclose(gLogFile);
#endif #endif




+ 17
- 6
src/settings.cpp View File

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




bool skipAutosaveOnLaunch = false;


static json_t *settingsToJson() { static json_t *settingsToJson() {
// root // root
json_t *rootJ = json_object(); json_t *rootJ = json_object();
@@ -56,6 +59,11 @@ static json_t *settingsToJson() {
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);


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

return rootJ; return rootJ;
} }


@@ -114,22 +122,25 @@ static void settingsFromJson(json_t *rootJ) {
json_t *lastPathJ = json_object_get(rootJ, "lastPath"); json_t *lastPathJ = json_object_get(rootJ, "lastPath");
if (lastPathJ) if (lastPathJ)
gRackWidget->lastPath = json_string_value(lastPathJ); gRackWidget->lastPath = json_string_value(lastPathJ);

json_t *skipAutosaveOnLaunchJ = json_object_get(rootJ, "skipAutosaveOnLaunch");
if (skipAutosaveOnLaunchJ)
skipAutosaveOnLaunch = json_boolean_value(skipAutosaveOnLaunchJ);
} }




void settingsSave(std::string filename) { void settingsSave(std::string filename) {
info("Saving settings %s", filename.c_str()); info("Saving settings %s", filename.c_str());
FILE *file = fopen(filename.c_str(), "w");
if (!file)
return;

json_t *rootJ = settingsToJson(); json_t *rootJ = settingsToJson();
if (rootJ) { if (rootJ) {
FILE *file = fopen(filename.c_str(), "w");
if (!file)
return;

json_dumpf(rootJ, file, JSON_INDENT(2)); json_dumpf(rootJ, file, JSON_INDENT(2));
json_decref(rootJ); json_decref(rootJ);
fclose(file);
} }

fclose(file);
} }


void settingsLoad(std::string filename) { void settingsLoad(std::string filename) {


+ 6
- 2
src/util.cpp View File

@@ -99,12 +99,12 @@ std::string stringf(const char *format, ...) {
return s; return s;
} }


std::string tolower(std::string s) {
std::string lowercase(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower); std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s; return s;
} }


std::string toupper(std::string s) {
std::string uppercase(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::toupper); std::transform(s.begin(), s.end(), s.begin(), ::toupper);
return s; return s;
} }
@@ -116,6 +116,10 @@ std::string ellipsize(std::string s, size_t len) {
return s.substr(0, len - 3) + "..."; return s.substr(0, len - 3) + "...";
} }


bool startsWith(std::string str, std::string prefix) {
return str.substr(0, prefix.size()) == prefix;
}

std::string extractDirectory(std::string path) { std::string extractDirectory(std::string path) {
char *pathDup = strdup(path.c_str()); char *pathDup = strdup(path.c_str());
std::string directory = dirname(pathDup); std::string directory = dirname(pathDup);


Loading…
Cancel
Save