HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
DSPFunction< SampleType > Class Template Reference

A DSP processor defined by a user-provided function. More...

#include <hart_dsp_function.hpp>

Inheritance diagram for DSPFunction< SampleType >:

Public Member Functions

 DSPFunction (std::function< SampleType(SampleType)> dspFunction, const std::string &label={})
 Creates a DSP instance based on a sample-wise DSP function.
 
 DSPFunction (std::function< void(AudioBuffer< SampleType > &)> dspFunction, const std::string &label={})
 Creates a DSP instance based on a block-wise replacing (in-place) DSP function.
 
 DSPFunction (std::function< void(const AudioBuffer< SampleType > &, AudioBuffer< SampleType > &)> dspFunction, const std::string &label={})
 Creates a DSP instance based on a block-wise non-replacing (separate input and output buffers) DSP function.
 
void prepare (double sampleRateHz, size_t numInputChannels, size_t numOutputChannels, size_t maxBlockSizeFrames) override
 Prepare for processing.
 
void process (const AudioBuffer< SampleType > &input, AudioBuffer< SampleType > &output, const EnvelopeBuffers &, ChannelFlags) override
 Processes the audio.
 
void represent (std::ostream &stream) const override
 Makes a text representation of this DSP effect for test failure outputs.
 
void reset () override
 Resets to initial state.
 
void setValue (int, double) override
 Sets DSP value.
 
bool supportsSampleRate (double) const override
 Tells whether this effect supports given sample rate.
 
bool supportsEnvelopeFor (int) const override
 Tells whether this effect accepts automation envelopes for a particular parameter.
 
bool supportsChannelLayout (size_t numInputChannels, size_t numOutputChannels) const override
 Tells the runner (host) whether this effect supports a specific i/o configuration.
 
- Public Member Functions inherited from DSP< SampleType, DSPFunction< SampleType > >
DSPFunction< SampleType > & withEnvelope (int paramId, Envelope &&envelope) &
 Adds envelope to a specific parameter by moving it.
 
DSPFunction< SampleType > && withEnvelope (int paramId, Envelope &&envelope) &&
 Adds envelope to a specific parameter by moving it.
 
DSPFunction< SampleType > & withEnvelope (int paramId, const Envelope &envelope) &
 Adds envelope to a specific parameter by copying it.
 
DSPFunction< SampleType > && withEnvelope (int paramId, const Envelope &envelope) &&
 Adds envelope to a specific parameter by copying it.
 
virtual std::unique_ptr< DSPBase< SampleType > > move () override
 Returns a smart pointer with a moved instance of this object.
 
DSPFunction< SampleType > & atChannels (std::initializer_list< size_t > channelsToProcess) &
 Makes this DSP process only specific channels, and ignore the rest.
 
DSPFunction< SampleType > && atChannels (std::initializer_list< size_t > channelsToProcess) &&
 Makes this DSP process only specific channels, and ignore the rest.
 
DSPFunction< SampleType > & atChannel (size_t channelToProcess) &
 Makes this DSP process only specific channels, and bypass the rest.
 
DSPFunction< SampleType > && atChannel (size_t channelToProcess) &&
 Makes this DSP process only specific channels, and bypass the rest.
 
DSPFunction< SampleType > & atAllChannels () &
 Makes this DSP apply to all channels.
 
DSPFunction< SampleType > && atAllChannels () &&
 Makes this DSP apply to all channels.
 
DSPFunction< SampleType > & atAllChannelsExcept (std::initializer_list< size_t > channelsToSkip) &
 Makes this DSP process only specific channels, and bypass the rest.
 
DSPFunction< SampleType > && atAllChannelsExcept (std::initializer_list< size_t > channelsToSkip) &&
 Makes this DSP process only specific channels, and bypass the rest.
 
- Public Member Functions inherited from DSPBase< SampleType >
virtual double getValue (int) const
 Retrieves DSP value.
 
virtual std::unique_ptr< DSPBase< SampleType > > copy () const
 Returns a smart pointer with a copy of this object.
 
