Created
May 8, 2020 12:37
-
-
Save andres-fr/2f117d17380e2701bc1bea78c5b3ec43 to your computer and use it in GitHub Desktop.
ALMAT 2017 SuperCollider script
This file contains 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
(//server config and start | |
Server.default = s; // = Server.internal; | |
s.options.memSize = 1500*1024;// up to 1500MB RAM allocable | |
s.reboot; | |
//s.quit; | |
) | |
( | |
//s.volume.gui; | |
//s.plotTree; | |
//s.meter; | |
//s.plotTree; | |
{SinOsc.ar([440, 500,],0,[0.2,0.2])}.play; | |
//{ SoundIn.ar([0, 1]) }.play; | |
) | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
/// GLOBALS | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
( // addresses | |
~working_dir = "/home/afr/IMPULS/WORKSPACE/"; // File.getcwd++ | |
~audio_dir = ~working_dir++"AUDIO/"; | |
~wav2wav = ~working_dir++"wav2wav_v3"; | |
) | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
/// INTERACTION WITH WAV2WAV (CLIENT SIDE) | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// EXAMPLE OF COMPILING PROGRAM | |
// g++ -O4 -std=c++14 -Wall -Wextra -pedantic MAIN.cpp doublesignal.cpp crosscorrelator.cpp freefunctions.cpp inputparser.cpp -o MAIN -lsndfile -lalglib | |
// EXAMPLE OF GENERATING CCS | |
// ./MAIN -a preprocess -s /home/afr/IMPULS/WORKSPACE/AUDIO/child-short.wav -m /home/afr/IMPULS/WORKSPACE/AUDIO/anvil[0].wav /home/afr/IMPULS/WORKSPACE/AUDIO/anvil[100].wav /home/afr/IMPULS/WORKSPACE/AUDIO/anvil[-100].wav -r 60 -p /home/afr/IMPULS/WORKSPACE/test_child | |
// EXAMPLE OF GENERATING D-LIST | |
// ./MAIN -a generate_list -p /home/afr/IMPULS/WORKSPACE/test_child -i 300 | |
// EXAMPLE OF GENERATING WAV | |
// ./MAIN -a generate_wav -p /home/afr/IMPULS/WORKSPACE/test_child -d reconstruction_300iterations_60ratio.txt | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// ~preprocessCMD.(~audio_dir++"child-short.wav", [~audio_dir++"anvil[0].wav",~audio_dir++"anvil[100].wav",~audio_dir++"anvil[-100].wav"], 60, ~working_dir++"test_child").unixCmd | |
// ~generate_listCMD.(~working_dir++"test_child", 300).unixCmd | |
// ~generate_wavCMD.(~working_dir++"test_child", 300, 60).unixCmd; | |
// ~playReconstruction.(~working_dir++"test_child", 300, 60); | |
//~processGenerateAndPlay.(~audio_dir++"child-short.wav", ((-20..20)*4).collect{|x| ~audio_dir++"anvil["++x++"].wav"}, 20, 400, ~working_dir++"asdf"); | |
//~generateAndPlay.(20, 1000, ~working_dir++"asdf"); | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
( | |
//1) generate the analysis files | |
~preprocessCMD = {|origPath, matPathsList, downRatio, projectPath| var matPaths; | |
matPathsList.do{|name| matPaths = matPaths ++ name ++ " "}; | |
~wav2wav++" -a preprocess -s "++origPath++" -m "++matPaths++"-r "++downRatio++" -p "++projectPath; | |
}; | |
//2) calculate an optimized reconstruction and save as a .txt list | |
~generate_listCMD = {|projectPath, iterations| | |
~wav2wav++" -a generate_list -p "++projectPath++" -i "++iterations; | |
}; | |
//3) generate the .wav file from the list | |
~reconstruction_name = {|iter, downSamp| | |
"reconstruction_" ++ iter ++ "iterations_" ++ downSamp ++ "ratio.txt"; | |
}; | |
~generate_wavCMD = {|projectPath, iterations, ratio| | |
~wav2wav++" -a generate_wav -p "++projectPath++" -d "++~reconstruction_name.(iterations, ratio); | |
}; | |
//4) play the .wav file in the project folder | |
~playReconstruction = {|projectPath, iterations, ratio| | |
Buffer.read(s, projectPath++"/"++~reconstruction_name.(iterations, ratio)++".wav",action:{ | |
|buf| {PlayBuf.ar(buf.numChannels, buf, doneAction:2)}.play}); | |
}; | |
// 5) all together as a convenient callback chain (asynchronous: doesn't stop other processes, done ASAP) | |
~generateAndPlay = {|downRatio, iterations, projectPath| | |
~generate_listCMD.(projectPath, iterations).unixCmd{|res, pid| | |
"test1".postln; | |
if(res==0){~generate_wavCMD.(projectPath, iterations, downRatio).unixCmd{|res, pid| | |
"test2".postln; | |
if(res==0){"test3".postln; ~playReconstruction.(projectPath, iterations, downRatio); | |
}}} | |
} | |
}; | |
~processGenerateAndPlay = {|origPath, matPathsList, downRatio, iterations, projectPath| | |
~preprocessCMD.(origPath, matPathsList, downRatio, projectPath).unixCmd{|res, pid| | |
if(res==0){~generateAndPlay.(downRatio, iterations,projectPath)} | |
} | |
}; | |
) | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
/// INTERACTION WITH DB (CLIENT SIDE) | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
~osc2wav.(~bufCirc,~bufLin,0,4*44100); | |
~materials | |
0.do{|x| x.postln;} | |
( | |
~tBuf = Buffer.alloc(s, 20*44100); | |
~windowMat = (0..(0.5*44100)).collect{|x| (x*2pi/(3*4410)).cos*(-0.5)+0.5**0.1}; | |
~originals = List.new; | |
~materials = List.new; | |
~osc2wav = {|circBuf, linBuf, firstIdx, lastIdx| | |
var numFrames, linbuf,linsig, offset, filename, tbuf; | |
if(lastIdx<firstIdx){ | |
var chunk1length = circBuf.numFrames-firstIdx; | |
var chunk2length = lastIdx; | |
circBuf.copyData(linBuf, 0, firstIdx, chunk1length); | |
circBuf.copyData(linBuf, chunk1length, 0, chunk2length); | |
linbuf = linBuf; | |
offset = 0; | |
numFrames = chunk1length+chunk2length; | |
}{ | |
linbuf = circBuf; | |
offset = firstIdx; | |
numFrames = lastIdx-firstIdx; | |
}; | |
filename = ~working_dir++Main.elapsedTime.asString.replace(".", "_"); | |
linbuf.loadToFloatArray(action:{|arr| | |
var numMats=2; | |
linsig = arr.as(Signal); | |
numMats.do{|x| var tmpLst, mName; | |
fork{ | |
mName = filename++"_mat"++x++".wav"; | |
~materials.add(mName); | |
tmpLst = ~windowMat.collect{|y,i| y*arr[x*(numFrames/numMats)+i]}; | |
~tBuf.loadCollection(tmpLst, 1, action:{|buf| | |
buf.write(mName, "wav", startFrame:1, numFrames:~windowMat.size-1) | |
}); | |
}; | |
s.sync; | |
} | |
}); | |
linbuf.write(filename++".wav", "wav", startFrame:offset, numFrames:numFrames); | |
~originals.add(filename++".wav"); | |
}; | |
~doSomething = { | |
if((~originals.size>1) && (~materials.size>1)){ | |
~processGenerateAndPlay.(~originals[0], ~materials[0..0], 1, 100, ~working_dir++"asdf"); | |
"did something".postln; | |
~originals = ~originals[1..]; | |
~materials = ~materials[1..]; | |
} | |
}; | |
) | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
/// INPUT+FEATURE EXTRACTOR (SERVER SIDE) | |
/// BLOB DETECTOR BY HANNS HOLGER RUTZ | |
///////////////////////////////////////////////////////////////////////////////////////////////////// | |
( | |
~bufDur = 20.0; // total circular buf duration in seconds | |
~minBlobDur = 0.7; // in seconds | |
~maxBlobDur = ~bufDur; // maximum blob duration in seconds | |
~minBlobIntegral = 1; | |
~sr = 44100; // sample rate in Hz | |
~lowThresh = -90.dbamp; // lower envelope threshold | |
~highThresh = -75.dbamp; // upper envelope threshold | |
~bufCircFrames = (~bufDur * ~sr).asInteger; | |
~bufLinFrames = (~maxBlobDur * ~sr).asInteger; | |
~bufCirc = Buffer.alloc(s, ~bufCircFrames); | |
~bufLin = Buffer.alloc(s, ~bufLinFrames); | |
~debugBus = Bus.audio(s, 6); | |
~kBus = Bus.control(s,1); | |
// helper function for UGen comparison | |
~is = { arg a, b; BinaryOpUGen('==', a, b) }; | |
~isNot = { arg a, b; BinaryOpUGen('!=', a, b) }; | |
) | |
( | |
~analysis = play { | |
var buf, bufFrames, in, phase, phaseK, state, env, startFrame, | |
cond1, gate1, cond2, cond3, cond4, condSend, | |
elapsed, values, isLow, isNotLow, isHigh, debug, condBackTo1, envIntegral, hasEnergy; | |
#state, startFrame = LocalIn.kr(numChannels: 2); | |
debug = \debug.kr; | |
buf = ~bufCirc.bufnum; | |
bufFrames = BufFrames.kr(buf); | |
in = SoundIn.ar; | |
phase = Phasor.ar(rate: 1, start: 0, end: bufFrames); | |
phaseK = A2K.kr(phase); | |
BufWr.ar(in, buf, phase); | |
env = Lag.ar(in.squared, 0.05); | |
env = Compander.ar(env, env, 1, 1, 0.5, 0.01, 0.01); | |
env = A2K.kr(env); | |
isLow = env < ~lowThresh; | |
isNotLow = env >= ~lowThresh; | |
isHigh = env > ~highThresh; | |
envIntegral= Integrator.kr(env, 1-isLow); | |
hasEnergy = envIntegral >= ~minBlobIntegral; | |
cond1 = ~is.(state, 0) & isLow; // transition to state 1 | |
cond2 = ~is.(state, 1) & isNotLow; // transition to state 2 | |
cond3 = ~is.(state, 2) & isHigh; // transition to state 3 | |
cond4 = ~is.(state, 3) & isLow; // transition to state 0 | |
condBackTo1 = ~is.(state, 2) & isLow; | |
env.ampdb.poll(Impulse.kr(4) & debug, "env"); | |
elapsed = Sweep.kr(trig: cond2, rate: 1); | |
condSend = cond4 & (elapsed > ~minBlobDur) & (elapsed < ~maxBlobDur) & hasEnergy; | |
/////// PATCH FOR INSTALLATION: ADDING EXTRA CONDITION | |
condSend = condSend;// & LFPulse.kr(1/(59*2)); // 59 secs on, 59 off | |
/////// | |
values = [startFrame, phaseK]; | |
SendReply.kr(condSend, cmdName: '/blob', values: values); | |
values.poll(condSend & debug, "send"); | |
state = (state + (cond1 | cond2 | cond3 | cond4)) % 4; | |
state = condBackTo1 + (condBackTo1.not * state); | |
startFrame = Latch.kr(phaseK, cond2); | |
LocalOut.kr([state, startFrame]); | |
hasEnergy.poll(hasEnergy & debug, "send"); | |
Out.kr(~kBus, condSend); | |
/* | |
cond1.poll(cond1 & debug, "state 0"); | |
cond2.poll(cond2 & debug, "state 1"); | |
cond3.poll(cond3 & debug, "state 2"); | |
cond4.poll(cond4 & debug, "state 3"); | |
condBackTo1.poll(condBackTo1 & debug, "reset 1");*/ | |
}; | |
) | |
(// for debugging | |
~analysis.set(\debug, 1); | |
//~debugBus.scope | |
) | |
~kBus.scope | |
( | |
// restart lists | |
~originals = List.new; | |
~materials = List.new; | |
// listener | |
~listen = OSCFunc(path:'/blob', func:{|msg| | |
msg.postln; | |
~osc2wav.(~bufCirc, ~bufLin, msg[3], msg[4]); | |
~doSomething.(); | |
}); | |
) | |
// create test send | |
( | |
play { | |
Out.ar(NumOutputBuses.ir, WhiteNoise.ar(Line.ar(0, 2, 2, doneAction: 2))) | |
}; | |
) | |
// stop | |
( | |
~analysis.free; | |
~listen.free; | |
) | |
s.meter | |
~originals; | |
~originals.size | |
~materials.size | |
~processGenerateAndPlay.(~originals[0], ~materials[1..1], 1, 100, ~working_dir++"asdf"); | |
~doSomething.() | |
// | |
// ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// /// INPUT+FEATURE EXTRACTOR (SERVER SIDE) | |
// ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// ( | |
// ~circularBuf = Buffer.alloc(s, 5*44100); | |
// ~linearBuf = Buffer.alloc(s, ~circularBuf.numFrames); | |
// ~debugBus = Bus.audio(s, 6); | |
// ~bus1 = Bus.audio(s,1); // also for debugging | |
// ) | |
// | |
// ( | |
// SynthDef("test",{ |bufId, noiseGate=0.1, debug=1| var blobBoundary, lastBlobBoundary, blobIntegral, suitableOriginal, suitableMaterial, lastIdx, newIdx, elapsedSamples, in, env, phasor, buf, sig, cond1, cond2, cond3, cond4, cond5, cond6, cond7, entropy; | |
// #blobBoundary, lastIdx = LocalIn.ar(2); | |
// elapsedSamples = Integrator.ar(DC.ar(1), 1-blobBoundary); | |
// //in = WhiteNoise.ar*(SinOsc.ar(0.5)**2)*debug; | |
// in = WhiteNoise.ar(LFNoise1.ar(3).pow(2))*1;//.pow(2)*1; // noise blob generator; | |
// phasor = Phasor.ar(end:BufFrames.kr(bufId)); | |
// newIdx = phasor; | |
// buf = BufWr.ar(in, bufnum:bufId, phase:phasor); | |
// env = LagUD.ar(in.abs, lagTimeU:0.02, lagTimeD:0.1); // env follower | |
// cond1 = env < 0.1; // if envelope is low | |
// cond2 = DC.ar(1);//HPZ1.ar(env) < 0.2; // if derivative of envelope is low | |
// blobIntegral = Integrator.ar(env, 1-blobBoundary); | |
// cond3 = blobIntegral/44100 > 0.1; // if blob has enough surface | |
// blobBoundary = cond1&cond2&cond3; // if (cond1 ... ): | |
// lastBlobBoundary = (elapsedSamples>=1)&(elapsedSamples<=1); //****** ): | |
// // calculate entropy | |
// entropy = -1*env/blobIntegral* Integrator.ar((env/blobIntegral).log2, 1-blobBoundary); | |
// // conditions for original | |
// cond4 = elapsedSamples>=1000 & elapsedSamples<44100; // suitable size | |
// cond5 = DC.ar(1);//entropy < 0.5; // suitable entropy | |
// suitableOriginal = cond4&cond5; | |
// // conditions for material | |
// cond6 = elapsedSamples>=44100 & elapsedSamples<BufFrames.kr(bufId); // suitable size | |
// cond7 = DC.ar(1);// entropy >= 0.5; // suitable entropy | |
// suitableMaterial = cond6&cond7; | |
// | |
// Out.ar(~debugBus.index, in); // send to a global bus, and then ~debugBus1.scope | |
// Out.ar(~debugBus.index+1, cond1); | |
// Out.ar(~debugBus.index+2, cond2); | |
// Out.ar(~debugBus.index+3, cond3); | |
// Out.ar(~debugBus.index+4, elapsedSamples/44100); | |
// Out.ar(~debugBus.index+5, phasor); | |
// Out.ar(0, in); | |
// | |
// // //entropy.poll(10, "entropy"); | |
// //elapsedSamples.poll(10, "elapsedSamples"); | |
// Out.ar(~bus1, elapsedSamples/44100); | |
// | |
// // send accepted blobs | |
// SendReply.ar(blobBoundary&suitableOriginal, '/original', [lastIdx, newIdx, entropy]); | |
// SendReply.ar(blobBoundary&suitableMaterial, '/material', [lastIdx, newIdx, entropy]); | |
// // reinitialize blob | |
// lastIdx = Latch.ar(newIdx, blobBoundary); | |
// LocalOut.ar([blobBoundary, lastIdx]); | |
// }).add; | |
// ) | |
// | |
// | |
// ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// /// INTERACTION WITH DB (CLIENT SIDE) | |
// ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// | |
// ( | |
// l = List.new; | |
// ~wavPath = {}; | |
// | |
// ~osc2wav = {|firstIdx, lastIdx| var numFrames, linbuf, offset, filename; | |
// if(lastIdx<firstIdx){ | |
// var chunk1length = ~circularBuf.numFrames-firstIdx; | |
// var chunk2length = lastIdx; | |
// ~circularBuf.copyData(~linearBuf, 0, firstIdx, chunk1length); | |
// ~circularBuf.copyData(~linearBuf, chunk1length, 0, chunk2length); | |
// linbuf = ~linearBuf; | |
// offset = 0; | |
// numFrames = chunk1length+chunk2length; | |
// }{ | |
// linbuf = ~circularBuf; | |
// offset = firstIdx; | |
// numFrames = lastIdx-firstIdx; | |
// }; | |
// filename = ~working_dir++Main.elapsedTime.asString.replace(".", "_") ++".wav"; | |
// l.add(filename); | |
// linbuf.write(filename, "wav", startFrame:offset, numFrames:numFrames); | |
// }; | |
// | |
// ~doSomething = {var orig, materials, project_name, sampledown_ratio, iterations, cmd; | |
// l.size.postln; | |
// ~counter = ~counter+1; | |
// if (~counter%8==0){ | |
// // take samples from list | |
// ~generateAndPlay.(l.pop, l[0..4], 20, 200, ~working_dir++counter); | |
// l = l[5..]; | |
// } | |
// }; | |
// | |
// ) | |
// | |
// | |
// | |
// 4294934096.asHexString | |
// (0xFFFFFFFF-0xFFFF7E50) | |
// | |
// ~generate_listCMD.("almat_test_1", 600).unixCmd | |
// | |
// ~preprocessCMD.(l.pop, l[0..4], 20, "almat_test_1").unixCmd | |
// | |
// ~preprocessCMD.("child-short.wav", ["anvil[0].wav","anvil[100].wav","anvil[-100].wav"], 60, "test_child").unixCmd{|res, pid| res.postln}; | |
// | |
// "/home/afr/IMPULS/WORKSPACE/wav2wav_v1 -a preprocess -s /home/afr/IMPULS/WORKSPACE/1487262003_8116.wav -m /home/afr/IMPULS/WORKSPACE/1487261999_0974.wav /home/afr/IMPULS/WORKSPACE/1487262000_2124.wav /home/afr/IMPULS/WORKSPACE/1487262001_3504.wav /home/afr/IMPULS/WORKSPACE/1487262002_5808.wav /home/afr/IMPULS/WORKSPACE/1487262002_581.wav -r 20 -p almat_test_1".unixCmd | |
// | |
// ( | |
// ~counter = 0; | |
// // start the feature extractor! | |
// x= Synth("test", [\bufId, ~circularBuf.bufnum]); | |
// p= OSCFunc({|msg| | |
// fork { | |
// ~osc2wav.(msg[3], msg[4]); | |
// s.sync; | |
// ~doSomething.(); | |
// }; | |
// }, '/original'); | |
// ) | |
// | |
// | |
// ~circularBuf.play | |
// | |
// ~debugBus.scope; | |
// ~bus1.scope; | |
// | |
// x.set(\noiseGate,0.1, \debug, 0); | |
// | |
// x= Synth("test", [\bufId, ~circularBuf.bufnum]); | |
// o= OSCFunc({|msg| msg.postln}, '/asdf'); | |
// | |
// 1 | |
// o.() | |
// | |
// Timer | |
// Integrator | |
// | |
// | |
// | |
// x={SoundIn.ar*2}.play | |
// | |
// {SinOsc.ar*1}.play | |
// | |
// | |
// LagUD | |
// Z1 | |
// Abs | |
// | |
// LagUD // env. follower | |
// OneZero // derivative | |
// | |
// Latch // memory cell (integers as states | |
// Gate | |
// ToggleFF | |
// SetResetFF | |
// Schmidt // thresholding (higher & lower) | |
// | |
// RecordBuf // easier but buf position has to becalculatedout of sync? | |
// | |
// BufWr // controlled by a phasor, info is there | |
// | |
// | |
// ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// /// CLASSIFIER (CLIENT SIDE) | |
// ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
// | |
// ( | |
// ~bufEntropy = {|bufId| var x; | |
// [1,2,a]; | |
// }; | |
// ~test.(10); | |
// ) | |
// | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment