"Post Window" -> "Post window" prevents it being seen as two separate
[supercollider.git] / include / plugin_interface / SC_Unit.h
blob9061d2b3c9a69bf6f18af9b98967630be1b72ee6
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 uint32 mNumInputs, mNumOutputs; // changed from uint16 for synthdef ver 2
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) {
107 lock1();
108 return;
111 for(;;) {
112 lock1();
114 if (lock2())
115 return;
116 unlock1();
120 ~buffer_lock2(void)
122 unlock1();
123 if (buf1_ != buf2_)
124 unlock2();
127 private:
128 void lock1(void)
130 if (buf1_->isLocal)
131 return;
133 if (!shared1)
134 buf1_->lock.lock();
135 else
136 buf1_->lock.lock_shared();
139 bool lock2(void)
141 if (buf2_->isLocal)
142 return true;
144 if (!shared2)
145 return buf2_->lock.try_lock();
146 else
147 return buf2_->lock.try_lock_shared();
150 void unlock1(void)
152 if (buf1_->isLocal)
153 return;
155 if (!shared1)
156 buf1_->lock.unlock();
157 else
158 buf1_->lock.unlock_shared();
161 void unlock2(void)
163 if (buf2_->isLocal)
164 return;
166 if (!shared2)
167 buf2_->lock.unlock();
168 else
169 buf2_->lock.unlock_shared();
172 const SndBuf * buf1_;
173 const SndBuf * buf2_;
176 template <bool shared>
177 struct buffer_lock
179 buffer_lock(const SndBuf * buf):
180 buf_(buf)
182 if (!buf->isLocal) {
183 if (shared)
184 buf->lock.lock_shared();
185 else
186 buf->lock.lock();
190 ~buffer_lock(void)
192 if (!buf_->isLocal) {
193 if (shared)
194 buf_->lock.unlock_shared();
195 else
196 buf_->lock.unlock();
200 const SndBuf * buf_;
203 #define ACQUIRE_BUS_AUDIO(index) unit->mWorld->mAudioBusLocks[index].lock()
204 #define ACQUIRE_BUS_AUDIO_SHARED(index) unit->mWorld->mAudioBusLocks[index].lock_shared()
205 #define RELEASE_BUS_AUDIO(index) unit->mWorld->mAudioBusLocks[index].unlock()
206 #define RELEASE_BUS_AUDIO_SHARED(index) unit->mWorld->mAudioBusLocks[index].unlock_shared()
208 #define LOCK_SNDBUF(buf) buffer_lock<false> lock_##buf(buf)
209 #define LOCK_SNDBUF_SHARED(buf) buffer_lock<true> lock_##buf(buf);
211 #define LOCK_SNDBUF2(buf1, buf2) buffer_lock2<false, false> lock_##buf1##_##buf2(buf1, buf2);
212 #define LOCK_SNDBUF2_SHARED(buf1, buf2) buffer_lock2<true, true> lock_##buf1##_##buf2(buf1, buf2);
213 #define LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2) buffer_lock2<false, true> lock_##buf1##_##buf2(buf1, buf2);
214 #define LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2) buffer_lock2<true, false> lock_##buf1##_##buf2(buf1, buf2);
216 #define ACQUIRE_SNDBUF(buf) do { if (!buf->isLocal) buf->lock.lock(); } while (false)
217 #define ACQUIRE_SNDBUF_SHARED(buf) do { if (!buf->isLocal) buf->lock.lock_shared(); } while (false)
218 #define RELEASE_SNDBUF(buf) do { if (!buf->isLocal) buf->lock.unlock(); } while (false)
219 #define RELEASE_SNDBUF_SHARED(buf) do { if (!buf->isLocal) buf->lock.unlock_shared(); } while (false)
222 #define ACQUIRE_BUS_CONTROL(index) unit->mWorld->mControlBusLock->lock()
223 #define RELEASE_BUS_CONTROL(index) unit->mWorld->mControlBusLock->unlock()
225 #else
227 #define ACQUIRE_BUS_AUDIO(index)
228 #define ACQUIRE_BUS_AUDIO_SHARED(index)
229 #define RELEASE_BUS_AUDIO(index)
230 #define RELEASE_BUS_AUDIO_SHARED(index)
232 #define LOCK_SNDBUF(buf)
233 #define LOCK_SNDBUF_SHARED(buf)
235 #define LOCK_SNDBUF2(buf1, buf2)
236 #define LOCK_SNDBUF2_SHARED(buf1, buf2)
237 #define LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2)
238 #define LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2)
240 #define ACQUIRE_SNDBUF(buf)
241 #define ACQUIRE_SNDBUF_SHARED(buf)
242 #define RELEASE_SNDBUF(buf)
243 #define RELEASE_SNDBUF_SHARED(buf)
245 #define ACQUIRE_BUS_CONTROL(index)
246 #define RELEASE_BUS_CONTROL(index)
248 #endif
250 // macros to grab a Buffer reference from the buffer indicated by the UGen's FIRST input
251 #define GET_BUF \
252 float fbufnum = ZIN0(0); \
253 if (fbufnum < 0.f) { fbufnum = 0.f; } \
254 if (fbufnum != unit->m_fbufnum) { \
255 uint32 bufnum = (int)fbufnum; \
256 World *world = unit->mWorld; \
257 if (bufnum >= world->mNumSndBufs) { \
258 int localBufNum = bufnum - world->mNumSndBufs; \
259 Graph *parent = unit->mParent; \
260 if(localBufNum <= parent->localBufNum) { \
261 unit->m_buf = parent->mLocalSndBufs + localBufNum; \
262 } else { \
263 bufnum = 0; \
264 unit->m_buf = world->mSndBufs + bufnum; \
266 } else { \
267 unit->m_buf = world->mSndBufs + bufnum; \
269 unit->m_fbufnum = fbufnum; \
271 SndBuf *buf = unit->m_buf; \
272 LOCK_SNDBUF(buf); \
273 float *bufData __attribute__((__unused__)) = buf->data; \
274 uint32 bufChannels __attribute__((__unused__)) = buf->channels; \
275 uint32 bufSamples __attribute__((__unused__)) = buf->samples; \
276 uint32 bufFrames = buf->frames; \
277 int mask __attribute__((__unused__)) = buf->mask; \
278 int guardFrame __attribute__((__unused__)) = bufFrames - 2;
280 #define GET_BUF_SHARED \
281 float fbufnum = ZIN0(0); \
282 if (fbufnum < 0.f) { fbufnum = 0.f; } \
283 if (fbufnum != unit->m_fbufnum) { \
284 uint32 bufnum = (int)fbufnum; \
285 World *world = unit->mWorld; \
286 if (bufnum >= world->mNumSndBufs) { \
287 int localBufNum = bufnum - world->mNumSndBufs; \
288 Graph *parent = unit->mParent; \
289 if(localBufNum <= parent->localBufNum) { \
290 unit->m_buf = parent->mLocalSndBufs + localBufNum; \
291 } else { \
292 bufnum = 0; \
293 unit->m_buf = world->mSndBufs + bufnum; \
295 } else { \
296 unit->m_buf = world->mSndBufs + bufnum; \
298 unit->m_fbufnum = fbufnum; \
300 const SndBuf *buf = unit->m_buf; \
301 LOCK_SNDBUF_SHARED(buf); \
302 const float *bufData __attribute__((__unused__)) = buf->data; \
303 uint32 bufChannels __attribute__((__unused__)) = buf->channels; \
304 uint32 bufSamples __attribute__((__unused__)) = buf->samples; \
305 uint32 bufFrames = buf->frames; \
306 int mask __attribute__((__unused__)) = buf->mask; \
307 int guardFrame __attribute__((__unused__)) = bufFrames - 2;
309 #define SIMPLE_GET_BUF \
310 float fbufnum = ZIN0(0); \
311 fbufnum = sc_max(0.f, fbufnum); \
312 if (fbufnum != unit->m_fbufnum) { \
313 uint32 bufnum = (int)fbufnum; \
314 World *world = unit->mWorld; \
315 if (bufnum >= world->mNumSndBufs) { \
316 int localBufNum = bufnum - world->mNumSndBufs; \
317 Graph *parent = unit->mParent; \
318 if(localBufNum <= parent->localBufNum) { \
319 unit->m_buf = parent->mLocalSndBufs + localBufNum; \
320 } else { \
321 bufnum = 0; \
322 unit->m_buf = world->mSndBufs + bufnum; \
324 } else { \
325 unit->m_buf = world->mSndBufs + bufnum; \
327 unit->m_fbufnum = fbufnum; \
329 SndBuf *buf = unit->m_buf; \
331 #define SIMPLE_GET_BUF_EXCLUSIVE \
332 SIMPLE_GET_BUF; \
333 LOCK_SNDBUF(buf);
335 #define SIMPLE_GET_BUF_SHARED \
336 SIMPLE_GET_BUF; \
337 LOCK_SNDBUF_SHARED(buf);
339 // macros to get pseudo-random number generator, and put its state in registers
340 #define RGET \
341 RGen& rgen = *unit->mParent->mRGen; \
342 uint32 s1 = rgen.s1; \
343 uint32 s2 = rgen.s2; \
344 uint32 s3 = rgen.s3;
345 #define RPUT \
346 rgen.s1 = s1; \
347 rgen.s2 = s2; \
348 rgen.s3 = s3;
350 typedef void (*UnitCmdFunc)(struct Unit *unit, struct sc_msg_iter *args);
351 typedef void (*PlugInCmdFunc)(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr);
353 #endif