Skip to main content

14 posts tagged with "supercollider"

View All Tags

Recursive synthesis

recursivesynth.jpg

I've been working for a while with an improvising setup that uses what is sometimes jokingly called 'recursive synthesis' – that is, plugging an effect unit back in to itself and experimenting with the no-input feedback sounds.

Today I've had some success with the next step in developing this system. I've written a SuperCollider patch that allows me to gate and pitchshift the feedback sounds, so that I can begin to find a way to play them musically using a keyboard. Here's the very first run at playing this system: careful, some rather loud and uncontrolled noises here!

recursor01demoedit.mp3

In the picture, you can see the work-in-progress setup. There's a cheapo DigiTech RP55 guitar pedal feeding back through a small mixing desk. I'm using a swell pedal to contral some of the parameters of the various fx from the DigiTech, particularly sweeping the pitch of the 'whammy' and 'pitch shift' functions, set up in various presets. The mixing desk is not entirely necessary, but the tone controls are useful to have in the feedback loop.

Below is the code for the SuperCollider patch. As always, my thanks to the developers of this software, and all the help received from the community on the mailing list.

(
fork{
~velbus = Bus.control.set(1); // not using yet
s.sync;
SynthDef(\pitchin, { | midinote = 60, gate = 1, amp = 0.1 |
var in, sig, env, ratio, trans, shift, sel;
trans = midinote - 60;
in = SoundIn.ar([0,1]);
ratio = trans.midiratio;
shift = PitchShift.ar(in, pitchRatio: ratio, timeDispersion: 0.1);
sel = trans.abs > 0;
sig = Select.ar(sel, [in, shift]);
env = EnvGen.kr(Env.adsr, gate, doneAction: 2);
Out.ar(0, sig * env * amp * 37) // compensate for quiet;
}).add;
};
MIDIClient.init;
MIDIIn.connectAll;
~on.free;
~off.free;
~cc1.free;
~notes = Array.newClear(128); // array one slot per MIDI note
~on = MIDIFunc.noteOn({ |veloc, num, chan, src|
~notes[num] = Synth(\pitchin, [\midinote, num, \amp, veloc * 0.2/127]);
});
~off = MIDIFunc.noteOff({ |veloc, num, chan, src|
~notes[num].release;
});
~cc1 = MIDIFunc.cc({ |val|
val.postln;
~velbus.set(val/127*4);
}, 1, 0 ); // cc1 on channel 0 = midi channel 1, not using yet
)

Sonifying IR spectroscopy data - finding peaks

Emperor Joseph II: Well, I mean occasionally it seems to have, how shall one say? [he stops in difficulty; turning to Orsini-Rosenberg] How shall one say, Director? Orsini-Rosenberg: Too many notes, Your Majesty? Emperor Joseph II: [to Mozart] Exactly. Very well put. Too many notes. From Amadeus (1984)

It occured to me after a while that my previous attempts at dealing with these sets of data were running into a 'too many notes' problem: 784 resonators at once is always likely to sound like noise! What one would like to be able to do would be to focus in on the visible 'peaks':

This is something a human can do quite intuitively: in fact, I seem to dimly remember that, many years ago, when I worked with HPLC (High Performance Liquid Chromatography) data at Schweppes, there was a pencil and paper method we used to estimate the height and width of a peak, and thus determine the concentration of a compound by calculating the area under the graph.

A little research into the problem of doing this algorithmically rapidly took me far out of my mathematical depth:

Chao Yang, Zengyou He, Weichuan Yu Comparison of public peak detection algorithms for MALDI mass spectrometry data analysis BMC Bioinformatics. 2009; 10: 4. Published online 2009 January 6. doi: 10.1186/1471-2105-10-4 http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2631518/

Instead, I got some hints on a rather simpler approach from Daniel Mayer by asking a question on the SuperCollider mailing list.

Here's the code I eventually came up with:


