1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
//TODO: use GrainFM or GrainSin?
(
s.waitForBoot{
s.makeWindow;
s.record;
OSCFunc.trace(true);
OSCFunc.trace(false);
//Dictionary for storing timing and related synths
~tasks = Dictionary.new();
//maximum allowed nodes on Server
~maximumSynths = 300;
~upperFrequency = 16000;
~lowerFrequency = 20;
~channels = 8; //define channels for panning (2,4,8 allowed)
~allowOSC = true;
~test = 0;
// Filter SynthDef for post-processing
// TODO: use filter only for some Synths (long ones)
~filter = SynthDef(\filter, {|in, mix = 0.68, room = 0.54, damp = 0.15, volume = 0.5|
in = In.ar(0, 2);
ReplaceOut.ar(0,
FreeVerb.ar(
in,
mix,
room,
damp
) * volume
);
}).play;
// OSCFunc for putting a task to the Dictionary and playing it
OSCFunc({
|msg, time, address, receivingPort|
var task;
var synth;
var release = msg[1].asFloat; //length (in seconds) between this spot and the one before
var freqIn = msg[3].asFloat; //X-values (frequency)
var ampIn = msg[2].asFloat; //Y-values (amplitude)
if(~allowOSC, {
// ("msg: "++msg++" at port "++receivingPort++" from address "++address).postln;
//randomized SynthDef to be played
synth = SynthDef(time.asSymbol, {|out=0, attackTime=0.01|
var freq = freqIn.linexp(0.0, 1.0, ~lowerFrequency, ~upperFrequency);
var amplitude = ampIn;
var releaseTime = release;
var env = EnvGen.kr(//envelope to automatically release the Synth
Env.perc(attackTime, releaseTime, amplitude, -4), doneAction:2
);
var position = LinLin.kr([freqIn, ampIn].median, 0.0, 1.0, -1.0, 1.0);
// ("freq: "++freq++", amplitude: "++amplitude++", position: "++position).postln;
Out.ar(
out,
switch(~channels,
2, {
Pan2.ar(// pan using median of freq and amplitude
Saw.ar(
freq, env, SinOsc.ar(//TODO: lower volume for bbb
freq, 0, env*0.9
);
), position
);
},
4,{
Pan4.ar(
Saw.ar(
freq, env, SinOsc.ar(//TODO: lower volume for bbb
freq, 0, env*0.9
);
),
freqIn.linlin(0.0, 1.0, -1.0, 1.0),
ampIn.linlin(0.0, 1.0, -1.0, 1.0),
0.1
);
},
8,{
PanAz.ar(
8,//numChannels
Saw.ar(
freq, env, SinOsc.ar(//TODO: lower volume for bbb
freq, 0, env*0.9
);
),// in
freqIn.linlin(0.0, 1.0, 0.0, 2.0),// position
0.1,// level
release,//width
0.5 //orientation
);
}
);
//Pan4 for 4chan with x/y and PanAz
);
}).add;
// Task for each SynthDef
task = Task.new({
{
//play the synth and loop in its own length
synth.play;
msg[1].wait;
}.loop;
});
NotificationCenter.notify(task, \stopped);
NotificationCenter.register(task, \stopped, ~test, {
("Task has stopped").postln;
});
// Put to Task Dictionary and play task (in a loop)
~tasks.add(time.asSymbol -> task);
~tasks.at(time.asSymbol).play;
//if the maximum number of synths is reached, remove the oldest
if(s.numSynths > ~maximumSynths,{
// //get all Tasks ordered, remove the oldest
// ~tasks.atAll(~tasks.order).do({
// arg item, i;
// if(i < (~tasks.size.asInt - ~maximumSynths.asInt),{
// item.stop;
// });
// });
// disable OSC handling for now
~allowOSC = false;
~tasks.atAll(~tasks.order).do({
arg item, i;
item.stop;
});
s.stopRecording;
});
// ("Number of synths playing: "++s.numSynths.asString).postln;
});
}, '/random');
// OSCFunc for analog inputs to set
// maximum numbers of synths, FreeVerb setttings
OSCFunc({
|msg, time, address, receivingPort|
("msg: "++msg++" at port "++receivingPort++" from address "++address).postln;
switch(msg[1].asSymbol,
\P9_39, ~filter.set(\mix, msg[2]),
\P9_40, ~filter.set(\room, msg[2]),
\P9_41, ~filter.set(\damp, msg[2]),
\P9_42, ~filter.set(\volume, msg[2]),
);
}, '/analog');
};
)
|