aboutsummaryrefslogtreecommitdiff
path: root/lib/Engine_Rhodes.sc
blob: 02da1af16a194f2a5d0f7a71b0fed49454e31ac2 (plain)
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.2, mix = 0.2,
               lfoSpeed = 0.4, 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 {
    }
}