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;
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)
124 other.m_numChannels = 0;
125 other.m_startTimestampSeconds = 0.0;
154 virtual void prepare (
double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames) = 0;
189 virtual void represent (std::ostream& stream)
const = 0;
199 prepare (sampleRateHz
, numOutputChannels
, maxBlockSizeFrames
);
200 const size_t numInputChannels = numOutputChannels;
204 if (! dsp->supportsChannelLayout (numInputChannels, numOutputChannels))
207 if (! dsp->supportsSampleRate (sampleRateHz))
210 dsp->prepareWithEnvelopes (sampleRateHz, numInputChannels, numOutputChannels, maxBlockSizeFrames);
215 performSkipTo (sampleRateHz, numOutputChannels, maxBlockSizeFrames);
229 dsp->processWithEnvelopes (inputReplacing, output);
240 dsp->resetWithEnvelopes();
247 void representWithDSPChain (std::ostream& stream)
const
252 stream <<
" >> " << *dsp;
259 return this->m_dspChain.size();
269 if (
this->m_dspChain.empty())
272 const int size =
static_cast<
int> (
this->m_dspChain.size());
274 if (index >= size || index < -size)
280 hassert (index >= 0 && index < size);
281 return this->m_dspChain[index].get();
291 if (
this->m_dspChain.empty())
294 const int size =
static_cast<
int> (
this->m_dspChain.size());
296 if (index >= size || index < -size)
302 hassert (index >= 0 && index < size);
304 std::unique_ptr<
DSPBase<SampleType>> dsp = std::move (
this->m_dspChain[index]);
305 this->m_dspChain.erase (
this->m_dspChain.begin() + index);
325 void performSkipTo (
double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames)
331 while (fastForwardFramesLeft != 0)
333 const size_t blockSizeFrames = fastForwardFramesLeft >= maxBlockSizeFrames ? maxBlockSizeFrames : fastForwardFramesLeft;
334 AudioBuffer<SampleType> dummyAudioBlock (numOutputChannels, blockSizeFrames, sampleRateHz);
336 fastForwardFramesLeft -= blockSizeFrames;
347template<
typename SampleType,
typename DerivedSignal>
356 template<
typename DerivedDSP,
357 typename =
typename std::enable_if<
358 ! std::is_lvalue_reference<DerivedDSP>::value
361 typename std::decay<DerivedDSP>::type
367 _followedBy (std::forward<DerivedDSP> (dsp));
368 return static_cast<DerivedSignal&> (*
this);
375 template<
typename DerivedDSP,
376 typename =
typename std::enable_if<
377 ! std::is_lvalue_reference<DerivedDSP>::value
380 typename std::decay<DerivedDSP>::type
386 _followedBy (std::forward<DerivedDSP> (dsp));
387 return static_cast<DerivedSignal&&> (*
this);
395 _followedBy (std::move (dsp));
396 return static_cast<DerivedSignal&> (*
this);
404 _followedBy (std::move (dsp));
405 return static_cast<DerivedSignal&&> (*
this);
410 return hart::make_unique<DerivedSignal> (
static_cast<
const DerivedSignal&> (*
this));
415 return hart::make_unique<DerivedSignal> (std::move (
static_cast<DerivedSignal&&> (*
this)));
423 DerivedSignal&
skipTo (
double startTimestampSeconds) &
425 _skipTo (startTimestampSeconds);
426 return static_cast<DerivedSignal&> (*
this);
434 DerivedSignal&&
skipTo (
double startTimestampSeconds) &&
436 _skipTo (startTimestampSeconds);
437 return static_cast<DerivedSignal&&> (*
this);
443 auto newSignal =
static_cast<
const DerivedSignal&> (*
this);
444 newSignal.m_dspChain.emplace_back (hart::make_unique<GainLinear<SampleType>> (SampleType (-1)));
455 void _skipTo (
double startTimestampSeconds)
457 if (startTimestampSeconds < 0)
460 this->m_startTimestampSeconds += startTimestampSeconds;
463 template <
typename DerivedDSP>
464 void _followedBy (DerivedDSP&& dsp)
466 static_assert (!std::is_lvalue_reference<DerivedDSP>::value,
"DSP must be passed as an rvalue");
467 static_assert (std::is_base_of<
DSPBase<SampleType>,
typename std::decay<DerivedDSP>::type>::value,
"Argument must be a DSP object");
468 this->m_dspChain.emplace_back (dsp.move());
471 void _followedBy(std::unique_ptr<
DSPBase<SampleType>> dsp)
473 this->m_dspChain.emplace_back (std::move (dsp));
480template<
typename SampleType>
481std::ostream& operator<< (std::ostream& stream,
const SignalBase<SampleType>& signal)
483 signal.representWithDSPChain (stream);
493template<
typename DerivedSignal,
typename DerivedDSP>
494auto operator>> (DerivedSignal& signal, DerivedDSP&& dsp) ->
decltype (signal.followedBy (std::forward<DerivedDSP> (dsp)))
496 return signal.followedBy (std::forward<DerivedDSP> (dsp));
505template<
typename DerivedSignal,
typename DerivedDSP>
506auto operator>> (DerivedSignal&& signal, DerivedDSP&& dsp) ->
decltype (std::move (signal).followedBy (std::forward<DerivedDSP> (dsp)))
508 return std::move (signal).followedBy (std::forward<DerivedDSP> (dsp));
529#define HART_SIGNAL_FORBID_COPY_AND_MOVE
530 std::unique_ptr<Signal<SampleType>> copy() const override {
531 static_assert(false, "This Signal cannot be copied");
534 std::unique_ptr<Signal<SampleType>> move() override {
535 static_assert(false, "This Signal cannot be moved");
540#define HART_SIGNAL_DECLARE_ALIASES_FOR(ClassName)
541 namespace aliases_float{
542 using ClassName = hart::ClassName<float>;
544 namespace aliases_double{
545 using ClassName = hart::ClassName<double>;
Container for audio data.
Thrown when a numbers of channels is mismatched.
Polymorphic base for all DSP.
Thrown when a container index is out of range.
Thrown when a nullptr could be handled gracefully.
Thrown when sample rate is mismatched.
Polymorphic base for all signals.
virtual void reset()=0
Resets the Signal to initial state.
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
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 HART_THROW_OR_RETURN_VOID(ExceptionType, message)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns otherwise.
#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.