HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_mixed_signal.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4#include <vector>
5
6#include "signals/hart_signal.hpp"
7
8namespace hart
9{
10
11/// @brief Produces a mix of multiple signals
12/// @details You get this class as a result of adding or subtracting signals,
13/// so you don't want to instantiate it directly.
14/// @ingroup Signals
15template<typename SampleType>
17 public Signal<SampleType, MixedSignal<SampleType>>
18{
19public:
20 /// @brief Default constructor
21 MixedSignal() = default;
22
23 /// @brief Destructor
24 ~MixedSignal() = default;
25
26 // TODO: Move and smart pointer transfer
27 /// @brief Creates a MixedSignals from two existing signals
28 /// @details For internal use by "+" and "-" operators,
29 /// so you probably don't want to call it directly.
30 /// @param signalA Signal to add to the mix
31 /// @param signalB Another signal to add to the mix
32 MixedSignal (const SignalBase<SampleType>& signalA, const SignalBase<SampleType>& signalB)
33 {
34 m_signals.push_back (signalA.copy());
35 m_signals.push_back (signalB.copy());
36 }
37
38 /// @brief Copies other MixedSignal
39 MixedSignal (const MixedSignal& other):
40 Signal<SampleType, MixedSignal<SampleType>> (other)
41 {
42 m_signals.reserve (other.m_signals.size());
43
44 for (const auto& src : other.m_signals)
45 m_signals.emplace_back (src->copy());
46 }
47
48 /// @brief Moves from other MixedSignal
49 MixedSignal (MixedSignal&& other) noexcept:
50 Signal<SampleType, MixedSignal<SampleType>> (std::move (other)),
51 m_signals (std::move (other.m_signals))
52 {
53 }
54
55 /// @brief Copies other MixedSignal
57 {
58 if (this == &other)
59 return *this;
60
61 // Copy base + its dspChain
62 Signal<SampleType, MixedSignal<SampleType>>::operator=(other);
63
64 // Deep-copy owned signals
65 m_signals.clear();
66 m_signals.reserve (other.m_signals.size());
67
68 for (const auto& signal : other.m_signals)
69 m_signals.emplace_back (signal->copy());
70
71 return *this;
72 }
73
74 /// @brief Moves from other MixedSignal
75 MixedSignal& operator=(MixedSignal&& other) noexcept
76 {
77 // Move base + its dspChain
78 Signal<SampleType, MixedSignal<SampleType>>::operator= (std::move (other));
79
80 // Move owned signals
81 m_signals = std::move (other.m_signals);
82
83 return *this;
84 }
85
86 void prepare (double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames) override
87 {
88 for (auto& signal : m_signals)
89 signal->prepareWithDSPChain (sampleRateHz, numOutputChannels, maxBlockSizeFrames);
90 }
91
92 void renderNextBlock (AudioBuffer<SampleType>& output) override
93 {
94 if (m_signals.empty())
95 {
96 output.clear();
97 return;
98 }
99
100 // Render first signal
101 m_signals[0]->renderNextBlockWithDSPChain (output);
102
103 // Add all subsequent ones
104 // TODO: Avoid memory allocation in this method, move it to prepare() and resize when needed
105 AudioBuffer<SampleType> buffer = AudioBuffer<SampleType>::emptyLike (output);
106
107 for (size_t i = 1; i < m_signals.size(); ++i)
108 {
109 m_signals[i]->renderNextBlockWithDSPChain (buffer);
110
111 // TODO: implement AudioBuffer.addFrom()
112 for (size_t channel = 0; channel < output.getNumChannels(); ++channel)
113 for (size_t frame = 0; frame < output.getNumFrames(); ++frame)
114 output[channel][frame] += buffer[channel][frame];
115 }
116 }
117
118 void reset() override
119 {
120 for (auto& signal : m_signals)
121 signal->resetWithDSPChain();
122 }
123
124 void represent (std::ostream& s) const override
125 {
126 s << "<MixedSignal: {";
127
128 for (size_t i = 0; i < m_signals.size(); ++i)
129 {
130 if (i > 0)
131 s << ", ";
132
133 m_signals[i]->representWithDSPChain (s);
134 }
135
136 s << "}>";
137 }
138
139private:
140 std::vector<std::unique_ptr<SignalBase<SampleType>>> m_signals;
141};
142
143/// @brief Adds one signal to another, resulting in a new mixed signal
144/// @ingroup Signals
145/// @relates Signal
146template<typename SampleType, typename DerivedSignalTypeLHS, typename DerivedSignalTypeRHS>
147MixedSignal<SampleType> operator+ (
148 const Signal<SampleType, DerivedSignalTypeLHS>& lhs,
149 const Signal<SampleType, DerivedSignalTypeRHS>& rhs
150 )
151{
152 return MixedSignal<SampleType> (
153 static_cast<const DerivedSignalTypeLHS&> (lhs),
154 static_cast<const DerivedSignalTypeRHS&> (rhs)
155 );
156}
157
158/// @brief Subtracts one signal from another, resulting in a new mixed signal
159/// @ingroup Signals
160/// @relates Signal
161template<typename SampleType, typename DerivedSignalTypeLHS, typename DerivedSignalTypeRHS>
162MixedSignal<SampleType> operator- (
163 const Signal<SampleType, DerivedSignalTypeLHS>& lhs,
164 const Signal<SampleType, DerivedSignalTypeRHS>& rhs
165 )
166{
167 return MixedSignal<SampleType> (
168 static_cast<const DerivedSignalTypeLHS&> (lhs),
169 -static_cast<const DerivedSignalTypeRHS&> (rhs)
170 );
171}
172
173} // namespace hart
Produces a mix of multiple signals.
void renderNextBlock(AudioBuffer< SampleType > &output) override
Renders next block audio for the signal.
void represent(std::ostream &s) const override
Makes a text representation of this Signal for test failure outputs.
MixedSignal(MixedSignal &&other) noexcept
Moves from other MixedSignal.
~MixedSignal()=default
Destructor.
MixedSignal()=default
Default constructor.
MixedSignal & operator=(MixedSignal &&other) noexcept
Moves from other MixedSignal.
MixedSignal & operator=(const MixedSignal &other)
Copies other MixedSignal.
void prepare(double sampleRateHz, size_t numOutputChannels, size_t maxBlockSizeFrames) override
Prepare the signal for rendering.
void reset() override
Resets the Signal to initial state.
MixedSignal(const SignalBase< SampleType > &signalA, const SignalBase< SampleType > &signalB)
Creates a MixedSignals from two existing signals.
MixedSignal(const MixedSignal &other)
Copies other MixedSignal.
Polymorphic base for all signals.
Base class for signals.
MixedSignal< SampleType > operator-(const Signal< SampleType, DerivedSignalTypeLHS > &lhs, const Signal< SampleType, DerivedSignalTypeRHS > &rhs)
Subtracts one signal from another, resulting in a new mixed signal.
MixedSignal< SampleType > operator+(const Signal< SampleType, DerivedSignalTypeLHS > &lhs, const Signal< SampleType, DerivedSignalTypeRHS > &rhs)
Adds one signal to another, resulting in a new mixed signal.