Advertisement
Guest User

Gooey :P

a guest
May 3rd, 2025
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.     MIDIClient.init;
  2.     MIDIIn.connectAll;
  3.    
  4.     // BECAUSE YOU KEEP COMPLAINING WHEN I UNPLUG MY HEADPHONES
  5.     Server.default.options.numInputBusChannels = 0;
  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.     };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement