« 17 / 30 »

Growing More Sounds

2010-12-03 03:25 supercollider

clean-up #18:

I found more code I never published. Again it is about generating SynthDefs using genetic algorithms. See /f0blog/growing-sounds/ and /f0blog/work-with-mark-genetics/ for previous stories.

To run the attached files you will need to install my RedGA library from the /code/sc/#classes page.

First, is a little exploration tool called growing_sounds10. It makes a single SynthDef from the settings of a multi slider. Draw something and press space to generate and play the SynthDef. If you like what you hear you can copy the code from the post window and refine it manually.

Also, try the preset functions. They will either generate, modify or set a fixed setting/drawing in the multi-slider.

the SynthDef generated in the screenshot above was this one...

{LFPar.ar(LFTri.kr(LFDNoise3.kr(0.836588, 0.257632, 0.772292).exprange(3.7376802825928, 15.120258769989)).exprange(11935.654205322, 5408.6393985748)).range(0.31427707672119, -0.23100700378418)}.play

Another file is called growing_soundsBreed and it gives you control over 6 parent genomes that can be transformed into SynthDefs and listened to by clicking the play buttons. Mark good sounding parents and breed a new generation. The genomes should now have been mixed and mutated and there are 6 new children as a result of the operation. It is likely that they sound similar to their parents and the longer you repeat the process, the more similar the genomes and in turn, the SynthDefs (phenomes) will be.

Yet another piece of code is growing_soundsBreedFitness and it works the same way as the previous except that you here give a rating i.e. fitness to each parent (blue sliders = fitness amount). So instead of marking which parents you give ratings. The system will use these ratings as a guideline of importance when choosing which parents' genes to use for the new generation.

And last is a file called growing_soundsBreedPattern in which you can not only breed SynthDefs but also the amplitude pattern they play in a simple sequencer.

As always, all code published under GNU GPL v2 license.

Updates:


Even More Low Life

2010-12-01 20:31 supercollider

clean-up #17:

This one also belongs to my family of low life audiovisual creatures.

The SuperCollider code attached below. Note: will only run under older SuperCollider, version <=3.6 with OSX (Cocoa).

redSlug

Attachments:


More Low Life

2010-12-01 15:55 supercollider

clean-up #16:

Here is another piece of self-referential code. It belongs to my family of low life audiovisual creatures.

SuperCollider document attached below. Note: will only run under older SuperCollider, version <=3.6 with OSX (Cocoa).

At 00:40 I start to type into the document. Mainly hitting the delete key as the system runs.

redEel

Attachments:


hansm-bird

2010-11-30 03:56 supercollider

clean-up #15:

This birdcall synthesis tutorial by Andy Farnell I found very good when it was published. And as I wanted to learn more by synthetic bird songs I ported the Pure Data patches. So here is a version of hansm-bird-control.pd for SuperCollider.

/*
hansm-bird-control.pd
http://obiwannabe.co.uk/tutorials/html/tutorial_birds.html
SC port by redFrik 080430
*/
s.boot;

