12#include "dsp/hart_dsp.hpp"
26template<
typename SampleType>
38 if (other.m_dspChain.size() == 0)
43 for (
auto& dsp : other.m_dspChain)
45 std::unique_ptr<
DSPBase<SampleType>> dspCopy = dsp->copy();
57 if (dspCopy ==
nullptr)
70 other.m_numChannels = 0;
71 other.m_startTimestampSeconds = 0.0;
78 SignalBase&
operator= (
const SignalBase& other)
87 if (other.m_dspChain.size() == 0)
92 for (
auto& dsp : other.m_dspChain)
94 std::unique_ptr<
DSPBase<SampleType>> dspCopy = dsp->copy();
106 if (dspCopy ==
nullptr)
116 SignalBase&
operator= (SignalBase&& other)
noexcept
124 other.m_numChannels = 0;
125 other.m_startTimestampSeconds = 0.0;
154 virtual void prepare (
double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames) = 0;
174 virtual std::unique_ptr<SignalBase<SampleType>>
copy()
const = 0;
177 virtual std::unique_ptr<SignalBase<SampleType>>
move() = 0;
187 virtual void represent (std::ostream& stream)
const = 0;
197 if (! dsp->supportsChannelLayout (numChannels, numChannels))
211 if (! dsp->supportsSampleRate (sampleRateHz))
227 prepare (sampleRateHz
, numOutputChannels
, maxBlockSizeFrames
);
228 const size_t numInputChannels = numOutputChannels;
231 dsp->prepareWithEnvelopes (sampleRateHz, numInputChannels, numOutputChannels, maxBlockSizeFrames);
235 performSkipTo (sampleRateHz, numOutputChannels, maxBlockSizeFrames);
262 dsp->processWithEnvelopes (inputReplacing, output);
273 dsp->resetWithEnvelopes();
280 void representWithDSPChain (std::ostream& stream)
const
285 stream <<
" >> " << *dsp;
292 return this->m_dspChain.size();
302 if (
this->m_dspChain.empty())
305 const int size =
static_cast<
int> (
this->m_dspChain.size());
307 if (index >= size || index < -size)
313 hassert (index >= 0 && index < size);
314 return this->m_dspChain[index].get();
324 if (
this->m_dspChain.empty())
327 const int size =
static_cast<
int> (
this->m_dspChain.size());
329 if (index >= size || index < -size)
335 hassert (index >= 0 && index < size);
337 std::unique_ptr<
DSPBase<SampleType>> dsp = std::move (
this->m_dspChain[index]);
338 this->m_dspChain.erase (
this->m_dspChain.begin() + index);
359 void performSkipTo (
double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames)
365 while (fastForwardFramesLeft != 0)
367 const size_t blockSizeFrames = fastForwardFramesLeft >= maxBlockSizeFrames ? maxBlockSizeFrames : fastForwardFramesLeft;
368 AudioBuffer<SampleType> dummyAudioBlock (numOutputChannels, blockSizeFrames, sampleRateHz);
370 fastForwardFramesLeft -= blockSizeFrames;
381template<
typename SampleType,
typename DerivedSignal>
383 public SignalBase<SampleType>
390 template<
typename DerivedDSP,
391 typename =
typename std::enable_if<
392 ! std::is_lvalue_reference<DerivedDSP>::value
395 typename std::decay<DerivedDSP>::type
401 _followedBy (std::forward<DerivedDSP> (dsp));
402 return static_cast<DerivedSignal&> (*
this);
409 template<
typename DerivedDSP,
410 typename =
typename std::enable_if<
411 ! std::is_lvalue_reference<DerivedDSP>::value
414 typename std::decay<DerivedDSP>::type
420 _followedBy (std::forward<DerivedDSP> (dsp));
421 return static_cast<DerivedSignal&&> (*
this);
429 _followedBy (std::move (dsp));
430 return static_cast<DerivedSignal&> (*
this);
438 _followedBy (std::move (dsp));
439 return static_cast<DerivedSignal&&> (*
this);
442 std::unique_ptr<SignalBase<SampleType>>
copy()
const override
444 return hart::make_unique<DerivedSignal> (
static_cast<
const DerivedSignal&> (*
this));
447 std::unique_ptr<SignalBase<SampleType>>
move()
override
449 return hart::make_unique<DerivedSignal> (std::move (
static_cast<DerivedSignal&&> (*
this)));
457 DerivedSignal&
skipTo (
double startTimestampSeconds) &
459 _skipTo (startTimestampSeconds);
460 return static_cast<DerivedSignal&> (*
this);
468 DerivedSignal&&
skipTo (
double startTimestampSeconds) &&
470 _skipTo (startTimestampSeconds);
471 return static_cast<DerivedSignal&&> (*
this);
477 auto newSignal =
static_cast<
const DerivedSignal&> (*
this);
478 newSignal.m_dspChain.emplace_back (hart::make_unique<GainLinear<SampleType>> (SampleType (-1)));
489 void _skipTo (
double startTimestampSeconds)
491 if (startTimestampSeconds < 0)
494 this->m_startTimestampSeconds += startTimestampSeconds;
497 template <
typename DerivedDSP>
498 void _followedBy (DerivedDSP&& dsp)
500 static_assert (!std::is_lvalue_reference<DerivedDSP>::value,
"DSP must be passed as an rvalue");
501 static_assert (std::is_base_of<
DSPBase<SampleType>,
typename std::decay<DerivedDSP>::type>::value,
"Argument must be a DSP object");
502 this->m_dspChain.emplace_back (dsp.move());
505 void _followedBy(std::unique_ptr<
DSPBase<SampleType>> dsp)
507 this->m_dspChain.emplace_back (std::move (dsp));
514template<
typename SampleType>
515std::ostream& operator<< (std::ostream& stream,
const SignalBase<SampleType>& signal)
517 signal.representWithDSPChain (stream);
527template<
typename DerivedSignal,
typename DerivedDSP>
528auto operator>> (DerivedSignal& signal, DerivedDSP&& dsp) ->
decltype (signal.followedBy (std::forward<DerivedDSP> (dsp)))
530 return signal.followedBy (std::forward<DerivedDSP> (dsp));
539template<
typename DerivedSignal,
typename DerivedDSP>
540auto operator>> (DerivedSignal&& signal, DerivedDSP&& dsp) ->
decltype (std::move (signal).followedBy (std::forward<DerivedDSP> (dsp)))
542 return std::move (signal).followedBy (std::forward<DerivedDSP> (dsp));
563#define HART_SIGNAL_FORBID_COPY_AND_MOVE
564 std::unique_ptr<Signal<SampleType>> copy() const override {
565 static_assert(false, "This Signal cannot be copied");
568 std::unique_ptr<Signal<SampleType>> move() override {
569 static_assert(false, "This Signal cannot be moved");
574#define HART_SIGNAL_DECLARE_ALIASES_FOR(ClassName)
575 namespace aliases_float{
576 using ClassName = hart::ClassName<float>;
578 namespace aliases_double{
579 using ClassName = hart::ClassName<double>;
Container for audio data.
Polymorphic base for all DSP.
Thrown when a container index is out of range.
Thrown when a nullptr could be handled gracefully.
bool supportsNumChannelsWithDSPChain(size_t numChannels)
Checks whether the signal itself, and all the DSP instances in its signal chain support the requested...
virtual void reset()=0
Resets the Signal to initial state.
size_t m_maxBlockSizeFrames
virtual ~SignalBase()=default
Destructor.
virtual void represent(std::ostream &stream) const =0
Makes a text representation of this Signal for test failure outputs.
double m_startTimestampSeconds
bool supportsSampleRateWithDSPChain(double sampleRateHz)
Checks whether the signal itself, and all the DSP instances in its signal chain support the requested...
SignalBase(const SignalBase &other)
Copies other signal.
DSPBase< SampleType > * getDSP(int index=-1) const
Access a specific element in the DSP chain.
virtual std::unique_ptr< SignalBase< SampleType > > copy() const =0
Returns a smart pointer with a copy of this object.
void renderNextBlockWithDSPChain(AudioBuffer< SampleType > &output)
Renders next block audio for the signal and all the effects in the DSP chain.
std::vector< std::unique_ptr< DSPBase< SampleType > > > m_dspChain
virtual void resetWithDSPChain()
Resets to Signal and all the effects attached to its DSP chain to initial state.
SignalBase & operator=(const SignalBase &other)
Copies from other signal.
SignalBase()=default
Default constructor.
SignalBase & operator=(SignalBase &&other) noexcept
Moves from other signal.
virtual void renderNextBlock(AudioBuffer< SampleType > &output)=0
Renders next block audio for the signal.
void prepareWithDSPChain(double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames)
Prepares the signal and all attached effects in the DSP chain for rendering.
void setNumChannels(size_t numChannels)
SignalBase(SignalBase &&other) noexcept
Moves from other signal.
std::unique_ptr< DSPBase< SampleType > > popDSP(int index=-1)
Extract a specific element in the DSP chain by removing it.
virtual std::unique_ptr< SignalBase< SampleType > > move()=0
Returns a smart pointer with a moved instance of this object.
virtual bool supportsNumChannels(size_t) const
Tells the host whether this Signal is capable of generating audio for a certain amount of channels.
virtual bool supportsSampleRate(double) const
Tells whether this Signal supports given sample rate.
size_t getDSPChainSize() const
Returns the size of the DSP chain attached to the Signal.
virtual void prepare(double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames)=0
Prepare the signal for rendering.
DerivedSignal && skipTo(double startTimestampSeconds) &&
Skips the signal to a specific timestamp.
DerivedSignal operator-() const
Returns a copy of this signal, but with flipped phase.
DerivedSignal & followedBy(std::unique_ptr< DSPBase< SampleType > > dsp) &
Adds a DSP effect to the end of signal's DSP chain.
DerivedSignal operator~() const
Returns a copy of this signal, but with flipped phase.
std::unique_ptr< SignalBase< SampleType > > move() override
Returns a smart pointer with a moved instance of this object.
DerivedSignal & skipTo(double startTimestampSeconds) &
Skips the signal to a specific timestamp.
std::unique_ptr< SignalBase< SampleType > > copy() const override
Returns a smart pointer with a copy of this object.
DerivedSignal & followedBy(DerivedDSP &&dsp) &
Adds a DSP effect to the end of signal's DSP chain.
DerivedSignal && followedBy(std::unique_ptr< DSPBase< SampleType > > dsp) &&
Adds a DSP effect to the end of signal's DSP chain.
DerivedSignal && followedBy(DerivedDSP &&dsp) &&
Adds a DSP effect to the end of signal's DSP chain.
Thrown when an inappropriate value is encountered.
#define hassert(condition)
Triggers a HartAssertException if the condition is false
#define HART_THROW_OR_RETURN(ExceptionType, message, returnValue)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns a specified ...
#define HART_THROW_OR_CONTINUE(ExceptionType, message)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and jumps to the next it...
auto operator>>(DerivedSignal &signal, DerivedDSP &&dsp) -> decltype(signal.followedBy(std::forward< DerivedDSP >(dsp)))
Adds a DSP effect to the end of signal's DSP chain by transfering it.
auto operator>>(DerivedSignal &&signal, DerivedDSP &&dsp) -> decltype(std::move(signal).followedBy(std::forward< DerivedDSP >(dsp)))
Adds a DSP effect to the end of signal's DSP chain by transfering it.
static size_t roundToSizeT(SampleType x)
Rounds a floating point value to a size_t value.
static SampleType floatsNotEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.