virtual ~DSPBase ()=default
 Destructor.
 
 DSPBase ()=default
 Default constructor.
 
 DSPBase (const DSPBase &other)
 Copies from another DSP effect instance.
 
 DSPBase (DSPBase &&other) noexcept
 Move constructor.
 
DSPBaseoperator= (const DSPBase &other)
 Copies from another DSP effect instance.
 
DSPBaseoperator= (DSPBase &&other) noexcept
 Move assignment.
 
bool hasEnvelopeFor (int paramId)
 Checks if there's an automation envelope attached to a specific parameter.
 
void prepareWithEnvelopes (double sampleRateHz, size_t numInputChannels, size_t numOutputChannels, size_t maxBlockSizeFrames)
 Prepares all the attached envelopes and the effect itself for processing.
 
void resetWithEnvelopes ()
 Resets the DSP instance, and all associated Envelopes.
 
ChannelFlags getChannelsToProcess ()
 Returns a structure indicating which channels should be processed by this DSP.
 
void processWithEnvelopes (const AudioBuffer< SampleType > &input, AudioBuffer< SampleType > &output)
 Renders all the automation envelopes and processes the audio.
 
void representWithActiveChannels (std::ostream &stream) const
 Makes a text representation of this DSP with optional "atChannels" appendix.
 

Additional Inherited Members

- Protected Attributes inherited from DSPBase< SampleType >
std::unordered_map< int, std::unique_ptr< Envelope > > m_envelopes
 
ChannelFlags m_channelsToProcess {true}
 

Detailed Description

template<typename SampleType>
class hart::DSPFunction< SampleType >

A DSP processor defined by a user-provided function.

It allows defining audio processing logic using a lambda or function object, without defining a dedicated DSP subclass.

Three function styles are supported:

1. Sample-wise processing
A DSP processor defined by a user-provided function.
Processes each sample independently.
2. Block-wise replacing (in-place) processing
Processes the buffer in-place. The buffer is pre-filled with input data.
3. Block-wise non-replacing processing
Provides separate input and output buffers.
Buffer invariants
For mutable buffers in block-wise replacing and non-replacing modes:
  • Number of frames must not be changed
  • Number of channels must not be changed
  • Sample rate must not be changed

Disobeying those constraints will result in a runtime error.

Example
[] (float x) { return x * 0.5f; },
"Gain"
);
Note
This class is primarily intended for simple and expressive DSP definitions in tests. For more complex or stateful processors, it's encouraged to implement a dedicated DSP subclass.

Definition at line 60 of file hart_dsp_function.hpp.

Constructor & Destructor Documentation

◆ DSPFunction() [1/3]

template<typename SampleType >
DSPFunction ( std::function< SampleType(SampleType)>  dspFunction,
const std::string &  label = {} 
)
inline

Creates a DSP instance based on a sample-wise DSP function.

Note
If you need to be aware of sample rate value, or what channel a given sample is from, use block-wise function signature instead (see other ctors of this class for details). Or define a full-featured DSP subclass for your DSP, instead of a simple function-based one.

This is the simplest form of a custom DSP. The function is applied independently to each sample in the input signal.

Example
[] (float x) { return x * 0.5f; },
"Gain"
);
Parameters
dspFunctionFunction with signature: Will be called to process each sample, expected to return a processed value.
labelOptional human-readable label to use in test error reporting.

Definition at line 86 of file hart_dsp_function.hpp.

◆ DSPFunction() [2/3]

template<typename SampleType >
DSPFunction ( std::function< void(AudioBuffer< SampleType > &)>  dspFunction,
const std::string &  label = {} 
)
inline

Creates a DSP instance based on a block-wise replacing (in-place) DSP function.

The provided function will be called for each block of input audio. It will receive a buffer pre-filled with input audio data. The function is expected to modify the buffer directly. The provided buffer is guaranteed to have:

  • A number of channels equal to max (inputChannels, outputChannels)
  • Input channels populated with input data
  • Additional channels (if any) initialized to zero
  • Number of frames equal to the block size specified in the test case, or less than that in case of partial blocks.
  • Correct sample rate value in its metadata (see AudioBuffer::getSampleRateHz())

For the provided buffer, the function must not change:

  • Number of channels
  • Number of frames
  • Sample rate

Disobeying those constraints will result in a runtime error.

Example
[] (auto& buffer)
{
// Process buffer in-place
},
"My DSP function"
);
Parameters
dspFunctionFunction with signature: Expected to read the input samples in the buffer and replace them with processed data.
labelOptional human-readable label to use in test error reporting.

Definition at line 124 of file hart_dsp_function.hpp.

◆ DSPFunction() [3/3]

template<typename SampleType >
DSPFunction ( std::function< void(const AudioBuffer< SampleType > &, AudioBuffer< SampleType > &)>  dspFunction,
const std::string &  label = {} 
)
inline

Creates a DSP instance based on a block-wise non-replacing (separate input and output buffers) DSP function.

This form provides full control over how output is generated from input. The output buffer is pre-allocated with the expected size.

For the output buffer, the function must not change:

  • Number of channels
  • Number of frames
  • Sample rate

Disobeying those constraints will result in a runtime error.

Example
[] (const auto& in, auto& out)
{
// Fill output using input
},
"My DSP function"
);
Parameters
dspFunctionFunction with signature: Expected to fill the output buffer with processed data from the input buffer.
labelOptional human-readable label to use in test error reporting.

Definition at line 158 of file hart_dsp_function.hpp.

Member Function Documentation

◆ prepare()

template<typename SampleType >
void prepare ( double  sampleRateHz,
size_t  numInputChannels,
size_t  numOutputChannels,
size_t  maxBlockSizeFrames 
)
inlineoverridevirtual

Prepare for processing.

In real-time DSP, such methods are usually used for allocating memory and other non-realtime-safe and heavyweight operations. But keep in mind that that HART does not do real-time processing, so this merely follows common real-time DSP design conventions, where non-realtime operations are done in a separate callback like this one. This method is guaranteed to be called after supportsChannelLayout() and supportsSampleRate(), but before process(). It is guaranteed that the number of input and output channels obeys supportsChannelLayout() and supportsSampleRate() preferences. It is guaranteed that all subsequent process() calls will be in line with the arguments received in this callback.

Parameters
sampleRateHzsample rate at which the audio should be interpreted and processed
numInputChannelsNumber of input channels
numOutputChannelsNumber of output channels
maxBlockSizeFramesMaximum block size in frames (samples)

Implements DSPBase< SampleType >.

Definition at line 163 of file hart_dsp_function.hpp.

◆ process()

template<typename SampleType >
void process ( const AudioBuffer< SampleType > &  input,
AudioBuffer< SampleType > &  output,
const EnvelopeBuffers envelopeBuffers,
ChannelFlags  channelsToProcess 
)
inlineoverridevirtual

Processes the audio.

Depending on circumstances, this callback will either be called once to process an entire piece of audio from start to finish, or called repeatedly, one block at a time (see AudioTestBuilder::withBlockSize()). All audio blocks except the last one are guaranteed to be equal to maxBlockSizeFrames set in prepare() callback. It is guaranteed that input and output buffers are equal in length in frames (samples) to each, but they might have different number of channels. Use supportsChannelLayout() to indicate whether the effect supports a specific i/o configuration or not, as it will be called before prepare(). It is guaranteed that envelopeBuffers will only contain the values for all attached envelopes for this instance of DSP effect, and will not contain any data (including key with empty item) if there's no envelope attached to a specific parameter ID in this effects's instance. It will never contain envelopes for IDs that get rejected by supportsEnvelopeFor(). Each vector in the envelopeBuffers map is guaranteed to be at least as large as input (and output) block. For partial blocks, only the first input.getNumFrames() elements contain valid data for the current block; the rest may be stale or uninitialized. DSP implementations are expected to ignore values beyond that index range.