(
~name = "glycine";
~path = Document.current.dir.asString++"/"++ ~name ++".csv";
f = CSVFileReader.readInterpret(~path);

f = ((f.flop[1] * -1) + 1).normalize;

f = (f*100).asInteger;
f = f.differentiate.removeEvery([0]).integrate;
f = f/100;

~peaksIndices = f.differentiate.sign.findAll([1,-1]);

g = Array.fill(f.size, 0);

~peaksIndices.do { |i| g[i] = f[i] }; // Daniel's line

~amps = g;

// [f,~amps].plot(~name, Rect(840,0,600,450));

~freqs = (36..128).resamp1(f.size).midicps;

SynthDef(\glycine, { | gate=1, amp |
var env, sig;
sig = Klank.ar(`[~freqs, ~amps, nil], PinkNoise.ar(amp/100));
env = EnvGen.kr(Env.perc, gate, doneAction: 2);
Out.ar(0, Pan2.ar(sig, 0, env))
}).add;

Pbind( \instrument, \glycine,
\amp, Pseq(~amps, 4).collect { |amp| if(amp > 0) {amp} {Rest}},
\dur, 0.02,
).play;
)


At the very end of the plot you can see one of the problems: this method finds any and all local peaks, including ones which to the eye look unimportant:

I think what would be needed here would be some low-pass filtering to get rid of small glitches. However, the musical results so far are quite good: once again, here's a short gesture made by crossfading from one compound to another:

Sonifying IR spectroscopy data - automating pitch

Going off in a bit of a different direction here, using the data as automation to drive the pitch of a synth:


( f = CSVFileReader.readInterpret(Document.current.dir.asString++"/water.csv");

f = ((f.flop\[1\] \* -1) + 1).normalize(48,84); //midinotes

Pmono( \default, \midinote, Pseq(f, inf), \dur, 0.005).play )

In this recording, looping up the three chemicals one by one. Kind of cute - early days for this approach.

pmono01.mp3

Sonifying IR spectroscopy data - 'chords'

Finding the .resamp1 method in SuperCollider gave me an idea for reducing this rather large set of data into something perhaps more musically useful. Could I make something more like a tonal chord, with pitches repeated in every octave?

I first drastically resampled my data into just twelve points:

f = ((f.flop[1] * -1) + 1).resamp1(12);

These would then be the probabilities of those twelve pitch classes appearing across a range of eight and a half octaves:

f = (f++f++f++f++f++f++f++f++f[..7]); // 104 notes

Then what I did was to multiply this chordal structure by the original data, so that my final sound is the 'glycine chord' amplitude modulated (sort of) by the absorbtion data.

Here's the final code:


( ~name = "glycine"; ~path = Document.current.dir.asString++"/"++ ~name ++".csv"; f = CSVFileReader.readInterpret(~path);
g = f;

f = ((f.flop[1] * -1) + 1).resamp1(12);
f = (f++f++f++f++f++f++f++f++f[..7]);
// 104 notes g = ((g.flop[1] * -1) + 1).resamp1(104);
// 104 samples of orig graph ~amps = f.cubed * g;
// combining two approaches ~amps = ~amps.normalize;
~amps.plot(~name, Rect(840,0,600,450));
~freqs = (25..128).midicps;

{ Splay.ar(Klank.ar(`[~freqs, ~amps, nil], PinkNoise.ar(0.01))) }.play; )

I used this approach to make the sound below, which crossfades from glycine to tyrosine to water, then back to glycine again.

Sonifying IR spectroscopy data

I'm in the very early stages of a collaborative project with Dr Steven Ford, Senior Research Fellow and QC Manager at the Cancer Research UK Formulation Unit of Strathclyde University. Steve came to me with an idea about sonifying IR spectroscopy data, with a view to perhaps drawing some creative parallels between vibrations at the atomic scale and musical sound.

Steve sent me some IR data relating to three compounds, water, glycine and tyrosine, and I've been trying some things out in SuperCollider. Here's a plot of the data which Steve sent me:

Thinking in terms of sound, my immediate thought was to try to scale those resonances into the audio region. Here's one of my first attempts:

( ~name = "water"; ~path = Document.current.dir.asString++"/"++ ~name ++".csv";
f = CSVFileReader.readInterpret(~path);

~amps = f.flop\[1\]; // array of amplitudes ~amps.plot(~name, Rect(840,0,600,450));

~freqs = Array.series(f.size, 40, 100); // size, start, step

{ Klank.ar(`[~freqs, ~amps, nil], PinkNoise.ar(0.01)) }.play; )

water01.mp3

There are 784 points of data here, and I've just mapped those arbitrarily to a bank of 784 resonators, spaced 100 Hz apart, starting at 40Hz. It sounds pretty nasty. Then it occured to me that Steve's data is for transmittance, not absorbance: the points of interest are the troughs, not the peaks, the graph is upside down for what I wanted to do. So:

( ~name = "tyrosine"; ~path = Document.current.dir.asString++"/"++ ~name ++".csv";

f = CSVFileReader.readInterpret(~path);

~amps = ((f.flop\[1\] \* -1) + 1).cubed; // invert, massage ~amps.plot(~name, Rect(840,0,600,450));

~freqs = (64..128).resamp1(f.size).midicps;

{ Klank.ar(`[~freqs, ~amps, nil], PinkNoise.ar(0.01)) }.play; )

Here I was also starting to think about how to bring out the peaks in the data, hence the .cubed. This does make the data 'pointier', but at the expense of the smaller peaks. A slightly different strategy with the frequencies here also, 784 microtonal pitches between midi notes 64 and 128. It still sounds really pretty nasty:

tyrosine01.mp3

Working on 'The Black Rain'

After the success of the 'The Seventh Voyage', I have high hopes for my next two laptop-and-acoustic-instruments pieces, both to be performed at Plug 12 in a month's time. Today I'm working on 'The Black Rain', which is for five players from the Scottish Ensemble - two violins, viola, cello and double bass - and live processing in SuperCollider. Here's the (rather long and convoluted) programme note:

‘When the last trace of the rocket’s presence, a whitish haze, had been absorbed by the atmosphere, when the wandering sandy waves gradually began to cover up the naked rock of the ground, at the same time filling in the deserted digging spaces – only then, much later, did a dark cloud gather in the west. Hovering low above the ground it pushed closer, grew, encircled the landing area with a threatening arm. There it remained, motionless.

As the sun was about to set, a black rain fell on the desert.’

‘The Black Rain’ takes its title from the first chapter of Stanis!aw Lem’s 1967 science fiction novel ‘The Invincible’, in which a mighty spaceship and her crew are overcome by a race of microscopic mechanical flies, individually insignificant, but capable of joining together into a vast quasi-intelligent ‘cloud’: surely one of the first fictional works to speculate on the possibilities of nanotechnology, calling to mind such devices as the nanostats which inhabit Neal Stephenson’s 1995 novel ‘The Diamond Age’, and the EDust, or Everything Dust, in Iain M. Banks 2000 ‘Look to Windward’.

Aesthetically, ‘The Black Rain’ carries forward the composer’s ongoing reconstruction of the career of his fictional alter ego Edward ‘Teddy’ Edwards. Something like:

‘In 1959, Edwards created a work for string quartet (or quintet?) and five (or four?) taperecorders, incorporating radio equipment borrowed from Aldermaston, where he was at the time employed as an engineer on the ill-fated Blue Streak missile system. Working from his original sketches, I have replicated the piece using the music programming language SuperCollider, with the addition of a reconstructed lost (?) part for double bass.’

In terms of musical devices, ‘The Black Rain’ represents, through self-quotation, a critique of a group earlier works of mine (‘smir’, ‘4thought’, ‘5lipside’ etc), all of which float angular melodies across polymetric rhythmic frameworks, usually according to some quartal scheme, and usually, it would seem, in roughly the same key.

Working on a new piece

Here's how composing looks to me at the moment:

(
a=[46!5,39!4,41!4,36!3,44!3,43!2,37!2,38,42].flat;
Pbind(\midinote, Pstutter(
Pwhite(5,17,inf), //min max number repeated notes
Pxrand(a,10) //get 10 pitches (actually 8???)
),
\dur, 0.25,
\legato, 0.5
).play;
)


gamelan = hardcore

Don't listen to this one at all unless you like really hardcore distortion. No, scrub that, just don't listen to this one. Please. (Brownian walks in SuperCollider, samples & fx in Logic Pro.)

gamhum.mp3