Add state support and startup state polling for the ui
This commit is contained in:
		
							parent
							
								
									dc2872309c
								
							
						
					
					
						commit
						1715d437e9
					
				
							
								
								
									
										105
									
								
								drmr.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								drmr.c
									
									
									
									
									
								
							| @ -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); | ||||||
|   lv2_atom_forge_property_head(&drmr->forge, drmr->uris.kit_path,0); |   if (drmr->current_path) { | ||||||
|   lv2_atom_forge_string(&drmr->forge, kit, strlen(kit)); |     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); | ||||||
|  |   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
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								drmr.h
									
									
									
									
									
								
							| @ -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 =  | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								drmr.ttl
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								drmr.ttl
									
									
									
									
									
								
							| @ -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 ; | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
							
								
								
									
										42
									
								
								drmr_ui.c
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								drmr_ui.c
									
									
									
									
									
								
							| @ -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"); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user