Add state support and startup state polling for the ui

This commit is contained in:
Nick Lanham 2012-03-25 18:10:49 +02:00
parent dc2872309c
commit 1715d437e9
5 changed files with 153 additions and 8 deletions

103
drmr.c
View File

@ -159,12 +159,26 @@ connect_port(LV2_Handle instance,
} }
} }
static inline LV2_Atom* build_update_message(DrMr *drmr, const char* kit) { static inline LV2_Atom *build_update_message(DrMr *drmr) {
LV2_Atom_Forge_Frame set_frame; LV2_Atom_Forge_Frame set_frame;
LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_resource LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_resource
(&drmr->forge, &set_frame, 1, drmr->uris.ui_msg); (&drmr->forge, &set_frame, 1, drmr->uris.ui_msg);
if (drmr->current_path) {
lv2_atom_forge_property_head(&drmr->forge, drmr->uris.kit_path,0); lv2_atom_forge_property_head(&drmr->forge, drmr->uris.kit_path,0);
lv2_atom_forge_string(&drmr->forge, kit, strlen(kit)); lv2_atom_forge_string(&drmr->forge, drmr->current_path, strlen(drmr->current_path));
}
lv2_atom_forge_pop(&drmr->forge,&set_frame);
return msg;
}
static inline LV2_Atom *build_state_message(DrMr *drmr) {
LV2_Atom_Forge_Frame set_frame;
LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_resource
(&drmr->forge, &set_frame, 1, drmr->uris.get_state);
if (drmr->current_path) {
lv2_atom_forge_property_head(&drmr->forge, drmr->uris.kit_path,0);
lv2_atom_forge_string(&drmr->forge, drmr->current_path, strlen(drmr->current_path));
}
lv2_atom_forge_pop(&drmr->forge,&set_frame); lv2_atom_forge_pop(&drmr->forge,&set_frame);
return msg; return msg;
} }
@ -257,6 +271,10 @@ static void run(LV2_Handle instance, uint32_t n_samples) {
drmr->curReq = reqPos; drmr->curReq = reqPos;
if (tmp) free(tmp); if (tmp) free(tmp);
} }
} else if (obj->body.otype == drmr->uris.get_state) {
lv2_atom_forge_frame_time(&drmr->forge, 0);
build_state_message(drmr);
printf("Sent state message: %s\n",drmr->current_path);
} }
} }
else printf("unrecognized event\n"); else printf("unrecognized event\n");
@ -272,7 +290,8 @@ static void run(LV2_Handle instance, uint32_t n_samples) {
if (current_kit_changed) { if (current_kit_changed) {
current_kit_changed = 0; current_kit_changed = 0;
lv2_atom_forge_frame_time(&drmr->forge, 0); lv2_atom_forge_frame_time(&drmr->forge, 0);
build_update_message(drmr,drmr->current_path); build_update_message(drmr);
printf("Sent current path message\n");
} }
lv2_atom_forge_pop(&drmr->forge, &seq_frame); lv2_atom_forge_pop(&drmr->forge, &seq_frame);
@ -330,7 +349,85 @@ static void cleanup(LV2_Handle instance) {
free(instance); free(instance);
} }
void save_state(LV2_Handle instance,
LV2_State_Store_Function store,
void* handle,
uint32_t flags,
const LV2_Feature *const * features) {
DrMr *drmr = (DrMr*)instance;
LV2_State_Map_Path* map_path = NULL;
while(*features) {
if (!strcmp((*features)->URI, LV2_STATE__mapPath))
map_path = (LV2_State_Map_Path*)((*features)->data);
features++;
}
if (map_path == NULL) {
fprintf(stderr,"Host does not support map_path, cannot save state\n");
return;
}
char* mapped_path = map_path->abstract_path(map_path->handle,
drmr->current_path);
if (store(handle,
drmr->uris.kit_path,
mapped_path,
strlen(mapped_path) + 1,
drmr->uris.string_urid,
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
printf("Store failed\n");
}
}
void restore_state(LV2_Handle instance,
LV2_State_Retrieve_Function retrieve,
void* handle,
uint32_t flags,
const LV2_Feature *const * features) {
DrMr* drmr = (DrMr*)instance;
size_t size;
uint32_t type;
uint32_t fgs;
LV2_State_Map_Path* map_path = NULL;
while(*features) {
if (!strcmp((*features)->URI, LV2_STATE__mapPath))
map_path = (LV2_State_Map_Path*)((*features)->data);
features++;
}
if (map_path == NULL) {
fprintf(stderr,"Host does not support map_path, cannot restore state\n");
return;
}
const char* abstract_path =
retrieve(handle, drmr->uris.kit_path, &size, &type, &fgs);
if (!abstract_path) {
fprintf(stderr,"Found no path in state, not restoring\n");
return;
}
char *kit_path = map_path->absolute_path(map_path->handle,abstract_path);
if (kit_path) { // safe as we're in "Instantiation" threading class
int reqPos = (drmr->curReq+1)%REQ_BUF_SIZE;
char *tmp = NULL;
if (reqPos >= 0 && drmr->request_buf[reqPos])
tmp = drmr->request_buf[reqPos];
drmr->request_buf[reqPos] = strdup(kit_path);
drmr->curReq = reqPos;
if (tmp) free(tmp);
}
}
static const void* extension_data(const char* uri) { static const void* extension_data(const char* uri) {
static const LV2_State_Interface state_iface = { save_state, restore_state };
if (!strcmp(uri, LV2_STATE_URI "#Interface")) return &state_iface;
return NULL; return NULL;
} }

9
drmr.h
View File

@ -25,6 +25,7 @@
#include "lv2/lv2plug.in/ns/ext/atom/util.h" #include "lv2/lv2plug.in/ns/ext/atom/util.h"
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
#include "lv2/lv2plug.in/ns/ext/urid/urid.h" #include "lv2/lv2plug.in/ns/ext/urid/urid.h"
#include "lv2/lv2plug.in/ns/ext/state/state.h"
// drumkit scanned from a hydrogen xml file // drumkit scanned from a hydrogen xml file
typedef struct { typedef struct {
@ -147,6 +148,8 @@ typedef struct {
LV2_URID kit_path; LV2_URID kit_path;
LV2_URID atom_eventTransfer; LV2_URID atom_eventTransfer;
LV2_URID atom_resource; LV2_URID atom_resource;
LV2_URID string_urid;
LV2_URID get_state;
} drmr_uris; } drmr_uris;
typedef struct { typedef struct {
@ -190,12 +193,18 @@ void map_drmr_uris(LV2_URID_Map *map,
uris->midi_event = uris->midi_event =
map->map(map->handle, map->map(map->handle,
"http://lv2plug.in/ns/ext/midi#MidiEvent"); "http://lv2plug.in/ns/ext/midi#MidiEvent");
uris->string_urid =
map->map(map->handle,
"http://lv2plug.in/ns/ext/atom#String");
uris->ui_msg = uris->ui_msg =
map->map(map->handle, map->map(map->handle,
DRMR_URI "#uimsg"); DRMR_URI "#uimsg");
uris->kit_path = uris->kit_path =
map->map(map->handle, map->map(map->handle,
DRMR_URI "#kitpath"); DRMR_URI "#kitpath");
uris->kit_path =
map->map(map->handle,
DRMR_URI "#getstate");
uris->atom_eventTransfer = uris->atom_eventTransfer =
map->map(map->handle, LV2_ATOM__eventTransfer); map->map(map->handle, LV2_ATOM__eventTransfer);
uris->atom_resource = uris->atom_resource =

View File

@ -19,6 +19,7 @@
doap:license <http://usefulinc.com/doap/licenses/gpl> ; doap:license <http://usefulinc.com/doap/licenses/gpl> ;
lv2:requiredFeature urid:map ; lv2:requiredFeature urid:map ;
ui:ui <http://github.com/nicklan/drmr#ui> ; ui:ui <http://github.com/nicklan/drmr#ui> ;
lv2:extensionData <http://lv2plug.in/ns/ext/state#Interface> ;
lv2:port [ lv2:port [
a lv2:InputPort , atom:MessagePort; a lv2:InputPort , atom:MessagePort;
atom:bufferType atom:Sequence ; atom:bufferType atom:Sequence ;

View File

@ -18,6 +18,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <dirent.h>
@ -307,7 +309,7 @@ kits* scan_kits() {
} }
snprintf(buf,BUFSIZ,"%s/%s/",cur_path,ep->d_name); snprintf(buf,BUFSIZ,"%s/%s/",cur_path,ep->d_name);
kit->path = strdup(buf); kit->path = realpath(buf,NULL); // realpath will malloc for us
node->skit = kit; node->skit = kit;
struct kit_list * cur_k = scanned_kits; struct kit_list * cur_k = scanned_kits;
if (cur_k) { if (cur_k) {

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
@ -295,6 +296,14 @@ static LV2_Atom* build_path_message(DrMrUi *ui, const char* path) {
return msg; return msg;
} }
static LV2_Atom* build_get_state_message(DrMrUi *ui) {
LV2_Atom_Forge_Frame set_frame;
LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_resource
(&ui->forge, &set_frame, 1, ui->uris.get_state);
lv2_atom_forge_pop(&ui->forge,&set_frame);
return msg;
}
static void kit_combobox_changed(GtkComboBox* box, gpointer data) { static void kit_combobox_changed(GtkComboBox* box, gpointer data) {
DrMrUi* ui = (DrMrUi*)data; DrMrUi* ui = (DrMrUi*)data;
gint new_kit = gtk_combo_box_get_active (GTK_COMBO_BOX(box)); gint new_kit = gtk_combo_box_get_active (GTK_COMBO_BOX(box));
@ -357,6 +366,20 @@ static GtkWidget *create_position_combo(void)
return combo; return combo;
} }
static gulong expose_id;
static gboolean expose_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) {
DrMrUi* ui = (DrMrUi*)data;
uint8_t msg_buf[1024];
lv2_atom_forge_set_buffer(&ui->forge, msg_buf, 1024);
LV2_Atom *msg = build_get_state_message(ui);
ui->write(ui->controller,DRMR_CONTROL,
lv2_atom_total_size(msg),
ui->uris.atom_eventTransfer,
msg);
g_signal_handler_disconnect(widget,expose_id);
return FALSE;
}
static void build_drmr_ui(DrMrUi* ui) { static void build_drmr_ui(DrMrUi* ui) {
GtkWidget *drmr_ui_widget; GtkWidget *drmr_ui_widget;
GtkWidget *opts_hbox1, *opts_hbox2, GtkWidget *opts_hbox1, *opts_hbox2,
@ -369,6 +392,7 @@ static void build_drmr_ui(DrMrUi* ui) {
PangoAttribute *attr; PangoAttribute *attr;
drmr_ui_widget = gtk_vbox_new(false,0); drmr_ui_widget = gtk_vbox_new(false,0);
expose_id = g_signal_connect (drmr_ui_widget, "expose-event", G_CALLBACK (expose_callback), ui);
g_object_set(drmr_ui_widget,"border-width",6,NULL); g_object_set(drmr_ui_widget,"border-width",6,NULL);
ui->kit_store = gtk_list_store_new(1,G_TYPE_STRING); ui->kit_store = gtk_list_store_new(1,G_TYPE_STRING);
@ -503,7 +527,6 @@ instantiate(const LV2UI_Descriptor* descriptor,
ui->startSamp = 0; ui->startSamp = 0;
#endif #endif
*widget = ui->drmr_widget; *widget = ui->drmr_widget;
return ui; return ui;
@ -548,20 +571,33 @@ port_event(LV2UI_Handle handle,
LV2_Atom* atom = (LV2_Atom*)buffer; LV2_Atom* atom = (LV2_Atom*)buffer;
if (atom->type == ui->uris.atom_resource) { if (atom->type == ui->uris.atom_resource) {
LV2_Atom_Object* obj = (LV2_Atom_Object*)atom; LV2_Atom_Object* obj = (LV2_Atom_Object*)atom;
if (obj->body.otype != ui->uris.get_state &&
obj->body.otype != ui->uris.ui_msg) {
// both state and ui_msg are the same at the moment
fprintf(stderr,"Invalid message type to ui\n");
return;
}
const LV2_Atom* path = NULL; const LV2_Atom* path = NULL;
lv2_object_get(obj, ui->uris.kit_path, &path, 0); lv2_object_get(obj, ui->uris.kit_path, &path, 0);
if (!path) if (!path)
fprintf(stderr,"Got UI message without kit_path, ignoring\n"); fprintf(stderr,"Got UI message without kit_path, ignoring\n");
else { else {
char *kitpath = LV2_ATOM_BODY(path); char *kitpath = LV2_ATOM_BODY(path);
char *realp = realpath(kitpath,NULL);
if (!realp) {
fprintf(stderr,"Passed a path I can't resolve, bailing out\n");
return;
}
int i; int i;
for(i = 0;i < ui->kits->num_kits;i++) for(i = 0;i < ui->kits->num_kits;i++)
if (!strcmp(ui->kits->kits[i].path,kitpath)) if (!strcmp(ui->kits->kits[i].path,realp))
break; break;
if (i < ui->kits->num_kits) { if (i < ui->kits->num_kits) {
ui->kitReq = i; ui->kitReq = i;
g_idle_add(kit_callback,ui); g_idle_add(kit_callback,ui);
} } else
fprintf(stderr,"Couldn't find kit %s\n",realp);
free(realp);
} }
} else } else
fprintf(stderr, "Unknown message type.\n"); fprintf(stderr, "Unknown message type.\n");