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