Created
November 13, 2017 08:20
-
-
Save xavriley/ce1becd7f2d97d93aced74e88ae7ba54 to your computer and use it in GitHub Desktop.
SuperCollider wavetable experiments for Sonic Pi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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