Add state support and startup state polling for the ui
This commit is contained in:
		
							parent
							
								
									dc2872309c
								
							
						
					
					
						commit
						1715d437e9
					
				
							
								
								
									
										103
									
								
								drmr.c
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								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* msg = (LV2_Atom*)lv2_atom_forge_resource | ||||
|     (&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_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); | ||||
|   return msg; | ||||
| } | ||||
| @ -257,6 +271,10 @@ static void run(LV2_Handle instance, uint32_t n_samples) { | ||||
| 	  drmr->curReq = reqPos; | ||||
| 	  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"); | ||||
| @ -272,7 +290,8 @@ static void run(LV2_Handle instance, uint32_t n_samples) { | ||||
|   if (current_kit_changed) { | ||||
|     current_kit_changed = 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); | ||||
| @ -330,7 +349,85 @@ static void cleanup(LV2_Handle 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 LV2_State_Interface state_iface = { save_state, restore_state }; | ||||
|   if (!strcmp(uri, LV2_STATE_URI "#Interface")) return &state_iface; | ||||
|   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/lv2core/lv2.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
 | ||||
| typedef struct { | ||||
| @ -147,6 +148,8 @@ typedef struct { | ||||
|   LV2_URID kit_path; | ||||
|   LV2_URID atom_eventTransfer; | ||||
|   LV2_URID atom_resource; | ||||
|   LV2_URID string_urid; | ||||
|   LV2_URID get_state; | ||||
| } drmr_uris; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -190,12 +193,18 @@ void map_drmr_uris(LV2_URID_Map *map, | ||||
|   uris->midi_event = | ||||
|     map->map(map->handle, | ||||
| 	     "http://lv2plug.in/ns/ext/midi#MidiEvent"); | ||||
|   uris->string_urid = | ||||
|     map->map(map->handle, | ||||
| 	     "http://lv2plug.in/ns/ext/atom#String"); | ||||
|   uris->ui_msg = | ||||
|     map->map(map->handle, | ||||
| 	     DRMR_URI "#uimsg"); | ||||
|   uris->kit_path = | ||||
|     map->map(map->handle, | ||||
| 	     DRMR_URI "#kitpath"); | ||||
|   uris->kit_path = | ||||
|     map->map(map->handle, | ||||
| 	     DRMR_URI "#getstate"); | ||||
|   uris->atom_eventTransfer =  | ||||
|     map->map(map->handle, LV2_ATOM__eventTransfer); | ||||
|   uris->atom_resource =  | ||||
|  | ||||
							
								
								
									
										1
									
								
								drmr.ttl
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								drmr.ttl
									
									
									
									
									
								
							| @ -19,6 +19,7 @@ | ||||
|   doap:license <http://usefulinc.com/doap/licenses/gpl> ; | ||||
|   lv2:requiredFeature urid:map ; | ||||
|   ui:ui <http://github.com/nicklan/drmr#ui> ; | ||||
|   lv2:extensionData <http://lv2plug.in/ns/ext/state#Interface> ; | ||||
|   lv2:port [ | ||||
|     a lv2:InputPort , atom:MessagePort; | ||||
|     atom:bufferType atom:Sequence ; | ||||
|  | ||||
| @ -18,6 +18,8 @@ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <limits.h> | ||||
| #include <stdlib.h> | ||||
| #include <ctype.h> | ||||
| #include <sys/types.h> | ||||
| #include <dirent.h> | ||||
| @ -307,7 +309,7 @@ kits* scan_kits() { | ||||
| 	  } | ||||
| 
 | ||||
| 	  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; | ||||
| 	  struct kit_list * cur_k = scanned_kits; | ||||
| 	  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. | ||||
|  */ | ||||
| 
 | ||||
| #include <limits.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <gtk/gtk.h> | ||||
| @ -295,6 +296,14 @@ static LV2_Atom* build_path_message(DrMrUi *ui, const char* path) { | ||||
|   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) { | ||||
|   DrMrUi* ui = (DrMrUi*)data; | ||||
|   gint new_kit = gtk_combo_box_get_active (GTK_COMBO_BOX(box)); | ||||
| @ -357,6 +366,20 @@ static GtkWidget *create_position_combo(void) | ||||
|   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) { | ||||
|   GtkWidget *drmr_ui_widget; | ||||
|   GtkWidget *opts_hbox1, *opts_hbox2, | ||||
| @ -369,6 +392,7 @@ static void build_drmr_ui(DrMrUi* ui) { | ||||
|   PangoAttribute *attr; | ||||
| 
 | ||||
|   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); | ||||
| 
 | ||||
|   ui->kit_store = gtk_list_store_new(1,G_TYPE_STRING); | ||||
| @ -503,7 +527,6 @@ instantiate(const LV2UI_Descriptor*   descriptor, | ||||
|   ui->startSamp = 0; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
|   *widget = ui->drmr_widget; | ||||
| 
 | ||||
|   return ui; | ||||
| @ -548,20 +571,33 @@ port_event(LV2UI_Handle handle, | ||||
|       LV2_Atom* atom = (LV2_Atom*)buffer; | ||||
|       if (atom->type == ui->uris.atom_resource) { | ||||
| 	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; | ||||
| 	lv2_object_get(obj, ui->uris.kit_path, &path, 0); | ||||
| 	if (!path) | ||||
| 	  fprintf(stderr,"Got UI message without kit_path, ignoring\n"); | ||||
| 	else { | ||||
| 	  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; | ||||
| 	  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; | ||||
| 	  if (i < ui->kits->num_kits) { | ||||
| 	    ui->kitReq = i; | ||||
| 	    g_idle_add(kit_callback,ui); | ||||
| 	  } | ||||
| 	  } else | ||||
| 	    fprintf(stderr,"Couldn't find kit %s\n",realp); | ||||
| 	  free(realp); | ||||
| 	} | ||||
|       } else | ||||
| 	fprintf(stderr, "Unknown message type.\n"); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user