//practical sound analysis - fredrik olofsson
//organized by lullcec 28-30oct 2011, hangar, barcelona
//--some online resources:
http://sccode.org/
http://sctweets.tumblr.com/
http://supercollider.sourceforge.net/sc140/
http://swiki.hfbk-hamburg.de:8888/MusicTechnology/899
mfcc http://en.wikipedia.org/wiki/Mel-frequency_cepstral_coefficient
mel scale http://en.wikipedia.org/wiki/Mel_scale
bark scale http://en.wikipedia.org/wiki/Bark_scale
//--
//--selected relevant classes/ugens in common:
Amplitude
Pitch
ZeroCrossing
Timer
PulseCount
Stepper
Peak
PeakFollower
RunningMin
RunningMax
RunningSum
Slope
Median
HPZ1
Latch
Schmidt
Trig1
FFT
FFT Overview
Loudness
SpecCentroid
SpecFlatness
SpecPcile
Onsets
BeatTrack
BeatTrack2
KeyTrack
MFCC
PV_HainsworthFoote
PV_JensenAndersen
//--a selection of relevant sc3-plugins:
//note: install sc3-plugins to access these
AtsFile
LPCFile
PVFile
Coyote
FrameCompare
TrigAvg
WAmp
AnalyseEvents2
AutoTrack
Concat
Cepstrum
CQ_Diff
Crest
FFTCrest
FFTDiffMags
FFTFlux
FFTPeak
FFTPhaseDev
FFTPower
FFTSlope
FFTSpread
FFTSubbandFlatness
FFTSubbandPower
Goertzel
MeanTriggered
MedianTriggered
OnsetsDS
PV_ExtractRepeat
PV_Whiten
SOMTrain
LPCAnalyzer
SMS
TPV
WalshHadamard
WaveletDaub
Qitch
Tartini
EnvDetect
EnvFollow
Max
SLOnset
//--selected 3rd party:
//note: download from the gives urls and install
//http://www.cogs.susx.ac.uk/users/nc81/code.html
SCMIR
Chromagram
FeatureSave
SensoryDissonance
DWT //wavelets
PolyPitch
//--addendum - raised questions
//--how to do automatic syntax colorize? (mac osx only)
//put this in startup.rtf file inside ~/User/Library/Application Support/SuperCollider and restart
//it will colorize the entire document each time the return key is pressed
Document.globalKeyDownAction= {|doc, char, bbb, ascii| if(ascii==13, {Document.current.syntaxColorize})}
//--what's that !?
//! is a shortcut for dup and means duplicate an object and creating arrays
7!2
7.dup(2)
5.3.dup(100)
4.dup(2)
4!2
//here 30 sine oscillators are created and spread over the stereo field
a= {Splay.ar({SinOsc.ar(Rand(400, 4000))}!30*0.1)}.play
a.free
Mix = mix to mono
Splay = spread over the stereo field
!2 = .dup(2) = duplicate any object
Pan2.ar(SinOsc.ar, 0) //take mono signal, pan in stereo -1 to 1
//--can sc output midi?
//here pitch is tracked and converted to nearest midinote value
a= {Pitch.kr(SoundIn.ar)[0].cpsmidi.round.poll; DC.ar(0)}.play
a.free
//this example will track pitch and output midi on the first available device. sendtrig is used to send the pitch data when it changes (hpz1) back to sclang. the oscresponder receives it and outputs midi notes
//make sure you have a midi device connected that can receive the noteOn messages
(
{
var pch= Pitch.kr(SoundIn.ar, minFreq: 90, maxFreq: 1000, median: 8);
var src= pch[0].cpsmidi.round;
SendTrig.kr(Trig.kr(HPZ1.kr(src).abs>0*pch[1], 0.1), 0, src); //send to oscresponder only when it changes and hasFreq flag is set. 0.1 is speedlimit to avoid doubletriggers
DC.ar(0); //silence
}.play;
MIDIClient.init;
n= MIDIOut(0, MIDIClient.destinations.at(0).uid);
o= OSCresponder(s.addr, \tr, {|t, r, m|
m.postln; //debug
n.noteOn(0, m[3], 70); //send noteOn directly
{n.noteOff(0, m[3])}.defer(0.1); //schedule a noteOff 0.1sec later
}).add;
)
//cmd+. to stop
//--how to do fft brickwall filters and track pitches in different frequency bands?
Server.default= Server.internal;
s.boot;
s.freqscope; //handy visualisation for testing this patch
//mouse x and y control min and max fft bins
(
SynthDef(\brick, {
var src, chain, buf;
buf= LocalBuf(2048); //window size - may change
src= WhiteNoise.ar(0.1);
chain= FFT(buf, src);
chain= PV_BrickWall(chain, MouseX.kr(0, 1).poll);
chain= PV_BrickWall(chain, MouseY.kr(0, -1).poll);
Out.ar(0, IFFT(chain)!2);
}).add;
)
u= Synth(\brick)
u.free
//brick fft filter with pitchtracking
//use patch above to find settings for min/max
(
SynthDef(\brickPitch, {|min= -0.7, max= 0.1, pan= 0, amp= 0.2|
var src, chain, buf, filtered, pch;
buf= LocalBuf(2048); //window size - may change
src= SoundIn.ar; //mic input
chain= FFT(buf, src);
chain= PV_BrickWall(chain, max);
chain= PV_BrickWall(chain, min);
filtered= IFFT(chain);
pch= Pitch.kr(filtered);
pch.poll;
Out.ar(0, Pan2.ar(SinOsc.ar(pch[0], 0, amp*pch[1].lag(0.05)), pan));
}).add;
)
a= Synth(\brickPitch, [\max, 0.11, \min, 0]); //roughly 2khz and up
b= Synth(\brickPitch, [\max, 0.015, \min, -0.95]); //roughly 350hz to 1.1khz
c= Synth(\brickPitch, [\max, 0, \min, -0.99]); //roughly 250hz and down
a.free
b.free
c.free
//try running the three of them at the same time
//how to play sound in many channels?
s.meter
a= {PanAz.ar(8, WhiteNoise.ar(0.1), MouseX.kr(-1, 1))}.play
a.free
//how to skip over arguments?
//use keywords - here we leave the second argument (mix) to its default
{FreeVerb.ar(SoundIn.ar, room:0.7)}.play