Commit 52672c93 authored by jhammen's avatar jhammen
Browse files

use typed messages, stringbuffer class

parent 9929be3d
......@@ -63,7 +63,6 @@ Plugin::Plugin(const LV2_Feature *const *features, uint16_t channelCount)
}
handrumr_init_uris(map, &uris);
lv2_atom_forge_init(&forge, map);
errbuffer[0] = '\0';
}
Plugin::~Plugin() {
......@@ -93,7 +92,7 @@ void Plugin::connectPort(uint32_t port, void *data) {
}
LV2_State_Status Plugin::restore(LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle,
uint32_t flags, const LV2_Feature *const *features) {
uint32_t, const LV2_Feature *const *) {
for (int i = 0; i < HD_MAX_PATCHES; i++) {
// get config file from state
size_t size;
......@@ -101,20 +100,25 @@ LV2_State_Status Plugin::restore(LV2_State_Retrieve_Function retrieve, LV2_State
const void *value = retrieve(handle, uris.hd_config[i], &size, &type, &valflags);
if (!value) {
if (i == 0) {
printf("Handrumr: cannot restore, missing config %d\n", i);
printf("Handrumr cannot restore, missing config %d\n", i);
return LV2_STATE_ERR_NO_PROPERTY;
}
break;
} else if (type != uris.atom_String) {
printf("Handrumr, cannot restore: non-string config %d\n", i);
printf("Handrumr cannot restore: non-string config %d\n", i);
return LV2_STATE_ERR_BAD_TYPE;
}
// launch worker
if (size > 1) {
ConfigMessage message(static_cast<const char *>(value), i);
char buffer[HD_BUFFER_SIZE];
message.serialize(buffer, HD_BUFFER_SIZE);
worker->schedule_work(worker->handle, message.size(), buffer);
StringMesg mesg;
mesg.index(i);
const char *path = static_cast<const char *>(value);
if (mesg.name(path, strlen(path))) {
worker->schedule_work(worker->handle, mesg.size(), &mesg);
} else {
printf("Handrumr cannot restore: path too long at config %d\n", i);
return LV2_STATE_ERR_NO_SPACE;
}
}
}
return LV2_STATE_SUCCESS;
......@@ -123,23 +127,28 @@ LV2_State_Status Plugin::restore(LV2_State_Retrieve_Function retrieve, LV2_State
LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
LV2_Worker_Respond_Handle handle, uint32_t size, const void *data) {
// const LV2_Atom *value = static_cast<const LV2_Atom *>(data);
ConfigMessage mesg;
mesg.deserialize((char *)data);
if (mesg.config()) { // request to delete config
int32_t mesgtype = *((int64_t *)(data));
if (mesgtype == WKR_DELETE_REQUEST) {
DeleteRequestMesg mesg;
mesg.deserialize((const char *)data);
delete mesg.config();
return LV2_WORKER_SUCCESS;
} else if (mesgtype != WKR_STRING_MESG) {
return LV2_WORKER_ERR_UNKNOWN;
}
const char *path = mesg.string();
const uint16_t index = mesg.index();
StringMesg mesg;
if (!mesg.deserialize((const char *)data, size)) {
return LV2_WORKER_ERR_NO_SPACE;
}
const char *path = mesg.name();
const uint32_t index = mesg.index();
std::ifstream ifs;
ifs.open(path);
if (!ifs.is_open()) {
string mesg("Cannot open config file: ");
mesg.append(path);
ConfigMessage errmesg(mesg.c_str(), index);
errmesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, errmesg.size(), workerbuf);
StringMesg errmesg(mesg.c_str(), index);
respond(handle, errmesg.size(), &errmesg);
return LV2_WORKER_ERR_UNKNOWN;
}
Json::Value root;
......@@ -148,9 +157,8 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
if (!parseFromStream(builder, ifs, &root, &errs)) {
string mesg("Handrumr JSON parse error: ");
mesg.append(errs);
ConfigMessage errmesg(mesg.c_str(), index);
errmesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, errmesg.size(), workerbuf);
StringMesg errmesg(mesg.c_str(), index);
respond(handle, errmesg.size(), &errmesg);
return LV2_WORKER_ERR_UNKNOWN;
}
// start new config
......@@ -168,9 +176,8 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
int err = 0;
zip = zip_open(zipfile.c_str(), 0, &err);
if (!zip) {
ConfigMessage mesg("Could not open zipfile", index);
mesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, mesg.size(), workerbuf);
StringMesg mesg("Could not open zipfile", index);
respond(handle, mesg.size(), &mesg);
return LV2_WORKER_ERR_UNKNOWN;
}
}
......@@ -187,9 +194,8 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
Json::Value jsonSamples = jsonLayers[l]["samples"];
uint16_t sampleCount = jsonSamples.size();
if (!sampleCount) {
ConfigMessage mesg("Samples array cannot be empty", index);
mesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, mesg.size(), workerbuf);
StringMesg mesg("Samples array cannot be empty", index);
respond(handle, mesg.size(), &mesg);
return LV2_WORKER_ERR_UNKNOWN;
}
Sample *samples = new Sample[sampleCount];
......@@ -204,9 +210,8 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
fileCount = jsonSample.size();
jsamples = jsonSample;
} else {
ConfigMessage mesg("Samples array item must be an array or object", index);
mesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, mesg.size(), workerbuf);
StringMesg mesg("Samples array item must be an array or object", index);
respond(handle, mesg.size(), &mesg);
return LV2_WORKER_ERR_UNKNOWN;
}
uint16_t bufferCount = 0; // overall channel count for sample
......@@ -220,9 +225,8 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
file = new SampleFile(zip, path);
filecache[path] = file;
} catch (const std::logic_error &e) {
ConfigMessage mesg(e.what(), index);
mesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, mesg.size(), workerbuf);
StringMesg mesg(e.what(), index);
respond(handle, mesg.size(), &mesg);
return LV2_WORKER_ERR_UNKNOWN;
}
}
......@@ -297,9 +301,8 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
} catch (Json::LogicError err) {
string mesg("Error parsing JSON: ");
mesg.append(err.what());
ConfigMessage errmesg(mesg.c_str(), index);
errmesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, errmesg.size(), workerbuf);
StringMesg errmesg(mesg.c_str(), index);
respond(handle, errmesg.size(), &errmesg);
return LV2_WORKER_ERR_UNKNOWN;
}
......@@ -307,9 +310,10 @@ LV2_Worker_Status Plugin::work(LV2_Worker_Respond_Function respond,
zip_close(zip);
}
config->filepath = path;
ConfigMessage response(config, index);
response.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, response.size(), workerbuf);
NewConfigMesg response;
response.index(index);
response.config(config);
respond(handle, sizeof(response), &response);
return LV2_WORKER_SUCCESS;
}
......@@ -330,9 +334,8 @@ LV2_Worker_Status Plugin::channelMismatch(LV2_Worker_Respond_Function respond,
mesg.append(std::to_string(filechannels));
mesg.append(" channels: ");
mesg.append(path);
ConfigMessage errmesg(mesg.c_str(), index);
errmesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, errmesg.size(), workerbuf);
StringMesg errmesg(mesg.c_str(), index);
respond(handle, errmesg.size(), &errmesg);
return LV2_WORKER_ERR_UNKNOWN;
}
......@@ -341,32 +344,37 @@ LV2_Worker_Status Plugin::channelOutOfRange(LV2_Worker_Respond_Function respond,
uint16_t index) {
string mesg = "Channel index out of bounds: ";
mesg.append(std::to_string(channel));
ConfigMessage errmesg(mesg.c_str(), index);
errmesg.serialize(workerbuf, HD_BUFFER_SIZE);
respond(handle, errmesg.size(), workerbuf);
StringMesg errmesg(mesg.c_str(), index);
respond(handle, errmesg.size(), &errmesg);
return LV2_WORKER_ERR_UNKNOWN;
}
LV2_Worker_Status Plugin::workResponse(uint32_t size, const void *data) {
ConfigMessage mesg;
mesg.deserialize((char *)data);
if (mesg.config()) {
int32_t mesgtype = *((int64_t *)(data));
if (mesgtype == WKR_STRING_MESG) {
StringMesg mesg;
mesg.deserialize((const char *)data, size);
errbuffer.append("Error loading config ", 21);
errbuffer.append(mesg.index());
errbuffer.append(". ", 2);
errbuffer.append(mesg.name(), mesg.strlen());
} else {
NewConfigMesg mesg;
mesg.deserialize((const char *)data);
PluginConfig *existing = config[mesg.index()];
config[mesg.index()] = mesg.config();
if (existing) {
existing->next = inactiveList;
inactiveList = existing;
}
inactiveList = existing;
} else { // an error
strcpy(errbuffer, mesg.string());
}
// trigger set patch message to UI
setpatch = true;
return LV2_WORKER_SUCCESS;
}
LV2_State_Status Plugin::save(LV2_State_Store_Function store, LV2_State_Handle handle,
uint32_t flags, const LV2_Feature *const *features) {
LV2_State_Status Plugin::save(LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t,
const LV2_Feature *const *) {
for (int i = 0; i < HD_MAX_PATCHES; i++) {
if (config[i]) {
store(handle, uris.hd_config[i], config[i]->filepath.c_str(),
......@@ -476,18 +484,18 @@ void Plugin::run(uint32_t sampleCount) {
const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
if (obj->body.otype == uris.patch_Get) {
setpatch = true;
} else if (obj->body.otype == uris.patch_Set) {
} else if (obj->body.otype == uris.patch_Set) { // change to add
// get atom value from patch set message
const LV2_Atom *value = NULL;
lv2_atom_object_get(obj, uris.patch_value, &value, 0);
if (value && value->type == uris.atom_String) {
const char *path = (const char *)LV2_ATOM_BODY_CONST(value);
ConfigMessage mesg(path, 0);
if (mesg.serialize(mesgbuffer, HD_BUFFER_SIZE)) {
worker->schedule_work(worker->handle, mesg.size(), mesgbuffer);
StringMesg mesg;
mesg.index(0);
if (mesg.name(path, strlen(path))) {
worker->schedule_work(worker->handle, mesg.size(), &mesg);
} else {
strcpy(errbuffer, "Path to config file is too long");
setpatch = true;
errbuffer.append("Path to config file is too long", 31);
}
}
} else if (obj->body.otype == uris.time_Position) {
......@@ -530,13 +538,13 @@ void Plugin::run(uint32_t sampleCount) {
if (inactive) {
PluginConfig *done = inactiveList;
inactiveList = done->next;
ConfigMessage mesg(done, 0); // index doesn't matter here
mesg.serialize(mesgbuffer, HD_BUFFER_SIZE);
worker->schedule_work(worker->handle, mesg.size(), mesgbuffer);
DeleteRequestMesg mesg;
mesg.config(done);
worker->schedule_work(worker->handle, sizeof(mesg), &mesg);
}
// update UI via notify port
if (velocity || setpatch || errbuffer[0] != '\0') {
if (velocity || setpatch || errbuffer.strlen()) {
const uint32_t space = uioutput->atom.size;
lv2_atom_forge_set_buffer(&forge, (uint8_t *)uioutput, space);
lv2_atom_forge_sequence_head(&forge, &this->frame, 0);
......@@ -562,14 +570,14 @@ void Plugin::run(uint32_t sampleCount) {
setpatch = false;
}
if (errbuffer[0] != '\0') {
if (errbuffer.strlen()) {
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_frame_time(&forge, 0);
lv2_atom_forge_object(&forge, &frame, 0, uris.ui_Error);
lv2_atom_forge_key(&forge, uris.errorMessage);
lv2_atom_forge_string(&forge, errbuffer, strlen(errbuffer));
lv2_atom_forge_string(&forge, errbuffer.ptr(), errbuffer.size());
lv2_atom_forge_pop(&forge, &frame);
errbuffer[0] = '\0';
errbuffer.clear();
}
if (velocity) {
......
......@@ -77,48 +77,85 @@ class SamplePlay {
}
};
class ConfigMessage {
uint16_t mindex;
PluginConfig *mconfig;
const char *mstring;
size_t msize;
class StringBuffer {
char buffer[HD_BUFFER_SIZE];
uint32_t mend; //
public:
ConfigMessage() : mconfig(nullptr), mstring(nullptr) {}
ConfigMessage(PluginConfig *config, uint16_t index)
: mindex(index), mconfig(config), mstring(nullptr) {}
ConfigMessage(const char *string, uint16_t index)
: mindex(index), mconfig(nullptr), mstring(string) {}
size_t size() { return msize; }
uint16_t index() { return mindex; }
bool serialize(char *buffer, size_t bufsize) {
*((PluginConfig **)buffer) = mconfig;
*((uint16_t *)(buffer + sizeof(mconfig))) = mindex;
size_t hsize = sizeof(mconfig) + sizeof(uint16_t);
if (mstring) {
size_t copysize = bufsize - hsize;
size_t strsize = strlen(mstring) + 1;
if (strsize <= copysize) {
strncpy(buffer + hsize, mstring, strsize);
msize = hsize + strsize;
return true;
} else { // string larger than buffer
strncpy(buffer + hsize, mstring, copysize);
buffer[bufsize - 1] = '\0';
msize = bufsize;
return false;
}
StringBuffer() : mend(0) {}
bool append(const char *str, uint32_t strlen) {
uint32_t strsize = strlen + 1;
size_t copysize = HD_BUFFER_SIZE - mend;
if (strsize <= copysize) {
strncpy(buffer + mend, str, strsize);
mend += strlen;
return true;
} else { // string larger than buffer
strncpy(buffer + mend, str, copysize);
buffer[HD_BUFFER_SIZE - 1] = '\0';
mend = HD_BUFFER_SIZE;
return false;
}
msize = hsize;
return true;
}
void deserialize(char *buffer) {
mconfig = *((PluginConfig **)buffer);
mindex = *((uint16_t *)(buffer + sizeof(mconfig)));
mstring = mconfig ? nullptr : buffer + sizeof(mconfig) + sizeof(uint16_t);
bool append(uint32_t number) {
char numbuf[64];
sprintf(numbuf, "%u", number);
return append(numbuf, ::strlen(numbuf));
}
size_t size() { return mend + 1; }
size_t strlen() { return mend; }
const char *ptr() { return buffer; }
void clear() { mend = 0; }
};
// worker message types
enum { WKR_STRING_MESG, WKR_DELETE_REQUEST, WKR_CONFIG_RESPONSE };
class StringMesg {
const int64_t mtype = WKR_STRING_MESG;
uint32_t mindex;
StringBuffer mname;
public:
StringMesg() {}
StringMesg(const char *str, uint32_t index) : mindex(index) { name(str, ::strlen(str)); }
int32_t type() { return mtype; }
bool name(const char *str, uint32_t size) { return mname.append(str, size); }
const char *name() { return mname.ptr(); }
void index(uint32_t index) { mindex = index; }
uint32_t index() { return mindex; }
size_t size() { return sizeof(mtype) + sizeof(mindex) + mname.size(); }
size_t strlen() { return mname.strlen(); }
bool deserialize(const char *buffer, uint32_t size) {
mindex = *((uint32_t *)(buffer + sizeof(mtype)));
uint32_t header = sizeof(mtype) + sizeof(mindex);
return mname.append(buffer + header, size - header);
}
};
class DeleteRequestMesg {
const int64_t mtype = WKR_DELETE_REQUEST;
PluginConfig *mconfig;
public:
void config(PluginConfig *config) { mconfig = config; }
PluginConfig *config() { return mconfig; }
void deserialize(const char *buffer) { mconfig = *((PluginConfig **)(buffer + sizeof(mtype))); }
};
class NewConfigMesg {
const int64_t mtype = WKR_CONFIG_RESPONSE;
uint32_t mindex;
PluginConfig *mconfig;
public:
void index(uint32_t index) { mindex = index; }
uint32_t index() { return mindex; }
void config(PluginConfig *config) { mconfig = config; }
PluginConfig *config() { return mconfig; }
const char *string() { return mstring; }
void deserialize(const char *buffer) {
mindex = *((uint32_t *)(buffer + sizeof(mtype)));
mconfig = *((PluginConfig **)(buffer + sizeof(mtype) + sizeof(mconfig)));
}
};
class Plugin {
......@@ -140,9 +177,7 @@ class Plugin {
LV2_Atom_Forge forge;
LV2_Atom_Forge_Frame frame;
LV2_Atom_Sequence *uioutput;
char mesgbuffer[HD_BUFFER_SIZE];
char errbuffer[HD_BUFFER_SIZE];
char workerbuf[HD_BUFFER_SIZE]; // for worker thread
StringBuffer errbuffer;
bool setpatch;
public:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment