From b59a394c441357ed0c60f4cee81fa5891ea588ae Mon Sep 17 00:00:00 2001 From: Daniel Jones Date: Wed, 14 Feb 2024 00:17:35 +0000 Subject: [PATCH] Add SIGNALFLOW_NULL_FLOAT, and use as default trigger() value argument --- .../libs/signalflow-stubs/signalflow.pyi | 4 ++-- source/include/signalflow/core/constants.h | 6 +++++ .../node/buffer/granulation/grainsegments.h | 5 ++-- source/include/signalflow/node/node.h | 2 +- source/include/signalflow/patch/patch.h | 2 +- .../node/buffer/granulation/grainsegments.cpp | 24 +++++++++++-------- 6 files changed, 27 insertions(+), 16 deletions(-) diff --git a/auxiliary/libs/signalflow-stubs/signalflow.pyi b/auxiliary/libs/signalflow-stubs/signalflow.pyi index 9368758f..2a901371 100644 --- a/auxiliary/libs/signalflow-stubs/signalflow.pyi +++ b/auxiliary/libs/signalflow-stubs/signalflow.pyi @@ -711,7 +711,7 @@ class FFTRandomPhase(FFTOpNode): """ Randomise phase values. """ - def __init__(self, input: Node = 0) -> None: + def __init__(self, input: Node = 0, level: Node = 1.0) -> None: ... class FFTTonality(FFTOpNode): """ @@ -866,7 +866,7 @@ class LessThanOrEqual(Node): ... class Line(Node): """ - Line segment with the given start/end values and duration. If loop is true, repeats indefinitely. Retriggers on a clock signal. + Line segment with the given start/end values, and duration (in seconds). If loop is true, repeats indefinitely. Retriggers on a clock signal. """ def __init__(self, start: Node = 0.0, end: Node = 1.0, time: Node = 1.0, loop: Node = 0, clock: Node = None) -> None: ... diff --git a/source/include/signalflow/core/constants.h b/source/include/signalflow/core/constants.h index d79950b0..f241fff2 100644 --- a/source/include/signalflow/core/constants.h +++ b/source/include/signalflow/core/constants.h @@ -3,6 +3,7 @@ #include "signalflow/buffer/ringbuffer.h" #include "signalflow/core/exceptions.h" +#include #include #include #include @@ -31,6 +32,11 @@ typedef RingBuffer SampleRingBuffer; (void) (expr); \ } while (0) +/*------------------------------------------------------------------------ + * Sentinel value, used to represent an undefined or unset float value. + *-----------------------------------------------------------------------*/ +#define SIGNALFLOW_NULL_FLOAT std::numeric_limits::max() + /*------------------------------------------------------------------------ * Max supported number of output channels. Impacts memory usage. * TODO: Retire this constant. diff --git a/source/include/signalflow/node/buffer/granulation/grainsegments.h b/source/include/signalflow/node/buffer/granulation/grainsegments.h index 84707a92..6bb21e65 100644 --- a/source/include/signalflow/node/buffer/granulation/grainsegments.h +++ b/source/include/signalflow/node/buffer/granulation/grainsegments.h @@ -22,7 +22,8 @@ class SegmentedGranulator : public Node NodeRef max_grains = 2048); virtual void process(Buffer &out, int num_frames) override; - virtual void trigger(std::string name = SIGNALFLOW_DEFAULT_TRIGGER, float value = 1.0) override; + virtual void trigger(std::string name = SIGNALFLOW_DEFAULT_TRIGGER, + float value = SIGNALFLOW_NULL_FLOAT) override; virtual void set_buffer(std::string, BufferRef buffer) override; protected: @@ -38,7 +39,7 @@ class SegmentedGranulator : public Node std::vector durations; float rate_scale_factor; std::vector grains; - std::mutex mutex; + bool triggered = false; }; REGISTER(SegmentedGranulator, "segmented-granulator") diff --git a/source/include/signalflow/node/node.h b/source/include/signalflow/node/node.h index 81e52559..837cf700 100644 --- a/source/include/signalflow/node/node.h +++ b/source/include/signalflow/node/node.h @@ -198,7 +198,7 @@ class Node * Generic trigger method. *-----------------------------------------------------------------------*/ virtual void trigger(std::string name = SIGNALFLOW_DEFAULT_TRIGGER, - float value = 1); + float value = SIGNALFLOW_NULL_FLOAT); /*------------------------------------------------------------------------ * Print the node's output value to stdout at a specified frequency. diff --git a/source/include/signalflow/patch/patch.h b/source/include/signalflow/patch/patch.h index 7b17d0a0..6b7a874d 100644 --- a/source/include/signalflow/patch/patch.h +++ b/source/include/signalflow/patch/patch.h @@ -133,7 +133,7 @@ class Patch * Trigger this Patch. *--------------------------------------------------------------------------------*/ void trigger(std::string name = SIGNALFLOW_DEFAULT_TRIGGER, - float value = 1.0); + float value = SIGNALFLOW_NULL_FLOAT); /**-------------------------------------------------------------------------------- * Parse a template from live Node objects to create a network of NodeDefs diff --git a/source/src/node/buffer/granulation/grainsegments.cpp b/source/src/node/buffer/granulation/grainsegments.cpp index 2d278bc5..1642e900 100644 --- a/source/src/node/buffer/granulation/grainsegments.cpp +++ b/source/src/node/buffer/granulation/grainsegments.cpp @@ -64,8 +64,9 @@ void SegmentedGranulator::process(Buffer &out, int num_frames) for (int frame = 0; frame < num_frames; frame++) { - if (SIGNALFLOW_CHECK_TRIGGER(this->clock, frame)) + if (SIGNALFLOW_CHECK_TRIGGER(this->clock, frame) || this->triggered) { + this->triggered = false; int index = (int) this->index->out[0][frame]; if (index < 0 || index >= this->onset_times.size()) { @@ -78,9 +79,7 @@ void SegmentedGranulator::process(Buffer &out, int num_frames) this->onset_times[index] * buffer->get_sample_rate(), this->durations[index] * buffer->get_sample_rate(), this->rate->out[0][frame] * this->rate_scale_factor); - this->mutex.lock(); this->grains.push_back(grain); - this->mutex.unlock(); } } @@ -109,9 +108,7 @@ void SegmentedGranulator::process(Buffer &out, int num_frames) else { delete grain; - this->mutex.lock(); grains.erase(it); - this->mutex.unlock(); } } } @@ -121,12 +118,21 @@ void SegmentedGranulator::trigger(std::string name, float value) { /*-------------------------------------------------------------------------------- * TODO: Don't repeat this same block of code from the trigger block above - * TODO: How to honour `value` here, if specified? - * Perhaps the default should be a null value, that gets ignored in favour - * of `index` if not specified. *--------------------------------------------------------------------------------*/ if (name == SIGNALFLOW_DEFAULT_TRIGGER) { + if (value == SIGNALFLOW_NULL_FLOAT) + { + /*-------------------------------------------------------------------------------- + * If triggered without an explicitly-specified index, defer the trigger + * until the next process() block. This is because, if the .index property of + * the granulator is set at the same time as trigger() is called, the .index + * update won't take effect until the next process(). + *--------------------------------------------------------------------------------*/ + this->triggered = true; + return; + } + int index = (int) value; if (index < 0 || index >= this->onset_times.size()) { @@ -139,9 +145,7 @@ void SegmentedGranulator::trigger(std::string name, float value) this->onset_times[index] * buffer->get_sample_rate(), this->durations[index] * buffer->get_sample_rate(), this->rate->out[0][0] * this->rate_scale_factor); - this->mutex.lock(); this->grains.push_back(grain); - this->mutex.unlock(); } } }