13597 variations

These four (related) tracks were really fun to develop and explore, and they highlight another way of using SuperCollider to transform an audio recording from the “real, everyday world” into something more musical. In the present examples, a source recording is granulated and then modulated with the spectral character of a saw wave. And like The B Loop @ Stark, the source recording provides a fundamental structure for both sound and composition.

The GrainBuf ugen has a trigger argument which starts a new grain. A periodic trigger, like Impulse, will impart a rhythmic character to the sound, particularly at frequencies ranging from 0.125 to 16 hz or so. A sequenced nature will arise if the frequency argument of Impulse ranges over discrete multiples (0.5, 1.0, 2.0, 4.0, etc). This effect is further clarified when the size of each grain (the dur argument of GrainBuf) is also a multiple of the frequency and does not vary.

The synth creates an fft of each grain (oh how I do love computers these days!), along with a separate fft of saw waves at specified frequencies (a minor scale). The spectral “chain” of the grain is then “morphed” with that of the saw by PV_MagMul, which multiplies the magnitude components of two fft buffers while retaining the phase character of only one of them. 13597v1 retains the noise-like character of the source recording, while 13597v2 retains the synth-like character of the saw waves. The resultant signal is then mixed back with a minor component of its parent grain.

13597v1:

13597v2:

This Pbindef player uses Pfuncn to call a function (with arguments) that generates a random (minor) chord of midinotes; the Pseq repeats every 5th chord. The function can be updated (re-evaluated) independently of the Pbindef while its playing, which may also be re-evaluated with new arguments for the function.

If individual notes are layered instead of chords, a less structured composition emerges as transitions become less articulated. Its also a nice effect, but I think I like the chords better, especially for sound recordings that have a more narrow range of sound events. For individual notes, the Pbindef player must be modified to accommodate shorter note events (\dur, \pos) and different arguments for the Env (\atk, \sus, \rel). And once again, 13597v3 has a more noise-like character, while 13597v4 is more synth-like.

13597v3:

13597v4:

The source file is exactly the same as The B Loop @ Stark, and is processed in more or less the same way (sequentially thru time). So again, the source recording has a substantial impact on the entire piece as well as at a more granular level, and there are highly common characteristics among all three pieces.

source recording:

Remember that the PV ugens are part of the SC3 plugins, so you need to have them installed in order to run the code. And many many thanks to Josh Parmenter for writing them; they’re really a lot of fun to work with and easy to use.

// only use a 1-channel audio file
~path01 = PathName("add your own path to an audio file here");
~aBuf01 = Buffer.read(s, ~path01.fullPath);

// a function to generate a chord
// args: num, [baseNote], [scale]
(
~fnChord01 = {
    arg num = 3, baseNote = [36, 48, 60], scale = [0, 2, 3, 5, 7, 10];
    var chord;
    chord = Array.fill(num, {baseNote.choose + scale.choose});
    };
)

(
SynthDef.new(\grainBufMagMul01, {
    arg out = 0, ampMin = 0.1, ampMax = 0.3, freq = 220, detuneFreq = 0.2, aBuf, numFrames = 2048, density = 8, detuneDensity = 0.2, rate = 0.5, duration = 1.0, aBufRate = 1.0, pos = 0, interp = 2, xfade = 0, envBuf = -1, balance = 1, dBalance = 0.8, numDA = 2, atk = 4.0, sus = 4.0, rel = 4.0, c1 = 1, c2 = 0, c3 = -2;
    var sig, env, amp, sig1, sig2, chain1, chain2;

    env = EnvGen.ar(Env.new([0, 1, 1, 0], [atk, sus, rel], [c1, c2, c3]), doneAction:numDA);

    density = {density * LFNoise1.kr(rate, detuneDensity).midiratio}!2;
    freq = {freq * LFNoise1.kr(rate, detuneFreq).midiratio}!2;
    balance = balance * LFNoise1.kr(rate/Rand(1.0, 3.0)).range(-1 * dBalance, dBalance);
    amp = LFNoise1.kr(rate/Rand(1.0, 3.0)).range(ampMin, ampMax);

    sig1 = Impulse.ar(density);
    sig1 = GrainBuf.ar(1, sig1, duration, aBuf, aBufRate, pos, interp, 0, envBuf);
    sig2 = Saw.ar(freq);
    chain1 = FFT(LocalBuf(numFrames, 1).clear, Mix(sig1));
    chain2 = FFT(LocalBuf(numFrames, 1).clear, Mix(sig2));

    sig = PV_MagMul(chain1, chain2);  // v1 == more sample character (phases of GrainBuf)
    // sig = PV_MagMul(chain2, chain1); // v2 == more synth character (phases of Saw)
    sig = IFFT(sig) * 0.05;

    sig = XFade2.ar(sig, sig1, xfade);
    sig = Balance2.ar(sig[0], sig[1], balance);
    sig = sig * env * amp;

    Out.ar(out, sig);

}).add;
)

(
Pbindef(\grainPlayer04,
    \instrument, \grainBufMagMul01,
    \aBuf, ~aBuf01,
    \dur, 8,
    \midinote, Pseq([[67, 79], Pfuncn({~fnChord01.value(rrand(1, 5))}, 4)], inf),
    \detuneFreq, 0.2,
    \density, Pseq([Pseq([0.25, Prand([0.5, 1.0], 1), Pxrand([0.25, 0.5, 1.0, 2.0], 2)], 1), Pseq([2.0], 3)], inf),
    \detuneDensity, Pwhite(0.1, 0.3, inf),
    \duration, 1.0,
    \rate, Pwhite(0.25, 1.5, inf),
    \pos, Pseries(0.0, Pwhite(1.5, 2.5, inf)/~aBuf01.duration, ~aBuf01.duration/2.0),
    \atk, Pkey(\dur),
    \sus, Pkey(\dur) * 2,
    \rel, Pkey(\dur),
    \xfade, Pwhite(-0.9, 0.0, inf),
    \balance, 0.8,
    \ampMin, 0.10,
    \ampMax, 0.3,
);
)

Pbindef(\grainPlayer04).play(quant:4.0);

 

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Leave a Reply

Your email address will not be published. Required fields are marked *