A chromagram, measuring the energy at particular chroma within an nTET tuning system.
Possible extension: TODO: Could have arbitrary tuning systems if precalculated the exact fft bin + interpolation data.
fft |
input fft chain, that is, from an FFT UGen |
fftsize |
FFT size, required for initialisation |
n |
Equal divisions of an octave, e.g. n=12 is 12TET, 12 steps in an octave |
tuningbase |
Base frequency or tuning; will correspong to index 0 in results (conventionally, this would be a 'C' in 12TET, but its an arbitrary reference) |
octaves |
Number of octaves considered from tuning base up |
integrationflag |
Whether to integrate from frame to frame, off by default |
coeff |
Coefficient of integration |
octaveratio |
Default of 2 is a 'normal' octave; other ratios are possible, e.g. Bohlen-Pierce scale uses 13 equal divisions over the ratio of 3 for a 'tritave' |
perframenormalize |
Defaults to off, but if set to 1 will normalize each frame with respect to itself (as long as there is non-negligible power), potentially providing a more robust measure for comparison between frames (each frame will have then a normalized distribution over chroma, independent of volume) |
( { var in, fft, chroma; //in = SinOsc.ar(440,0,0.1); in= SoundIn.ar; fft = FFT(LocalBuf(2048), in); chroma=Chromagram.kr(fft); chroma.poll; Out.ar(0,Pan2.ar(in)); }.play ) //n TET display n= 12; //19, 24 ( x = { var in, fft, chroma; //in = SinOsc.ar(440,0,0.1); in= SoundIn.ar; fft = FFT(LocalBuf(2048), in); chroma=Chromagram.kr(fft, 2048, n); //chroma=Chromagram.kr(fft, 2048, n, 36.midicps, 7, 1, 0.9); Out.kr(0,chroma); }.play; c= Bus.new('control', 0, n); ) //poll coefficients snapshot c.getn(n,{arg val; {val.plot;}.defer}); //Continuous graphical display of Chromagram values; free routine before closing window ( var ms; w=Window.new((n.asString)++" chroma coefficients", Rect(200,400,n*20+50,300)); ms= MultiSliderView.new(w, Rect(10,10,n*20,280)); ms.value_(Array.fill(n,0.0)); ms.valueThumbSize_(20.0); ms.indexThumbSize_(20.0); ms.gap_(0); w.front; r= { inf.do{ c.getn(n,{arg val; {ms.value_(val)}.defer}); 0.04.wait; //25 frames per second }; }.fork; w.onClose = { r.stop; c.free; x.free; }; ) b.free; //Bohlen-Pierce over 3 tritaves, normalized results per frame ( { var in, fft, chroma; //in = SinOsc.ar(440,0,0.1); in= SoundIn.ar; fft = FFT(LocalBuf(2048), in); chroma=Chromagram.kr(fft,2048,13,octaves:3,octaveratio:3,perframenormalize:1); chroma.poll; Out.ar(0,Pan2.ar(in)); }.play )