class library: SynthDef - replaceUGen fixes
[supercollider.git] / server / plugins / PhysicalModelingUGens.cpp
blob35cfff3595a11ff7364cfc52e3efd6aee7cf4d75
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
21 // some basic physical modeling ugens - julian rohrhuber 1/04
22 // these are very simple implementations with cartoonification aspects.
25 #include "SC_PlugIn.h"
27 static InterfaceTable *ft;
29 //////////////////////////////////////////////////////////////////////////////////////////////////
32 struct Spring : public Unit
34 float m_pos;
35 float m_vel;
38 struct Friction : public Unit
40 float m_pos;
41 float m_vel;
42 int m_state;
46 struct Ball : public Unit
48 float m_pos;
49 float m_vel;
50 float m_prev;
53 struct TBall : public Unit
55 double m_pos;
56 float m_vel;
57 double m_prev;
62 extern "C"
65 void Spring_Ctor(Spring *unit);
66 void Spring_next(Spring *unit, int inNumSamples);
68 //void Friction_Ctor(Friction *unit);
69 //void Friction_next(Friction *unit, int inNumSamples);
71 void Ball_Ctor(Ball *unit);
72 void Ball_next(Ball *unit, int inNumSamples);
74 void TBall_Ctor(TBall *unit);
75 void TBall_next(TBall *unit, int inNumSamples);
78 ////////////////////////////////////////////////////////////////////////////////////////////////////////
81 void Spring_Ctor(Spring *unit)
83 SETCALC(Spring_next);
84 unit->m_vel = 0.f;
85 unit->m_pos = 0.f;
86 Spring_next(unit, 1);
90 // in, spring, damping
92 void Spring_next(Spring *unit, int inNumSamples)
94 float pos = unit->m_pos;
95 float vel = unit->m_vel;
96 float *out = ZOUT(0); // out force
97 float *in = ZIN(0); // in force
98 float spring = ZIN0(1); // spring constant
99 float damping = 1.f - ZIN0(2);// damping
100 float c = SAMPLEDUR;
101 float rc = SAMPLERATE;
102 spring = spring * c;
103 LOOP1(inNumSamples,
104 float force = ZXP(in) * c - pos * spring;
105 vel = (force + vel) * damping;
106 pos += vel;
107 ZXP(out) = force * rc;
110 unit->m_pos = pos;
111 unit->m_vel = vel;
115 //////////////////////////////////////////////////////////////////////////////////////////
118 void Friction_Ctor(Friction *unit)
120 SETCALC(Friction_next);
121 unit->m_vel = 0.f;
122 unit->m_pos = 0.f;
123 unit->m_state = 0;
124 Friction_next(unit, 1);
128 // in, spring, damping
130 void Friction_next(Friction *unit, int inNumSamples)
132 float pos = unit->m_pos;
133 float vel = unit->m_vel;
134 int state = unit->m_state;
136 void Index_next_a(Index *unit, int inNumSamples)
138 // get table
139 GET_TABLE
140 float *table = bufData;
141 int32 maxindex = tableSize - 1;
143 float *out = ZOUT(0);
144 float *in = ZIN(1);
146 LOOP1(inNumSamples,
147 int32 index = (int32)ZXP(in);
148 index = sc_clip(index, 0, maxindex);
149 ZXP(out) = table[index];
155 float *out = ZOUT(0); // out force
156 float *in = ZIN(0); // in displacement
157 float spring = ZIN0(1); // spring constant
158 float damping = 1.f - ZIN0(2); // friction -> replace by buffer number for friction table
159 float c = SAMPLEDUR;
160 float rc = SAMPLERATE;
161 spring *= c;
162 LOOP1(inNumSamples,
163 float inpos = ZXP(in) * c;
164 float force = inpos + pos * spring;
165 state = (vel > damping) ? 1 : 0; // friction table here
166 if(state) { // stuck
167 vel = 0.f;
168 pos += inpos;
169 } else { // loose
170 vel += force;
171 pos -= vel;
173 ZXP(out) = force * rc;
176 unit->m_pos = pos;
177 unit->m_vel = vel;
178 unit->m_state = state;
182 #define GET_TABLE \
183 float fbufnum = ZIN0(0); \
184 if (fbufnum != unit->m_fbufnum) { \
185 uint32 bufnum = (uint32)fbufnum; \
186 World *world = unit->mWorld; \
187 if (bufnum >= world->mNumSndBufs) bufnum = 0; \
188 unit->m_buf = world->mSndBufs + bufnum; \
190 SndBuf *buf = unit->m_buf; \
191 if(!buf) { \
192 ClearUnitOutputs(unit, inNumSamples); \
193 return; \
195 LOCK_SNDBUF(buf); \
196 float *bufData __attribute__((__unused__)) = buf->data; \
197 if (!bufData) { \
198 ClearUnitOutputs(unit, inNumSamples); \
199 return; \
201 int tableSize = buf->samples;
204 //////////////////////////////////////////////////////////////////////////////////////////
207 void Ball_Ctor(Ball *unit)
209 SETCALC(Ball_next);
210 unit->m_vel = 0.f;
211 unit->m_pos = ZIN0(0);
212 unit->m_prev = ZIN0(0);
213 Ball_next(unit, 1);
217 void Ball_next(Ball *unit, int inNumSamples)
219 float *out = ZOUT(0);
220 float *in = ZIN(0); // floor position
221 float g_in = ZIN0(1); // gravity
222 float damping = 1 - ZIN0(2); // damping
223 float k = ZIN0(3); // friction
225 float pos = unit->m_pos;
226 float vel = unit->m_vel;
227 float prev_floor = unit->m_prev;
228 float c = SAMPLEDUR;
229 float maxvel = c * 1000.f;
230 float minvel = 0.f - maxvel;
231 float inter = c * 1000.f;
232 RGen& rgen = *unit->mParent->mRGen;
233 float g = c * g_in;
234 #ifdef _MSC_VER
235 k *= g_in; // stickyness proportional to gravity
236 #else //#ifdef _MSC_VER
237 k = (double) k * (double) g_in; // stickyness proportional to gravity
238 #endif //#ifdef _MSC_VER
240 LOOP1(inNumSamples,
241 float floor = ZXP(in);
242 float floorvel;
243 float dither;
244 vel -= g;
245 pos += vel;
246 float dist = pos - floor;
247 floorvel = floor - prev_floor;
248 floorvel = sc_clip(floorvel, minvel, maxvel);
249 float vel_diff = floorvel - vel;
250 if(sc_abs(dist) < k) { // sticky friction: maybe vel dependant?
252 if(sc_abs(dist) < (k*0.005)) {
253 vel = 0.f;
254 pos = floor + g;
255 } else {
256 vel = vel_diff * inter + vel;
257 pos = (floor - pos) * inter + pos;
260 } else if(dist <= 0.f) {
262 pos = floor - dist;
263 vel = vel_diff;
264 vel *= damping;
266 dither = rgen.frand() * 0.00005f * g_in; // dither to reduce jitter
267 //if(sc_abs(dist) < 0.000001) { vel += dither; }
268 vel += dither;
270 prev_floor = floor;
271 ZXP(out) = pos;
274 unit->m_pos = pos;
275 unit->m_vel = vel;
276 unit->m_prev = prev_floor;
280 //////////////////////////////////////////////////////////////////////////////////////////
282 void TBall_Ctor(TBall *unit)
284 SETCALC(TBall_next);
285 unit->m_vel = 0.f;
286 unit->m_pos = ZIN0(0);
287 unit->m_prev = ZIN0(0);
288 TBall_next(unit, 1);
291 void TBall_next(TBall *unit, int inNumSamples)
293 float *out = ZOUT(0);
294 float *in = ZIN(0); // floor position
295 float g_in = ZIN0(1); // gravity
296 float damping = 1 - ZIN0(2);// damping
297 float k = ZIN0(3); // friction
299 double pos = unit->m_pos;
300 float vel = unit->m_vel;
301 double prev_floor = unit->m_prev;
302 float c = SAMPLEDUR;
303 float maxvel = c * 1000.f;
304 float minvel = 0.f - maxvel;
305 float inter = c * 10000.f;
306 RGen& rgen = *unit->mParent->mRGen;
307 float g = c * g_in;
308 #ifdef _MSC_VER
309 k *= g_in; // stickyness proportional to gravity
310 #else //#ifdef _MSC_VER
311 k = (double) k * (double) g_in; // stickyness proportional to gravity
312 #endif //#ifdef _MSC_VER
314 LOOP1(inNumSamples,
315 double floor = ZXP(in);
316 float floorvel;
317 float outval = 0.f;
318 float dither;
319 vel -= g;
320 pos += vel;
321 double dist = pos - floor;
322 floorvel = floor - prev_floor;
323 floorvel = sc_clip(floorvel, minvel, maxvel);
324 float vel_diff = floorvel - vel;
325 if(sc_abs(dist) < k) { // sticky friction: vel dependant?
326 if(sc_abs(dist) < (k*0.005)) {
327 vel = 0.f;
328 pos = floor + g;
329 } else {
330 vel = vel_diff * inter + vel;
331 pos = (floor - pos) * inter + pos;
333 } else if(dist <= 0.f) {
334 pos = floor - dist;
335 vel = floorvel - vel;
336 vel *= damping;
337 outval = vel;
338 dither = rgen.frand() * 0.001f * g_in; // dither to reduce sampling jitter
339 //if(sc_abs(dist) < 0.003) { vel += dither; }
340 vel += dither;
343 prev_floor = floor;
344 ZXP(out) = outval;
347 unit->m_pos = pos;
348 unit->m_vel = vel;
349 unit->m_prev = prev_floor;
355 ////////////////////////////////////////////////////////////////////////////////////////////////////////
357 PluginLoad(PhysicalModeling)
359 ft = inTable;
361 DefineSimpleUnit(Spring);
362 // DefineSimpleUnit(Friction);
363 DefineSimpleUnit(Ball);
364 DefineSimpleUnit(TBall);