Browse Source

Add Notes to Core, added manufacturer slug/name to Model, reverted to

Plugins
tags/v0.5.0
Andrew Belt 7 years ago
parent
commit
fde88775d4
9 changed files with 167 additions and 118 deletions
  1. +4
    -4
      include/asset.hpp
  2. +18
    -17
      include/plugin.hpp
  3. +3
    -1
      include/rack.hpp
  4. +3
    -3
      src/app/ModuleWidget.cpp
  5. +54
    -40
      src/app/RackWidget.cpp
  6. +3
    -3
      src/asset.cpp
  7. +44
    -0
      src/core/Notes.cpp
  8. +10
    -12
      src/core/core.cpp
  9. +28
    -38
      src/plugin.cpp

+ 4
- 4
include/asset.hpp View File

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


/** Searches for a global read-only resource and returns its path, or "" if not found
/** Returns the path of a global resource. Read-only
*/
std::string assetGlobal(std::string filename);
/** Searches for a local resource
/** Returns the path of a local resource. Read/write
*/
std::string assetLocal(std::string filename);
/** Searches for a manufacturer resource, given a Manufacturer object
/** Returns the path of a resource in the plugin's folder. Read-only
*/
std::string assetManufacturer(Manufacturer *manufacturer, std::string filename);
std::string assetPlugin(Plugin *plugin, std::string filename);


} // namespace rack

+ 18
- 17
include/plugin.hpp View File

@@ -10,41 +10,42 @@ struct ModuleWidget;
struct Model;

