Skip to content

Instantly share code, notes, and snippets.

@xavriley
Created November 13, 2017 08:20
Show Gist options
  • Save xavriley/ce1becd7f2d97d93aced74e88ae7ba54 to your computer and use it in GitHub Desktop.
Save xavriley/ce1becd7f2d97d93aced74e88ae7ba54 to your computer and use it in GitHub Desktop.
SuperCollider wavetable experiments for Sonic Pi
s.boot
// BEGIN code to convert AKWF wavetables from 600 samples in length to 1024
// because VOsc3 needs a buffer which is a power of two to work properly
// this pipes in stdout from ls
(
var p, l;
p = Pipe.new("find ~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_0001 -iname *.wav", "r"); // list directory contents in long format
l = p.getLine; // get the first line
while({l.notNil and: {l != ""}}, {
l.postln;
l.postln;
if((l.notNil and: {l.stripWhiteSpace != ""}), {
f = SoundFile.openRead(l);
a = FloatArray.newClear(f.numFrames);
f.readData(a);
f.close; // close the file
a.size; // should be 1024
a = a.as(Signal);
a = a.asWavetable;
b = Buffer.loadCollection(s, a);
b.write(l ++ ".wavetable", sampleFormat: "float");
b.free;
});
l = p.getLine;
}); // post until l = nil
p.close; // close the pipe to avoid that nasty buildup
Buffer.freeAll;
)
"~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_0001/AKWF_0001.wav".standardizePath
// SoundFile
f = SoundFile.openRead("~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_bw_saw/AKWF_saw_0002.wavetable".standardizePath);
f = SoundFile.openRead("~/Downloads/AKWF/AKWF_piano/AKWF_piano_0002.wav".standardizePath);
f = SoundFile.openRead("~/Downloads/AKWF/AKWF_bw_saw/AKWF_saw_0002.wav".standardizePath);
// f = SoundFile.openRead("~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_0001/AKWF_0001.wav".standardizePath);
f.path // ok
// An array to load the data
a = FloatArray.newClear(f.numFrames);
f.readData(a);
f.close; // close the file
a.size; // 169 in my file
// resamp the table to have a pow of 2 (bigger to avoid aliassing)
// if u read many diff samples choose a bigger pow of 2
a = a.resamp1(1024);
// Conver it to a Signal
a = a.as(Signal);
a.size; // 256 ok
// Convert it to a Wavetable
a = a.asWavetable;
a.size; // 512 ok, (wavetable format is signal.size * 2
// END wavetable conversion code
//BEGIN example to play sound from a single buffer
// Server side
s.boot;
b = Buffer.loadCollection(s, a);
x = b.play(loop: true); // ok sounds
e = Env([1.0, 0.0], [0.5]);
g = EnvGen.ar(e, doneAction: 2);
x = { Osc.ar(b, 60.midicps, 5.6.mod(2pi), 0.3) }.play;
x.free;
f = SoundFile.openRead("~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_clarinett/AKWF_clarinett_0001.wavetable".standardizePath);
// An array to load the data
a = FloatArray.newClear(f.numFrames);
f.readData(a);
f.close; // close the file
a.size; // 169 in my file
b = Buffer.loadCollection(s, a);
Array
c.last.bufnum;
c.first.plot;
c.last.plot;
c[1].bufnum;
x = { Osc.ar(b, 52.midicps, 0, 1) * EnvGen.ar(Env.perc(0.1, 1)) }.play;
x = { LPF.ar(Osc.ar(b, MouseX.kr(110, 880)), SampleRate.ir/2-1000) }.play;
s.freqscope
x.free;
s.quit;
//END example to play sound from a single buffer
// Waveshaper example ???
b = Buffer.alloc(s, 512, 1);
b.cheby([1,0,1,1,0,1]);
x = play({
Shaper.ar(
b,
SinOsc.ar(300, 0, Line.kr(0,1,1)),
0.5
)
});
// END waveshaper example
// Begin code to chain wavetables together, back to back
// load the 25 clarinet wavetables into buffers that are next to each other in memory
c = Buffer.allocConsecutive(25, s, 2048, 1, { |buf, idx|
buf.read(("~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_clarinett/AKWF_clarinett_" ++ (idx + 1).asStringToBase(10, 4) ++ ".wavetable").standardizePath);
});
// sample code to plot the first three
(0..3).do {arg i;
c[i].plot;
}
// I have no idea...
Post << ((c.first.bufnum)..(c.last.bufnum));
Env.new(((c.first.bufnum)..(c.last.bufnum)),[0.25],\step).plot;
// load violin wavetables into a var called c
c = Array.fill(14, {arg i;
var inst = "violin";
Buffer.read(s, ("~/Projects/sonic-pi/etc/wavetables/AKWF/AKWF_"++inst++"/AKWF_"++inst++"_"++((i+1).asStringToBase(10, 4))++".wav").standardizePath);
});
// Can be used to bring up Quarks (SuperCollider plugin system) menu
// Quarks.gui;
// This plays a sequence of buffers using the Duty Ugen
// watch out for the internally scoped var named b - it's not the same as the b above
({
Duty.ar((1.0/44100)/1.0, 0,
Dseq(c.collect { |b| Dbufrd(b , Dseries(0, 1, BufFrames.kr(b)), 1) } );
)
}.play);
c[17].plot;
// trying to play them with OscN using an envelope
// from what I recall the 73.5 here was to adjust in some way for the
// frequency change from 600 to 1024 sample above
Env.new(((c.first.bufnum-1)..(c.last.bufnum-1)),[0.2],\step).plot
(
{
OscN.ar(
EnvGen.ar(Env.new(((c.first.bufnum)..(c.last.bufnum)),[0.03401361],\linear), doneAction: 2),
73.5
);
}.play;
)
c.first.plot;
Dseries
{ Duty.ar(SampleDur.ir, 0, Demand.kr(Impulse.kr(73.5), 0, Dseries(c.first.bufnum,1,c.last.bufnum))) }.scope
play{BPF.ar(Mix(Pulse.ar(587.3*[1,1.5074]))*EnvGen.ar(Env([0,1,0.1,0],[0.0005, 0.015,0.283]),Impulse.ar(2)),2640,0.9)!2}
Buffer.allocConsecutive(8,s,1024,1,{|b,i|b.sine1Msg(1/(1..((i+1)*6)))},0);
{f=[50,75,99];VOsc3.ar(LFNoise1.kr(1/4,3,4),*f).lag(3e-3)!2}.play
a = {
var freq = LinExp.kr(SinOsc.kr(0.25), -1.0, 1.0, 50, 2000),
basefreq = 131, // base frequency of first buffer
numOctaves = 7,
numbufs = 8,
// note that subtraction of logs corresponds to division of original values
freqmap = ((log2(freq) - log2(basefreq)) * (numbufs / numOctaves))
.clip(0, numbufs - 1.001),
bufbase = b.first.bufnum;
VOsc3.ar(bufbase + freqmap, freq, freq * 0.997, freq * 1.003, mul: 0.1) ! 2
}.play;
a.free;
n = SoundFile.openRead("/Users/xriley/Downloads/AKWF_nes/AKSA_nes_noise.wav").duration*44100;
226800/600;
n = Buffer.read(s, "/Users/xriley/Downloads/AKWF_nes/AKSA_nes_noise.wav");
226800/600;
n.plot;
n.num
{ OscN.ar(n.bufnum, 73.5) }.play
{ Decimator.ar(LFTri.ar(120), bits: 4) }.plot;
~triangleAmps = { |topPartial = 20| [(1, 3 .. topPartial).reciprocal.squared * #[1, -1], 0].lace(topPartial) };
f = { |numbufs, server, numFrames, lowFreq, spectrumFunc|
numbufs = numbufs ? 8;
server = server ? Server.default;
numFrames = numFrames ? 2048;
// default is sawtooth
spectrumFunc = spectrumFunc ? { |numharm| (1..numharm).reciprocal };
lowFreq = lowFreq ? 131;
Buffer.allocConsecutive(numbufs, server, numFrames, 1, { |buf, i|
var numharm = (server.sampleRate * 0.5 / lowFreq).asInteger;
lowFreq = lowFreq * 2;
buf.sine1Msg(spectrumFunc.(numharm));
});
};
b = f.value(8, s, 2048, 131, ~triangleAmps);
a = {
var freq = 440, //LinExp.kr(SinOsc.kr(0.25), -1.0, 1.0, 50, 2000),
basefreq = 131, // base frequency of first buffer
numOctaves = 7,
numbufs = 8,
// note that subtraction of logs corresponds to division of original values
freqmap = ((log2(freq) - log2(basefreq)) * (numbufs / numOctaves))
.clip(0, numbufs - 1.001),
bufbase = b.first.bufnum;
VOsc.ar(bufbase + freqmap, freq, mul: 0.1) ! 2
}.scope;
{ Summer.ar(Impulse.ar(330), 1.0/7.5, -1, 1).fold(-0.99,0.99) }.scope;
{ OscN.ar([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0].linlin(0,15,-1,1).as(LocalBuf), 330) }.plot
FloatArray
// VOsc
[(0..15) * #[1, -1], 0].lace(15).plot;
{ PlayBuf.ar(1, n.bufnum, BufRateScale.kr(n.bufnum)*4, loop: 1) }.play;
OscN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment