Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //////////////////////////////////////////////
- // //
- // KippleGEN or, The Empathy Box //
- // 2024 //
- // Daniel L. Lythgoe //
- // //
- //////////////////////////////////////////////
- // This is a script for an (ambient) wavetable synth and sequencer with GUI.
- // Place the desired sound files in a subfolder called "/Samples/", relative to the folder the Supercollider document is located in.
- // This works best with very short sound files; longer ones can sometimes break the interpreter.
- // You can create your own .wav files, but a library of single cycle wave forms that can be used with the synth can be downloaded here:
- // https://www.adventurekid.se/akrt/waveforms/adventure-kid-waveforms/
- // I recommend the OVERTONE pack to start
- // Special thanks for Reflectives on Youtube and his excellent video "Wave Terrainish adventures with VOsc"
- // Boot the server
- s.boot;
- // Directory for recordings
- Platform.recordingsDir;
- (
- // Run once to convert and resample wavetable files. This may take a few seconds. Refer to the Post Window for confirmation of completion.
- // After "Conversion successfully completed", the active buffers and their corresponding symbols will be posted.
- var paths, file, data, n, newData, outFile, bufLenChecker, shortestBuf, dataList;
- dataList = List.new;
- paths = (thisProcess.nowExecutingPath.dirname +/+ "/Samples/*.wav").pathMatch; // <---- search relative path for all .wav files, excluding other file types
- // paths = "MYPATH/Samples/*.wav".pathMatch; // <-- if the relative path doesn't work, replace the MYPATH string in this line to hard code the search path
- //////////////////////////////////////
- // //
- // Reading and Resampling //
- // //
- //////////////////////////////////////
- Routine({
- Routine({
- // Step 1: Check for the shortest provided sample.
- paths.do { |it, i|
- file = SoundFile.openRead(paths[i]);
- data = Signal.newClear(file.numFrames);
- dataList.add(data.size);
- shortestBuf = dataList.minItem({|item, i| item});
- // shortestBuf.postln; //<--- Troubleshooting
- };
- // Step 2: Set wavetable frame size "n". By default set to 4096.
- // Since VOsc requires the length of the wavetable to be a power of 2, "shortestBuf" is always converted to the next power of two greater than or equal to the receiver.
- 1.do {
- n = 4096;
- // n.postln; //<--- Troubleshooting
- // if (shortestBuf < 4096) {n = shortestBuf.nextPowerOfTwo};
- if (shortestBuf > 4096) {n = shortestBuf.nextPowerOfTwo};
- if (shortestBuf > 8192) {n = 8192};
- ("Wavetable Frame Size is " ++ n ++ ".").postln;
- };
- // Step 3: Convert the samples to wavetables
- paths.do { |it, i|
- // 'protect' guarantees the file objects will be closed in case of error
- protect {
- // Read original size of data
- file = SoundFile.openRead(paths[i]);
- data = Signal.newClear(file.numFrames);
- file.readData(data);
- 0.1.wait;
- // Here we use the new frame size "n" that we calculated in Step 2 to resample the .wav files to the desired equal length
- newData = data.resamp1(n);
- 0.1.wait;
- // Convert the resampled signal into a Wavetable.
- // resamp1 outputs an Array, so we have to reconvert to Signal
- newData = newData.as(Signal).asWavetable;
- 0.1.wait;
- // save to disk.
- outFile = SoundFile(paths[i] ++ "_4096.wtable")
- .headerFormat_("WAV")
- .sampleFormat_("float")
- .numChannels_(1)
- .sampleRate_(44100);
- if(outFile.openWrite.notNil) {
- outFile.writeData(newData);
- 0.1.wait;
- } {
- "Couldn't write output file".warn;
- };
- } {
- file.close;
- if(outFile.notNil) { outFile.close };
- };
- };
- "Conversion successfully completed.".postln;
- // 0.1.wait;
- }).play;
- // Wait for the previous routine to finish
- (paths.size * 0.41 + 0.1).wait;
- "...".postln;
- 0.1.wait;
- //////////////////////////////////////////////////////
- // //
- // Loading the Wavetables to Buffer Memory //
- // //
- //////////////////////////////////////////////////////
- Routine({
- var wtsize, wtpaths, wtbuffers;
- "-----------wavetables begin-----------".postln;
- wtsize = n;
- // Read back all the wavetables we created above
- wtpaths = (thisProcess.nowExecutingPath.dirname +/+ "/Samples/*.wtable").pathMatch;
- // Allocate double the wavetable frame size to the buffer to be safe
- wtbuffers = Buffer.allocConsecutive(wtpaths.size, s, wtsize * 2, 1, );
- // Here we add each wavetable to the Buffers we created above.
- // We assign each buffer a name as a Symbol for easy access later on. This name is equivalent to the file name of the sample.
- // The buffer number and name are added to a global variable called "~bufferReference" for easy reference. This is however not needed for the synth in this file.
- wtpaths.do { |it, i|
- wtbuffers[i].read(wtpaths[i])};
- ~wtbufnums = List[];
- ~wavetables = ();
- ~bufferReference = List.new;
- wtpaths.do { |it i|
- var name, buffer;
- name = wtbuffers[i].path.basename.findRegexp(".*\.wav")[0][1].splitext[0];
- buffer = wtbuffers[i].bufnum;
- ~wavetables[name.asSymbol] = buffer;
- ~wtbufnums.add(buffer);
- buffer.postln;
- name.postln;
- ~bufferReference.add((buffer + "=" + name).asString);
- };
- // ~bufferReference.postln;
- "-----------wavetables end-----------".postln;
- };).play;
- };).play;
- )
- // For reference
- ~wtbufnums; //<------------ Returns an array of the loaded buffer channels
- ~bufferReference; //<------ Returns an array of the loaded buffers and their respective names, i.e. Symbols
- //////////////////////////////////////////////////////
- // //
- // Deckard's Synthdef //
- // //
- //////////////////////////////////////////////////////
- (
- var voices;
- // Specify the number of chorusing oscillators
- voices = 8;
- //Specify the number of channels
- ~numChans = 2;
- SynthDef.new(\vosc1, {|out=0, buf=0, numBufs=2, freq=200, amp=0.2, bufRate=0.01, bitRate = 44100.0, bitDepth = 24.0,atk=12,sus=6,rel=20, timeScale=1.0, detuneAmt=0.2,shaperWet=0.0, decimWet = 1.0, hpf=10,lpf=20000|
- var sig, bufpos, detuneSig, env, envG, shaperDry, decimDry;
- shaperWet = shaperWet.fold2(0.8).squared.sqrt;
- shaperDry = 1-shaperWet;
- decimDry = 1-decimWet;
- env = Env([0,0.5,1,1,0.5,0],[atk/2,atk/2,sus,rel/2,rel/2], curve: [5,-5,0,4,-3]);
- env.asArray.size.postln;
- env = EnvGen.kr(env,timeScale:timeScale, doneAction:2);
- detuneSig = LFNoise1.kr(0.2!voices).bipolar(detuneAmt).midiratio;
- bufpos = buf + LFNoise1.kr(bufRate).range(0, numBufs-1);
- sig = VOsc.ar(bufpos, freq*detuneSig);
- sig = (Decimator.ar(sig, Lag.kr(bitRate,5.0), Lag.kr(bitDepth,5.0))*decimWet) + (sig*decimDry);
- sig = (Shaper.ar(~wtbufnums[rrand(~wtbufnums.size-1,~wtbufnums[0])],sig)*shaperWet) + (sig*shaperDry);
- sig = HPF.ar(sig, Lag2.kr(hpf,8.0));
- sig = LPF.ar(sig, Lag2.kr(lpf,8.0));
- sig = SplayAz.ar(~numChans, sig);
- sig = LeakDC.ar(sig) * env * amp;
- Out.ar(out, sig);
- }).add
- )
- //////////////////////////////////////////////////////
- // //
- // Sequencer //
- // //
- //////////////////////////////////////////////////////
- (
- var sequencer, dictRoutine;
- ~voices = [1,1,1,1];
- ~degrees = [0,7,9,10];
- ~atk = 12;
- ~sus = 6;
- ~rel = 20;
- ~timeScale=1.0;
- ~dDict = Dictionary.newFrom([ \buf, ~wtbufnums[0],
- \numBufs, ~wtbufnums.size-1,
- \bufRate, 0.02,
- \degree1, 0,
- \degree2, 7,
- \degree3, 9,
- \degree4, 10,
- \freq, rrand(24,72).nearestInScale(~degrees, 12).postln.midicps,
- \amp, 0.2,
- \atk, 12,
- \sus, 6,
- \rel, 20,
- \timeScale, 1.0,
- \detuneAmt, 0.17,
- \decimWet, 1.0,
- \bitRate, 44100,
- \bitDepth, 24,
- \shaperWet, 0.0,
- \hpf, 10,
- \lpf, 20000]);
- ~dDictReset = Routine({1.do{
- ~dDict[\buf] = ~wtbufnums[0];
- ~dDict[\numBufs] = ~wtbufnums.size-1;
- ~dDict[\bufRate] = 0.02;
- ~dDict[\amp] = 0.2;
- ~dDict[\atk] = 12;
- ~dDict[\sus] = 6;
- ~dDict[\rel] = 20;
- ~dDict[\timeScale] = 1.0;
- ~dDict[\detuneAmt] = 0.17;
- ~dDict[\decimWet] = 1.0;
- ~dDict[\bitRate] = 44100;
- ~dDict[\bitDepth] = 24;
- ~dDict[\shaperWet] = 0.0;
- ~dDict[\hpf] = 20;
- ~dDict[\lpf] = 20000;
- }});
- ~sequencer = Routine({
- inf.do{
- ///// VOICE 1 /////
- 1.do{
- if (~voices[0] == 1) {
- |it, i|
- ~v1 = Synth (\vosc1,
- [ \buf, ~dDict[\buf],
- \numBufs, ~dDict[\numBufs],
- \bufRate, ~dDict[\bufRate],
- \freq, rrand(24,72).nearestInScale(~degrees, 12).postln.midicps,
- \amp, ~dDict[\amp],
- \atk, ~dDict[\atk],
- \sus, ~dDict[\sus],
- \rel, ~dDict[\rel],
- \timeScale, ~dDict[\timeScale],
- \detuneAmt, ~dDict[\detuneAmt],
- \decimWet, ~dDict[\decimWet],
- \bitRate, ~dDict[\bitRate],
- \bitDepth, ~dDict[\bitDepth],
- \shaperWet, ~dDict[\shaperWet],
- \hpf, ~dDict[\hpf],
- \lpf, ~dDict[\lpf]]
- );}};
- ///// VOICE 2 /////
- 1.do{
- if (~voices[1] == 1) {
- |it, i|
- ~v2 = Synth (\vosc1,
- [ \buf, ~dDict[\buf],
- \numBufs, ~dDict[\numBufs],
- \bufRate, ~dDict[\bufRate],
- \freq, rrand(24,72).nearestInScale(~degrees, 12).postln.midicps,
- \amp, ~dDict[\amp],
- \atk, ~dDict[\atk],
- \sus, ~dDict[\sus],
- \rel, ~dDict[\rel],
- \timeScale, ~dDict[\timeScale],
- \detuneAmt, ~dDict[\detuneAmt],
- \decimWet, ~dDict[\decimWet],
- \bitRate, ~dDict[\bitRate],
- \bitDepth, ~dDict[\bitDepth],
- \shaperWet, ~dDict[\shaperWet],
- \hpf, ~dDict[\hpf],
- \lpf, ~dDict[\lpf]]
- );}};
- ///// VOICE 3 /////
- 1.do{
- if (~voices[2] == 1) {
- |it, i|
- ~v3 = Synth (\vosc1,
- [ \buf, ~dDict[\buf],
- \numBufs, ~dDict[\numBufs],
- \bufRate, ~dDict[\bufRate],
- \freq, rrand(24,72).nearestInScale(~degrees, 12).postln.midicps,
- \amp, ~dDict[\amp],
- \atk, ~dDict[\atk],
- \sus, ~dDict[\sus],
- \rel, ~dDict[\rel],
- \timeScale, ~dDict[\timeScale],
- \detuneAmt, ~dDict[\detuneAmt],
- \decimWet, ~dDict[\decimWet],
- \bitRate, ~dDict[\bitRate],
- \bitDepth, ~dDict[\bitDepth],
- \shaperWet, ~dDict[\shaperWet],
- \hpf, ~dDict[\hpf],
- \lpf, ~dDict[\lpf]]
- );}};
- ///// VOICE 4 /////
- 1.do{
- if (~voices[3] == 1) {
- |it, i|
- ~v4 = Synth (\vosc1,
- [ \buf, ~dDict[\buf],
- \numBufs, ~dDict[\numBufs],
- \bufRate, ~dDict[\bufRate],
- \freq, rrand(24,72).nearestInScale(~degrees, 12).postln.midicps,
- \amp, ~dDict[\amp],
- \atk, ~dDict[\atk],
- \sus, ~dDict[\sus],
- \rel, ~dDict[\rel],
- \timeScale, ~dDict[\timeScale],
- \detuneAmt, ~dDict[\detuneAmt],
- \decimWet, ~dDict[\decimWet],
- \bitRate, ~dDict[\bitRate],
- \bitDepth, ~dDict[\bitDepth],
- \shaperWet, ~dDict[\shaperWet],
- \hpf, ~dDict[\hpf],
- \lpf, ~dDict[\lpf]]
- );}};
- //4.wait; //<------ For troubleshooting purposes, ignore
- ((~dDict[\atk]+~dDict[\sus]+(~dDict[\rel]/7))*~dDict[\timeScale]).wait;
- }});
- )
- // The following controls for the "~sequencer" Routine are included in the GUI and are only included as text for troubleshooting purposes
- ~sequencer.reset;
- ~sequencer.play;
- ~sequencer.stop;
- //////////////////////////////////////////////////////
- // //
- // GUI //
- // //
- //////////////////////////////////////////////////////
- (
- Routine({
- var displayWindow = {
- var synth, ampSpec, intervalSpec, window, winX=550, winY=450;
- var knobAtk, knobSus, knobRel, knobTimeScale, knobDetune, knobDecim, knobBitRate, knobBitDepth, knobShaper, knobBufRate, knobHPF, knobLPF;
- var column2, column3, column4, row1, row2,row3,row4,row5, row6, row7,row8,row9,row10,row11,row12;
- var vs1,vs2,vs3; //vs -> vertical spacing
- ~voices = [1,1,1,1];
- ~degrees = [0,7,9,10];
- // Resets the dictionary to its default values
- ~dDictReset.reset;
- ~dDictReset.play;
- 0.05.wait;
- vs1 = 28;
- vs2 = 20;
- vs3 = 45;
- row1 = 30;
- row2 = (row1+vs2);
- row3 = (row2+vs3);
- row4 = (row3+vs1);
- row5 = (row4+vs2);
- row6 = (row5+vs3);
- row7 = (row6+vs1);
- row8 = (row7+vs2);
- row9 = (row8+vs3);
- row10 = (row9+vs1);
- row11 = (row10+vs2);
- row12 = (row11+vs3);
- column2 = 320;
- column3 = column2+60;
- column4 = column3+60;
- window = Window("Do Androids Dream of Electric Sheep?", Rect(100,200,winX,winY));
- window.background = Color.fromHexString("#222A2D"); //#A96E6E
- intervalSpec = ControlSpec(0, 12,'lin',1);
- // CONTROLS FOR THE 4 VOICES -> interval, on/off
- 4.do {|i|
- var slider, text, offset, number, onOff;
- i = i + 1;
- offset = 60 * i;
- number = NumberBox(window, Rect(offset,255,50,20));
- number.value = ~degrees[i-1];
- slider = Slider(window, Rect(offset,row2,50,200));
- slider.knobColor = Color.fromHexString("#B0BDE0");
- slider.value = intervalSpec.unmap(~degrees[i-1]);
- slider.action = {|v|
- var val=intervalSpec.map(v.value);
- ~degrees[i-1] = val.asInteger;
- number.value=val };
- text = StaticText(window,Rect(offset,30,50,20));
- text.string = "Interval" ++ i;
- text.stringColor = Color.white;
- text.align = \center;
- onOff = Button(window, Rect(offset, 280,50,21))
- .states_([["", Color.fromHexString("#B0BDE0"), Color.fromHexString("#B0BDE0")], ["", Color.white, Color.white]])
- .action_({|view| if (view.value == 0)
- {~voices[i-1]=1}
- {~voices[i-1]=0}
- });
- };
- // ATTACK
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.1,30,'lin');
- text = StaticText(window,Rect(column2,row1,40,20));
- text.string = "Atk";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column2,row3,41,20));
- knobAtk =Knob.new(window, Rect(column2,row2,40,40));
- knobAtk.value = spec.unmap(~dDict[\atk]);
- number.value= spec.map(knobAtk.value);
- knobAtk.action = {|v|
- var val = ~dDict[\atk];
- val = spec.map(v.value);
- ~dDict[\atk] = val;
- ~v1.set(\atk,val);
- ~v2.set(\atk,val);
- ~v3.set(\atk,val);
- ~v4.set(\atk,val);
- number.value=val;
- }};
- // SUSTAIN
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.1,30,'lin');
- text = StaticText(window,Rect(column2,row4,40,20));
- text.string = "Sus";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column2,row6,41,20));
- knobSus =Knob.new(window, Rect(column2,row5,40,40));
- knobSus.value = spec.unmap(~dDict[\sus]);
- number.value= spec.map(knobSus.value);
- knobSus.action = {|v|
- var val = ~dDict[\sus];
- val = spec.map(v.value);
- ~dDict[\sus] = val;
- ~v1.set(\sus,val);
- ~v2.set(\sus,val);
- ~v3.set(\sus,val);
- ~v4.set(\sus,val);
- number.value=val;
- }};
- // RELEASE
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.1,30,'lin');
- text = StaticText(window,Rect(column2,row7,40,20));
- text.string = "Rel";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column2,row9,41,20));
- knobRel =Knob.new(window, Rect(column2,row8,40,40));
- knobRel.value = spec.unmap(~dDict[\rel]);
- number.value= spec.map(knobRel.value);
- knobRel.action = {|v|
- var val = ~dDict[\rel];
- val = spec.map(v.value);
- ~dDict[\rel] = val;
- ~v1.set(\rel,val);
- ~v2.set(\rel,val);
- ~v3.set(\rel,val);
- ~v4.set(\rel,val);
- number.value=val;
- }};
- // TIMESCALE
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.1,30,'exponential');
- text = StaticText(window,Rect(column2,row10,40,20));
- text.string = "tScale";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column2,row12,41,20));
- knobTimeScale =Knob.new(window, Rect(column2,row11,40,40));
- knobTimeScale.value = spec.unmap(~dDict[\timeScale]);
- number.value= spec.map(knobTimeScale.value);
- knobTimeScale.action = {|v|
- var val = ~dDict[\timeScale];
- val = spec.map(v.value);
- ~dDict[\timeScale] = val;
- ~v1.set(\timeScale,val);
- ~v2.set(\timeScale,val);
- ~v3.set(\timeScale,val);
- ~v4.set(\timeScale,val);
- number.value=val;
- }};
- // DETUNE
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.0,1,'lin');
- text = StaticText(window,Rect(column3,row1,40,20));
- text.string = "Detune";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column3,row3,41,20));
- knobDetune =Knob.new(window, Rect(column3,row2,40,40));
- knobDetune.value = spec.unmap(~dDict[\detuneAmt]);
- number.value= spec.map(knobDetune.value);
- knobDetune.action = {|v|
- var val = ~dDict[\detuneAmt];
- val = spec.map(v.value);
- ~dDict[\detuneAmt] = val;
- ~v1.set(\detuneAmt,val);
- ~v2.set(\detuneAmt,val);
- ~v3.set(\detuneAmt,val);
- ~v4.set(\detuneAmt,val);
- number.value=val;
- }};
- // DECIMATE
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.0,1,'lin');
- text = StaticText(window,Rect(column3,row4,40,20));
- text.string = "dcmWet";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column3,row6,41,20));
- knobDecim =Knob.new(window, Rect(column3,row5,40,40));
- knobDecim.value = spec.unmap(~dDict[\decimWet]);
- number.value= spec.map(knobDecim.value);
- knobDecim.action = {|v|
- var val = ~dDict[\decimWet];
- val = spec.map(v.value);
- ~dDict[\decimWet] = val;
- ~v1.set(\decimWet,val);
- ~v2.set(\decimWet,val);
- ~v3.set(\decimWet,val);
- ~v4.set(\decimWet,val);
- number.value=val;
- }};
- // BITRATE
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.0,44100,'lin');
- text = StaticText(window,Rect(column3,row7,40,20));
- text.string = "Bitrate";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column3,row9,41,20));
- knobBitRate =Knob.new(window, Rect(column3,row8,40,40));
- knobBitRate.value = spec.unmap(~dDict[\bitRate]);
- number.value= spec.map(knobBitRate.value);
- knobBitRate.action = {|v|
- var val = ~dDict[\bitRate];
- val = spec.map(v.value);
- ~dDict[\bitRate] = val;
- ~v1.set(\bitRate,val);
- ~v2.set(\bitRate,val);
- ~v3.set(\bitRate,val);
- ~v4.set(\bitRate,val);
- number.value=val;
- }};
- // BITDEPTH
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.0,24,'lin');
- text = StaticText(window,Rect(column3,row10,40,20));
- text.string = "Bitdepth";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column3,row12,41,20));
- knobBitDepth =Knob.new(window, Rect(column3,row11,40,40));
- knobBitDepth.value = spec.unmap(~dDict[\bitDepth]);
- number.value= spec.map(knobBitDepth.value);
- knobBitDepth.action = {|v|
- var val = ~dDict[\bitDepth];
- val = spec.map(v.value);
- ~dDict[\bitDepth] = val;
- ~v1.set(\bitDepth,val);
- ~v2.set(\bitDepth,val);
- ~v3.set(\bitDepth,val);
- ~v4.set(\bitDepth,val);
- number.value=val;
- }};
- // SHAPER
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.0,1,'lin');
- text = StaticText(window,Rect(column4,row1,40,20));
- text.string = "Shaper";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column4,row3,41,20));
- knobShaper =Knob.new(window, Rect(column4,row2,40,40));
- knobShaper.value = spec.unmap(~dDict[\shaperWet]);
- number.value= spec.map(knobShaper.value);
- knobShaper.action = {|v|
- var val = ~dDict[\shaperWet];
- val = spec.map(v.value);
- ~dDict[\shaperWet] = val;
- ~v1.set(\shaperWet,val);
- ~v2.set(\shaperWet,val);
- ~v3.set(\shaperWet,val);
- ~v4.set(\shaperWet,val);
- number.value=val;
- }};
- // BUFRATE
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(0.0,1,'lin');
- text = StaticText(window,Rect(column4,row4,40,20));
- text.string = "Bufrate";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column4,row6,41,20));
- knobBufRate =Knob.new(window, Rect(column4,row5,40,40));
- knobBufRate.value = spec.unmap(~dDict[\bufRate]);
- number.value= spec.map(knobBufRate.value);
- knobBufRate.action = {|v|
- var val = ~dDict[\bufRate];
- val = spec.map(v.value).postln;
- ~dDict[\bufRate] = val;
- ~v1.set(\bufRate,val);
- ~v2.set(\bufRate,val);
- ~v3.set(\bufRate,val);
- ~v4.set(\bufRate,val);
- number.value=val;
- }};
- // HIGH-PASS FILTER
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(10,20000,'exponential');
- text = StaticText(window,Rect(column4,row7,40,20));
- text.string = "HPF";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column4,row9,41,20));
- knobHPF =Knob.new(window, Rect(column4,row8,40,40));
- knobHPF.value = spec.unmap(~dDict[\hpf]);
- number.value= spec.map(knobHPF.value);
- knobHPF.action = {|v|
- var val = ~dDict[\hpf];
- val = spec.map(v.value).postln;
- ~dDict[\hpf] = val;
- ~v1.set(\hpf,val);
- ~v2.set(\hpf,val);
- ~v3.set(\hpf,val);
- ~v4.set(\hpf,val);
- number.value=val;
- }};
- // LOW-PASS FILTER
- 1.do{|i|
- var knob, text, number,spec;
- spec = ControlSpec(10,20000,'exponential');
- text = StaticText(window,Rect(column4,row10,40,20));
- text.string = "LPF";
- text.stringColor = Color.white;
- text.align = \center;
- number = NumberBox(window, Rect(column4,row12,41,20));
- knobLPF =Knob.new(window, Rect(column4,row11,40,40));
- knobLPF.value = spec.unmap(~dDict[\lpf]);
- number.value= spec.map(knobLPF.value);
- knobLPF.action = {|v|
- var val = ~dDict[\lpf];
- val = spec.map(v.value).postln;
- ~dDict[\lpf] = val;
- ~v1.set(\lpf,val);
- ~v2.set(\lpf,val);
- ~v3.set(\lpf,val);
- ~v4.set(\lpf,val);
- number.value=val;
- }};
- // BUTTON TO START/STOP SEQUENCER
- Button(window, Rect(60,(row10+6),110,83))
- .states_([["START", Color.black, Color.white], ["STOP", Color.white, Color.fromHexString("#8DB38B")]]) //#70AE6E
- .action_({|view| view.value.postln;
- if (view.value == 1)
- {~sequencer.reset;~sequencer.play}
- {~sequencer.stop}
- });
- // BUTTON TO START/STOP RECORDING
- Button(window, Rect(180,(row10+6),110,83))
- .states_([["REC", Color.black, Color.white], ["STOP REC", Color.white, Color.fromHexString("#D72638")]])
- .action_({|view| view.value.postln;
- if (view.value == 1)
- {s.record(numChannels: ~numChans)}
- {s.stopRecording}
- });
- //Notes
- 1.do{var text1, text2;
- text1 = StaticText.new(window, Rect(60,row10+92,200,20));
- text1.string = "KippleGEN or, The Empathy Box (2024)";
- text1.stringColor = Color.new(1,1,1,0.4);
- text1.align = \left;
- text2 = StaticText.new(window, Rect(60,row10+107,200,20));
- text2.string = "Daniel L. Lythgoe";
- text2.stringColor = Color.new(1,1,1,0.4);
- text2.align = \left;
- };
- window.front;
- window.alwaysOnTop = true;
- };
- displayWindow.value();
- }).play(AppClock))
Advertisement
Add Comment
Please, Sign In to add comment