(
SynthDef(\birdCall, {|
  out= 0, pan= 0, gate= 1, freq= 0, amp= 0.5, atk= 0.5, dcy= 0.5,
  fmod1= 1, atkf1= 0.5, dcyf1= 0.5,
  fmod2= 1, atkf2= 0.5, dcyf2= 0.5,
  amod1= 1, atka1= 0.5, dcya1= 0.5,
  amod2= 1, atka2= 0.5, dcya2= 0.5|
  var env, freq1, freq2, amp1, amp2, fmod, amod, z;
  env= EnvGen.ar(Env([0, amp, 0], [atk, dcy], -4), gate, timeScale:0.9, doneAction:2);
  freq1= EnvGen.ar(Env([0, fmod1, 0], [atkf1, dcyf1], -4), 1, 3000, 0, 0.9);
  freq2= EnvGen.ar(Env([0, fmod2, 0], [atkf2, dcyf2], -4), 1, 3000, 0, 0.9);
  amp1= EnvGen.ar(Env([0, amod1, 0], [atka1, dcya1], -4), 1, 1, 0, 0.9);
  amp2= EnvGen.ar(Env([0, amod2, 0], [atka2, dcya2], -4), 1, 1, 0, 0.9);
  fmod= SinOsc.ar(freq1, 0, amp1, 1);
  amod= 1-SinOsc.ar(freq2, 0, amp2);
  z= SinOsc.ar(freq*7000+300*fmod, 0, amod);
  Out.ar(out, Pan2.ar(z, pan, env));
}).add;
f= {|freq, atk, dcy, fmod1, atkf1, dcyf1, fmod2, atkf2, dcyf2, amod1, atka1, dcya1, amod2, atka2, dcya2|
  Synth(\birdCall, [\freq, freq, \atk, atk, \dcy, dcy,
    \fmod1, fmod1, \atkf1, atkf1, \dcyf1, dcyf1,
    \fmod2, fmod2, \atkf2, atkf2, \dcyf2, dcyf2,
    \amod1, amod1, \atka1, atka1, \dcya1, dcya1,
    \amod2, amod2, \atka2, atka2, \dcya2, dcya2]);
};
)
(
//triple-tailed-tree-troubler
f.value(0.387755, 0.0204082, 0.204082,
  0.367347, 0.571429, 0.734694,
  0.918367, 1, 0.77551,
  0.571429, 0.367347, 0.22449,
  0.0204082, 0.183673, 0.44898);
)
(
//speckled-throated-spew
f.value(0.183673, 0.591837, 0.387755,
  0.0104082, 0.530612, 0.346939,
  0.244898, 0.55102, 0.122449,
  0.387755, 1, 0.612245,
  0.346939, 0.816327, 0.653061);
)
(
//lesser-spotted-grinchwarbler
f.value(0.55102, 0.591837, 0.387755,
  0.0716327, 0.0204082, 0.346939,
  0.0204082, 0.55102, 0.122449,
  0.632653, 1, 0.612245,
  0.346939, 0.816327, 0.653061);
)
(
//long-toed-mudhopper
f.value(0.163265, 0.22449, 0.183673,
  0.00306122, 0.122449, 1,
  0.0612245, 1, 0.77551,
  0.979592, 0.204082, 0.734694,
  1, 0.142857, 0.612245);
)
(
//yellow-yiffled-yaffle
f.value(0.0204082, 0.367347, 0.183673,
  0.0612245, 0, 1,
  0.285714, 0.22449, 0.489796,
  0.367347, 0.387755, 0.734694,
  0.204082, 0.428571, 0.142857);
)
(
//pointy-beaked-beetlefiend
f.value(0.428571, 0.204082, 0.489796,
  0.0204082, 0.795918, 0.591837,
  0.285714, 0.22449, 0.489796,
  0.204082, 0.836735, 0.734694,
  0.77551, 0.428571, 0.142857);
)
(
//african-boojuboolubala
f.value(0.306122, 0.959184, 0.0408163,
  1, 0, 0.591837,
  0.285714, 0.22449, 0.489796,
  0.204082, 0.836735, 0.734694,
  0.77551, 0.428571, 0.142857
);
)
(
//common-muckoink
f.value(0.0204082, 0.8, 0.0816327,
  0.0204082, 0.001, 0.99,
  0.0204082, 0.01, 1,
  1, 0.142857, 0.734694,
  1, 0.0612245, 0.530612);
)

Hamburg

2010-11-29 03:02 supercollider

clean-up #14:

Here is a file from a short introduction to / demonstration of SuperCollider given at the Hochschule für Musik und Theater Hamburg, July 2009. It was all live-coded from scratch during my talk, but in the video above I just run through the lines one by one found in the file (attached).

I recorded this screencast and published the code to serve as an example for people new to and curious of SuperCollider. Pardon the silly music.

hamburg, 02:47, 7.2MB

The \asdf synth definition is a phase modulation synth with some random panning. \hh and \sn are both built by filtering noise and the \bd is a simple oscillator. All three definitions use a percussive envelope.

All Pdefs (the sequencers sort of) is set to use a quantise of 4. That means that any change I do in the sequencing code waits to kick in until the next bar (4/4, 60 BPM).

At 01:35 I start live-coding some changes to the \bd bass drum. First changing the duration from a static 0.5 to a stream of numbers using the Pseq. Then I change the release time (hard to hear) and last I play with the frequencies. That might give an idea of how one can interact with code in SuperCollider and change the system as it is running.

Updates:

Attachments:


Growing Sounds

2010-11-28 03:23 supercollider

clean-up #13:

growing some sounds

This is a demonstration of a simple sequencer using the RedGA library - a library for genetic algorithms. See the story /f0blog/work-with-mark-genetics/ for more info and get the classes here: /code/sc/#classes.

The whole program consists of six voices. For each voice, there are individual genomes for the SynthDef as well as for the amplitude pattern (the step-sequencer) and for the envelope shape. The genomes are all randomised at startup or when the 'restart' button is clicked. One can monitor the complete result of one voice (SynthDef+pattern+envelope) with the 'play' button and edit the detailed multi-slider views manually if desired. As the play button is clicked, the SynthDef genome is translated to a phenome (a real working SynthDef) and sent to the server as well as posted to the post window.

With the 'mark' buttons one select which voices that will be parents in the next generation. One can mark from zero up to all six voices, but a more sensible number is two or three. There is the choice of keeping the parent voices alive to the next generation or to overwrite them with new children.

In any case, this program is not meant to be taken completely serious. It is more of a fun toy using a genetic algorithm to create some chaotic and glitchy little sounds.

Below is the printout of the genomes (arrays) and phenomes (SynthDefs) that were produced in the video demonstration.

