I don’t think this is the case, a quick print to the console shows that jsonSavePath does indeed update to the current path even though it’s not a pointer (and it doesn’t cause a seg fault)
…scrub that, the path going to and from JSON is the default image, not the updated one, so jsonSavePath is not getting updated, so the pointers are not working as it’s only changing the jsonSavePath on creation
Woohoo! got a new error…
Rack(13817,0x10ece15c0) malloc: Incorrect checksum for freed object 0x7f7f15cadaa8: probably modified after being freed.
Corrupt value: 0x36
Rack(13817,0x10ece15c0) malloc: *** set a breakpoint in malloc_error_break to debug
Maybe it’s something to do with how JSON handles memory allocation, maybe that’s why I can’t have a shared memloc between the widgets and the JSON save load?
I told you those JSON things are tricky. I would not pass them around, and I would for sure not pass a pointer to one. Like @carbon14 says, pass around std::string
. Or if you insist on efficiency, std::string&
And, if you used and debugger, it would tell you immediately where your problems is. Clearly there is memory monkey business going on…
it’s not really about efficiency, since the path is required by the widgets and the only reason i need it in the Module struct is because I want to save out to JSON, how else am i supposed to get it from the widget to the Module if I don’t use a pointer?
I guess my issue is that, even if I do use a debugger to confirm that I have a memory leak associated with jsonSavePath, I still wouldn’t have a clue how to fix it. Do you know of a module that saves a file path from a widget? So I might be able to see a working implementation? I kinda thought it would be trivial, but I probably got that wrong too!
Always test what you get from json_object_get
as it returns NULL if it can’t find an object.
void dataFromJson(json_t *rootJ) override {
json_t *savedPATHJ = json_object_get(rootJ, "sPATH");
if (savedPATHJ)
jsonSavePath = json_string_value(savedPATHJ);
}
Thanks for the tip
pass a string.
foo(std::string z) {
}
bar() {
std;:string x ("here I am");
foo(x); // just pass the whole string. it works by magic.
}
so I have a function in the Module struct that takes a string argument and I call that function from one of the widgets? Sorry, I’m confused as to where this “foo” function is located
i didn’t think i could call a function in one struct from another struct, I thought it all had to be handled with pointers in the Module widget
I’m aware of how to pass a string into a function using an argument, just not sure how that’s going to get a string from the SvgWidget to the Module, if that makes sense?
I can’t keep up. I’ll bow out. Good luck.
thank you for trying, it’s most appreciated
#include "plugin.hpp"
struct _4hp : Module
{
enum ParamId
{
PARAMS_LEN
};
enum InputId
{
INPUTS_LEN
};
enum OutputId
{
OUTPUTS_LEN
};
enum LightId
{
LIGHTS_LEN
};
_4hp()
{
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
}
std::string jsonSavePath; // storage for SVG image file path
bool pathDirty = false; // flag to indicate path has been changed
// save and load filepath to JSON file
json_t *dataToJson() override
{
json_t *rootJ = json_object();
json_object_set_new(rootJ, "sPATH", json_string(jsonSavePath.c_str()));
return rootJ;
}
void dataFromJson(json_t *rootJ) override
{
json_t *savedPATHJ = json_object_get(rootJ, "sPATH");
if (savedPATHJ)
jsonSavePath = json_string_value(savedPATHJ);
}
};
struct customPanel : SvgWidget
{
_4hp *module;
customPanel()
{
// Does nothing because PATH is empty on construction
// setSvg(Svg::load(asset::plugin(pluginInstance, PATH))); // set SVG file on creation of customPanel
}
void draw(const DrawArgs& args) override
{
if (module) {
if (module->pathDirty) {
module->pathDirty = false;
setSvg(Svg::load(asset::plugin(pluginInstance, module->jsonSavePath))); // set new file path
}
}
SvgWidget::draw(args); // continue to run the rest of the default draw function
}
};
struct dnd : TransparentWidget
{
_4hp *module;
std::string svgPath = asset::plugin(pluginInstance, "res/test.svg"); // path with SVG extension
void onPathDrop(const PathDropEvent &e) override
{
std::string filePath = e.paths.front(); // get first path in array, all other paths are ignored
if(filePath.substr(filePath.find_last_of(".") + 1) == "svg") // check for SVG extension
{
svgPath = filePath; // store path
if (module) {
module->jsonSavePath = svgPath;
module->pathDirty = true;
}
}
else
{
DEBUG("Invalid file extension: try *.svg\n");
}
}
};
struct _4hpWidget : ModuleWidget
{
_4hpWidget(_4hp *module)
{
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/4hp.svg")));
// maunally add widgets to allow for pointer references
dnd *DND = new dnd();
DND->module = module;
DND->box.pos = Vec(0, 0);
DND->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
addChild(DND);
customPanel *CP = new customPanel();
CP->module = module;
CP->box.pos = Vec(0, 0);
CP->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
addChild(CP);
if (module)
{
module->jsonSavePath = DND->svgPath;
module->pathDirty = true;
DEBUG("%s\n", module->jsonSavePath.c_str());
}
}
};
Model* model_4hp = createModel<_4hp, _4hpWidget>("4hp");
Or this version which will reload the last dragged svg, when you restart Rack. I’m guessing this is what you actually want
#include "plugin.hpp"
struct _4hp : Module
{
enum ParamId
{
PARAMS_LEN
};
enum InputId
{
INPUTS_LEN
};
enum OutputId
{
OUTPUTS_LEN
};
enum LightId
{
LIGHTS_LEN
};
_4hp()
{
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
}
std::string jsonSavePath; // storage for SVG image file path
bool pathDirty = false; // flag to indicate path has been changed
// save and load filepath to JSON file
json_t *dataToJson() override
{
json_t *rootJ = json_object();
json_object_set_new(rootJ, "sPATH", json_string(jsonSavePath.c_str()));
return rootJ;
}
void dataFromJson(json_t *rootJ) override
{
json_t *savedPATHJ = json_object_get(rootJ, "sPATH");
if (savedPATHJ) {
jsonSavePath = json_string_value(savedPATHJ);
pathDirty = true;
}
}
};
struct customPanel : SvgWidget
{
_4hp *module;
customPanel()
{
// Does nothing because PATH is empty on construction
// setSvg(Svg::load(asset::plugin(pluginInstance, PATH))); // set SVG file on creation of customPanel
}
void draw(const DrawArgs& args) override
{
if (module) {
if (module->pathDirty) {
module->pathDirty = false;
setSvg(Svg::load(asset::plugin(pluginInstance, module->jsonSavePath))); // set new file path
}
}
SvgWidget::draw(args); // continue to run the rest of the default draw function
}
};
struct dnd : TransparentWidget
{
_4hp *module;
std::string svgPath = asset::plugin(pluginInstance, "res/test.svg"); // path with SVG extension
void onPathDrop(const PathDropEvent &e) override
{
std::string filePath = e.paths.front(); // get first path in array, all other paths are ignored
if(filePath.substr(filePath.find_last_of(".") + 1) == "svg") // check for SVG extension
{
svgPath = filePath; // store path
if (module) {
module->jsonSavePath = svgPath;
module->pathDirty = true;
}
}
else
{
DEBUG("Invalid file extension: try *.svg\n");
}
}
};
struct _4hpWidget : ModuleWidget
{
_4hpWidget(_4hp *module)
{
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/4hp.svg")));
// maunally add widgets to allow for pointer references
dnd *DND = new dnd();
DND->module = module;
DND->box.pos = Vec(0, 0);
DND->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
addChild(DND);
customPanel *CP = new customPanel();
CP->module = module;
CP->box.pos = Vec(0, 0);
CP->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
addChild(CP);
if (module)
{
if (!module->pathDirty) {
module->jsonSavePath = DND->svgPath;
module->pathDirty = true;
}
DEBUG("%s\n", module->jsonSavePath.c_str());
}
}
};
Model* model_4hp = createModel<_4hp, _4hpWidget>("4hp");
Oh my goodness! Thank you very much David, super appreciated
Yeah, that’s exactly the functionality I was after, and it totally makes sense, I think the missing key for me was not knowing I could reference the module from within the widgets, I had presumed that was only possible from the actual moduleWidget. Really appreciate you spending the time going through my code
I think that you’ll find lldb
a lot more friendly, whether you’re on a Mac, windows, or linux. the llvm suite is quite nice.
lldb
has been part of Xcode since Xcode started using llvm in Xcode 4 (2010), so it’s not some “new thing”, nor is it a “wrapper”. you can simply start up rack in the debugger (lldb), and run it. if you crash, you should end up with a good backtrace (bt
).
you can also attach to the process if you know the PID, which makes it even easier (you can do this in gdb as well):
lldb -p PID
where PID is the process id rack is running as.
if you do this, don’t forget to cont
, or continue in the debugger to continue code execution.
Yeah I’ll have to have a good look at it when I have some time, not used debugger before for anything like this.
Thanks very much jerrysv, y’all have been most helpful