1 /*
2 * SuperCollider real time audio synthesis system
3 * Copyright (c) 2002 James McCartney. All rights reserved.
4 * Copyright (c) 2011 Tim Blechmann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #pragma once
22
23 #include <cassert>
24
25 #include "SC_PlugIn.h"
26 #include "function_attributes.h"
27
28 #include <type_traits>
29
30 /// c++ wrapper for Unit struct
31 class SCUnit : public Unit {
32 public:
33 ///@{
34 /// generic signal wrappers
35 template <typename FloatType> struct ScalarSignal {
ScalarSignalSCUnit::ScalarSignal36 explicit ScalarSignal(FloatType value): value(value) {}
37
consumeSCUnit::ScalarSignal38 FloatType consume() const { return value; }
39
40 FloatType value;
41 };
42
43 template <typename FloatType> struct SlopeSignal {
SlopeSignalSCUnit::SlopeSignal44 SlopeSignal(FloatType value, FloatType slope): value(value), slope(slope) {}
45
consumeSCUnit::SlopeSignal46 FloatType consume() {
47 FloatType ret = value;
48 value += slope;
49 return ret;
50 }
51
52 FloatType value, slope;
53 };
54
55 template <typename FloatType> struct AudioSignal {
AudioSignalSCUnit::AudioSignal56 explicit AudioSignal(const FloatType* pointer): pointer(pointer) {}
57
consumeSCUnit::AudioSignal58 FloatType consume() { return *pointer++; }
59
60 const FloatType* pointer;
61 };
62
makeScalar(FloatType value) const63 template <typename FloatType> inline ScalarSignal<FloatType> makeScalar(FloatType value) const {
64 return ScalarSignal<FloatType>(value);
65 }
66
makeSlope(FloatType next,FloatType last) const67 template <typename FloatType> inline SlopeSignal<FloatType> makeSlope(FloatType next, FloatType last) const {
68 return SlopeSignal<FloatType>(last, calcSlope(next, last));
69 }
70
makeSignal(int index) const71 inline AudioSignal<float> makeSignal(int index) const {
72 const float* input = in(index);
73 return AudioSignal<float>(input);
74 }
75 ///@}
76
77 /// get input signal at index
in(int index) const78 const float* in(int index) const {
79 assert(uint32(index) < mNumInputs);
80 const Unit* unit = this;
81 return IN(index);
82 }
83
84 /// get input signal at index (to be used with ZXP)
zin(int index) const85 const float* zin(int index) const {
86 assert(uint32(index) < mNumInputs);
87 const Unit* unit = this;
88 return ZIN(index);
89 }
90
91 /// get first sample of input signal
in0(int index) const92 float in0(int index) const {
93 assert(uint32(index) < mNumInputs);
94 const Unit* unit = this;
95 return IN0(index);
96 }
97
98 /// get output signal at index
out(int index) const99 float* out(int index) const {
100 assert(uint32(index) < mNumOutputs);
101 const Unit* unit = this;
102 return OUT(index);
103 }
104
105 /// get output signal at index (to be used with ZXP)
zout(int index) const106 float* zout(int index) const {
107 assert(uint32(index) < mNumOutputs);
108 const Unit* unit = this;
109 return ZOUT(index);
110 }
111
112 /// get reference to first sample of output signal
out0(int index) const113 float& out0(int index) const {
114 assert(uint32(index) < mNumOutputs);
115 const Unit* unit = this;
116 return OUT0(index);
117 }
118
119 /// get rate of input signal
inRate(int index) const120 int inRate(int index) const {
121 assert(uint32(index) < mNumInputs);
122 const Unit* unit = this;
123 return INRATE(index);
124 }
125
126 /// get number of inputs
numInputs() const127 int numInputs() const { return int(mNumInputs); }
128
129 /// get number of outputs
numOutputs() const130 int numOutputs() const { return int(mNumOutputs); }
131
132 /// test if input signal at index is scalar rate
isScalarRateIn(int index) const133 bool isScalarRateIn(int index) const {
134 assert(uint32(index) < mNumInputs);
135 return inRate(index) == calc_ScalarRate;
136 }
137
138 /// test if input signal at index is demand rate
isDemandRateIn(int index) const139 bool isDemandRateIn(int index) const {
140 assert(uint32(index) < mNumInputs);
141 return inRate(index) == calc_DemandRate;
142 }
143
144 /// test if input signal at index is control rate
isControlRateIn(int index) const145 bool isControlRateIn(int index) const {
146 assert(uint32(index) < mNumInputs);
147 return inRate(index) == calc_BufRate;
148 }
149
150 /// test if input signal at index is audio rate
isAudioRateIn(int index) const151 bool isAudioRateIn(int index) const {
152 assert(uint32(index) < mNumInputs);
153 return inRate(index) == calc_FullRate;
154 }
155
156 /// get the blocksize of the input
inBufferSize(int index) const157 int inBufferSize(int index) const {
158 assert(uint32(index) < mNumInputs);
159 const Unit* unit = this;
160 return INBUFLENGTH(index);
161 }
162
163 /// get sample rate of ugen
sampleRate() const164 double sampleRate() const {
165 const Unit* unit = this;
166 return SAMPLERATE;
167 }
168
169 /// get sample duration
sampleDur() const170 double sampleDur() const {
171 const Unit* unit = this;
172 return SAMPLEDUR;
173 }
174
175 /// get buffer size of ugen
bufferSize() const176 int bufferSize() const { return mBufLength; }
177
178 /// get control rate
controlRate() const179 double controlRate() const {
180 const Unit* unit = this;
181 return BUFRATE;
182 }
183
184 /// get duration of a control block
controlDur() const185 double controlDur() const {
186 const Unit* unit = this;
187 return BUFDUR;
188 }
189
190 /// get sampling rate of audio signal
fullSampleRate() const191 double fullSampleRate() const {
192 const Unit* unit = this;
193 return FULLRATE;
194 }
195
196 /// get buffer size of audio signals
fullBufferSize() const197 int fullBufferSize() const {
198 const Unit* unit = this;
199 return FULLBUFLENGTH;
200 }
201
202 /// calculate slope value
calcSlope(FloatType next,FloatType prev) const203 template <typename FloatType> FloatType calcSlope(FloatType next, FloatType prev) const {
204 const Unit* unit = this;
205 return CALCSLOPE(next, prev);
206 }
207
make_calc_function(void)208 template <typename UnitType, void (UnitType::*PointerToMember)(int)> static UnitCalcFunc make_calc_function(void) {
209 return &run_member_function<UnitType, PointerToMember>;
210 }
211
212 /// set calc function & compute initial sample
set_calc_function(void)213 template <typename UnitType, void (UnitType::*PointerToMember)(int)> void set_calc_function(void) {
214 mCalcFunc = make_calc_function<UnitType, PointerToMember>();
215 (mCalcFunc)(this, 1);
216 }
217
218 /// set calc function & compute initial sample
219 template <typename UnitType, void (UnitType::*VectorCalcFunc)(int), void (UnitType::*ScalarCalcFunc)(int)>
set_vector_calc_function(void)220 void set_vector_calc_function(void) {
221 mCalcFunc = make_calc_function<UnitType, VectorCalcFunc>();
222 make_calc_function<UnitType, ScalarCalcFunc>()(this, 1);
223 }
224 /// @}
225
226 private:
227 template <typename UnitType, void (UnitType::*PointerToMember)(int)>
run_member_function(struct Unit * unit,int inNumSamples)228 HOT static void run_member_function(struct Unit* unit, int inNumSamples) {
229 UnitType* realUnit = static_cast<UnitType*>(unit);
230 ((realUnit)->*(PointerToMember))(inNumSamples);
231 }
232 };
233
234 /// define Ctor/Dtor functions for a class
235 #define DEFINE_XTORS(CLASSNAME) \
236 void CLASSNAME##_Ctor(CLASSNAME* unit) { new (unit) CLASSNAME(); } \
237 \
238 void CLASSNAME##_Dtor(CLASSNAME* unit) { unit->~CLASSNAME(); }
239
240 namespace detail {
241
constructClass(Unit * unit)242 template <class UGenClass> void constructClass(Unit* unit) { new (static_cast<UGenClass*>(unit)) UGenClass(); }
destroyClass(Unit * unit)243 template <class UGenClass> void destroyClass(Unit* unit) { static_cast<UGenClass*>(unit)->~UGenClass(); }
244
245 }
246
registerUnit(InterfaceTable * ft,const char * name,int disableBufferAliasing=0)247 template <class Unit> void registerUnit(InterfaceTable* ft, const char* name, int disableBufferAliasing = 0) {
248 UnitCtorFunc ctor = detail::constructClass<Unit>;
249 UnitDtorFunc dtor = std::is_trivially_destructible<Unit>::value ? nullptr : detail::destroyClass<Unit>;
250
251 (*ft->fDefineUnit)(name, sizeof(Unit), ctor, dtor, disableBufferAliasing);
252 }
253