Skip to content

Instantly share code, notes, and snippets.

@andres-fr
Created May 8, 2020 12:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andres-fr/2f117d17380e2701bc1bea78c5b3ec43 to your computer and use it in GitHub Desktop.
Save andres-fr/2f117d17380e2701bc1bea78c5b3ec43 to your computer and use it in GitHub Desktop.
ALMAT 2017 SuperCollider script
(//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