common: prevent buffer overflow
[supercollider.git] / include / plugin_interface / SC_Unit.h
blobde089afe9b3d18a97d8349204588675e9228f4cf
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
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.
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.
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
22 #ifndef _SC_Unit_
23 #define _SC_Unit_
25 #include "SC_Types.h"
26 #include "SC_SndBuf.h"
28 typedef void (*UnitCtorFunc)(struct Unit* inUnit);
29 typedef void (*UnitDtorFunc)(struct Unit* inUnit);
31 typedef void (*UnitCalcFunc)(struct Unit *inThing, int inNumSamples);
33 struct SC_Unit_Extensions {
34 float * todo;
37 struct Unit
39 struct World *mWorld;
40 struct UnitDef *mUnitDef;
41 struct Graph *mParent;
42 uint16 mNumInputs, mNumOutputs;
43 int16 mCalcRate;
44 int16 mSpecialIndex; // used by unary and binary ops
45 int16 mParentIndex;
46 int16 mDone;
47 struct Wire **mInput, **mOutput;
48 struct Rate *mRate;
49 SC_Unit_Extensions* mExtensions; //future proofing and backwards compatibility; used to be SC_Dimension struct pointer
50 float **mInBuf, **mOutBuf;
52 UnitCalcFunc mCalcFunc;
53 int mBufLength;
56 typedef struct Unit Unit;
58 enum {
59 kUnitDef_CantAliasInputsToOutputs = 1
62 #ifdef _WIN32
63 // Win32 headers (included by C std library headers) define IN and OUT macros
64 // for their own purposes.
65 #undef IN
66 #undef OUT
67 #endif
69 // These return float* pointers to input and output buffers.
70 #define IN(index) (unit->mInBuf[index])
71 #define OUT(index) (unit->mOutBuf[index])
73 // These return a float value. Used for control rate inputs and outputs.
74 #define IN0(index) (IN(index)[0])
75 #define OUT0(index) (OUT(index)[0])
77 // get the rate of the input.
78 #define INRATE(index) (unit->mInput[index]->mCalcRate)
80 // get the blocksize of the input
81 #define INBUFLENGTH(index) (unit->mInput[index]->mFromUnit->mBufLength)
83 // set the calculation function
84 #define SETCALC(func) (unit->mCalcFunc = (UnitCalcFunc)&func)
86 // calculate a slope for control rate interpolation to audio rate.
87 #define CALCSLOPE(next,prev) ((next - prev) * sc_typeof_cast(next)unit->mRate->mSlopeFactor)
89 // get useful values
90 #define SAMPLERATE (unit->mRate->mSampleRate)
91 #define SAMPLEDUR (unit->mRate->mSampleDur)
92 #define BUFLENGTH (unit->mBufLength)
93 #define BUFRATE (unit->mRate->mBufRate)
94 #define BUFDUR (unit->mRate->mBufDuration)
95 #define FULLRATE (unit->mWorld->mFullRate.mSampleRate)
96 #define FULLBUFLENGTH (unit->mWorld->mFullRate.mBufLength)
98 #ifdef SUPERNOVA
100 template <bool shared1, bool shared2>
101 struct buffer_lock2
103 buffer_lock2(const SndBuf * buf1, const SndBuf * buf2):
104 buf1_(buf1), buf2_(buf2)
106 if (buf1 == buf2)
108 lock1();
109 return;
112 for(;;)
114 lock1();
116 if (lock2())
117 return;
118 unlock1();
122 ~buffer_lock2(void)
124 unlock1();
125 if (buf1_ != buf2_)
126 unlock2();
129 private:
130 void lock1(void)
132 if (!shared1)
133 buf1_->lock.lock();
134 else
135 buf1_->lock.lock_shared();
138 bool lock2(void)
140 if (!shared2)
141 return buf2_->lock.try_lock();
142 else
143 return buf2_->lock.try_lock_shared();
146 void unlock1(void)
148 if (!shared1)
149 buf1_->lock.unlock();
150 else
151 buf1_->lock.unlock_shared();
154 void unlock2(void)
156 if (!shared2)
157 buf2_->lock.unlock();
158 else
159 buf2_->lock.unlock_shared();
162 const SndBuf * buf1_;
163 const SndBuf * buf2_;
166 #define ACQUIRE_BUS_AUDIO(index) unit->mWorld->mAudioBusLocks[index].lock()
167 #define ACQUIRE_BUS_AUDIO_SHARED(index) unit->mWorld->mAudioBusLocks[index].lock_shared()
168 #define RELEASE_BUS_AUDIO(index) unit->mWorld->mAudioBusLocks[index].unlock()
169 #define RELEASE_BUS_AUDIO_SHARED(index) unit->mWorld->mAudioBusLocks[index].unlock_shared()
171 #define LOCK_SNDBUF(buf) nova::rw_spinlock::scoped_lock lock_##buf(buf->lock)
172 #define LOCK_SNDBUF_SHARED(buf) nova::rw_spinlock::shared_lock lock_##buf(buf->lock);
174 #define LOCK_SNDBUF2(buf1, buf2) buffer_lock2<false, false> lock_##buf1##_##buf2(buf1, buf2);
175 #define LOCK_SNDBUF2_SHARED(buf1, buf2) buffer_lock2<true, true> lock_##buf1##_##buf2(buf1, buf2);
176 #define LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2) buffer_lock2<false, true> lock_##buf1##_##buf2(buf1, buf2);
177 #define LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2) buffer_lock2<true, false> lock_##buf1##_##buf2(buf1, buf2);
179 #define ACQUIRE_SNDBUF(buf) buf->lock.lock()
180 #define ACQUIRE_SNDBUF_SHARED(buf) buf->lock.lock_shared()
181 #define RELEASE_SNDBUF(buf) buf->lock.unlock()
182 #define RELEASE_SNDBUF_SHARED(buf) buf->lock.unlock_shared()
185 #define ACQUIRE_BUS_CONTROL(index) unit->mWorld->mControlBusLock->lock()
186 #define RELEASE_BUS_CONTROL(index) unit->mWorld->mControlBusLock->unlock()
188 #else
190 #define ACQUIRE_BUS_AUDIO(index)
191 #define ACQUIRE_BUS_AUDIO_SHARED(index)
192 #define RELEASE_BUS_AUDIO(index)
193 #define RELEASE_BUS_AUDIO_SHARED(index)
195 #define LOCK_SNDBUF(buf)
196 #define LOCK_SNDBUF_SHARED(buf)
198 #define LOCK_SNDBUF2(buf1, buf2)
199 #define LOCK_SNDBUF2_SHARED(buf1, buf2)
200 #define LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2)
201 #define LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2)
203 #define ACQUIRE_SNDBUF(buf)
204 #define ACQUIRE_SNDBUF_SHARED(buf)
205 #define RELEASE_SNDBUF(buf)
206 #define RELEASE_SNDBUF_SHARED(buf)
208 #define ACQUIRE_BUS_CONTROL(index)
209 #define RELEASE_BUS_CONTROL(index)
211 #endif
213 // macros to grab a Buffer reference from the buffer indicated by the UGen's FIRST input
214 #define GET_BUF \
215 float fbufnum = ZIN0(0); \
216 if (fbufnum < 0.f) { fbufnum = 0.f; } \
217 if (fbufnum != unit->m_fbufnum) { \
218 uint32 bufnum = (int)fbufnum; \
219 World *world = unit->mWorld; \
220 if (bufnum >= world->mNumSndBufs) { \
221 int localBufNum = bufnum - world->mNumSndBufs; \
222 Graph *parent = unit->mParent; \
223 if(localBufNum <= parent->localBufNum) { \
224 unit->m_buf = parent->mLocalSndBufs + localBufNum; \
225 } else { \
226 bufnum = 0; \
227 unit->m_buf = world->mSndBufs + bufnum; \
229 } else { \
230 unit->m_buf = world->mSndBufs + bufnum; \
232 unit->m_fbufnum = fbufnum; \
234 SndBuf *buf = unit->m_buf; \
235 LOCK_SNDBUF(buf); \
236 float *bufData __attribute__((__unused__)) = buf->data; \
237 uint32 bufChannels __attribute__((__unused__)) = buf->channels; \
238 uint32 bufSamples __attribute__((__unused__)) = buf->samples; \
239 uint32 bufFrames = buf->frames; \
240 int mask __attribute__((__unused__)) = buf->mask; \
241 int guardFrame __attribute__((__unused__)) = bufFrames - 2;
243 #define GET_BUF_SHARED \
244 float fbufnum = ZIN0(0); \
245 if (fbufnum < 0.f) { fbufnum = 0.f; } \
246 if (fbufnum != unit->m_fbufnum) { \
247 uint32 bufnum = (int)fbufnum; \
248 World *world = unit->mWorld; \
249 if (bufnum >= world->mNumSndBufs) { \
250 int localBufNum = bufnum - world->mNumSndBufs; \
251 Graph *parent = unit->mParent; \
252 if(localBufNum <= parent->localBufNum) { \
253 unit->m_buf = parent->mLocalSndBufs + localBufNum; \
254 } else { \
255 bufnum = 0; \
256 unit->m_buf = world->mSndBufs + bufnum; \
258 } else { \
259 unit->m_buf = world->mSndBufs + bufnum; \
261 unit->m_fbufnum = fbufnum; \
263 const SndBuf *buf = unit->m_buf; \
264 LOCK_SNDBUF_SHARED(buf); \
265 const float *bufData __attribute__((__unused__)) = buf->data; \
266 uint32 bufChannels __attribute__((__unused__)) = buf->channels; \
267 uint32 bufSamples __attribute__((__unused__)) = buf->samples; \
268 uint32 bufFrames = buf->frames; \
269 int mask __attribute__((__unused__)) = buf->mask; \
270 int guardFrame __attribute__((__unused__)) = bufFrames - 2;
272 #define SIMPLE_GET_BUF \
273 float fbufnum = ZIN0(0); \
274 fbufnum = sc_max(0.f, fbufnum); \
275 if (fbufnum != unit->m_fbufnum) { \
276 uint32 bufnum = (int)fbufnum; \
277 World *world = unit->mWorld; \
278 if (bufnum >= world->mNumSndBufs) { \
279 int localBufNum = bufnum - world->mNumSndBufs; \
280 Graph *parent = unit->mParent; \
281 if(localBufNum <= parent->localBufNum) { \
282 unit->m_buf = parent->mLocalSndBufs + localBufNum; \
283 } else { \
284 bufnum = 0; \
285 unit->m_buf = world->mSndBufs + bufnum; \
287 } else { \
288 unit->m_buf = world->mSndBufs + bufnum; \
290 unit->m_fbufnum = fbufnum; \
292 SndBuf *buf = unit->m_buf; \
294 #define SIMPLE_GET_BUF_EXCLUSIVE \
295 SIMPLE_GET_BUF; \
296 LOCK_SNDBUF(buf);
298 #define SIMPLE_GET_BUF_SHARED \
299 SIMPLE_GET_BUF; \
300 LOCK_SNDBUF_SHARED(buf);
302 // macros to get pseudo-random number generator, and put its state in registers
303 #define RGET \
304 RGen& rgen = *unit->mParent->mRGen; \
305 uint32 s1 = rgen.s1; \
306 uint32 s2 = rgen.s2; \
307 uint32 s3 = rgen.s3;
308 #define RPUT \
309 rgen.s1 = s1; \
310 rgen.s2 = s2; \
311 rgen.s3 = s3;
313 typedef void (*UnitCmdFunc)(struct Unit *unit, struct sc_msg_iter *args);
314 typedef void (*PlugInCmdFunc)(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr);
316 #endif