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
|
// Adapted from https://sccode.org/1-522, which is adapted in
// turn from STK's 'rhodey', which is adapted from a TX81z
// algorithm.
Engine_Rhodes : CroneEngine {
var <notes;
*new { arg context, doneCallback;
^super.new(context, doneCallback);
}
*initClass {
// TODO store it as a classvar?
StartUp.add({
SynthDef("Rhodes",
{
| // standard meanings
out = 0, freq = 440, gate = 1, pan = 0, amp = 0.1,
// all of these range from 0 to 1
vel = 0.8, modIndex = 0.1, mix = 0.2,
lfoSpeed = 0.2, lfoDepth = 0.1
|
var env1, env2, env3, env4;
var osc1, osc2, osc3, osc4, snd;
lfoSpeed = lfoSpeed * 12;
freq = freq * 2;
env1 = EnvGen.ar(Env.adsr(0.001, 1.25, 0.0, 0.04, curve: \lin));
env2 = EnvGen.ar(Env.adsr(0.001, 1.00, 0.0, 0.04, curve: \lin));
env3 = EnvGen.ar(Env.adsr(0.001, 1.50, 0.0, 0.04, curve: \lin));
env4 = EnvGen.ar(Env.adsr(0.001, 1.50, 0.0, 0.04, curve: \lin));
osc4 = SinOsc.ar(freq * 0.5) * 2pi * 2 * 0.535887 * modIndex * env4 * vel;
osc3 = SinOsc.ar(freq, osc4) * env3 * vel;
osc2 = SinOsc.ar(freq * 15) * 2pi * 0.108819 * env2 * vel;
osc1 = SinOsc.ar(freq, osc2) * env1 * vel;
snd = Mix((osc3 * (1 - mix)) + (osc1 * mix));
snd = snd * (SinOsc.ar(lfoSpeed) * lfoDepth + 1);
snd = snd * EnvGen.ar(Env.asr(0, 1, 0.2));
snd = Pan2.ar(snd, pan, amp);
DetectSilence.ar(snd, doneAction: Done.freeSelf);
Out.ar(out, snd);
}).add;
});
}
alloc {
notes = nil!128;
this.addCommand("note_on", "ii", {
arg msg;
var note = msg[1];
var vel = msg[2];
if(notes[note].isNil) {
notes[note] = Synth("Rhodes",
[
\out, context.out_b,
\freq, note.midicps,
\vel, vel/127.0
],
target: context.xg);
}
});
this.addCommand("note_off", "f", {
arg msg;
var note = msg[1];
if(notes[note].notNil) {
notes[note].release;
notes[note] = nil;
}
});
}
free {
}
}
|