// this example uses the ConstQ class of Eisenkraut

// to get a logarithmic spectrum of some soundfile.

// i just included it to not loose the code ;-3

// but it's very slow due to the array mangling

// between swingOSC and sclang.


(

~path = "sounds/a11wlk01.wav".absolutePath; // "/Users/rutz/Desktop/FactoryHallWetCut.aif";

~stepSize = 1024;

~minFreq = 50.0;

~maxFreq = 16000.0;

~bandsPerOct = 24; // 12;

)


g.reboot;

// note: change the following URL according to your Eisenkraut installation.

// you need SVN revision 140 or newer!

g.addClasses( "file:///Users/rutz/Documents/workspace/Eisenkraut/Eisenkraut.jar" );


(

~sf = SoundFile.openRead( ~path );

~constQ = JavaObject( "de.sciss.eisenkraut.math.ConstQ" );

~constQ.setSampleRate( ~sf.sampleRate );

~constQ.setMinFreq( ~minFreq );

~constQ.setMaxFreq( ~maxFreq );

//~constQ.setMaxTimeRes( 4.0 );

~constQ.setBandsPerOct( ~bandsPerOct );

~constQ.createKernels;


// (

fork {

~fftSize = ~constQ.getFFTSize_; ~numKernels = ~constQ.getNumKernels_;

~numSteps = (~sf.numFrames - (~fftSize - ~stepSize)).div( ~stepSize );

~coeffs = nil ! ~numSteps;

[ ~fftSize, ~numKernels ].postln;

~numSteps.do({ arg step;

~sf.seek( ~stepSize * step );

~inBuf = FloatArray.newClear( ~fftSize );

~sf.readData( ~inBuf );

~fBuf = ~constQ.castToFloatArray__( ~inBuf );

~outBuf = ~constQ.transform__( ~fBuf, 0, ~fftSize, nil, 0 );

~coeffs[ step ] = Array.fill( ~numKernels, { arg i; ~constQ.getArrayElement_( ~outBuf, i )});

~fBuf.destroy;

~outBuf.destroy;

(((step+1)/~numSteps) * 100).asInteger.postln;

0.yield;

});

"Done.".postln;

~sf.close;

};

// )

)


// the frequencies are static

~freqs = Array.fill( ~numKernels, { arg k; ~minFreq * pow( 2, k / ~bandsPerOct )});


s.boot;


// use a bank of fast sine oscillators for reproducation

~osciClass = SinOsc;

//~osciClass = FSinOsc;

//~osciClass = LFSaw;

//~osciClass = LFTri;

x = { arg amp = 50; var amps = LagControl.names( \amps ).kr( Array.fill( ~numKernels, 0 ), Array.fill( ~numKernels, 0.1 )); Mix( ~osciClass.ar( ~freqs, 0, amps )) * amp }.play;


// let's go through the sonogram

(

fork {

~coeffs.do({ arg frame, i;

x.setn( \amps, frame );

(((frame+1)/~coeffs.size) * 100).asInteger.postln;

0.05.wait;

});

}

)


x.free;


// filtered noise? warning: needs lots of CPU

x = { arg amp = 50; var amps = LagControl.names( \amps ).kr( Array.fill( ~numKernels, 0 ), Array.fill( ~numKernels, 0.1 )); Mix( Resonz.ar( WhiteNoise.ar( amps ), ~freqs, 0.02 )) * amp }.play;


// backwards

(

fork {

~coeffs.reverseDo({ arg frame, i;

x.setn( \amps, frame );

(((frame+1)/~coeffs.size) * 100).asInteger.postln;

0.04.wait;

});

}

)


x.free;


//////////////////////////////

~logCoeffs = ~coeffs.collect({ arg frame; frame.collect(_.ampdb)});


//GUI.swing;

// headMap Quark required!

// warning: very slow, so we limit the number of frames shown!

~logCoeffs.keep( 50 ).heatMap( showVals: false, colscheme: \coals );