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
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
{
40 struct UnitDef
*mUnitDef
;
41 struct Graph
*mParent
;
42 uint16 mNumInputs
, mNumOutputs
;
44 int16 mSpecialIndex
; // used by unary and binary ops
47 struct Wire
**mInput
, **mOutput
;
49 SC_Unit_Extensions
* mExtensions
; //future proofing and backwards compatibility; used to be SC_Dimension struct pointer
50 float **mInBuf
, **mOutBuf
;
52 UnitCalcFunc mCalcFunc
;
56 typedef struct Unit Unit
;
59 kUnitDef_CantAliasInputsToOutputs
= 1
63 // Win32 headers (included by C std library headers) define IN and OUT macros
64 // for their own purposes.
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)
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)
100 template <bool shared1
, bool shared2
>
103 buffer_lock2(const SndBuf
* buf1
, const SndBuf
* buf2
):
104 buf1_(buf1
), buf2_(buf2
)
135 buf1_
->lock
.lock_shared();
141 return buf2_
->lock
.try_lock();
143 return buf2_
->lock
.try_lock_shared();
149 buf1_
->lock
.unlock();
151 buf1_
->lock
.unlock_shared();
157 buf2_
->lock
.unlock();
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()
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)
213 // macros to grab a Buffer reference from the buffer indicated by the UGen's FIRST input
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; \
227 unit->m_buf = world->mSndBufs + bufnum; \
230 unit->m_buf = world->mSndBufs + bufnum; \
232 unit->m_fbufnum = fbufnum; \
234 SndBuf *buf = unit->m_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; \
256 unit->m_buf = world->mSndBufs + bufnum; \
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; \
285 unit->m_buf = world->mSndBufs + bufnum; \
288 unit->m_buf = world->mSndBufs + bufnum; \
290 unit->m_fbufnum = fbufnum; \
292 SndBuf *buf = unit->m_buf; \
294 #define SIMPLE_GET_BUF_EXCLUSIVE \
298 #define SIMPLE_GET_BUF_SHARED \
300 LOCK_SNDBUF_SHARED(buf);
302 // macros to get pseudo-random number generator, and put its state in registers
304 RGen& rgen = *unit->mParent->mRGen; \
305 uint32 s1 = rgen.s1; \
306 uint32 s2 = rgen.s2; \
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
);