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
30 float mFreqMul
, mAmp
, mNextAmp
, mSpeed
, mDur
;
31 int mMemorySize
, mIndex
;
32 float* mMemoryAmp
; //could hard code as 12
36 //following Hoffmann paper from CMJ- primary and secondary random walks
37 struct Gendy2
: public Unit
40 float mFreqMul
, mAmp
, mNextAmp
, mSpeed
, mDur
;
41 int mMemorySize
, mIndex
;
43 float* mMemoryAmpStep
;
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
;
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
85 unit
->mNextAmp
= 0.0f
;
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;
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
)
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
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
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]
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
;
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);
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);
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!
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()
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
;
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
);
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]
295 //linear interpolation could be changed
296 z
= ((1.0-phase
)*amp
) + (phase
*nextamp
);
302 unit
->mPhase
= phase
;
304 unit
->mNextAmp
= nextamp
;
305 unit
->mSpeed
= speed
;
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
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;
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
);
357 in
= (2.0f
*upper
-lower
)-in
;
359 in
= fmod(in
-upper
,2.0f
*range
);
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
;
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
414 float lehmerxen
= fmod(((amp
)*a
)+c
,1.0f
);
416 //printf("lehmer %f \n", lehmerxen);
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]
459 //linear interpolation could be changed
460 z
= ((1.0-phase
)*amp
) + (phase
*nextamp
);
466 unit
->mPhase
= phase
;
468 unit
->mNextAmp
= nextamp
;
469 unit
->mSpeed
= speed
;
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
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;
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
;
547 if (phase
>= 1.) { //calculate all targets for new period
550 int num
= (int)(ZIN0(8));
551 if((num
>(unit
->mMemorySize
)) || (num
<1)) num
= unit
->mMemorySize
;
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
);
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
572 //normalising constant
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
];
589 amplist
[active
] = memoryamp
[j
];
590 phaselist
[active
] = dur
;
595 //add a zero on the end at active
596 amplist
[active
] = 0.0f
; //guard element
597 phaselist
[active
] = 2.0; //safety element
600 // nextphase= phaselist[0];
602 // nextamp=amplist[1];
604 // unit->mIndex=index;
606 //setup to trigger next block
608 nextamp
= amplist
[0];
612 if (phase
>= nextphase
) { //are we into a new region?
613 //new code for indexing
614 ++index
; //=index+1; //%num;
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
);
636 unit
->mPhase
= phase
;
637 unit
->mSpeed
= speed
;
638 unit
->mInterpMult
= interpmult
;
640 unit
->mNextAmp
= nextamp
;
641 unit
->mLastPhase
= lastphase
;
642 unit
->mNextPhase
= nextphase
;
649 DefineDtorUnit(Gendy1
);
650 DefineDtorUnit(Gendy2
);
651 DefineDtorUnit(Gendy3
);