You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.3 KiB
Plaintext
176 lines
4.3 KiB
Plaintext
b = Buffer.read(s, "/home/lcoogan/snd/samples/freesound/vocals/ymaaela/attribution/330909__ymaaela__discordant-clip.mono.wav");
|
|
b = Buffer.read(s, "/home/lcoogan/snd/samples/freesound/vocals/ymaaela/333264__ymaaela__female-vocal-cut-ups-collage.mono.wav");
|
|
|
|
// with this
|
|
b = Buffer.read(s, "/home/lcoogan/snd/releases/desolation-mountain/daven.stems/raoeu.wav");
|
|
w = Wavesets.from("/home/lcoogan/snd/releases/desolation-mountain/daven.stems/raoeu.wav");
|
|
|
|
b.play;
|
|
|
|
s.boot
|
|
|
|
|
|
|
|
// make a wavesets from a soundfile
|
|
w = Wavesets.from("/home/lcoogan/snd/samples/freesound/vocals/ymaaela/attribution/330909__ymaaela__discordant-clip.mono.wav");
|
|
w = Wavesets.from("/home/lcoogan/snd/samples/freesound/vocals/ymaaela/333264__ymaaela__female-vocal-cut-ups-collage.mono.wav");
|
|
w = Wavesets.from("/home/lcoogan/.local/share/SuperCollider/Recordings/SC_250525_194956.wav");
|
|
|
|
w.dump; // contains mainly analysis data
|
|
|
|
w.plot(200, 1); // plot a single waveset
|
|
w.signal.copyRange(w.xings[600], w.xings[601]).plot;
|
|
|
|
w.plot(600, 1); // a single
|
|
w.plot(600, 5); // a group of five contiguous wavesets
|
|
w.buffer;
|
|
w.buffer.play;
|
|
|
|
// build and add the SynthDefs
|
|
Wavesets.prepareSynthDefs;
|
|
|
|
// eventFor returns an event that can be played directly
|
|
w.eventFor(startWs: 600, length: 5, repeats: 2).postln.play;
|
|
w.eventFor(startWs: 600, length: 2, playRate: 1, repeats: 5).postln.play;
|
|
w.eventFor(startWs: 600, length: 2, playRate: 0.5, repeats: 5).postln.play;
|
|
w.eventFor(700, 20, 5, 1).play;
|
|
|
|
(
|
|
fork {
|
|
666.do { |i|
|
|
var ev = w.eventFor(i * 5, 2, 5, exprand(0.5, 1.0));
|
|
ev.put(\pan, 1.0.rand2).play;
|
|
ev.sustain.wait;
|
|
}
|
|
};
|
|
)
|
|
|
|
|
|
|
|
(
|
|
b = w.buffer;
|
|
|
|
Wavesets.prepareSynthDefs;
|
|
|
|
)
|
|
|
|
(
|
|
var start, length, sustain, repeats = 20;
|
|
#start, length, sustain = w.frameFor(150, 5);
|
|
|
|
( instrument: \wvst0, bufnum: b.bufnum, amp:1,
|
|
start: start, length: length, sustain: sustain * repeats
|
|
).play;
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
Quarks.directory;
|
|
|
|
|
|
|
|
|
|
w.lengths.do({ |len, i|
|
|
("Waveset %" ++ i ++ ": length = " ++ len ++ ", amp = " ++ w.amps[i]).postln;
|
|
});
|
|
|
|
|
|
w.plot(0, 1); // arg[0] = waveset index, arg[1] = waveset n
|
|
|
|
(
|
|
// Normalize
|
|
~lens = w.lengths.normalize;
|
|
~amps = w.amps.normalize;
|
|
|
|
// Combine into 2D array of feature vectors
|
|
~features = Array.fill(w.lengths.size, { |i|
|
|
[~lens[i] * 5, ~amps[i]]
|
|
});
|
|
|
|
// Very basic binning approach
|
|
~k = 10;
|
|
~clusters = Dictionary.new;
|
|
~features.do { |vec, i|
|
|
var clusterID = ((vec[0] + vec[1]) * 0.5 * ~k).floor;
|
|
~clusters[clusterID] = (~clusters[clusterID] ?? { [] }) ++ [i];
|
|
};
|
|
|
|
~clusters.keysValuesDo { |k, vals| ("Cluster " ++ k ++ ": " ++ vals).postln; };
|
|
)
|
|
|
|
|
|
(
|
|
// Play one representative from each cluster
|
|
~clusters.keysDo { |k|
|
|
var wsIndex = ~clusters[k][0]; // First waveset in the cluster
|
|
var ev = w.eventFor(startWs: wsIndex, length: 1, repeats: 1);
|
|
ev.put(\pan, 1.0.rand2); // Random pan for stereo fun
|
|
ev.play;
|
|
};
|
|
)
|
|
|
|
|
|
(
|
|
// Build a map of representative wavesets for each cluster
|
|
~reps = Dictionary.new;
|
|
~clusters.keysDo { |k|
|
|
~reps[k] = ~clusters[k][0]; // Could improve: use actual centroid distance
|
|
};
|
|
|
|
// Replace each waveset with its cluster's representative, but keep order
|
|
fork {
|
|
w.lengths.size.do { |i|
|
|
var vec = [~lens[i] * 5, ~amps[i]];
|
|
var clusterID = ((vec[0] + vec[1]) * 0.5 * ~k).floor;
|
|
var repIndex = ~reps[clusterID] ?? { i }; // fallback: original if rep not found
|
|
var ev = w.eventFor(repIndex, 1, 1, 1);
|
|
ev.put(\pan, 0).play;
|
|
ev.sustain.wait;
|
|
};
|
|
};
|
|
)
|
|
|
|
|
|
|
|
|
|
(
|
|
// Subtle morph: vary playback based on cluster
|
|
fork {
|
|
w.lengths.size.do { |i|
|
|
var vec = [~lens[i] * 5, ~amps[i]];
|
|
var clusterID = ((vec[0] + vec[1]) * 0.5 * ~k).floor;
|
|
var ev = w.eventFor(i, 1, 1, 1 + (clusterID * 0.01));
|
|
ev.put(\pan, clusterID.linlin(0, ~k, -1, 1));
|
|
ev.play;
|
|
ev.sustain.wait;
|
|
};
|
|
};
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////
|
|
|
|
|
|
(
|
|
// the simplest synthdef as implented in *prepareSynthDefs:
|
|
SynthDef(\wvst0, { arg out = 0, buf = 0, start = 0, length = 441, playRate = 1, sustain = 1, amp=0.2, pan;
|
|
var phasor = Phasor.ar(0, BufRateScale.ir(buf) * playRate, 0, length) + start;
|
|
var env = EnvGen.ar(Env([amp, amp, 0], [sustain, 0]), doneAction: 2);
|
|
var snd = BufRd.ar(1, buf, phasor) * env;
|
|
|
|
OffsetOut.ar(out, Pan2.ar(snd, pan));
|
|
}, \ir.dup(8)).add;
|
|
)
|
|
|
|
Synth("wvst0", [\bufnum, b, \start, 0, \length, 600, \sustain, 4, \playRate, -0.4]);
|
|
|