I might have the CD-ROM somewhere but would have to dig it out. One of my two pieces from it included below (but SC2 code; I think it got it running in emulation a year or two back. The other piece, iDAB, requires various sound files).
//pythcirc = pythagorean circulations
//copyright Nick Collins, finished 27/8/2001 all rights reserved
//lower CPU drain version
//runs at around average CPU use 25-35%, peaks up to 60%, initial peak over 100%
//many hundred UGens at once, but most are k rate
//measured on a G4 400MHz tibook with 384 MB RAM
//elliptical reading of scaled pythagorean scales with rhythmic pulsing
//and synthesised percussion
//no samples were used in this production
//requires Reverb and WavetableManipulation classes
(
var basefreq,startfreq;
var pyth,pyth1,pyth2;
var numranges,ranges;
var createpitchcirc,createfiltcirc,createindexarray;
var fadeprop;
var wavetables;
var percarray,drumpattern;
fadeprop= 0.5.rand+0.5;
//7 note scale using natural intervals from harmonic series
pyth= [1,9/8,5/4,4/3,3/2,5/3,15/8];
//octave completion scale versions
pyth1= pyth ++ [2];
pyth2= pyth ++ (2*pyth) ++ [4];
//a3
basefreq= 110;
//starting frequencies are dependent on pyth scale starting at base
startfreq= pyth*pyth2;
numranges=3; //for piece generations could make 4.rand
wavetables= Array.fill(numranges,{b=WavetableManipulation.bpsettowavetable(WavetableManipulation.randombps(3+(3.rand)),512,1);});
//creates scale readers for freq input in pitch and filt circulators
createindexarray=
{
arg dur,rangeindex;
var scalemult,bf;
var scaletemp,excess,scale,table;
var phase,indexarray;
var voices;
var initcirc,endcirc; //defaults 10 and 0.1
//choose length of spawned event, num voices, scale mult, circulation speed
voices= 1+ (5.rand);
initcirc= 1+(100.rand);
endcirc= 0.001+(1.rand); //0.1 should be more probable- need continuous distribution peaking around 0.1?
//choose base freq based on range
bf= basefreq*(2**(rangeindex))*(pyth.choose);
//scalemults depend on range
scaletemp= 0.9*(rangeindex+1)/numranges;
scalemult= 0.1+(scaletemp.rand);
//scale construction
excess= pyth2.log2;
excess= excess*scalemult;
scaletemp= 2**excess;
//delete 7 of the 15
7.do(
{
scaletemp=scaletemp.scramble;
scaletemp.pop;
});
//intervals
scaletemp= SortedList.newFrom(scaletemp);
//build over 2 octaves and add in mirror image
scale= bf*(((1.0/scaletemp).reverse) ++ scaletemp);
table=FloatArray.newFrom(scale);
//indexing procedure
//phase at rhythmic multiples? to force synchrony on some points?
//can randomise phase for other effects
if(0.7.coin,
{
phase=Array.fill(voices, {arg i; (i/voices)*2*pi});
},
{
phase=Array.fill(voices, {2*pi.rand});
}
);
indexarray=Array.fill(phase.size,{
arg i;
//stopping different voices at different times
var leng;
leng= (dur/voices)*(i+1); //dur
//different index methods- allow Oscs with odd wavetables! Discontinuous
Index.kr(
table,
SinOsc.kr(XLine.kr(initcirc,endcirc,leng),phase.at(i),(0.7+(0.3*(SinOsc.kr(XLine.kr(initcirc,endcirc,leng*0.6),phase.at(i),1.0).abs)))*(table.size-1)/2,(table.size-1)/2).round(1.0)
)
});
indexarray
};
createpitchcirc=
{
arg dur,rangeindex;
var indexarray,env;
indexarray=createindexarray.value(dur,rangeindex);
env=Env.new([1.0,1.0,0.0],[dur*fadeprop,dur*(1.0-fadeprop)]);
EnvGen.ar(env,
((0.2+(0.8*((numranges-rangeindex)/numranges)))/indexarray.size)*
Mix.arFill(indexarray.size,
{
arg i;
var maxpan,minpan;
//pan positions in an annulus around 0
maxpan= (rangeindex+1)/numranges;
minpan= (rangeindex)/numranges;
Pan2.ar(
//Use an Osc here- vary the wavetable based on rangeindex?
//can just be SinOsc
Osc.ar(
wavetables.at(rangeindex),
indexarray.at(i),
0,
0.1
)
,(rrand(maxpan,minpan)* ((-1)**(2.rand)))
)
}
)
)
};
createfiltcirc=
{
arg dur,rangeindex;
var env,indexarray;
indexarray=createindexarray.value(dur,rangeindex);
env=Env.new([1.0,1.0,0.0],[dur*fadeprop,dur*(1.0-fadeprop)]);
EnvGen.ar(env,
((0.2+(0.8*((numranges-rangeindex)/numranges)))/indexarray.size)*
Mix.arFill(indexarray.size,
{
arg i;
var maxpan,minpan;
//pan positions in an annulus around 0
maxpan= (rangeindex+1)/numranges;
minpan= (rangeindex)/numranges;
Pan2.ar(
//filtered noise
BPF.ar(
WhiteNoise.ar,
indexarray.at(i),
0.001,
15
)
,(rrand(maxpan,minpan)* ((-1)**(2.rand)))
)
}
)
)
};
//////////
//percussion sounds array
//array of ugenFuncs
percarray=
[
{ //bong kick
Klank.ar(`[[70,73,77,80,83,85], [-3.dbamp,-6.dbamp,-12.dbamp,-12.dbamp,-12.dbamp,-20.dbamp], [1, 0.5,0.4,0.3, 0.25, 0.125]],EnvGen.ar(Env.perc(0.0,0.1,1,-16),WhiteNoise.ar(0.5)))
},
{
var tightness;
tightness=0.01*(5.rand+1);
EnvGen.ar(Env.perc(0.0,tightness,8,-8),BrownNoise.ar)
}
,
{
EnvGen.ar(Env.perc(0.0,0.1,1,-8),PinkNoise.ar(FSinOsc.ar(20)))
}
,
{
EnvGen.ar(Env.perc(0.0,0.1,1,8),Integrator.ar(Impulse.ar(20),0.999,HPF.ar(WhiteNoise.ar,2000)))
}
,
{
BPF.ar(Decay.ar(Pulse.ar(1,0.01,WhiteNoise.ar),0.01,0.03),1000,XLine.kr(0.9,0.1,0.03))
}
,
{
BPF.ar(Pulse.ar(1,0.01,Normalizer.ar(LFNoise0.ar(5),1.0,0.01)),XLine.kr(100,5000,0.01),XLine.kr(0.9,0.1,0.01))
}
,
{
BPF.ar(Pulse.ar(1,0.01,LinCong.ar(0,7,17,486)),XLine.kr(1000,100,0.01),XLine.kr(0.9,0.1,0.01))
}
,
{
BPF.ar(Pulse.ar(1,0.01,LinCong.ar(5,38,17,48600)),100,XLine.kr(0.9,0.1,0.01))
}
,
{
BPF.ar(Pulse.ar(1,0.01,LinCong.ar(51,26,170,93400,0.2)),XLine.ar(10000,50,0.01),0.8)
}
,
{
BPF.ar(Integrator.ar(Pulse.ar(1,0.1,LinCong.ar(510,601,17,9300,0.2)),0.1),XLine.kr(1000,50,0.01),0.8)
}
,
{
EnvGen.ar
(
Env.perc(0.0,0.2,0.4,-1), //new([1,0],[0.2]),
Resonz.ar(LinCong.ar(4,6,13,800030,Line.kr(1.0,Line.kr(0.5,0.0,0.02),0.1)),6000,XLine.kr(0.8,0.1,0.1))
)
}
,
{
EnvGen.ar
(
Env.perc(0.0,0.2,1.0,-4), //new([1,0],[0.2]),
Resonz.ar(LinCong.ar(4,6,13,800030,Line.kr(1.0,Line.kr(0.5,0.0,0.02),0.1)),XLine.kr(300,10,0.2),XLine.kr(0.8,0.1,0.1))
)
}
];
drumpattern=
[
[
[Pseq([0.5,1.5,0.75,1.25],inf),Pseq([0.0,Pseq([1.0],3)],inf)],
[Pseq([0.5,1.5,0.75,1.25],inf),Pseq([1.0,Prand([1.0,0.0],2)],inf)],
[Pseq([0.5,Prand([0.5,1.5],1),0.75,1.25],inf),Pseq([0.0,Pseq([1.0],3)],inf)],
[Pseq([0.25,0.25,1.5,0.75,1.25],inf),Pseq([Pseq([1.0],4),0.0],inf)]
],
[
[Pseq([1.0,2.0,0.75,0.25],inf),Pseq([0.0,Pseq([1.0],3)],inf)],
[Pseq([1.0,2.0,Prand([Pseq([0.25,0.5,0.25],1),Pseq([0.5,0.25,0.25],1)],1)],inf),Pseq([0.0,Pseq([1.0],4)],inf)],
[Pseq([1.0,2.0,0.75,0.5],inf),Pseq([0.0,Pseq([1.0],3)],inf)],
[Pseq([1.0,2.0,0.75,0.25,0.25],inf),Pseq([0.0,Pseq([1.0],3)],inf)]
],
[
[Pseq([0.5,Pseq([1.0],3),0.5,Pseq([0.25],12)],inf),Pseq([0.0,Pseq([1.0],3),1.0,Pseries(0,1/12,12)],inf)],
[Pseq([0.5,Pseq([1.0],3),0.5,Pseq([0.25],12)],inf),Pseq([0.0,Pseq([1.0],3),1.0,Pseries(0,1/12,8)],inf)],
[Pseq([0.5,Pseq([1.0],3),0.5,Pseq([0.25],12)],inf),Pseq([0.0,Pseq([1.0],3),1.0,Pseries(0,1/12,10)],inf)],
[Pseq([0.5,Pseq([1.0],4),0.5,Pseq([0.25],12)],inf),Pseq([0.0,Pseq([1.0],3),1.0,Pseries(0,1/12,12)],inf)],
[Pseq([0.5,Pseq([1.0],5),0.5,Pseq([0.25],12)],inf),Pseq([0.0,Pseq([1.0],3),1.0,Pseries(0,1/12,12)],inf)]
],
[
[Pseq([1.0,0.25,0.75,0.25,0.75],inf),Pseq([1.0,1.0,1.0,0.0],inf)],
[Pseq([0.5,Pseq(0.25,0.25,8)],inf),Pseq([1.0,0.0,Prand([1.0,0.0],1),1.0],inf)],
[Prand([Pseq([0.5,0.25,0.25],1),Pseq([0.5,0.25,0.25],1)],inf),Pseq([1.0,0.0,Prand([1.0,0.0],1),1.0],inf)]
]
];
/////////
Synth.play({
var circulation;
//circulartempo
SetTempo.kr(thisSynth,SinOsc.kr(0.01,0,0.01,2));
circulation= Mix.arFill(numranges,
{
arg i;
Spawn.ar(
{
arg sp;
var dur,silence;
//1 to 60 beats
dur= 1+(59.rand);
sp.nextTime= dur;
silence=if(0.3.coin,0,1);
if(0.3.coin,
{silence*(createfiltcirc.value(dur,i))},
{silence*(createpitchcirc.value(dur,i))})
},2,30,nil
)
}
);
z=
Spawn.ar(
{
arg sp;
var dur,dursec,env;
var percindex,drumpattindex;
//80 to 200 beats
dur= 4*rrand(20,50);
sp.nextTime=dur;
//always take low estimate of dur in seconds
dursec= (dur-16)/2.01;
env= Env.new([1,1,0],[dursec,0.01]);
//choose without replacement would be better yet
percindex=Array.fill(4,{percarray.choose});
//so always reset take copies
drumpattindex=Array.fill(4,{arg i; drumpattern.at(i).choose});
EnvGen.ar(
env,
Mix.arFill(
4,
{
arg i;
var ampmul;
ampmul= 0.15+(0.1.rand);
Pan2.ar(
Pbind(
\dur,drumpattindex.at(i).at(0),
\amp,drumpattindex.at(i).at(1),
\ampmult,ampmul, //0.25,
\ugenFunc,{arg amp,ampmult;
amp*ampmult*EnvGen.ar
(
Env.new([1,1,0],[0.4,0.1]),
percindex.at(i).value
)
}
).asSpawn(channels:1)
,
0.2.rand2
)
}
)
)
},
2,
1,
nil
);
Limiter.ar(
1.0* //HERE IS MASTER VOLUME!
(z+
//circulation pulsing
(SinOsc.ar(GetTempo.kr,0,0.4*circulation))+
Decay.ar(Impulse.ar(2*GetTempo.kr),0.4,circulation)
//panning reverb
+Pan2.ar((0.3*Reverb.grlargeroom(circulation)),SinOsc.kr((GetTempo.kr)/16,0,1.0))
)
,0.99,0.01)
});
)