aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/eg-sampler.lv2/peaks.h
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/eg-sampler.lv2/peaks.h')
-rw-r--r--plugins/eg-sampler.lv2/peaks.h266
1 files changed, 0 insertions, 266 deletions
diff --git a/plugins/eg-sampler.lv2/peaks.h b/plugins/eg-sampler.lv2/peaks.h
deleted file mode 100644
index ff91546..0000000
--- a/plugins/eg-sampler.lv2/peaks.h
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright 2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#ifndef PEAKS_H_INCLUDED
-#define PEAKS_H_INCLUDED
-
-/**
- This file defines utilities for sending and receiving audio peaks for
- waveform display. The functionality is divided into two objects:
- PeaksSender, for sending peaks updates from the plugin, and PeaksReceiver,
- for receiving such updates and caching the peaks.
-
- This allows peaks for a waveform of any size at any resolution to be
- requested, with reasonably sized incremental updates sent over plugin ports.
-*/
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.h>
-#include <lv2/atom/util.h>
-#include <lv2/urid/urid.h>
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define PEAKS_URI "http://lv2plug.in/ns/peaks#"
-#define PEAKS__PeakUpdate PEAKS_URI "PeakUpdate"
-#define PEAKS__magnitudes PEAKS_URI "magnitudes"
-#define PEAKS__offset PEAKS_URI "offset"
-#define PEAKS__total PEAKS_URI "total"
-
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-typedef struct {
- LV2_URID atom_Float;
- LV2_URID atom_Int;
- LV2_URID atom_Vector;
- LV2_URID peaks_PeakUpdate;
- LV2_URID peaks_magnitudes;
- LV2_URID peaks_offset;
- LV2_URID peaks_total;
-} PeaksURIs;
-
-typedef struct {
- PeaksURIs uris; ///< URIDs used in protocol
- const float* samples; ///< Sample data
- uint32_t n_samples; ///< Total number of samples
- uint32_t n_peaks; ///< Total number of peaks
- uint32_t current_offset; ///< Current peak offset
- bool sending; ///< True iff currently sending
-} PeaksSender;
-
-typedef struct {
- PeaksURIs uris; ///< URIDs used in protocol
- float* peaks; ///< Received peaks, or zeroes
- uint32_t n_peaks; ///< Total number of peaks
-} PeaksReceiver;
-
-/**
- Map URIs used in the peaks protocol.
-*/
-static inline void
-peaks_map_uris(PeaksURIs* uris, LV2_URID_Map* map)
-{
- uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
- uris->atom_Int = map->map(map->handle, LV2_ATOM__Int);
- uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector);
- uris->peaks_PeakUpdate = map->map(map->handle, PEAKS__PeakUpdate);
- uris->peaks_magnitudes = map->map(map->handle, PEAKS__magnitudes);
- uris->peaks_offset = map->map(map->handle, PEAKS__offset);
- uris->peaks_total = map->map(map->handle, PEAKS__total);
-}
-
-/**
- Initialise peaks sender. The new sender is inactive and will do nothing
- when `peaks_sender_send()` is called, until a transmission is started with
- `peaks_sender_start()`.
-*/
-static inline PeaksSender*
-peaks_sender_init(PeaksSender* sender, LV2_URID_Map* map)
-{
- memset(sender, 0, sizeof(*sender));
- peaks_map_uris(&sender->uris, map);
- return sender;
-}
-
-/**
- Prepare to start a new peaks transmission. After this is called, the peaks
- can be sent with successive calls to `peaks_sender_send()`.
-*/
-static inline void
-peaks_sender_start(PeaksSender* sender,
- const float* samples,
- uint32_t n_samples,
- uint32_t n_peaks)
-{
- sender->samples = samples;
- sender->n_samples = n_samples;
- sender->n_peaks = n_peaks;
- sender->current_offset = 0;
- sender->sending = true;
-}
-
-/**
- Forge a message which sends a range of peaks. Writes a peaks:PeakUpdate
- object to `forge`, like:
-
- [source,turtle]
- ----
- []
- a peaks:PeakUpdate ;
- peaks:offset 256 ;
- peaks:total 1024 ;
- peaks:magnitudes [ 0.2f, 0.3f, ... ] .
- ----
-*/
-static inline bool
-peaks_sender_send(PeaksSender* sender,
- LV2_Atom_Forge* forge,
- uint32_t n_frames,
- uint32_t offset)
-{
- const PeaksURIs* uris = &sender->uris;
- if (!sender->sending || sender->current_offset >= sender->n_peaks) {
- return sender->sending = false;
- }
-
- // Start PeakUpdate object
- lv2_atom_forge_frame_time(forge, offset);
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_object(forge, &frame, 0, uris->peaks_PeakUpdate);
-
- // eg:offset = OFFSET
- lv2_atom_forge_key(forge, uris->peaks_offset);
- lv2_atom_forge_int(forge, (int32_t)sender->current_offset);
-
- // eg:total = TOTAL
- lv2_atom_forge_key(forge, uris->peaks_total);
- lv2_atom_forge_int(forge, (int32_t)sender->n_peaks);
-
- // eg:magnitudes = Vector<Float>(PEAK, PEAK, ...)
- lv2_atom_forge_key(forge, uris->peaks_magnitudes);
- LV2_Atom_Forge_Frame vec_frame;
- lv2_atom_forge_vector_head(
- forge, &vec_frame, sizeof(float), uris->atom_Float);
-
- // Calculate how many peaks to send this update
- const uint32_t chunk_size = MAX(1U, sender->n_samples / sender->n_peaks);
- const uint32_t space = forge->size - forge->offset;
- const uint32_t remaining = sender->n_peaks - sender->current_offset;
- const uint32_t n_update =
- MIN(remaining, MIN(n_frames / 4U, space / sizeof(float)));
-
- // Calculate peak (maximum magnitude) for each chunk
- for (uint32_t i = 0; i < n_update; ++i) {
- const uint32_t start = (sender->current_offset + i) * chunk_size;
- float peak = 0.0f;
- for (uint32_t j = 0; j < chunk_size; ++j) {
- peak = fmaxf(peak, fabsf(sender->samples[start + j]));
- }
- lv2_atom_forge_float(forge, peak);
- }
-
- // Finish message
- lv2_atom_forge_pop(forge, &vec_frame);
- lv2_atom_forge_pop(forge, &frame);
-
- sender->current_offset += n_update;
- return true;
-}
-
-/**
- Initialise a peaks receiver. The receiver stores an array of all peaks,
- which is updated incrementally with peaks_receiver_receive().
-*/
-static inline PeaksReceiver*
-peaks_receiver_init(PeaksReceiver* receiver, LV2_URID_Map* map)
-{
- memset(receiver, 0, sizeof(*receiver));
- peaks_map_uris(&receiver->uris, map);
- return receiver;
-}
-
-/**
- Clear stored peaks and free all memory. This should be called when the
- peaks are to be updated with a different audio source.
-*/
-static inline void
-peaks_receiver_clear(PeaksReceiver* receiver)
-{
- free(receiver->peaks);
- receiver->peaks = NULL;
- receiver->n_peaks = 0;
-}
-
-/**
- Handle PeakUpdate message.
-
- The stored peaks array is updated with the slice of peaks in `update`,
- resizing if necessary while preserving contents.
-
- Returns 0 if peaks have been updated, negative on error.
-*/
-static inline int
-peaks_receiver_receive(PeaksReceiver* receiver, const LV2_Atom_Object* update)
-{
- const PeaksURIs* uris = &receiver->uris;
-
- // Get properties of interest from update
- const LV2_Atom_Int* offset = NULL;
- const LV2_Atom_Int* total = NULL;
- const LV2_Atom_Vector* peaks = NULL;
-
- // clang-format off
- lv2_atom_object_get_typed(update,
- uris->peaks_offset, &offset, uris->atom_Int,
- uris->peaks_total, &total, uris->atom_Int,
- uris->peaks_magnitudes, &peaks, uris->atom_Vector,
- 0);
- // clang-format on
-
- if (!offset || !total || !peaks ||
- peaks->body.child_type != uris->atom_Float) {
- return -1; // Invalid update
- }
-
- const uint32_t n = (uint32_t)total->body;
- if (receiver->n_peaks != n) {
- // Update is for a different total number of peaks, resize
- receiver->peaks = (float*)realloc(receiver->peaks, n * sizeof(float));
- if (receiver->n_peaks > 0 && receiver->n_peaks < n) {
- /* The peaks array is being expanded. Copy the old peaks,
- duplicating each as necessary to fill the new peaks buffer.
- This preserves the current peaks so that the peaks array can be
- reasonably drawn at any time, but the resolution will increase
- as new updates arrive. */
- const int64_t n_per = n / receiver->n_peaks;
- for (int64_t i = n - 1; i >= 0; --i) {
- receiver->peaks[i] = receiver->peaks[i / n_per];
- }
- } else if (receiver->n_peaks > 0) {
- /* The peak array is being shrunk. Similar to the above. */
- const int64_t n_per = receiver->n_peaks / n;
- for (int64_t i = n - 1; i >= 0; --i) {
- receiver->peaks[i] = receiver->peaks[i * n_per];
- }
- }
- receiver->n_peaks = n;
- }
-
- // Copy vector contents to corresponding range in peaks array
- memcpy(receiver->peaks + offset->body,
- peaks + 1,
- peaks->atom.size - sizeof(LV2_Atom_Vector_Body));
-
- return 0;
-}
-
-#endif // PEAKS_H_INCLUDED