class library: SynthDef - replaceUGen fixes
[supercollider.git] / server / plugins / GendynUGens.cpp
blob249b74d7c5b112647022d88bb922fdfcdcb678d8
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 //Gendyn UGens implemented by Nick Collins
23 #include "SC_PlugIn.h"
25 static InterfaceTable *ft;
27 struct Gendy1 : public Unit // Iannis Xenakis/Marie-Helene Serra GENDYN simulation
29 double mPhase;
30 float mFreqMul, mAmp, mNextAmp, mSpeed, mDur;
31 int mMemorySize, mIndex;
32 float* mMemoryAmp; //could hard code as 12
33 float* mMemoryDur;
36 //following Hoffmann paper from CMJ- primary and secondary random walks
37 struct Gendy2 : public Unit
39 double mPhase;
40 float mFreqMul, mAmp, mNextAmp, mSpeed, mDur;
41 int mMemorySize, mIndex;
42 float* mMemoryAmp;
43 float* mMemoryAmpStep;
44 float* mMemoryDur;
45 float* mMemoryDurStep;
49 //Random walks as Gendy1 but works out all breakpoints per cycle and normalises time intervals to desired frequency
50 struct Gendy3 : public Unit
52 double mPhase, mNextPhase, mLastPhase;
53 float mSpeed, mFreqMul;
54 float mAmp, mNextAmp, mInterpMult;
55 int mMemorySize, mIndex;
56 float* mMemoryAmp;
57 float* mMemoryDur;
58 double* mPhaseList;
59 float* mAmpList;
62 extern "C" {
64 void Gendy1_next_k(Gendy1 *unit, int inNumSamples);
65 void Gendy1_Ctor(Gendy1* unit);
66 void Gendy1_Dtor(Gendy1* unit);
68 void Gendy2_next_k(Gendy2 *unit, int inNumSamples);
69 void Gendy2_Ctor(Gendy2* unit);
70 void Gendy2_Dtor(Gendy2* unit);
72 void Gendy3_next_k(Gendy3 *unit, int inNumSamples);
73 void Gendy3_Ctor(Gendy3* unit);
74 void Gendy3_Dtor(Gendy3* unit);
78 void Gendy1_Ctor( Gendy1* unit )
80 SETCALC(Gendy1_next_k);
82 unit->mFreqMul = unit->mRate->mSampleDur;
83 unit->mPhase = 1.0; //should immediately decide on new target
84 unit->mAmp = 0.0f;
85 unit->mNextAmp = 0.0f;
86 unit->mSpeed = 100.f;
88 unit->mMemorySize = (int) ZIN0(8); //default is 12
89 //printf("memsize %d %f", unit->mMemorySize, ZIN0(8));
90 if(unit->mMemorySize<1)
91 unit->mMemorySize = 1;
92 unit->mIndex = 0;
93 unit->mMemoryAmp = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
94 unit->mMemoryDur = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
96 RGen& rgen = *unit->mParent->mRGen;
98 //initialise to zeroes and separations
99 for(int i=0; i<unit->mMemorySize;++i) {
100 unit->mMemoryAmp[i] = 2*rgen.frand() - 1.0f;
101 unit->mMemoryDur[i] = rgen.frand();
105 void Gendy1_Dtor(Gendy1 *unit)
107 RTFree(unit->mWorld, unit->mMemoryAmp);
108 RTFree(unit->mWorld, unit->mMemoryDur);
112 //called once per period so OK to work out constants in here
113 static float Gendyn_distribution( int which, float a, float f)
115 float temp, c;
117 if(a>1.f) a = 1.f; //a must be in range 0 to 1
118 if(a<0.0001f) a = 0.0001f; //for safety with some distributions, don't want divide by zero errors
120 switch (which)
122 case 0: //LINEAR
123 //linear
124 break;
125 case 1: //CAUCHY
126 //X has a*tan((z-0.5)*pi)
127 //I went back to first principles of the Cauchy distribution and re-integrated with a
128 //normalisation constant
130 //choice of 10 here is such that f=0.95 gives about 0.35 for temp, could go with 2 to make it finer
131 c = atan(10*a); //PERHAPS CHANGE TO a=1/a;
132 //incorrect- missed out divisor of pi in norm temp= a*tan(c*(2*pi*f - 1));
133 temp = (1.f/a)*tan(c*(2.f*f - 1.f)); //Cauchy distribution, C is precalculated
135 //printf("cauchy f %f c %f temp %f out %f \n",f, c, temp, temp/10);
137 return temp*0.1f; //(temp+100)/200;
139 case 2: //LOGIST (ic)
140 //X has -(log((1-z)/z)+b)/a which is not very usable as is
142 c = 0.5f+(0.499f*a); //calculate normalisation constant
143 c = log((1.f-c)/c);
145 //remap into range of valid inputs to avoid infinities in the log
147 //f= ((f-0.5)*0.499*a)+0.5;
148 f = ((f-0.5f)*0.998f*a)+0.5f; //[0,1]->[0.001,0.999]; squashed around midpoint 0.5 by a
149 //Xenakis calls this the LOGIST map, it's from the range [0,1] to [inf,0] where 0.5->1
150 //than take natural log. to avoid infinities in practise I take [0,1] -> [0.001,0.999]->[6.9,-6.9]
151 //an interesting property is that 0.5-e is the reciprocal of 0.5+e under (1-f)/f
152 //and hence the logs are the negative of each other
153 temp = log((1.f-f)/f)/c; //n range [-1,1]
154 //X also had two constants in his- I don't bother
156 //printf("logist f %f temp %f\n", f, temp);
158 return temp; //a*0.5*(temp+1.0); //to [0,1]
160 case 3: //HYPERBCOS
161 //X original a*log(tan(z*pi/2)) which is [0,1]->[0,pi/2]->[0,inf]->[-inf,inf]
162 //unmanageable in this pure form
163 c = tan(1.5692255f*a); //tan(0.999*a*pi*0.5); //[0, 636.6] maximum range
164 temp = tan(1.5692255f*a*f)/c; //[0,1]->[0,1]
165 temp = log(temp*0.999f+0.001f)*(-0.1447648f); // multiplier same as /(-6.9077553); //[0,1]->[0,1]
167 //printf("hyperbcos f %f c %f temp %f\n", f, c, temp);
169 return 2.f*temp-1.0f;
171 case 4: //ARCSINE
172 //X original a/2*(1-sin((0.5-z)*pi)) aha almost a better behaved one though [0,1]->[2,0]->[a,0]
173 c = sin(1.5707963f*a); //sin(pi*0.5*a); //a as scaling factor of domain of sine input to use
174 temp = sin(pi_f*(f-0.5f)*a)/c; //[-1,1] which is what I need
176 //printf("arcsine f %f c %f temp %f\n", f, c, temp);
178 return temp;
180 case 5: //EXPON
181 //X original -(log(1-z))/a [0,1]-> [1,0]-> [0,-inf]->[0,inf]
182 c = log(1.f-(0.999f*a));
183 temp = log(1.f-(f*0.999f*a))/c;
185 //printf("expon f %f c %f temp %f\n", f, c, temp);
187 return 2.f*temp-1.f;
189 case 6: //SINUS
190 //X original a*sin(smp * 2*pi/44100 * b) ie depends on a second oscillator's value-
191 //hmmm, plug this in as a I guess, will automatically accept control rate inputs then!
192 return 2.f*a-1.f;
194 default:
195 break;
198 return 2.f*f-1.f;
202 void Gendy1_next_k( Gendy1 *unit, int inNumSamples )
204 float *out = ZOUT(0);
206 //distribution choices for amp and dur and constants of distribution
207 int whichamp = (int)ZIN0(0);
208 int whichdur = (int)ZIN0(1);
209 float aamp = ZIN0(2);
210 float adur = ZIN0(3);
211 float minfreq = ZIN0(4);
212 float maxfreq = ZIN0(5);
213 float scaleamp = ZIN0(6);
214 float scaledur = ZIN0(7);
216 float rate = unit->mDur;
218 //phase gives proportion for linear interpolation automatically
219 double phase = unit->mPhase;
221 float amp = unit->mAmp;
222 float nextamp = unit->mNextAmp;
224 float speed = unit->mSpeed;
226 RGen& rgen = *unit->mParent->mRGen;
227 //linear distribution 0.0 to 1.0 using rgen.frand()
229 LOOP1(inNumSamples,
230 float z;
232 if (phase >= 1.0) {
233 phase -= 1.0;
235 int index = unit->mIndex;
236 int num = (int)(ZIN0(9));//(unit->mMemorySize);(((int)ZIN0(9))%(unit->mMemorySize))+1;
237 if((num>(unit->mMemorySize)) || (num<1)) num=unit->mMemorySize;
239 //new code for indexing
240 index = (index+1)%num;
241 amp = nextamp;
243 unit->mIndex = index;
245 //Gendy dist gives value [-1,1], then use scaleamp
246 //first term was amp before, now must check new memory slot
247 nextamp = (unit->mMemoryAmp[index])+(scaleamp*Gendyn_distribution(whichamp, aamp,rgen.frand()));
249 //mirroring for bounds- safe version
250 if(nextamp>1.0f || nextamp<-1.0f) {
252 //printf("mirroring nextamp %f ", nextamp);
254 //to force mirroring to be sensible
255 if(nextamp<0.0f) nextamp = nextamp+4.f;
257 nextamp = fmod(nextamp,4.f);
258 //printf("fmod %f ", nextamp);
260 if(nextamp>1.0f && nextamp<3.f)
261 nextamp = 2.f-nextamp;
263 else if(nextamp>1.0f)
264 nextamp = nextamp-4.f;
266 //printf("mirrorednextamp %f \n", nextamp);
269 unit->mMemoryAmp[index] = nextamp;
271 //Gendy dist gives value [-1,1]
272 rate= (unit->mMemoryDur[index]) + (scaledur*Gendyn_distribution(whichdur, adur, rgen.frand()));
274 if(rate>1.0f || rate<0.0f)
276 if(rate<0.0) rate = rate+2.f;
277 rate = fmod(rate,2.0f);
278 rate = 2.f-rate;
281 unit->mMemoryDur[index] = rate;
283 //printf("nextamp %f rate %f \n", nextamp, rate);
285 //define range of speeds (say between 20 and 1000 Hz)
286 //can have bounds as fourth and fifth inputs
287 speed = (minfreq+((maxfreq-minfreq)*rate))*(unit->mFreqMul);
289 //if there are 12 control points in memory, that is 12 per cycle
290 //the speed is multiplied by 12
291 //(I don't store this because updating rates must remain in range [0,1]
292 speed *= num;
295 //linear interpolation could be changed
296 z = ((1.0-phase)*amp) + (phase*nextamp);
298 phase += speed;
299 ZXP(out) = z;
302 unit->mPhase = phase;
303 unit->mAmp = amp;
304 unit->mNextAmp = nextamp;
305 unit->mSpeed = speed;
306 unit->mDur = rate;
312 void Gendy2_Ctor( Gendy2* unit )
314 SETCALC(Gendy2_next_k);
316 unit->mFreqMul = unit->mRate->mSampleDur;
317 unit->mPhase = 1.0; //should immediately decide on new target
318 unit->mAmp = 0.0f;
319 unit->mNextAmp = 0.0f;
320 unit->mSpeed = 100.f;
322 unit->mMemorySize = (int) ZIN0(8); //default is 12
323 //printf("memsize %d %f", unit->mMemorySize, ZIN0(8));
324 if(unit->mMemorySize<1) unit->mMemorySize = 1;
325 unit->mIndex = 0;
326 unit->mMemoryAmp = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
327 unit->mMemoryDur = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
328 unit->mMemoryAmpStep = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
329 unit->mMemoryDurStep = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
331 RGen& rgen = *unit->mParent->mRGen;
333 //initialise to zeroes and separations
334 for(int i=0; i<unit->mMemorySize;++i) {
335 unit->mMemoryAmp[i] = 2*rgen.frand() - 1.0f;
336 unit->mMemoryDur[i] = rgen.frand();
337 unit->mMemoryAmpStep[i] = 2*rgen.frand() - 1.0f;
338 unit->mMemoryDurStep[i] = 2*rgen.frand() - 1.0f;
342 void Gendy2_Dtor(Gendy2 *unit)
344 RTFree(unit->mWorld, unit->mMemoryAmp);
345 RTFree(unit->mWorld, unit->mMemoryDur);
346 RTFree(unit->mWorld, unit->mMemoryAmpStep);
347 RTFree(unit->mWorld, unit->mMemoryDurStep);
350 static float Gendyn_mirroring (float lower, float upper, float in)
352 //mirroring for bounds- safe version
353 if(in>upper || in<lower) {
354 float range= (upper-lower);
356 if(in<lower)
357 in = (2.0f*upper-lower)-in;
359 in = fmod(in-upper,2.0f*range);
361 if(in<range)
362 in = upper-in;
363 else
364 in = in- (range);
367 return in;
370 void Gendy2_next_k( Gendy2 *unit, int inNumSamples )
372 float *out = ZOUT(0);
374 //distribution choices for amp and dur and constants of distribution
375 int whichamp = (int)ZIN0(0);
376 int whichdur = (int)ZIN0(1);
377 float aamp = ZIN0(2);
378 float adur = ZIN0(3);
379 float minfreq = ZIN0(4);
380 float maxfreq = ZIN0(5);
381 float scaleamp = ZIN0(6);
382 float scaledur = ZIN0(7);
384 float rate = unit->mDur;
386 //phase gives proportion for linear interpolation automatically
387 double phase = unit->mPhase;
389 float amp = unit->mAmp;
390 float nextamp = unit->mNextAmp;
392 float speed = unit->mSpeed;
394 RGen& rgen = *unit->mParent->mRGen;
396 LOOP1(inNumSamples,
397 float z;
399 if (phase >= 1.0) {
400 phase -= 1.0;
402 int index = unit->mIndex;
403 int num = (int)(ZIN0(9));//(unit->mMemorySize);(((int)ZIN0(9))%(unit->mMemorySize))+1;
404 if((num>(unit->mMemorySize)) || (num<1)) num=unit->mMemorySize;
406 //new code for indexing
407 index = (index+1)%num;
409 //using last amp value as seed
410 //random values made using a lehmer number generator xenakis style
411 float a = ZIN0(10);
412 float c = ZIN0(11);
414 float lehmerxen = fmod(((amp)*a)+c,1.0f);
416 //printf("lehmer %f \n", lehmerxen);
418 amp = nextamp;
420 unit->mIndex = index;
422 //Gendy dist gives value [-1,1], then use scaleamp
423 //first term was amp before, now must check new memory slot
425 float ampstep = (unit->mMemoryAmpStep[index])+ Gendyn_distribution(whichamp, aamp, fabs(lehmerxen));
426 ampstep = Gendyn_mirroring(-1.0f,1.0f,ampstep);
428 unit->mMemoryAmpStep[index] = ampstep;
430 nextamp = (unit->mMemoryAmp[index])+(scaleamp*ampstep);
432 nextamp = Gendyn_mirroring(-1.0f,1.0f,nextamp);
434 unit->mMemoryAmp[index] = nextamp;
436 float durstep = (unit->mMemoryDurStep[index])+ Gendyn_distribution(whichdur, adur, rgen.frand());
437 durstep = Gendyn_mirroring(-1.0f,1.0f,durstep);
439 unit->mMemoryDurStep[index] = durstep;
441 rate = (unit->mMemoryDur[index])+(scaledur*durstep);
443 rate = Gendyn_mirroring(0.0f,1.0f,rate);
445 unit->mMemoryDur[index] = rate;
447 //printf("nextamp %f rate %f \n", nextamp, rate);
449 //define range of speeds (say between 20 and 1000 Hz)
450 //can have bounds as fourth and fifth inputs
451 speed = (minfreq+((maxfreq-minfreq)*rate))*(unit->mFreqMul);
453 //if there are 12 control points in memory, that is 12 per cycle
454 //the speed is multiplied by 12
455 //(I don't store this because updating rates must remain in range [0,1]
456 speed *= num;
459 //linear interpolation could be changed
460 z = ((1.0-phase)*amp) + (phase*nextamp);
462 phase += speed;
463 ZXP(out) = z;
466 unit->mPhase = phase;
467 unit->mAmp = amp;
468 unit->mNextAmp = nextamp;
469 unit->mSpeed = speed;
470 unit->mDur = rate;
473 void Gendy3_Ctor( Gendy3* unit )
475 SETCALC(Gendy3_next_k);
477 unit->mFreqMul = unit->mRate->mSampleDur;
478 unit->mPhase = 1.0; //should immediately decide on new target
479 unit->mAmp = 0.0f;
480 unit->mNextAmp = 0.0f;
481 unit->mNextPhase = 0.0;
482 unit->mLastPhase = 0.0;
483 unit->mInterpMult = 1.0f;
484 unit->mSpeed = 100.f;
486 unit->mMemorySize = (int) ZIN0(7);
487 if(unit->mMemorySize<1) unit->mMemorySize = 1;
488 unit->mIndex = 0;
489 unit->mMemoryAmp = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
490 unit->mMemoryDur = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float));
492 //one more in amp list for guard (wrap) element
493 unit->mAmpList = (float*)RTAlloc(unit->mWorld, (unit->mMemorySize+1) * sizeof(float));
494 unit->mPhaseList = (double*)RTAlloc(unit->mWorld, (unit->mMemorySize+1) * sizeof(double));
496 RGen& rgen = *unit->mParent->mRGen;
498 //initialise to zeroes and separations
499 for(int i = 0; i<unit->mMemorySize;++i) {
500 unit->mMemoryAmp[i] = 2*rgen.frand() - 1.0f;
501 unit->mMemoryDur[i] = rgen.frand();
502 unit->mAmpList[i] = 2*rgen.frand() - 1.0f;
503 unit->mPhaseList[i] = 1.0; //will be intialised immediately
506 unit->mMemoryAmp[0] = 0.0f; //always zeroed first BP
509 void Gendy3_Dtor(Gendy3 *unit)
511 RTFree(unit->mWorld, unit->mMemoryAmp);
512 RTFree(unit->mWorld, unit->mMemoryDur);
513 RTFree(unit->mWorld, unit->mAmpList);
514 RTFree(unit->mWorld, unit->mPhaseList);
517 void Gendy3_next_k( Gendy3 *unit, int inNumSamples )
519 float *out = ZOUT(0);
521 //distribution choices for amp and dur and constants of distribution
522 int whichamp = (int)ZIN0(0);
523 int whichdur = (int)ZIN0(1);
524 float aamp = ZIN0(2);
525 float adur = ZIN0(3);
526 float freq = ZIN0(4);
527 float scaleamp = ZIN0(5);
528 float scaledur = ZIN0(6);
530 double phase = unit->mPhase;
531 float amp = unit->mAmp;
532 float nextamp= unit->mNextAmp;
533 float speed= unit->mSpeed;
534 int index = unit->mIndex;
535 int interpmult = (int)unit->mInterpMult;
536 double lastphase = unit->mLastPhase;
537 double nextphase = unit->mNextPhase;
539 RGen& rgen = *unit->mParent->mRGen;
541 float * amplist = unit->mAmpList;
542 double * phaselist = unit->mPhaseList;
544 LOOP1(inNumSamples,
545 float z;
547 if (phase >= 1.) { //calculate all targets for new period
548 phase -= 1.;
550 int num = (int)(ZIN0(8));
551 if((num>(unit->mMemorySize)) || (num<1)) num = unit->mMemorySize;
553 float dursum = 0.0f;
555 float * memoryamp = unit->mMemoryAmp;
556 float * memorydur = unit->mMemoryDur;
558 for(int j = 0; j<num; ++j) {
560 if(j>0) { //first BP always stays at 0
561 float amp = (memoryamp[j])+ (scaleamp*Gendyn_distribution(whichamp, aamp, rgen.frand()));
562 amp = Gendyn_mirroring(-1.0f,1.0f,amp);
563 memoryamp[j] = amp;
566 float dur = (memorydur[j])+ (scaledur*Gendyn_distribution(whichdur, adur, rgen.frand()));
567 dur = Gendyn_mirroring(0.01f,1.0f,dur); //will get normalised in a moment, don't allow zeroes
568 memorydur[j] = dur;
569 dursum += dur;
572 //normalising constant
573 dursum = 1.f/dursum;
575 int active = 0;
577 //phase duration of a sample
578 float minphase = unit->mFreqMul;
580 speed = freq*minphase;
582 //normalise and discard any too short (even first)
583 for(int j = 0; j<num; ++j) {
585 float dur = memorydur[j];
586 dur *= dursum;
588 if(dur>=minphase) {
589 amplist[active] = memoryamp[j];
590 phaselist[active] = dur;
591 ++active;
595 //add a zero on the end at active
596 amplist[active] = 0.0f; //guard element
597 phaselist[active] = 2.0; //safety element
599 //lastphase=0.0;
600 // nextphase= phaselist[0];
601 // amp=amplist[0];
602 // nextamp=amplist[1];
603 // index=0;
604 // unit->mIndex=index;
606 //setup to trigger next block
607 nextphase = 0.0;
608 nextamp = amplist[0];
609 index = -1;
612 if (phase >= nextphase) { //are we into a new region?
613 //new code for indexing
614 ++index; //=index+1; //%num;
616 amp = nextamp;
618 unit->mIndex = index;
620 lastphase = nextphase;
621 nextphase = lastphase+phaselist[index];
622 nextamp = amplist[index+1];
624 interpmult = (int)(1.0/(nextphase-lastphase));
627 float interp = (phase-lastphase)*interpmult;
629 //linear interpolation could be changed
630 z = ((1.0f-interp)*amp) + (interp*nextamp);
632 phase += speed;
633 ZXP(out) = z;
636 unit->mPhase = phase;
637 unit->mSpeed = speed;
638 unit->mInterpMult = interpmult;
639 unit->mAmp = amp;
640 unit->mNextAmp = nextamp;
641 unit->mLastPhase = lastphase;
642 unit->mNextPhase = nextphase;
645 PluginLoad(Gendyn)
647 ft = inTable;
649 DefineDtorUnit(Gendy1);
650 DefineDtorUnit(Gendy2);
651 DefineDtorUnit(Gendy3);