Add cellular automaton
authorEugene Petkevich <nasedil.genio.code@gmail.com>
Mon, 20 Jun 2022 09:04:10 +0000 (12:04 +0300)
committerEugene Petkevich <nasedil.genio.code@gmail.com>
Mon, 20 Jun 2022 09:04:10 +0000 (12:04 +0300)
extensions/classes/midipush.sc
extensions/classes/midisynths.sc
Хэзифу/automata.scd [new file with mode: 0644]
Хэзифу/bcr2000-control.scd
Хэзифу/test.scd

index eed33c9..aeadb50 100644 (file)
@@ -122,6 +122,7 @@ MidiPush : MidiHandler {
       \brightBlinkBeat -> -6,
       \brightBlinkFast -> -6,
       \brightBlink -> -6,
+      \blink -> -6,
       \red -> 1,
       \amber -> 7,
       \yellow -> 13,
index 6eff326..e291b3d 100644 (file)
@@ -1,29 +1,50 @@
-// connect synth to midi-keyboard
-KeySynth {
+// connect synth to midi-controller
+MidiSynth {
   var <midihandler, <>synthName, <>bendRadius, <>panAcross, <>params, <>amp, <>group;
-  var <bend, <notes, madeNewGroup;
+  var <bend, madeNewGroup;
+
+  midiInit {
+    bend = 0;
+    group = group ?? {madeNewGroup = true; Group.new()};
+    params = params ? ();
+  }
+
+  makePanParam {|n|
+    var panParam=#[];
+    if (panAcross) {
+      panParam = [\pan, n.bilin(63, 0, 127, 0, -0.7, 0.7)];
+    };
+    ^panParam;
+  }
+
+  free {
+    if (madeNewGroup) {
+      group.free;
+    };
+  }
+
+}
+
+//=============================================================================
+
+// connect synth to midi-keyboard
+KeySynth : MidiSynth {
+  var <notes;
 
   *new {|midihandler, synthName=\default, bendRadius=1, panAcross=false, params=nil, amp=1.0, group=nil|
-    ^super.newCopyArgs(midihandler, synthName, bendRadius, panAcross, params, amp, group).allInit;
+    ^super.newCopyArgs(midihandler, synthName, bendRadius, panAcross, params, amp, group).midiInit.keyInit;
   }
 
-  allInit {
-    bend = 0;
+  keyInit {
     notes = Array.newClear(128);
-    group = group ?? {madeNewGroup = true; Group.new()};
-    params = params ? ();
 
     midihandler.key_{|d, v, n|
-      var panParam=#[];
       if (d) {
-        if (panAcross) {
-          panParam = [\pan, n.bilin(63, 0, 127, 0, -0.7, 0.7)];
-        };
         notes[n] = Synth(synthName, params.value.asPairs++[
           \gate, 1,
           \freq, n.midicps,
           \amp, amp * v,
-        ]++panParam, group);
+        ]++this.makePanParam(n), group);
       } {
         notes[n].set(\gate, 0);
         notes[n] = nil;
@@ -42,11 +63,9 @@ KeySynth {
     notes.do{|item|
       item.free;
     };
-    if (madeNewGroup) {
-      group.free;
-    };
     midihandler.key = nil;
     midihandler.bend = nil;
+    super.free;
   }
 }
 
@@ -69,36 +88,29 @@ KeySynth {
 
 //=============================================================================
 // connect synth to pads
-PadSynth {
-  var <midihandler, <>synthName, <>bendRadius, <>panAcross, <>params, <>amp, <>group;
-  var <bend, <notes, <amps, madeNewGroup;
+PadSynth : KeySynth {
+  var <amps;
 
   *new {|midihandler, synthName=\default, bendRadius=1, panAcross=false, params=nil, amp=1.0, group=nil|
-    ^super.newCopyArgs(midihandler, synthName, bendRadius, panAcross, params, amp, group).allInit;
+    ^super.newCopyArgs(midihandler, synthName, bendRadius, panAcross, params, amp, group).keyInit.padInit;
   }
 
-  allInit {
-    bend = 0;
-    notes = Array.newClear(128);
+  padInit {
     amps = Array.fill(128, 0);
-    group = group ?? {madeNewGroup = true; Group.new()};
-    params = params ? ();
+
+    midihandler.key = nil;
 
     midihandler.pad_{|d, v, col, row|
       var freq, midinote;
-      var panParam=#[];
       freq = Scale.major.degreeToFreq(col, 0.midicps, row+1);
       midinote = freq.cpsmidi.asInteger;
       if (d) {
-        if (panAcross) {
-          panParam = [\pan, midinote.bilin(63, 0, 127, 0, -0.7, 0.7)];
-        };
         midihandler.ledPad(row, col, 2, 1, 1);
         notes[midinote] = Synth(synthName, params.value.asPairs++[
           \gate, 1,
           \freq, freq,
           \amp, amp * v,
-        ]++panParam, group);
+        ]++this.makePanParam(midinote), group);
         amps[midinote] = amp * v;
       } {
         midihandler.ledPad(row, col, 0, 1, 1);
@@ -121,26 +133,12 @@ PadSynth {
         });
       });
     };
-
-
-
-    midihandler.bend_{|v|
-      bend = v * bendRadius;
-      notes.do{|item, i|
-        item.set(\freq, (i+bend).midicps);
-      };
-    };
   }
 
   free {
-    notes.do{|item|
-      item.free;
-    };
-    if (madeNewGroup) {
-      group.free;
-    };
-    midihandler.key = nil;
-    midihandler.bend = nil;
+    midihandler.pad = nil;
+    midihandler.press = nil;
+    super.free;
   }
 }
 
@@ -163,6 +161,105 @@ PadSynth {
 
 //=============================================================================
 
+// connect synth to midi-keyboard, play only one note at a time
+KeySynthMono : MidiSynth {
+  var <note, <midinote;
+
+  *new {|midihandler, synthName=\default, bendRadius=1, panAcross=false, params=nil, amp=1.0, group=nil|
+    ^super.newCopyArgs(midihandler, synthName, bendRadius, panAcross, params, amp, group).midiInit.keyInit;
+  }
+
+  keyInit {
+    note = nil;
+    midinote = -1;
+
+    midihandler.key_{|d, v, n|
+      if (d) {
+        if (note.notNil) {
+          note.set(\gate, 0);
+        };
+        midinote = n;
+        note = Synth(synthName, params.value.asPairs++[
+          \gate, 1,
+          \freq, n.midicps,
+          \amp, amp * v,
+        ]++this.makePanParam(n), group);
+      } {
+        if (n == midinote) {
+          note.set(\gate, 0);
+          note = nil;
+        };
+      };
+    };
+
+    midihandler.bend_{|v|
+      bend = v * bendRadius;
+      if (note.notNil) {
+        note.set(\freq, (midinote+bend).midicps);
+      };
+    };
+  }
+
+  free {
+    note.free;
+    midihandler.key = nil;
+    midihandler.bend = nil;
+    super.free;
+  }
+}
+
+//=============================================================================
+
+// connect synth to midi-keyboard, play only one note at a time, relative keys
+KeySynthRelative : KeySynthMono {
+  var <>centerKey, <>intervals, keyNote;
+
+  *new {|midihandler, synthName=\default, bendRadius=1, panAcross=false, params=nil, amp=1.0, group=nil, centerKey=60, intervals=#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]|
+    ^super.newCopyArgs(
+      midihandler, synthName, bendRadius, panAcross, params, amp, group
+    ).midiInit.keyInit.relInit(centerKey, intervals);
+  }
+
+  relInit {|c, i|
+    centerKey = c;
+    intervals = i;
+    keyNote = -1;
+    midinote = 60;
+    midihandler.key_{|d, v, n|
+      if (d) {
+        if (note.notNil) {
+          note.set(\gate, 0);
+        };
+        keyNote = n;
+        midinote = case
+        { (n-centerKey) == 0 } {
+          midinote;
+        }
+        { (n-centerKey) > 0 } {
+          midinote + intervals[n-centerKey-1];
+        }
+        { (n-centerKey) < 0 } {
+          midinote - intervals[centerKey-n-1];
+        };
+        midinote.postln;
+        note = Synth(synthName, params.value.asPairs++[
+          \gate, 1,
+          \freq, midinote.midicps,
+          \amp, amp * v,
+        ]++this.makePanParam(midinote), group);
+      } {
+        if (n == keyNote) {
+          note.set(\gate, 0);
+          note = nil;
+          keyNote = -1;
+        };
+      };
+    };
+  }
+}
+
+//=============================================================================
+
 // connect sampler to pedals + push
 MidiSampler {
   var <push, <pedals, <sampler, <>tuneSound;
diff --git a/Хэзифу/automata.scd b/Хэзифу/automata.scd
new file mode 100644 (file)
index 0000000..e8e27ef
--- /dev/null
@@ -0,0 +1,223 @@
+~push = MidiPush();
+~push.midiout.latency_(0.2);
+
+~kedi = MidiRemote25SL();
+
+(
+~kedi.tempo_{|v|
+  TempoClock.tempo = v / 60;
+  v.postln;
+};
+
+TempoClock.play({|beats, time, clock|
+  ~push.syncTempo_(true);
+}, 1);
+)
+
+// infinite pattern
+// ###
+//   ###
+(
+~screen = Array2D.new(8, 8);
+8.do{|i|
+  8.do{|j|
+    ~screen[i, j] = 1.rand;
+  };
+};
+
+~draw = {|arr|
+  8.do{|i|
+    8.do{|j|
+      ~push.ledPad(i, j, arr[i, j]*3);
+    }
+  };
+};
+)
+
+~draw.value(~screen);
+
+(
+~conway = IdentityDictionary[
+  \arr -> Array2D.new(8, 8),
+  \time -> 0,
+  \init -> {|zi|
+    8.do{|i|
+      8.do{|j|
+        zi.arr[i, j] = 0;
+      };
+    };
+  },
+  \get -> {|zi, i, j|
+    i = i % 8;
+    j = j % 8;
+    zi.arr[i, j];
+  },
+  \nextGen -> {|zi|
+    var arrcopy = zi.arr.deepCopy;
+    8.do{|i|
+      8.do{|j|
+        var cur, sum;
+        cur = zi.get(i, j);
+        sum = 0;
+        (-1..1).do{|k|
+          (-1..1).do{|l|
+            sum = sum + zi.get(i+k, j+l);
+          };
+        };
+        sum = sum - cur;
+        if (cur == 1) {
+          if ((sum < 2) || (sum > 3)) {
+            arrcopy[i, j] = 0;
+          };
+        } {
+          if (sum == 3) {
+            arrcopy[i, j] = 1;
+          };
+        };
+      };
+    };
+    zi.arr = arrcopy;
+    zi.time = zi.time + 1;
+  }
+];
+~conway.know = true;
+~conway.init;
+)
+
+~conway.arr[1, 1] = 1;
+~conway.arr[2, 2] = 1;
+~conway.arr[1, 2] = 1;
+~conway.arr.postln;
+~conway.nextGen;
+
+(
+~eventGen = {|i, j, sum|
+  var ev = nil;
+  if (7.rand < 2) {
+    ev = (
+      instrument: [\dyti].choose,
+      midinote: 24+(i*5)+(j*2),
+      amp: 3/sum/(i+5),
+      legato: 0.2,
+      timingOffset: 3.rand/3// + 0.15
+    )
+  };
+  ev;
+};
+)
+
+~sum = 0;
+
+~routine.stop;
+
+(
+~conway.init;
+~conway.arr[2, 0] = 1;
+~conway.arr[2, 1] = 1;
+~conway.arr[2, 2] = 1;
+~conway.arr[3, 2] = 1;
+~conway.arr[3, 3] = 1;
+~conway.arr[3, 4] = 1;
+/*
+8.do{|i|
+8.do{|j|
+~conway.arr[i, j] = 2.rand;
+};
+};
+*/
+~routine = {
+  true.while{
+    ~sum = ~conway.arr.sum;
+    ~draw.value(~conway.arr);
+    8.do{|i|
+      8.do{|j|
+        if (~conway.arr[i, j] == 1) {
+          ~eventGen.value(i, j, ~sum).play;
+        };
+      };
+    };
+    1.wait;
+    ~conway.nextGen;
+  };
+}.fork(quant: 1);
+)
+
+(
+~push.pad_{|d, v, c, r|
+  ~conway.arr[r, c] = 1;
+  ~push.ledPad(r, c, ~conway.arr[r, c]*3);
+};
+)
+
+~push.ledButton(\play, \brightBlink);
+
+(
+Pdef(\ritm, Pmono(\liwe, *[
+  dur: Pwrand([
+    Pseq([1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([2, 2, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([4, 2, 2, 2, 2, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 3, 2, 3].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 2, 3, 3].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 3, 3, 2].normalizeSum*4, 1),
+    Pseq([2, 1, 2, 1, 4, 2, 2, 2].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 2, 1, 1, 1/2, 1/2, 1/2, 1/2, 2].normalizeSum*4, 1),
+  ], [5, 2, 1, 1, 2, 2, 2, 1, 1].normalizeSum, inf),
+  db: -21,
+  pan: Pwhite(-0.5, 0.5),
+  t_trig: Pwrand([1, 0], [15, 1], inf),
+  tension: 0.006/(Pkey(\dur)**0.4)*Pwhite(0.95, 1.05),
+  loss: Plprand(0.9999, 0.99995, inf),
+])).quant_(4).stop;
+)
+
+(
+Pdef(\ritm2, Pmono(\qoba, *[
+  dur: Pwrand([
+    Pseq([1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([2, 2, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([4, 2, 2, 2, 2, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 3, 2, 3].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 2, 3, 3].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 3, 3, 2].normalizeSum*4, 1),
+    Pseq([2, 1, 2, 1, 4, 2, 2, 2].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 2, 1, 1, 1/2, 1/2, 1/2, 1/2, 2].normalizeSum*4, 1),
+  ], [5, 2, 1, 1, 2, 2, 2, 1, 1].normalizeSum, inf),
+  db: 15,
+  pan: Pwhite(-0.5, 0.5),
+  trig: Pwrand([1, 0], [15, 1], inf),
+  accent: 0.3,
+  freq: Pexprand(40, 80),
+  tone: 0.01,
+  decay: 0.2,
+  attackfm: 0.15,
+  selffm: 0.6,
+])).quant_(4).stop;
+)
+
+(
+Pdef(\ritm3, Pmono(\buti, *[
+  dur: Pwrand([
+    Pseq([1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([2, 2, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([4, 2, 2, 2, 2, 1, 1, 1, 1].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 3, 2, 3].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 2, 3, 3].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 3, 3, 2].normalizeSum*4, 1),
+    Pseq([2, 1, 2, 1, 4, 2, 2, 2].normalizeSum*4, 1),
+    Pseq([3, 3, 2, 2, 1, 1, 1/2, 1/2, 1/2, 1/2, 2].normalizeSum*4, 1),
+  ], [5, 2, 1, 1, 2, 2, 2, 1, 1].normalizeSum, inf),
+  timingOffset: 1/2,
+  db: -20,
+  pan: Pwhite(-0.5, 0.5),
+  trig: Pwrand([1, 0], [15, 1], inf),
+  accent: 0.5,
+  freq: Pexprand(40, 160),
+  tone: 0.1,
+  decay: Pwhite(0.1, 0.5),
+  snappy: Pwhite(0.1, 0.9),
+])).quant_(4).stop;
+)
index 4724e84..38adc6b 100644 (file)
@@ -16,7 +16,7 @@
 
   MIDIdef.cc(\bcr2000defaultTurn, { |...args|
     controler.turn(*args);
-  }, (1..110), controler.channel, 2883584);
+  }, (1..110), controler.channel, 2621440);
 
   "Ԃиџуту готов к использованию 😊".postln;
 
index 4a9ebdd..9b3b78a 100644 (file)
@@ -133,3 +133,9 @@ s.waitForBoot{
 }
 )
 
+//=============================================================================
+
+~kedi = MidiRemote25SL();
+
+~monokeys = KeySynthRelative(~kedi);
+~monokeys.intervals = #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; // all white