From 472556ff28b99db416d6f0a926c32ea28698e1a3 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 4 Oct 2016 00:46:56 -0400 Subject: eg-sampler: Add waveform display to UI --- plugins/eg-sampler.lv2/sampler.c | 64 +++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 20 deletions(-) (limited to 'plugins/eg-sampler.lv2/sampler.c') diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c index 36acb2f..627ba45 100644 --- a/plugins/eg-sampler.lv2/sampler.c +++ b/plugins/eg-sampler.lv2/sampler.c @@ -38,8 +38,9 @@ #include "lv2/lv2plug.in/ns/lv2core/lv2.h" #include "lv2/lv2plug.in/ns/lv2core/lv2_util.h" -#include "uris.h" #include "atom_sink.h" +#include "peaks.h" +#include "uris.h" enum { SAMPLER_CONTROL = 0, @@ -60,16 +61,15 @@ typedef struct { LV2_Worker_Schedule* schedule; LV2_Log_Logger logger; - // Forge for creating atoms - LV2_Atom_Forge forge; - // Ports const LV2_Atom_Sequence* control_port; LV2_Atom_Sequence* notify_port; float* output_port; - // Forge frame for notify port (for writing worker replies) - LV2_Atom_Forge_Frame notify_frame; + // Communication utilities + LV2_Atom_Forge_Frame notify_frame; ///< Cached for worker replies + LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread + PeaksSender psend; ///< Audio peaks sender // URIs SamplerURIs uris; @@ -113,19 +113,25 @@ load_sample(LV2_Log_Logger* logger, const char* path) Sample* const sample = (Sample*)malloc(sizeof(Sample)); SF_INFO* const info = &sample->info; SNDFILE* const sndfile = sf_open(path, SFM_READ, info); + float* data = NULL; + bool error = true; + if (!sndfile || !info->frames) { + lv2_log_error(logger, "Failed to open %s\n", path); + } else if (info->channels != 1) { + lv2_log_error(logger, "%s has %d channels\n", path, info->channels); + } else if (!(data = (float*)malloc(sizeof(float) * info->frames))) { + lv2_log_error(logger, "Failed to allocate memory for sample\n"); + } else { + error = false; + } - if (!sndfile || !info->frames || (info->channels != 1)) { - lv2_log_error(logger, "Failed to open sample '%s'\n", path); + if (error) { free(sample); + free(data); + sf_close(sndfile); return NULL; } - // Read data - float* const data = (float*)malloc(sizeof(float) * info->frames); - if (!data) { - lv2_log_error(logger, "Failed to allocate memory for sample\n"); - return NULL; - } sf_seek(sndfile, 0ul, SEEK_SET); sf_read_float(sndfile, data, info->frames); sf_close(sndfile); @@ -155,7 +161,7 @@ free_sample(Sampler* self, Sample* sample) This is called for every piece of work scheduled in the audio thread using self->schedule->schedule_work(). A reply can be sent back to the audio - thread using the provided respond function. + thread using the provided `respond` function. */ static LV2_Worker_Status work(LV2_Handle instance, @@ -275,6 +281,7 @@ instantiate(const LV2_Descriptor* descriptor, // Map URIs and initialise forge map_sampler_uris(self->map, &self->uris); lv2_atom_forge_init(&self->forge, self->map); + peaks_sender_init(&self->psend, self->map); return (LV2_Handle)self; } @@ -308,6 +315,7 @@ run(LV2_Handle instance, { Sampler* self = (Sampler*)instance; SamplerURIs* uris = &self->uris; + PeaksURIs* peaks_uris = &self->psend.uris; sf_count_t start_frame = 0; sf_count_t pos = 0; float* output = self->output_port; @@ -378,11 +386,25 @@ run(LV2_Handle instance, } } } else if (obj->body.otype == uris->patch_Get) { - // Received a get message, emit our state (probably to UI) - lv2_atom_forge_frame_time(&self->forge, self->frame_offset); - write_set_file(&self->forge, &self->uris, - self->sample->path, - self->sample->path_len); + const LV2_Atom_URID* accept = NULL; + const LV2_Atom_Int* n_peaks = NULL; + lv2_atom_object_get_typed( + obj, + uris->patch_accept, &accept, uris->atom_URID, + peaks_uris->peaks_total, &n_peaks, peaks_uris->atom_Int, 0); + if (accept && accept->body == peaks_uris->peaks_PeakUpdate) { + // Received a request for peaks, prepare for transmission + peaks_sender_start(&self->psend, + self->sample->data, + self->sample->info.frames, + n_peaks->body); + } else { + // Received a get message, emit our state (probably to UI) + lv2_atom_forge_frame_time(&self->forge, self->frame_offset); + write_set_file(&self->forge, &self->uris, + self->sample->path, + self->sample->path_len); + } } else { lv2_log_trace(&self->logger, "Unknown object type %d\n", obj->body.otype); @@ -393,6 +415,8 @@ run(LV2_Handle instance, } } + peaks_sender_send(&self->psend, &self->forge, sample_count, self->frame_offset); + // Render the sample (possibly already in progress) if (self->play) { uint32_t f = self->frame; -- cgit v1.2.1