//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