GENOME:
[ 0.97673571109772, 0.25465285778046, 0.42777442932129, 0.67972803115845, 0.33054959774017, 0.6037335395813, 0.56670892238617, 0.90849816799164, 0.082634687423706, 0.60306036472321, 0.39336848258972, 0.40707266330719, 0.0089198350906372, 0.58077096939087, 0.79928719997406, 0.46543490886688, 0.58306109905243, 0.2658509016037, 0.2371027469635, 0.65999948978424 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015549', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(VarSaw.ar(SinOsc.kr(Dust.kr(LFSaw.kr(WhiteNoise.kr(WhiteNoise.kr(0.659999).range(0.2658509016037, 0.2371027469635)).exprange(16.005815279484, 9.362154686451)).exprange(8153.3118128777, 198.21830511093)).exprange(1.7444302797318, 12.100901257992)).exprange(12082.596120834, 11342.844269276)).range(-0.14445114135742, 0.35945606231689)*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.20719468593597, 0.044587969779968, 0.080502510070801, 0.57578802108765, 0.082075834274292, 0.75569093227386, 0.49076271057129, 0.017484903335571, 0.86507594585419, 0.24153673648834, 0.65859174728394, 0.0708167552948, 0.86804354190826, 0.01993727684021, 0.6159542798996, 0.10451817512512, 0.55506300926208, 0.35075616836548, 0.57417559623718, 0.94203984737396 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015552', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(SinOscFB.ar(111.474092, VarSaw.ar(LFNoise2.ar(32.619722, 0.868044, -0.960125).exprange(4845.9039950371, 13178.663110733)).range(0.49076271057129, 0.017484903335571)).range(-0.8389949798584, 0.15157604217529).perform('sqrdif', LFSaw.ar(1055.739533, 1.884080).range(0.11012601852417, -0.29848766326904))*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.093999624252319, 0.045899748802185, 0.94297802448273, 0.28493881225586, 0.53934347629547, 0.98470652103424, 0.042535185813904, 0.16906559467316, 0.80304133892059, 0.043324589729309, 0.060743093490601, 0.010264873504639, 0.48678374290466, 0.13158559799194, 0.052134871482849, 0.19801700115204, 0.09520161151886, 0.15453398227692, 0.5274965763092, 0.16556298732758 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015556', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(SinOscFB.ar(LFNoise1.kr(0.244920, 0.803041, -0.913351).exprange(19694.436290264, 869.8530125618)).range(0.88595604896545, -0.43012237548828).perform('-', SinOsc.ar(59.563934, 3.770235, 0.288490, -0.063430).range(-0.026432514190674, -0.73682880401611))*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.87658286094666, 0.13238632678986, 0.20194101333618, 0.81867587566376, 0.87399089336395, 0.60985088348389, 0.89901769161224, 0.27304971218109, 0.3851375579834, 0.6437246799469, 0.17010962963104, 0.31229841709137, 0.22293603420258, 0.56832695007324, 0.26486468315125, 0.25054693222046, 0.53271245956421, 0.048996567726135, 0.4028148651123, 0.7767539024353 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015559', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(LFPar.ar(LFClipNoise.ar(6071.557417, LFCub.kr(15.052203, 1.351127, Vibrato.kr(SyncSaw.kr(6.128215).exprange(1.0750316977501, 8.1160158157349)).range(0.26486468315125, 0.25054693222046)).range(0.6437246799469, 0.17010962963104)).exprange(12204.820652008, 17982.373478413)).range(-0.59611797332764, 0.63735175132751)*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.34140014648438, 0.30175685882568, 0.0056966543197632, 0.80570125579834, 0.04620635509491, 0.73648166656494, 0.52050232887268, 0.045454144477844, 0.40112888813019, 0.80093693733215, 0.16607248783112, 0.6278703212738, 0.67780292034149, 0.21197652816772, 0.92777013778687, 0.5347558259964, 0.61497759819031, 0.93128263950348, 0.67022502422333, 0.17048060894012 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015602', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(SyncSaw.ar(52.612358, LFTri.ar(LFPulse.kr(PinkNoise.kr(0.927770, 0.069512).exprange(13.588278114796, 4.3183329105377)).exprange(16022.720007896, 3338.1283068657)).exprange(10419.636530876, 928.17380666733)).range(-0.98860669136047, 0.61140251159668).perform('sqrsum', Blip.ar.range(0.34045004844666, -0.65903878211975))*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.21759104728699, 0.19168221950531, 0.96565890312195, 0.2745361328125, 0.71634376049042, 0.31953656673431, 0.075420379638672, 0.73166418075562, 0.21231842041016, 0.14699053764343, 0.48020792007446, 0.18293488025665, 0.93624556064606, 0.65213680267334, 0.49147021770477, 0.69864809513092, 0.49048376083374, 0.61236214637756, 0.0073232650756836, 0.21936917304993 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015605', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(LFTri.ar(LFPar.ar(LFTri.ar(551.637467, 0.731740, 0.936246, 0.304274).exprange(4262.1220397949, 2956.8709421158)).exprange(6404.3406033516, 1526.8991851807)).range(0.9313178062439, -0.450927734375).perform('ring4', LFDNoise1.ar(21.037774, 0.219369).range(-0.01903247833252, 0.22472429275513))*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.34140014648438, 0.30175685882568, 0.0056966543197632, 0.80570125579834, 0.04620635509491, 0.73648166656494, 0.52050232887268, 0.045454144477844, 0.40112888813019, 0.80093693733215, 0.16607248783112, 0.6278703212738, 0.67780292034149, 0.21197652816772, 0.92777013778687, 0.5347558259964, 0.61497759819031, 0.93128263950348, 0.67022502422333, 0.17048060894012 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015608', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(SyncSaw.ar(52.612358, LFTri.ar(LFPulse.kr(PinkNoise.kr(0.927770, 0.069512).exprange(13.588278114796, 4.3183329105377)).exprange(16022.720007896, 3338.1283068657)).exprange(10419.636530876, 928.17380666733)).range(-0.98860669136047, 0.61140251159668).perform('sqrsum', Blip.ar.range(0.34045004844666, -0.65903878211975))*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

GENOME:
[ 0.21759104728699, 0.19168221950531, 0.62269937992096, 0.2745361328125, 0.71634376049042, 0.31953656673431, 0.075420379638672, 0.73166418075562, 0.21231842041016, 0.69631904363632, 0.48020792007446, 0.18293488025665, 0.13190184533596, 0.65213680267334, 0.49147021770477, 0.14417177438736, 0.49048376083374, 0.61236214637756, 0.0073232650756836, 0.21936917304993 ]

PHENOME:
(SynthDef('RedGAPhenomeDef_101128_015625', {|out= 0, amp= 1, gate= 1| Out.ar(out, Limiter.ar(LeakDC.ar(LFTri.ar(LFPar.ar(LFTri.ar(551.637467, 0.731740, 0.131902, 0.304274).exprange(4262.1220397949, 13932.454491854)).exprange(6404.3406033516, 1526.8991851807)).range(0.24539875984192, -0.450927734375).perform('ring4', LFPar.ar(21.037774, 0.438738).range(-0.01903247833252, 0.22472429275513))*EnvGen.kr(#[ 0, 2, 1, -99, 1, 0.01, 5, -4, 0, 0.02, 5, -4 ], gate, amp, 0, 1, 2))))}).play)

Annette

2010-11-27 03:36 supercollider

clean-up #12:

This is a live patch for 4-channel sound written for a friend some time ago. To fully function it expects that you have an external soundcard with 4 inputs (mics) and 4 outputs (speakers) connected. The idea is to be able to route the sound from any of the inputs to any of the outputs and do all kinds of crossfades and mixes in between.

There are two areas with sliders that are used to do the 4x4 routing. One can also record the resulting quad output to disk and play it back, or use previously recorded quad files. There is also a sampler with 28 voices that can be triggered with the computer keyboard (keys A-Z). Additional features include MIDI learn (controllers) plus a preset system that can read and write to disk. Keys '0-9' with and without capslock recall presets while shift-clicking one of the preset buttons in the GUI stores the current setting. With the lag time, one can make all the changes smooth - it interpolates over x seconds.

Attached is the complete code for the program. Sorry for the ugly interface.

It has been tested on SC 3.4 on a OSX with both Cocoa and SwingOSC and should run cross-platform.

Updates:

Attachments:


2-bit Computer Sonification

2010-11-26 03:57 supercollider

clean-up #11:

As a continuation of the n-bit computer story, here are three snippets of SuperCollider code that sonifies all possible programs of a little 2-bit computer emulator. They all map the sound differently. Note that here I let load and stor instructions increase the program counter one extra step.

Rendered MP3s for corresponding code is attached below.

//2-bit computer
//sonification #1 - all possible programs 0-255 in order, 16 ticks each
(
s.waitForBoot{
  var mem;
  var pc= 0;  //program counter
  var reg= 0;  //register
  var format= {|x| x.collect{|x| x.asBinaryString(2)}};
  var rd= {|x| mem@@x};
  var wr= {|x, y| mem.put(x%mem.size, y)};

  var snd;
  SynthDef(\snd, {|amp= 0, freq= 400, width= 0.5, pan= 0|
    var src= LFPulse.ar(freq, 0, width, amp.lag(0, 0.1));
    Out.ar(0, Pan2.ar(FreeVerb.ar(src, 0.2, 0.3), pan));
  }).add;
  s.sync;
  snd= Synth(\snd);

  Routine.run{
    4.do{|m0|
    4.do{|m1|
    4.do{|m2|
    4.do{|m3|
      var op, running= true;
      mem= [m3, m2, m1, m0];  //reordering here makes slightly different pieces
      pc= 0;
      reg= 0;
      "".postln;
      16.do{
        if(running, {
          op= mem[pc];
          snd.set(\amp, 0.7, \freq, op.linexp(0, 3, 120, 1200), \pan, pc/3*2-1, \width, reg/3*0.8+0.1);
          switch(op,
            2r00, {running= false},  //halt
            2r01, {reg= rd.(pc+1); pc= pc+1},  //load  next addy into reg
            2r10, {reg= reg+1%4},  //incr  reg
            2r11, {wr.(rd.(pc+1), reg); pc= pc+1}  //stor  at addy in next byte
          );
          pc= pc+1%mem.size;
          [\pc, pc, \reg, reg, \mem, format.value(mem)].postln;
        });
        0.01.wait;
        snd.set(\amp, 0);
        0.001.wait;
      };
    };};};};
    1.wait;
    snd.free;
  };
};
)
//2-bit computer
//sonification #2 - all possible programs 0-255 in order, maximum 100 ticks
(
s.waitForBoot{
  var mem;
  var pc= 0;  //program counter
  var reg= 0;  //register
  var format= {|x| x.collect{|x| x.asBinaryString(2)}};
  var rd= {|x| mem@@x};
  var wr= {|x, y| mem.put(x%mem.size, y)};

  var snd;
  SynthDef(\snd, {|amp= 0, freq= 400, width= 0.5, mod= 0, t_trig= 0, pan= 0|
    var env= EnvGen.ar(Env.perc(0.01, 0.1, 1, 0), t_trig);
    var src= SinOsc.ar(mod, SinOsc.ar(freq, 0, 2pi*width), amp);
    Out.ar(0, Pan2.ar(src*env, pan));
  }).add;
  s.sync;
  snd= Synth(\snd, [\amp, 0.7]);

  Routine.run{
    var cnt= 0;
    4.do{|m0|
    4.do{|m1|
    4.do{|m2|
    4.do{|m3|
      var i= 0, op, running= true;
      mem= [m0, m1, m2, m3];  //reordering here makes slightly different pieces
      pc= 0;
      reg= 0;
      while({running and:{i<100}}, {
        op= mem[pc];
        snd.set(\t_trig, 1, \freq, op.linexp(0, 3, 120, 1200), \pan, pc/3*2-1, \width, pc+1, \mod, pc/3);
        switch(op,
          2r00, {running= false},  //halt
          2r01, {reg= rd.(pc+1); pc= pc+1},  //load  next addy into reg
          2r10, {reg= reg+1%4},  //incr  reg
          2r11, {wr.(rd.(pc+1), reg); pc= pc+1}  //stor  at addy in next byte
        );
        pc= pc+1%mem.size;
        i= i+1;
        0.008.wait;
      });
      ("program:"+cnt).postln;
      cnt= cnt+1;
    };};};};
    1.wait;
    snd.free;
  };
};
)
//2-bit computer
//sonification #3 - all possible programs 0-255 in order, 4 voices with freq from memory
(
s.waitForBoot{
  var mem;
  var pc= 0;  //program counter
  var reg= 0;  //register
  var format= {|x| x.collect{|x| x.asBinaryString(2)}};
  var rd= {|x| mem@@x};
  var wr= {|x, y| mem.put(x%mem.size, y)};

  var snds;
  SynthDef(\snd, {|amp= 0, freq= 400, width= 0.5, mod= 0, pm= 0, pan= 0|
    var src= SinOsc.ar(mod, SinOsc.ar(freq, SinOsc.ar(pm, 0, 2pi), 2pi*width), amp);
    Out.ar(0, Pan2.ar(src, pan));
  }).add;
  s.sync;
  snds= {Synth(\snd)}.dup(4);

  Routine.run{
    var cnt= 0;
    4.do{|m0|
    4.do{|m1|
    4.do{|m2|
    4.do{|m3|
      var i= 0, op, running= true;
      mem= [m3, m2, m1, m0];  //reordering here makes slightly different pieces
      pc= 0;
      reg= 0;
      while({running and:{i<16}}, {
        op= mem[pc];
        switch(op,
          2r00, {running= false},  //halt
          2r01, {reg= rd.(pc+1); pc= pc+1},  //load  next addy into reg
          2r10, {reg= reg+1%4},  //incr  reg
          2r11, {wr.(rd.(pc+1), reg); pc= pc+1}  //stor  at addy in next byte
        );
        pc= pc+1%mem.size;
        4.do{|r|
          snds[r].set(
            \amp, running.binaryValue*0.3,
            \freq, mem[r].linexp(0, 3, 300-cnt, 300+cnt),
            \pan, r/3*2-1,
            \width, op+1,
            \mod, reg/2,
            \pm, pc+1
          );
          0.01.wait;
        };
        i= i+1;
      });
      ("program:"+cnt).postln;
      cnt= cnt+1;
    };};};};
    1.wait;
    snds.do{|x| x.free};
  };
};
)

« 17 / 30 »