diff options
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/eg-sampler.lv2/sampler.c | 146 | ||||
| -rw-r--r-- | plugins/eg-sampler.lv2/sampler.ttl | 9 | ||||
| -rw-r--r-- | plugins/eg-sampler.lv2/sampler_ui.c | 22 | ||||
| -rw-r--r-- | plugins/eg-sampler.lv2/uris.h | 19 | 
4 files changed, 107 insertions, 89 deletions
| diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c index 1fd8c0e..5cc3c96 100644 --- a/plugins/eg-sampler.lv2/sampler.c +++ b/plugins/eg-sampler.lv2/sampler.c @@ -38,7 +38,8 @@  #include "lv2/lv2plug.in/ns/lv2core/lv2.h"  #include "lv2/lv2plug.in/ns/lv2core/lv2_util.h" -#include "./uris.h" +#include "uris.h" +#include "atom_sink.h"  enum {  	SAMPLER_CONTROL = 0, @@ -46,8 +47,6 @@ enum {  	SAMPLER_OUT     = 2  }; -static const char* default_sample_file = "click.wav"; -  typedef struct {  	SF_INFO  info;      // Info about sample from sndfile  	float*   data;      // Sample data in float @@ -64,10 +63,6 @@ typedef struct {  	// Forge for creating atoms  	LV2_Atom_Forge forge; -	// Sample -	Sample* sample; -	bool    sample_changed; -  	// Ports  	const LV2_Atom_Sequence* control_port;  	LV2_Atom_Sequence*       notify_port; @@ -79,13 +74,14 @@ typedef struct {  	// URIs  	SamplerURIs uris; -	// Current position in run() -	uint32_t frame_offset; -  	// Playback state +	Sample*    sample; +	uint32_t   frame_offset;  	float      gain;  	sf_count_t frame;  	bool       play; +	bool       activated; +	bool       sample_changed;  } Sampler;  /** @@ -109,18 +105,17 @@ typedef struct {     not modified.  */  static Sample* -load_sample(Sampler* self, const char* path) +load_sample(LV2_Log_Logger* logger, const char* path)  { -	const size_t path_len = strlen(path); +	lv2_log_trace(logger, "Loading %s\n", path); -	lv2_log_trace(&self->logger, "Loading sample %s\n", path); - -	Sample* const  sample  = (Sample*)malloc(sizeof(Sample)); -	SF_INFO* const info    = &sample->info; -	SNDFILE* const sndfile = sf_open(path, SFM_READ, info); +	const size_t   path_len = strlen(path); +	Sample* const  sample   = (Sample*)malloc(sizeof(Sample)); +	SF_INFO* const info     = &sample->info; +	SNDFILE* const sndfile  = sf_open(path, SFM_READ, info);  	if (!sndfile || !info->frames || (info->channels != 1)) { -		lv2_log_error(&self->logger, "Failed to open sample '%s'\n", path); +		lv2_log_error(logger, "Failed to open sample '%s'\n", path);  		free(sample);  		return NULL;  	} @@ -128,7 +123,7 @@ load_sample(Sampler* self, const char* path)  	// Read data  	float* const data = malloc(sizeof(float) * info->frames);  	if (!data) { -		lv2_log_error(&self->logger, "Failed to allocate memory for sample\n"); +		lv2_log_error(logger, "Failed to allocate memory for sample\n");  		return NULL;  	}  	sf_seek(sndfile, 0ul, SEEK_SET); @@ -175,20 +170,19 @@ work(LV2_Handle                  instance,  		// Free old sample  		const SampleMessage* msg = (const SampleMessage*)data;  		free_sample(self, msg->sample); -	} else { +	} else if (atom->type == self->forge.Object) {  		// Handle set message (load sample). -		const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data; - -		// Get file path from message -		const LV2_Atom* file_path = read_set_file(&self->uris, obj); -		if (!file_path) { +		const LV2_Atom_Object* obj  = (const LV2_Atom_Object*)data; +		const char*            path = read_set_file(&self->uris, obj); +		if (!path) { +			lv2_log_error(&self->logger, "Malformed set file request\n");  			return LV2_WORKER_ERR_UNKNOWN;  		}  		// Load sample. -		Sample* sample = load_sample(self, LV2_ATOM_BODY_CONST(file_path)); +		Sample* sample = load_sample(&self->logger, path);  		if (sample) { -			// Loaded sample, send it to run() to be applied. +			// Send new sample to run() to be applied  			respond(handle, sizeof(sample), &sample);  		}  	} @@ -208,22 +202,25 @@ work_response(LV2_Handle  instance,                uint32_t    size,                const void* data)  { -	Sampler* self = (Sampler*)instance; - -	SampleMessage msg = { { sizeof(Sample*), self->uris.eg_freeSample }, -	                      self->sample }; - -	// Send a message to the worker to free the current sample -	self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg); +	Sampler* self       = (Sampler*)instance; +	Sample*  old_sample = self->sample; +	Sample*  new_sample = *(Sample*const*)data;  	// Install the new sample  	self->sample = *(Sample*const*)data; -	// Send a notification that we're using a new sample. -	lv2_atom_forge_frame_time(&self->forge, self->frame_offset); -	write_set_file(&self->forge, &self->uris, -	               self->sample->path, -	               self->sample->path_len); +	// Schedule work to free the old sample +	SampleMessage msg = { { sizeof(Sample*), self->uris.eg_freeSample }, +	                      old_sample }; +	self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg); + +	if (strcmp(old_sample->path, new_sample->path)) { +		// Send a notification that we're using a new sample +		lv2_atom_forge_frame_time(&self->forge, self->frame_offset); +		write_set_file(&self->forge, &self->uris, +		               new_sample->path, +		               new_sample->path_len); +	}  	return LV2_WORKER_SUCCESS;  } @@ -279,15 +276,6 @@ instantiate(const LV2_Descriptor*     descriptor,  	map_sampler_uris(self->map, &self->uris);  	lv2_atom_forge_init(&self->forge, self->map); -	// Load the default sample file -	const size_t path_len    = strlen(path); -	const size_t file_len    = strlen(default_sample_file); -	const size_t len         = path_len + file_len; -	char*        sample_path = (char*)malloc(len + 1); -	snprintf(sample_path, len + 1, "%s%s", path, default_sample_file); -	self->sample = load_sample(self, sample_path); -	free(sample_path); -  	return (LV2_Handle)self;  } @@ -299,6 +287,18 @@ cleanup(LV2_Handle instance)  	free(self);  } +static void +activate(LV2_Handle instance) +{ +	((Sampler*)instance)->activated = true; +} + +static void +deactivate(LV2_Handle instance) +{ +	((Sampler*)instance)->activated = false; +} +  /** Define a macro for converting a gain in dB to a coefficient. */  #define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) @@ -367,7 +367,7 @@ run(LV2_Handle instance,  				const uint32_t key = ((const LV2_Atom_URID*)property)->body;  				if (key == uris->eg_sample) {  					// Sample change, send it to the worker. -					lv2_log_trace(&self->logger, "Queueing set message\n"); +					lv2_log_trace(&self->logger, "Scheduling sample change\n");  					self->schedule->schedule_work(self->schedule->handle,  					                              lv2_atom_total_size(&ev->body),  					                              &ev->body); @@ -379,7 +379,6 @@ run(LV2_Handle instance,  				}  			} else if (obj->body.otype == uris->patch_Get) {  				// Received a get message, emit our state (probably to UI) -				lv2_log_trace(&self->logger, "Responding to get request\n");  				lv2_atom_forge_frame_time(&self->forge, self->frame_offset);  				write_set_file(&self->forge, &self->uris,  				               self->sample->path, @@ -462,6 +461,19 @@ restore(LV2_Handle                  instance,  {  	Sampler* self = (Sampler*)instance; +	// Get host features +	LV2_Worker_Schedule* schedule = NULL; +	LV2_State_Map_Path*  paths    = NULL; +	const char*          missing  = lv2_features_query( +		features, +		LV2_STATE__mapPath,   &paths,    true, +		LV2_WORKER__schedule, &schedule, false, +		NULL); +	if (missing) { +		lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); +		return LV2_STATE_ERR_NO_FEATURE; +	} +  	// Get eg:sample from state  	size_t      size;  	uint32_t    type; @@ -476,21 +488,29 @@ restore(LV2_Handle                  instance,  		return LV2_STATE_ERR_BAD_TYPE;  	} -	LV2_State_Map_Path* map_path = (LV2_State_Map_Path*)lv2_features_data( -		features, LV2_STATE__mapPath); -	if (!map_path) { -		return LV2_STATE_ERR_NO_FEATURE; -	} -  	// Map abstract state path to absolute path  	const char* apath = (const char*)value; -	char*       path  = map_path->absolute_path(map_path->handle, apath); +	char*       path  = paths->absolute_path(paths->handle, apath);  	// Replace current sample with the new one -	lv2_log_trace(&self->logger, "Restoring file %s\n", path); -	free_sample(self, self->sample); -	self->sample = load_sample(self, path); -	self->sample_changed = true; +	if (!self->activated || !schedule) { +		// No scheduling available, load sample immediately +		lv2_log_trace(&self->logger, "Synchronous restore\n"); +		free_sample(self, self->sample); +		self->sample         = load_sample(&self->logger, path); +		self->sample_changed = true; +	} else { +		// Schedule sample to be loaded by the provided worker +		lv2_log_trace(&self->logger, "Scheduling restore\n"); +		LV2_Atom_Forge forge; +		LV2_Atom*      buf = calloc(1, sizeof(LV2_Atom) * 32 + strlen(path)); +		lv2_atom_forge_init(&forge, self->map); +		lv2_atom_forge_set_sink(&forge, atom_sink, atom_sink_deref, buf); +		write_set_file(&forge, &self->uris, path, strlen(path)); + +		const uint32_t msg_size = lv2_atom_pad_size(buf->size); +		schedule->schedule_work(self->schedule->handle, msg_size, buf + 1); +	}  	return LV2_STATE_SUCCESS;  } @@ -512,9 +532,9 @@ static const LV2_Descriptor descriptor = {  	EG_SAMPLER_URI,  	instantiate,  	connect_port, -	NULL,  // activate, +	activate,  	run, -	NULL,  // deactivate, +	deactivate,  	cleanup,  	extension_data  }; diff --git a/plugins/eg-sampler.lv2/sampler.ttl b/plugins/eg-sampler.lv2/sampler.ttl index 197a735..f4a9c43 100644 --- a/plugins/eg-sampler.lv2/sampler.ttl +++ b/plugins/eg-sampler.lv2/sampler.ttl @@ -19,15 +19,16 @@  	doap:name "Example Sampler" ;  	doap:license <http://opensource.org/licenses/isc> ;  	lv2:project <http://lv2plug.in/ns/lv2> ; -	lv2:requiredFeature urid:map , +	lv2:requiredFeature state:loadDefaultState , +		urid:map ,  		work:schedule ;  	lv2:optionalFeature lv2:hardRTCapable , -		state:loadDefaultState ; +		state:threadSafeRestore ;  	lv2:extensionData state:interface ,  		work:interface ;  	ui:ui <http://lv2plug.in/plugins/eg-sampler#ui> ; -	patch:writable <http://lv2plug.in/plugins/eg-sampler#sample> ; -	patch:writable param:gain ; +	patch:writable <http://lv2plug.in/plugins/eg-sampler#sample> , +		param:gain ;  	lv2:port [  		a lv2:InputPort ,  			atom:AtomPort ; diff --git a/plugins/eg-sampler.lv2/sampler_ui.c b/plugins/eg-sampler.lv2/sampler_ui.c index 1a8ee2e..23204c5 100644 --- a/plugins/eg-sampler.lv2/sampler_ui.c +++ b/plugins/eg-sampler.lv2/sampler_ui.c @@ -78,8 +78,8 @@ on_load_clicked(GtkWidget* widget,  	uint8_t obj_buf[OBJ_BUF_SIZE];  	lv2_atom_forge_set_buffer(&ui->forge, obj_buf, OBJ_BUF_SIZE); -	LV2_Atom* msg = write_set_file(&ui->forge, &ui->uris, -	                               filename, strlen(filename)); +	LV2_Atom* msg = (LV2_Atom*)write_set_file(&ui->forge, &ui->uris, +	                                          filename, strlen(filename));  	ui->write(ui->controller, 0, lv2_atom_total_size(msg),  	          ui->uris.atom_eventTransfer, @@ -170,20 +170,18 @@ port_event(LV2UI_Handle handle,  	if (format == ui->uris.atom_eventTransfer) {  		const LV2_Atom* atom = (const LV2_Atom*)buffer;  		if (lv2_atom_forge_is_object_type(&ui->forge, atom->type)) { -			const LV2_Atom_Object* obj      = (const LV2_Atom_Object*)atom; -			const LV2_Atom*        file_uri = read_set_file(&ui->uris, obj); -			if (!file_uri) { -				fprintf(stderr, "Unknown message sent to UI.\n"); -				return; +			const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom; +			const char*            uri = read_set_file(&ui->uris, obj); +			if (uri) { +				gtk_label_set_text(GTK_LABEL(ui->label), uri); +			} else { +				lv2_log_warning(&ui->logger, "Malformed message\n");  			} - -			const char* uri = (const char*)LV2_ATOM_BODY_CONST(file_uri); -			gtk_label_set_text(GTK_LABEL(ui->label), uri);  		} else { -			fprintf(stderr, "Unknown message type.\n"); +			lv2_log_error(&ui->logger, "Unknown message type\n");  		}  	} else { -		fprintf(stderr, "Unknown format.\n"); +		lv2_log_warning(&ui->logger, "Unknown port event format\n");  	}  } diff --git a/plugins/eg-sampler.lv2/uris.h b/plugins/eg-sampler.lv2/uris.h index e7c4dcd..fe0497f 100644 --- a/plugins/eg-sampler.lv2/uris.h +++ b/plugins/eg-sampler.lv2/uris.h @@ -1,6 +1,6 @@  /*    LV2 Sampler Example Plugin -  Copyright 2011-2012 David Robillard <d@drobilla.net> +  Copyright 2011-2016 David Robillard <d@drobilla.net>    Permission to use, copy, modify, and/or distribute this software for any    purpose with or without fee is hereby granted, provided that the above @@ -73,14 +73,14 @@ map_sampler_uris(LV2_URID_Map* map, SamplerURIs* uris)   *     patch:property eg:sample ;   *     patch:value </home/me/foo.wav> .   */ -static inline LV2_Atom* +static inline LV2_Atom_Forge_Ref  write_set_file(LV2_Atom_Forge*    forge,                 const SamplerURIs* uris,                 const char*        filename,                 const uint32_t     filename_len)  {  	LV2_Atom_Forge_Frame frame; -	LV2_Atom* set = (LV2_Atom*)lv2_atom_forge_object( +	LV2_Atom_Forge_Ref   set = lv2_atom_forge_object(  		forge, &frame, 0, uris->patch_Set);  	lv2_atom_forge_key(forge, uris->patch_property); @@ -89,7 +89,6 @@ write_set_file(LV2_Atom_Forge*    forge,  	lv2_atom_forge_path(forge, filename, filename_len);  	lv2_atom_forge_pop(forge, &frame); -  	return set;  } @@ -100,7 +99,7 @@ write_set_file(LV2_Atom_Forge*    forge,   *     patch:property eg:sample ;   *     patch:value </home/me/foo.wav> .   */ -static inline const LV2_Atom* +static inline const char*  read_set_file(const SamplerURIs*     uris,                const LV2_Atom_Object* obj)  { @@ -124,17 +123,17 @@ read_set_file(const SamplerURIs*     uris,  	}  	/* Get value. */ -	const LV2_Atom* file_path = NULL; -	lv2_atom_object_get(obj, uris->patch_value, &file_path, 0); -	if (!file_path) { +	const LV2_Atom* value = NULL; +	lv2_atom_object_get(obj, uris->patch_value, &value, 0); +	if (!value) {  		fprintf(stderr, "Malformed set message has no value.\n");  		return NULL; -	} else if (file_path->type != uris->atom_Path) { +	} else if (value->type != uris->atom_Path) {  		fprintf(stderr, "Set message value is not a Path.\n");  		return NULL;  	} -	return file_path; +	return LV2_ATOM_BODY_CONST(value);  }  #endif  /* SAMPLER_URIS_H */ |