// Subclass this and return a pointer to a new one when init() is called
struct Manufacturer {
/** A list of the models available by this manufacturer, add with addModel() */
struct Plugin {
/** A list of the models available by this plugin, add with addModel() */
std::list<Model*> models;
/** The file path of the plugins directory */
/** The file path of the plugin's directory */
std::string path;
/** OS-dependent library handle */
void *handle = NULL;

// You may set everything below this point in your plugin

/** A unique identifier for the manufacturer, e.g. "foo" */
/** Used when syncing plugins with the API */
std::string slug;
/** Human readable name for the manufacturer, e.g. "Foo Modular" */
std::string name;
/** Optional metadata for the Add Module context menu */
std::string homepageUrl;
std::string manualUrl;
/** The version of your plugin
Plugins should follow the versioning scheme described at https://github.com/VCVRack/Rack/issues/266
Do not include the "v" in "v1.0" for example.
*/
std::string version;

virtual ~Manufacturer();
virtual ~Plugin();
void addModel(Model *model);
};

struct Model {
Manufacturer *manufacturer = NULL;
/** A unique identifier for the model, e.g. "VCO" */
Plugin *plugin = NULL;
/** An identifier for the model, e.g. "VCO". Used for saving patches. The slug, manufacturerSlug pair must be unique. */
std::string slug;
/** Human readable name for your model, e.g. "Voltage Controlled Oscillator" */
std::string name;
/** An identifier for the manufacturer, e.g. "foo". Used for saving patches. */
std::string manufacturerSlug;
/** Human readable name for the manufacturer, e.g. "Foo Modular" */
std::string manufacturerName;

virtual ~Model() {}
virtual ModuleWidget *createModuleWidget() { return NULL; }
};

extern std::list<Manufacturer*> gManufacturers;
extern std::list<Plugin*> gPlugins;
extern std::string gToken;

void pluginInit();
@@ -66,8 +67,8 @@ std::string pluginGetLoginStatus();
// Implemented by plugin
////////////////////

/** Called once to initialize and return the Manufacturer instance.
/** Called once to initialize and return the Plugin instance.
You must implement this in your plugin
*/
extern "C"
void init(rack::Manufacturer *manufacturer);
void init(rack::Plugin *plugin);

+ 3
- 1
include/rack.hpp View File

@@ -18,7 +18,7 @@ namespace rack {
////////////////////

template <class TModuleWidget>
Model *createModel(std::string slug, std::string name) {
Model *createModel(std::string manufacturerSlug, std::string manufacturerName, std::string slug, std::string name) {
struct TModel : Model {
ModuleWidget *createModuleWidget() override {
ModuleWidget *moduleWidget = new TModuleWidget();
@@ -29,6 +29,8 @@ Model *createModel(std::string slug, std::string name) {
Model *model = new TModel();
model->slug = slug;
model->name = name;
model->manufacturerSlug = manufacturerSlug;
model->manufacturerName = manufacturerName;
return model;
}



+ 3
- 3
src/app/ModuleWidget.cpp View File

@@ -45,8 +45,8 @@ void ModuleWidget::addParam(ParamWidget *param) {
json_t *ModuleWidget::toJson() {
json_t *rootJ = json_object();

// plugin
json_object_set_new(rootJ, "plugin", json_string(model->manufacturer->slug.c_str()));
// manufacturer
json_object_set_new(rootJ, "manufacturer", json_string(model->manufacturerSlug.c_str()));
// model
json_object_set_new(rootJ, "model", json_string(model->slug.c_str()));
// pos
@@ -245,7 +245,7 @@ Menu *ModuleWidget::createContextMenu() {
Menu *menu = gScene->createMenu();

MenuLabel *menuLabel = new MenuLabel();
menuLabel->text = model->manufacturer->name + ": " + model->name;
menuLabel->text = model->manufacturerName + " " + model->name;
menu->pushChild(menuLabel);

ResetMenuItem *resetItem = new ResetMenuItem();


+ 54
- 40
src/app/RackWidget.cpp View File

@@ -1,12 +1,13 @@
#include <map>
#include <algorithm>
#include <thread>
#include "app.hpp"
#include "engine.hpp"
#include "plugin.hpp"
#include "gui.hpp"
#include "settings.hpp"
#include "asset.hpp"
#include <map>
#include <algorithm>
#include <thread>
#include <set>
#include "../ext/osdialog/osdialog.h"


@@ -200,36 +201,29 @@ void RackWidget::fromJson(json_t *rootJ) {
size_t moduleId;
json_t *moduleJ;
json_array_foreach(modulesJ, moduleId, moduleJ) {
json_t *pluginSlugJ = json_object_get(moduleJ, "plugin");
if (!pluginSlugJ) continue;
json_t *manufacturerSlugJ = json_object_get(moduleJ, "manufacturer");
if (!manufacturerSlugJ) {
// Backward compatibility with Rack v0.4 and lower
manufacturerSlugJ = json_object_get(moduleJ, "plugin");
if (!manufacturerSlugJ) continue;
}
json_t *modelSlugJ = json_object_get(moduleJ, "model");
if (!modelSlugJ) continue;
const char *pluginSlug = json_string_value(pluginSlugJ);
const char *modelSlug = json_string_value(modelSlugJ);

// Search for plugin
Manufacturer *manufacturer = NULL;
for (Manufacturer *m : gManufacturers) {
if (m->slug == pluginSlug) {
manufacturer = m;
break;
}
}
if (!manufacturer) {
message += stringf("Could not find plugin \"%s\" for module \"%s\".\n", pluginSlug, modelSlug);
continue;
}
std::string manufacturerSlug = json_string_value(manufacturerSlugJ);
std::string modelSlug = json_string_value(modelSlugJ);

// Get for model
// Search for model
Model *model = NULL;
for (Model *m : manufacturer->models) {
if (m->slug == modelSlug) {
model = m;
break;
for (Plugin *plugin : gPlugins) {
for (Model *m : plugin->models) {
if (m->manufacturerSlug == manufacturerSlug && m->slug == modelSlug) {
model = m;
}
}
}

if (!model) {
message += stringf("Could not find module \"%s\" in plugin \"%s\".\n", modelSlug, pluginSlug);
message += stringf("Could not find \"%s %s\" module\n", manufacturerSlug.c_str(), modelSlug.c_str());
continue;
}

@@ -389,12 +383,22 @@ struct UrlItem : MenuItem {
};

struct AddManufacturerMenuItem : MenuItem {
Manufacturer *manufacturer;
std::string manufacturerName;
Vec modulePos;
Menu *createChildMenu() override {
// Collect models which have this manufacturer name
std::set<Model*> models;
for (Plugin *plugin : gPlugins) {
for (Model *model : plugin->models) {
if (model->manufacturerName == manufacturerName) {
models.insert(model);
}
}
}

// Model items
Menu *menu = new Menu();
for (Model *model : manufacturer->models) {
for (Model *model : models) {
AddModuleMenuItem *item = new AddModuleMenuItem();
item->text = model->name;
item->model = model;
@@ -403,42 +407,44 @@ struct AddManufacturerMenuItem : MenuItem {
}

// Metadata items
/*
{
MenuLabel *label = new MenuLabel();
menu->pushChild(label);
}
{
MenuLabel *label = new MenuLabel();
label->text = manufacturer->name;
label->text = plugin->name;
menu->pushChild(label);
}

if (!manufacturer->homepageUrl.empty()) {
if (!plugin->homepageUrl.empty()) {
UrlItem *item = new UrlItem();
item->text = "Homepage";
item->url = manufacturer->homepageUrl;
item->url = plugin->homepageUrl;
menu->pushChild(item);
}

if (!manufacturer->manualUrl.empty()) {
if (!plugin->manualUrl.empty()) {
UrlItem *item = new UrlItem();
item->text = "Manual";
item->url = manufacturer->manualUrl;
item->url = plugin->manualUrl;
menu->pushChild(item);
}

if (!manufacturer->path.empty()) {
if (!plugin->path.empty()) {
UrlItem *item = new UrlItem();
item->text = "Browse directory";
item->url = manufacturer->path;
item->url = plugin->path;
menu->pushChild(item);
}

if (!manufacturer->version.empty()) {
if (!plugin->version.empty()) {
MenuLabel *item = new MenuLabel();
item->text = "Version: v" + manufacturer->version;
item->text = "Version: v" + plugin->version;
menu->pushChild(item);
}
*/

return menu;
}
@@ -452,10 +458,18 @@ void RackWidget::onMouseDownOpaque(int button) {
MenuLabel *menuLabel = new MenuLabel();
menuLabel->text = "Add module";
menu->pushChild(menuLabel);
for (Manufacturer *manufacturer : gManufacturers) {
// Collect manufacturer names
std::set<std::string> manufacturerNames;
for (Plugin *plugin : gPlugins) {
for (Model *model : plugin->models) {
manufacturerNames.insert(model->manufacturerName);
}
}
// Add menu item for each manufacturer name
for (std::string manufacturerName : manufacturerNames) {
AddManufacturerMenuItem *item = new AddManufacturerMenuItem();
item->text = manufacturer->name;
item->manufacturer = manufacturer;
item->text = manufacturerName;
item->manufacturerName = manufacturerName;
item->modulePos = modulePos;
menu->pushChild(item);
}


+ 3
- 3
src/asset.cpp View File

@@ -88,10 +88,10 @@ std::string assetLocal(std::string filename) {
return path;
}

std::string assetManufacturer(Manufacturer *manufacturer, std::string filename) {
assert(manufacturer);
std::string assetPlugin(Plugin *plugin, std::string filename) {
assert(plugin);
std::string path;
path = manufacturer->path + "/" + filename;
path = plugin->path + "/" + filename;
return path;
}



+ 44
- 0
src/core/Notes.cpp View File

@@ -0,0 +1,44 @@
#include "core.hpp"

using namespace rack;



NotesWidget::NotesWidget() {
box.size = Vec(RACK_GRID_WIDTH * 18, RACK_GRID_HEIGHT);

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

addChild(createScrew<ScrewSilver>(Vec(15, 0)));
addChild(createScrew<ScrewSilver>(Vec(15, 365)));
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0)));
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365)));

textField = new TextField();
textField->box.pos = Vec(15, 15);
textField->box.size = box.size.minus(Vec(30, 30));
textField->multiline = true;
addChild(textField);
}

json_t *NotesWidget::toJson() {
json_t *rootJ = ModuleWidget::toJson();

// text
json_object_set_new(rootJ, "text", json_string(textField->text.c_str()));

return rootJ;
}

void NotesWidget::fromJson(json_t *rootJ) {
ModuleWidget::fromJson(rootJ);

// text
json_t *textJ = json_object_get(rootJ, "text");
if (textJ)
textField->text = json_string_value(textJ);
}

+ 10
- 12
src/core/core.cpp View File

@@ -2,16 +2,14 @@
#include "MidiIO.hpp"


void init(rack::Manufacturer *m) {
m->slug = "Core";
m->name = "Core";
m->homepageUrl = "https://vcvrack.com/";
m->addModel(createModel<AudioInterfaceWidget>("AudioInterface", "Audio Interface"));
m->addModel(createModel<MidiToCVWidget>("MIDIToCVInterface", "MIDI-to-CV Interface"));
m->addModel(createModel<MIDICCToCVWidget>("MIDICCToCVInterface", "MIDI CC-to-CV Interface"));
m->addModel(createModel<MIDIClockToCVWidget>("MIDIClockToCVInterface", "MIDI Clock-to-CV Interface"));
m->addModel(createModel<MIDITriggerToCVWidget>("MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface"));
// m->addModel(createModel<BridgeWidget>("Bridge", "Bridge"));
m->addModel(createModel<BlankWidget>("Blank", "Blank"));
m->addModel(createModel<NotesWidget>("Notes", "Notes"));
void init(rack::Plugin *p) {
p->slug = "Core";
p->addModel(createModel<AudioInterfaceWidget>("Core", "Core", "AudioInterface", "Audio Interface"));
p->addModel(createModel<MidiToCVWidget>("Core", "Core", "MIDIToCVInterface", "MIDI-to-CV Interface"));
p->addModel(createModel<MIDICCToCVWidget>("Core", "Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface"));
p->addModel(createModel<MIDIClockToCVWidget>("Core", "Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface"));
p->addModel(createModel<MIDITriggerToCVWidget>("Core", "Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface"));
// p->addModel(createModel<BridgeWidget>("Core", "Core", "Bridge", "Bridge"));
p->addModel(createModel<BlankWidget>("Core", "Core", "Blank", "Blank"));
p->addModel(createModel<NotesWidget>("Core", "Core", "Notes", "Notes"));
}

+ 28
- 38
src/plugin.cpp View File

@@ -28,7 +28,7 @@

namespace rack {

std::list<Manufacturer*> gManufacturers;
std::list<Plugin*> gPlugins;
std::string gToken;

static bool isDownloading = false;
@@ -38,15 +38,15 @@ static std::string loginStatus;



Manufacturer::~Manufacturer() {
Plugin::~Plugin() {
for (Model *model : models) {
delete model;
}
}

void Manufacturer::addModel(Model *model) {
assert(!model->manufacturer);
model->manufacturer = this;
void Plugin::addModel(Model *model) {
assert(!model->plugin);
model->plugin = this;
models.push_back(model);
}

@@ -78,7 +78,7 @@ static int loadPlugin(std::string path) {
#endif

// Call plugin's init() function
typedef void (*InitCallback)(Manufacturer *);
typedef void (*InitCallback)(Plugin *);
InitCallback initCallback;
#if ARCH_WIN
initCallback = (InitCallback) GetProcAddress(handle, "init");
@@ -90,19 +90,14 @@ static int loadPlugin(std::string path) {
return -2;
}

// Construct and initialize Manufacturer instance
Manufacturer *manufacturer = new Manufacturer();
manufacturer->path = path;
manufacturer->handle = handle;
initCallback(manufacturer);
// Construct and initialize Plugin instance
Plugin *plugin = new Plugin();
plugin->path = path;
plugin->handle = handle;
initCallback(plugin);

// Check that this is a unique slug
for (Manufacturer *otherManufacturer : gManufacturers) {
assert(manufacturer->slug != otherManufacturer->slug);
}

// Add manufacturer to list
gManufacturers.push_back(manufacturer);
// Add plugin to list
gPlugins.push_back(plugin);
fprintf(stderr, "Loaded plugin %s\n", libraryFilename.c_str());
return 0;
}
@@ -200,13 +195,6 @@ static void refreshPurchase(json_t *pluginJ) {
url += "&token=";
url += gToken;

// Find slug in plugins list, and return silently if slug already exists
for (Manufacturer *m : gManufacturers) {
if (m->slug == slug) {
return;
}
}

// If plugin is not loaded, download the zip file to /plugins
downloadName = name;
downloadProgress = 0.0;
@@ -237,9 +225,9 @@ static void refreshPurchase(json_t *pluginJ) {
void pluginInit() {
// Load core
// This function is defined in core.cpp
Manufacturer *coreManufacturer = new Manufacturer();
Plugin *coreManufacturer = new Plugin();
init(coreManufacturer);
gManufacturers.push_back(coreManufacturer);
gPlugins.push_back(coreManufacturer);

// Load plugins from global directory
std::string globalPlugins = assetGlobal("plugins");
@@ -248,27 +236,29 @@ void pluginInit() {

// Load plugins from local directory
std::string localPlugins = assetLocal("plugins");
mkdir(localPlugins.c_str(), 0755);
printf("Loading plugins from %s\n", localPlugins.c_str());
if (globalPlugins != localPlugins)
if (globalPlugins != localPlugins) {
mkdir(localPlugins.c_str(), 0755);
printf("Loading plugins from %s\n", localPlugins.c_str());
loadPlugins(localPlugins);
}
}

void pluginDestroy() {
for (Manufacturer *manufacturer : gManufacturers) {
for (Plugin *plugin : gPlugins) {
// Free library handle
#if ARCH_WIN
if (manufacturer->handle)
FreeLibrary((HINSTANCE)manufacturer->handle);
if (plugin->handle)
FreeLibrary((HINSTANCE)plugin->handle);
#elif ARCH_LIN || ARCH_MAC
if (manufacturer->handle)
dlclose(manufacturer->handle);
if (plugin->handle)
dlclose(plugin->handle);
#endif

// For some reason this segfaults
// delete manufacturer;
// For some reason this segfaults.
// It might be best to let them leak anyway, because "crash on exit" issues would occur with badly-written plugins.
// delete plugin;
}
gManufacturers.clear();
gPlugins.clear();
}

void pluginLogIn(std::string email, std::string password) {


Loading…
Cancel
Save