View difference between Paste ID: ppcjhJ8G and vbCf8H3F
SHOW: | | - or go back to the newest paste.
1-
Sure! I'll message you it in a sec, I am making cup noodle atm :P
1+
2-
2+
3-
EDIT: I can't message u :(
3+
4-
4+
5-
Lol it's ok, I think I can paste it here, here you go :)
5+
6-
6+
7
    s.waitForBoot {
8
    
9
        var win, rootDropdown, scaleDropdown, notes, scaleNames, minOct, maxOct, synthTypeDropdown, relKnob, relKnobValue, atkKnob, atkKnobValue, highNoteKnob, highVolKnobValue, lowNoteKnob, lowVolKnobValue, highPanKnob, highPanValue, lowPanKnob, lowPanValue, scaleSnappingButton, recordButton;
10
    
11
    var font, fontbold, fontboldlarge, maincolor, titlecolor, pink;
12
    
13
        // Initial Settings
14
        ~rootNote = 0;  // C
15
        ~scale = Scale.major;
16
        ~minOctave = 4;
17
        ~maxOctave = 6;
18
    ~lowNoteVol = 0.05;
19
        ~highNoteVol = 0.05;
20
    ~attack = 0.0;
21
        ~release = 3.0;
22
    ~lowNotePan = 0;
23
        ~highNotePan = 0;
24
    ~isScaleSnappingEnabled = true;
25
    
26
        // Scale Snapping and Octave Clamping
27
    ~snapToScale = { |midiNote|
28
            if (~isScaleSnappingEnabled, {
29
                var baseNote, snapped, octave, minNote, maxNote;
30
    
31
                // Snap to scale
32
                octave = midiNote.div(12);
33
                baseNote = midiNote % 12;
34
                snapped = ~scale.degrees.collect { |deg| (octave * 12 + deg + (~rootNote % 12)) };
35
                snapped = snapped ++ snapped.collect { |n| n + 12 }; // add octave above
36
    
37
                snapped = snapped.sort({ |a, b| (a - midiNote).abs < (b - midiNote).abs }).first;
38
    
39
                minNote = ~minOctave * 12;
40
                maxNote = (~maxOctave + 1) * 12 - 1;
41
    
42
                while { snapped < minNote } {
43
                    snapped = snapped + 12;
44
                };
45
                while { snapped > maxNote } {
46
                    snapped = snapped - 12;
47
                };
48
    
49
                snapped;
50
            }, {
51
                midiNote;
52
            });
53
           };
54
    
55
    ~volumeForNote = { |note|
56
    var minNote = ~minOctave * 12;
57
    var maxNote = ((~maxOctave + 1) * 12) - 1;
58
    
59
    var normalized = (note - minNote) / (maxNote - minNote);
60
    normalized = normalized.clip(0, 1);
61
    
62
    ~lowNoteVol + (normalized * (~highNoteVol - ~lowNoteVol));
63
    };
64
    
65
    ~panForNote = { |note|
66
    var minNote = ~minOctave * 12;
67
    var maxNote = ((~maxOctave + 1) * 12) - 1;
68
    
69
    var normalized = (note - minNote) / (maxNote - minNote);
70
    normalized = normalized.clip(0, 1);
71
    
72
    ~lowNotePan + (normalized * (~highNotePan - ~lowNotePan));
73
    };
74
    
75
        // Recording
76
        ~recordingPath = nil;
77
    ~isRecording = false;
78
    
79
        // Output folder on Desktop
80
        ~recordingFolder = Platform.userHomeDir +/+ "Desktop/Supercollider/Recs";
81
        File.mkdir(~recordingFolder);
82
    
83
    ~makeTimestampedPath = {
84
    var timestamp = Date.localtime.stamp;
85
    ~recordingFolder +/+ ("recording_" ++ timestamp ++ ".wav");
86
    };
87
    
88
    ~stopRecording = {
89
    if (~isRecording) {
90
    "Stopping recording".postln;
91
    s.stopRecording;
92
    };
93
    };
94
    
95
    // Synth
96
    
97
    SynthDef(\simpleSynth, {
98
    |freq=440, amp=0.2, dur=1, atk=0.01, rel=0.3, out=0, waveType=0, pan=0|
99
    var env = EnvGen.kr(Env.perc(atk, rel), doneAction: 2);
100
    var sig;
101
    
102
    sig = Select.ar(waveType, [
103
    SinOsc.ar(freq),
104
    Saw.ar(freq),
105
    Pulse.ar(freq),
106
    LFTri.ar(freq),
107
    WhiteNoise.ar,
108
    PinkNoise.ar
109
    ]) * amp * env;
110
    
111
    Out.ar(out, Pan2.ar(sig, pan));
112
    }).add;
113
    
114
        s.sync;
115
    
116
        // MIDI source debugging
117
        MIDIClient.sources.do({ |src, i|
118
            ("[" ++ i ++ "] " ++ src.device).postln;
119
        });
120
    
121
        // MIDI Note Handler
122
        MIDIdef.noteOn(\fromIanniX, { |vel, note, chan, src|
123
            var snapped = ~snapToScale.(note);
124
    var amp = ~volumeForNote.(snapped);
125
        var pan = ~panForNote.(snapped);
126
    
127
    if (~isScaleSnappingEnabled){
128
    ("MIDI Note: " ++ note ++ " → Snapped: " ++ snapped ++ " | Amp: " ++ amp ++ " | Pan: " ++ pan).postln;
129
    } {
130
    ("MIDI Note: " ++ note ++ " | Amp: " ++ amp ++ " | Pan: " ++ pan).postln;
131
    };
132
    
133
    Synth(\simpleSynth, [
134
    \freq, snapped.midicps,
135
    \amp, amp,
136
    \atk, ~attack,
137
    \rel, ~release,
138
    \out, 0,
139
    \waveType, ~currentWaveType,
140
    \pan, pan
141
    ]);
142
    
143
        });
144
    
145
    // GUI (Gooeyyyy)
146
    win = Window("Control Suite", Rect(100, 100, 380, 720), false);
147
    win.background = Color.white;
148
    win.alwaysOnTop = true;
149
    
150
    font = Font("Courier New", 12);
151
        fontbold = Font("Courier New", 12, true);
152
    fontboldlarge = Font("Courier New", 20, true);
153
    maincolor = Color(0.4, 0.404, 0.569);
154
    titlecolor = Color(0.749, 0.392, 0.471);
155
    pink = Color(0.941, 0.631, 0.694);
156
    
157
    y = 10;
158
    
159
    // Wavetype Section
160
    StaticText(win, Rect(10, y, 360, 20))
161
    .string_("Wave Type")
162
    .background_(Color(0.922, 0.682, 0.733))
163
    .stringColor_(Color.white)
164
    .align_(\center)
165
    .font_(fontbold);
166
    
167
    y = y + 25;
168
    
169
    StaticText(win, Rect(10, y, 100, 20))
170
    .string_("Synth Type:")
171
    .background_(Color.clear)
172
    .stringColor_(maincolor)
173
        .font_(font);
174
    
175
    synthTypeDropdown = PopUpMenu(win, Rect(110, y, 150, 20));
176
    synthTypeDropdown.items = ["Sine", "Saw", "Square", "Triangle", "White Noise", "Pink Noise"];
177
    synthTypeDropdown.font = font;
178
    synthTypeDropdown.value = 0;
179
    synthTypeDropdown.action = {
180
    ~currentWaveType = synthTypeDropdown.value;
181
    };
182
    
183
    y = y + 40;
184
    
185
    // Scale Section
186
    StaticText(win, Rect(10, y, 360, 20))
187
    .string_("Scale")
188
    .background_(Color(0.682, 0.808, 0.922))
189
    .stringColor_(Color.white)
190
    .align_(\center)
191
    .font_(fontbold);
192
    
193
        // Scale Snap Toggle
194
    scaleSnappingButton = Button(win, Rect(320, y, 50, 20));
195
    scaleSnappingButton.states = [["Off", maincolor, Color.white], ["On", Color.white, Color(0.682, 0.808, 0.922)]];
196
    scaleSnappingButton.value = ~isScaleSnappingEnabled.binaryValue;
197
    scaleSnappingButton.font = fontbold;
198
    scaleSnappingButton.action = {
199
    ~isScaleSnappingEnabled = ~isScaleSnappingEnabled.not;
200
    scaleSnappingButton.value = ~isScaleSnappingEnabled.binaryValue;
201
    };
202
    
203
    y = y + 25;
204
    
205
    StaticText(win, Rect(10, y, 100, 20))
206
    .string_("Root Note:")
207
    .background_(Color.clear)
208
    .stringColor_(maincolor)
209
    .font_(font);
210
    
211
    rootDropdown = PopUpMenu(win, Rect(110, y, 150, 20));
212
    rootDropdown.items = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
213
    rootDropdown.value = 0;
214
    rootDropdown.font = font;
215
    rootDropdown.action = { ~rootNote = rootDropdown.value; };
216
    
217
    y = y + 30;
218
    
219
    StaticText(win, Rect(10, y, 100, 20))
220
    .string_("Scale:")
221
    .background_(Color.clear)
222
    .stringColor_(maincolor)
223
    .font_(font);
224
    
225
    scaleDropdown = PopUpMenu(win, Rect(110, y, 150, 20));
226
    scaleDropdown.items = Scale.names.asArray;
227
    scaleDropdown.value = scaleDropdown.items.indexOf("major");
228
    scaleDropdown.action = {
229
    ~scale = Scale.at(scaleDropdown.items[scaleDropdown.value]);
230
    };
231
    scaleDropdown.font = font;
232
    
233
    y = y + 40;
234
    
235
    // Octave Clamp Section
236
    StaticText(win, Rect(10, y, 360, 20))
237
    .string_("Octave Clamp")
238
    .background_(Color(0.69, 0.682, 0.922))
239
    .stringColor_(Color.white)
240
    .align_(\center)
241
    .font_(fontbold);
242
    
243
    y = y + 25;
244
    
245
    StaticText(win, Rect(10, y, 100, 20))
246
    .string_("Min Octave:")
247
    .background_(Color.clear)
248
    .stringColor_(maincolor)
249
    .font_(font);
250
    minOct = NumberBox(win, Rect(110, y, 50, 20))
251
    .value_(~minOctave)
252
    .font_(font)
253
    .action_({ |nb|
254
    ~minOctave = nb.value.round.clip(0, 9);
255
    if (~minOctave > ~maxOctave) {
256
    ~minOctave = ~maxOctave; nb.value = ~minOctave;
257
    };
258
    });
259
    
260
    StaticText(win, Rect(180, y, 100, 20))
261
    .string_("Max Octave:")
262
    .background_(Color.clear)
263
    .stringColor_(maincolor)
264
    .font_(font);
265
    maxOct = NumberBox(win, Rect(280, y, 50, 20))
266
    .value_(~maxOctave)
267
    .font_(font)
268
    .action_({ |nb|
269
    ~maxOctave = nb.value.round.clip(0, 9);
270
    if (~maxOctave < ~minOctave) {
271
    ~maxOctave = ~minOctave; nb.value = ~maxOctave;
272
    };
273
    });
274
    
275
    y = y + 40;
276
    
277
    // Linear Volume Control Section
278
    StaticText(win, Rect(10, y, 360, 20))
279
    .string_("Linear Volume Control")
280
    .background_(Color(0.631, 0.89, 0.812))
281
    .stringColor_(Color.white)
282
    .align_(\center)
283
    .font_(fontbold);
284
    
285
    y = y + 25;
286
    
287
    // Low Note Volume
288
    StaticText(win, Rect(40, y, 120, 20))
289
    .string_("Lowest Note Vol:")
290
    .font_(font)
291
    .background_(Color.clear)
292
    .stringColor_(maincolor);
293
    lowNoteKnob = Knob(win, Rect(80, y + 20, 40, 40))
294
    .value_(0.25)
295
    .font_(font)
296
    .action_({ |knob|
297
    ~lowNoteVol = knob.value * 0.2;
298
        lowVolKnobValue.value = ~lowNoteVol;
299
    });
300
    lowVolKnobValue = NumberBox(win, Rect(75, y + 65, 50, 20))
301
    .value_(~lowNoteVol)
302
    .enabled_(false)
303
    .font_(font);
304
    
305
    // High Note Volume
306
    StaticText(win, Rect(200, y, 140, 20))
307
    .string_("Highest Note Vol:")
308
    .background_(Color.clear)
309
    .font_(font)
310
    .stringColor_(maincolor);
311
    highNoteKnob = Knob(win, Rect(240, y + 20, 40, 40))
312
    .value_(0.25)
313
    .font_(font)
314
    .action_({ |knob|
315
    ~highNoteVol = knob.value * 0.2;
316
    highVolKnobValue.value = ~highNoteVol;
317
    });
318
    highVolKnobValue = NumberBox(win, Rect(235, y + 65, 50, 20))
319
    .value_(~highNoteVol)
320
    .font_(font)
321
    .enabled_(false);
322
    
323
    y = y + 100;
324
    
325
    // Envelope Section
326
    StaticText(win, Rect(10, y, 360, 20))
327
    .string_("Envelope")
328
    .background_(Color(0.949, 0.831, 0.596))
329
    .stringColor_(Color.white)
330
    .align_(\center)
331
    .font_(fontbold);
332
    
333
    y = y + 25;
334
    
335
    // Attack
336
    StaticText(win, Rect(75, y, 100, 20))
337
    .string_("Attack:")
338
    .font_(font)
339
    .background_(Color.clear)
340
    .stringColor_(maincolor);
341
    atkKnob = Knob(win, Rect(80, y + 20, 40, 40))
342
    .value_(~attack)
343
    .font_(font)
344
    .action_({ |knob|
345
    ~attack = knob.value.clip(0,1);
346
    atkKnobValue.value = ~attack;
347
    });
348
    atkKnobValue = NumberBox(win, Rect(75, y + 65, 50, 20))
349
    .value_(~attack)
350
    .font_(font)
351
    .enabled_(false);
352
    
353
    // Release
354
    StaticText(win, Rect(230, y, 100, 20))
355
    .string_("Release:")
356
    .font_(font)
357
    .background_(Color.clear)
358
    .stringColor_(maincolor);
359
    relKnob = Knob(win, Rect(240, y + 20, 40, 40))
360
    .value_(0.6)
361
    .font_(font)
362
    .action_({ |knob|
363
    ~release = knob.value * 5;
364
    relKnobValue.value = ~release;
365
    });
366
    relKnobValue = NumberBox(win, Rect(235, y + 65, 50, 20))
367
    .value_(~release)
368
    .font_(font)
369
    .enabled_(false);
370
    
371
       y = y + 108;
372
    
373
        // Pan Control Section
374
        StaticText(win, Rect(10, y, 360, 20))
375
    .string_("Linear Panning Control")
376
    .background_(Color(0.643, 0.706, 0.871))
377
    .stringColor_(Color.white)
378
    .align_(\center)
379
    .font_(fontbold);
380
    
381
         y = y + 25;
382
    
383
        // Low Note Pan
384
         StaticText(win, Rect(40, y, 120, 20))
385
    .string_("Lowest Note Pan:")
386
    .font_(font)
387
    .background_(Color.clear)
388
    .stringColor_(maincolor);
389
         lowPanKnob = Knob(win, Rect(80, y + 20, 40, 40))
390
    .value_(0.5)
391
    .action_({ |knob|
392
    ~lowNotePan = (knob.value * 2) - 1;
393
    lowPanValue.value = ~lowNotePan;
394
    });
395
         lowPanValue = NumberBox(win, Rect(75, y + 65, 50, 20))
396
    .value_(~lowNotePan)
397
    .enabled_(false)
398
    .font_(font);
399
    
400
        // High Note Pan
401
        StaticText(win, Rect(200, y, 140, 20))
402
    .string_("Highest Note Pan:")
403
    .background_(Color.clear)
404
    .font_(font)
405
    .stringColor_(maincolor);
406
         highPanKnob = Knob(win, Rect(240, y + 20, 40, 40))
407
    .value_(0.5)
408
    .action_({ |knob|
409
    ~highNotePan = (knob.value * 2) - 1;
410
    highPanValue.value = ~highNotePan;
411
    });
412
        highPanValue = NumberBox(win, Rect(235, y + 65, 50, 20))
413
    .value_(~highNotePan)
414
    .font_(font)
415
    .enabled_(false);
416
    
417
    y = y + 108;
418
    
419
    // Recording Button Section
420
    StaticText(win, Rect(10, y, 360, 30))
421
    .string_("Recording Control")
422
    .background_(Color.clear)
423
    .stringColor_(titlecolor)
424
    .align_(\top, \center)
425
    .font_(fontboldlarge);
426
    
427
    y = y + 28;
428
    
429
    recordButton = Button(win, Rect(140, y, 100, 40));
430
    recordButton.states = [["REC", maincolor, Color.white], ["STOP", Color.white, pink]];
431
    recordButton.font = fontbold;
432
    recordButton.action = {
433
            if (~isRecording.not) {
434
                ~recordingPath = ~makeTimestampedPath.();
435
                ("Starting recording to: " ++ ~recordingPath).postln;
436
    
437
                s.record(
438
                    path: ~recordingPath,
439
                    headerFormat: "wav",
440
                    sampleFormat: "int16"
441
                );
442
    
443
    ~isRecording = true;
444
            } {
445
    ~stopRecording.();
446
    ~isRecording = false;
447
    };
448
    };
449
    
450
    //Knob Colors
451
        lowNoteKnob.color = [Color.white, Color(0.639, 0.651, 0.89), Color.white, Color(0.639, 0.651, 0.89)];
452
        highNoteKnob.color = [Color.white, Color(0.639, 0.773, 0.89), Color.white, Color(0.639, 0.773, 0.89)];
453
    atkKnob.color = [Color.white, Color(0.89, 0.643, 0.678), Color.white, Color(0.89, 0.643, 0.678)];
454
    relKnob.color = [Color.white, Color(0.639, 0.89, 0.824), Color.white, Color(0.639, 0.89, 0.824)];
455
    lowPanKnob.color = [Color.white, Color(0.643, 0.706, 0.871), Color(0.714, 0.643, 0.871), Color(0.643, 0.706, 0.871)];
456
    highPanKnob.color = [Color.white, Color(0.714, 0.643, 0.871), Color(0.643, 0.706, 0.871), Color(0.643, 0.706, 0.871)];
457
    
458
    win.front;
459
    
460
        "Setup complete, GUI should appear".postln;
461
    };