Note
This method may be called in a replacing manner, i. e. input and output may be references to the same object.
Warning
Remember that the very last block of audio is almost always smaller than the block size set in prepare(), so be careful with buffer bounds.
Note
Note that this method does not have to be real-time safe, as all rendering always happens offline. Also note that, unlike real-time audio applications, this method is called on the same thread as all others like prepare().
Parameters
inputInput audio block
outputOutput audio block
envelopeBuffersEnvelope values for this block, see EnvelopeBuffers
channelsToProcessChannels that need processing. Process channels that are marked true, bypass ones marked false.

Implements DSPBase< SampleType >.

Definition at line 172 of file hart_dsp_function.hpp.

◆ represent()

template<typename SampleType >
void represent ( std::ostream &  stream) const
inlineoverridevirtual

Makes a text representation of this DSP effect for test failure outputs.

It is strongly encouraged to follow python's repr() conventions for returned text - basically, put something like "MyClass(value1, value2)" (with no quotes) into the stream whenever possible, or "<Readable info in angled brackets>" otherwise. Also, use built-in stream manipulators like dbPrecision wherever applicable. Use HART_DEFINE_GENERIC_REPRESENT() to get a basic implementation for this method.

Parameters
[out]streamOutput stream to write to

Implements DSPBase< SampleType >.

Definition at line 195 of file hart_dsp_function.hpp.

◆ reset()

template<typename SampleType >
void reset ( )
inlineoverridevirtual

Resets to initial state.

Ideally should be implemented in a way that audio produced after resetting is identical to audio produced after instantiation

Reimplemented from DSPBase< SampleType >.

Definition at line 200 of file hart_dsp_function.hpp.

◆ setValue()

template<typename SampleType >
void setValue ( int  paramId,
double  value 
)
inlineoverridevirtual

Sets DSP value.

Parameters
paramIdSome ID that your subclass understands; use of enums is encouraged for readability
valueValue of the param in an appropriate unit; use of SI units is encouraged (i.e. s instead of ms. Hz instead of kHz) to make better use of unit literals (see Units)
Warning
This method is only called to set a fixed value before processing, and is not called to do automation (via hart::Envelope) If you want your class to support automation for a specific parameter, override supportsEnvelopeFor(), and then use envelopeBuffers provided in process() callback.

Implements DSPBase< SampleType >.

Definition at line 201 of file hart_dsp_function.hpp.

◆ supportsSampleRate()

template<typename SampleType >
bool supportsSampleRate ( double  ) const
inlineoverridevirtual

Tells whether this effect supports given sample rate.

It is guaranteed to be called before prepare()

Parameters
sampleRateHzSample rate in question
Returns
true if effect is capable of interpreting and processing in a given sample rate, false otherwise

Reimplemented from DSPBase< SampleType >.

Definition at line 202 of file hart_dsp_function.hpp.

◆ supportsEnvelopeFor()

template<typename SampleType >
bool supportsEnvelopeFor ( int  ) const
inlineoverridevirtual

Tells whether this effect accepts automation envelopes for a particular parameter.

Parameters
paramIdSome ID that your subclass understands
Returns
true if your subclass can process automation for this parameter, false otherwise

Reimplemented from DSPBase< SampleType >.

Definition at line 203 of file hart_dsp_function.hpp.

◆ supportsChannelLayout()

template<typename SampleType >
bool supportsChannelLayout ( size_t  numInputChannels,
size_t  numOutputChannels 
) const
inlineoverridevirtual

Tells the runner (host) whether this effect supports a specific i/o configuration.

It is guaranteed that the effect will not receive unsupported number of channels in process(). However, it is not always possible to handle gracefully channel layout being unsupported, so in some circumstances it can cause an exception or a test failure. This method is guaranteed to be called at least once before prepare()

Implements DSPBase< SampleType >.

Definition at line 205 of file hart_dsp_function.hpp.


The documentation for this class was generated from the following file: