Discussion:
Plotter in editMode with specific domainSpecs
christophe lengelé
2014-10-08 14:44:45 UTC
Permalink
Hello,

By trying to build a spectral filter with GUI, I've found a problem with Plotter,
by specifying e.g. an exponential domainSpecs (\freq.asSpec) and trying to edit the values :

a = (0..200).scramble.plot;
a.editMode_(true);
a.domainSpecs = \freq.asSpec; a.refresh; // the edition does not match with the representation

Below is the spectral filter code with GUI reworked, coming from an example of a previous post :
http://new-supercollider-mailing-lists-forums-use-these.2681727.n2.nabble.com/Choosing-specific-FFT-bins-td5423719.html#a5424690

How to get an exponential representation (and correct edition) of domainSpecs with \freq.asSpec instead of linear bin representation ?


Thanks for the help,
Christophe

(
var w, loader;
s = Server.local;
~fftsize = 1024; // FFTsize containing for each bin -> magnitude and phase
~nbOfBins = ~fftsize / 2;

loader = {

SynthDef(\fftEQ, { arg out=0, fftsize= ~fftsize, bufnum=1;
var in, filtered, chain;
in = WhiteNoise.ar(0.3);
chain = FFT(LocalBuf(fftsize), in);
filtered = PV_MagMul(chain, bufnum);
Out.ar(out, Pan2.ar(IFFT(filtered), 0.0));
}).add;

~eqbuf = Buffer.alloc(s, ~fftsize, 1);
~eqBufValues = 0 ! ~fftsize; // initialize FFT buffer values
~eqbuf.loadCollection(~eqBufValues); // initialize FFT-buffer
~magValues = 0 ! ~nbOfBins; // // initialize magnitude values

s.sync;

~binResolution = (s.sampleRate / ~fftsize).postln;

w = Window("SpecEQ", Rect(200, 450, 10+(~nbOfBins), 250), false).alwaysOnTop_(true).front;
w.view.decorator = FlowLayout(w.view.bounds);

// Plotter
~plotterView = Plotter("FFT Filtering", Rect(0, 0, (~nbOfBins), 180), w)
.value_(~magValues)
.editMode_(true)
.resolution_(0.1)
.plotMode_(\levels)
.specs_([0, 1, \lin, 0.001 ].asSpec)
// .domainSpecs_(\freq.asSpec);
.editFunc = { |plotter, plotIndex, i, val|
("Bin index: "++ i ++" --- from "++ (~binResolution * i).asInt ++ " to " ++ (~binResolution * i + i).asInt ++ " Hz ::: "++ val).postln;
~magValues[i] = val;
~eqBufValues = [~magValues, (0 ! (~nbOfBins))].flop.flat;
~eqbuf.setn(0, ~eqBufValues);
// ~eqbuf.set(i * 2, val); // why set is not sufficient and compulsory to use setn to act "correctly" ?
};

// Clear button
~eqClearView = Button(w, Rect(200, 220, 50, 20));
~eqClearView.states = [["clear", Color.black, Color.grey]];
~eqClearView.action = {
~magValues = 0 ! ~nbOfBins;
~plotterView.value_(~magValues);
~plotterView.specs_([0, 1, \lin, 0.001 ].asSpec);
~eqBufValues = 0 ! ~fftsize;
~eqbuf.loadCollection(~eqBufValues);
};
StaticText(w,***@20).string_("FFT bins--->");

// start synth
~syn = Synth(\fftEQ, [\out, 0, \fftsize, ~fftsize, \bufnum, ~eqbuf.bufnum ]);
~syn.run(true);

w.onClose = { ~syn.free; ~eqbuf.free };

};

// load the whole thing, when server booted
s.waitForBoot(loader);

)

~plotterView.domainSpecs = \freq.asSpec; ~plotterView.refresh;
~plotterView.domainSpecs = [0, 511, 'linear', 1, 0, ""].asSpec; ~plotterView.refresh;
Daniel Mayer
2014-10-08 15:19:57 UTC
Permalink
Hi,

haven't checked your code,
but with exp mode never start from zero -

Greetings

Daniel

-----------------------------
www.daniel-mayer.at
-----------------------------


_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/
christophe lengelé
2014-10-08 17:11:25 UTC
Permalink
haven't checked your code, but with exp mode never start from zero -
Thanks, Daniel,
That's right,
But I can't find a way to represent visually and act consistently with domainSpecs in an exponential way (that does not generate errors), with the previous code.
Maybe Plotter is not appropriate for that.
Maybe someone has a solution for a GUI that can act on each FFT bin (what the code does) but get a visual representation of frequencies (or the size of each bin slider) in an exponential way and not in a linear "bin" way ?
Hope it is clear,
Many thanks,
Christophe
christophe lengelé
2014-10-08 17:34:49 UTC
Permalink
By trying the example in Plotter for domainSpecs and setting the editMode to true,
you can see the problem of "mismatch" and error generated :

a = { (40..300).scramble }.dup(2).plot;
a.domainSpecs = \freq.asSpec; a.refresh;
a.editMode_(true);

Thanks,
Christophe
haven't checked your code, but with exp mode never start from zero -
Thanks, Daniel,
That's right,
But I can't find a way to represent visually and act consistently with domainSpecs in an exponential way (that does not generate errors), with the previous code.
Maybe Plotter is not appropriate for that.
Maybe someone has a solution for a GUI that can act on each FFT bin (what the code does) but get a visual representation of frequencies (or the size of each bin slider) in an exponential way and not in a linear "bin" way ?
Hope it is clear,
Many thanks,
Christophe
christophe lengelé
2014-10-09 12:15:17 UTC
Permalink
I corrected the spectral EQ below with Plotter.
I had done a stupid mistake. Now, the freq bins are placed on a "more log" scale.
But, still a problem with the gridline on the frequency axis that does not correspond with the domainSpec.

Does someone know how to correct the horizontal gridline ?
You can see the issue of frequency scale that is linear with the line below :
DrawGrid.test( \freq.asSpec.grid, \amp.asSpec.grid );


Any tip to improve the spectral EQ appreciated.
The ability to see the spectrum in the background with FreqScope would be great,

but I'm far to achieve that and it might be too CPU expensive.

Thanks,
Christophe

(
var w, loader;
s = Server.local;
~fftsize = 1024; // FFTsize containing for each bin -> magnitude and phase
~nbOfBins = ~fftsize / 2;

~plotterViewDomainSpecs = ControlSpec(0.1, 511, 6, 0.1, 0, "");

loader = {

SynthDef(\fftEQ, { arg out=0, fftsize= ~fftsize, bufnum=1;
var in, filtered, chain;
in = WhiteNoise.ar(0.3);
chain = FFT(LocalBuf(fftsize), in);
filtered = PV_MagMul(chain, bufnum);
Out.ar(out, Pan2.ar(IFFT(filtered), 0.0));
}).add;

~eqbuf = Buffer.alloc(s, ~fftsize, 1);
~eqBufValues = 0 ! ~fftsize; // initialize FFT buffer values
~eqbuf.loadCollection(~eqBufValues); // initialize FFT-buffer
~magValues = 0 ! ~nbOfBins; // // initialize magnitude values

s.sync;

~binResolution = (s.sampleRate / ~fftsize).postln;

w = Window("FFT EQ", Rect(200, 450, 10+(~nbOfBins), 250), false).alwaysOnTop_(true).front;
w.view.decorator = FlowLayout(w.view.bounds);

// Plotter
~plotterView = Plotter("FFT Filtering", Rect(0, 0, (~nbOfBins), 180), w)
.value_(~magValues)
.editMode_(true)
.resolution_(0.1)
//.plotMode_(\levels)
//.plotMode_(\plines)
.plotMode_(\steps)
.specs_([0, 1, \lin, 0.01 ].asSpec)
.domainSpecs_(~plotterViewDomainSpecs)
.editFunc = { |plotter, plotIndex, i, val|
("Bin index: "++ i ++" --- from "++ (~binResolution * i).asInt ++ " to " ++ (~binResolution * i + ~binResolution).asInt ++ " Hz ::: "++ val).postln;
~magValues[i] = val;
~eqBufValues = [~magValues, (0 ! (~nbOfBins))].flop.flat;
~eqbuf.setn(0, ~eqBufValues);
// ~eqbuf.set(i * 2, val); // why set is not sufficient and compulsory to use setn to act "correctly" ?
};

// Clear button
~eqClearView = Button(w, Rect(200, 220, 50, 20));
~eqClearView.states = [["clear", Color.black, Color.grey]];
~eqClearView.action = {
~magValues = 0 ! ~nbOfBins;
~plotterView.value_(~magValues);
~plotterView.specs_([0, 1, \lin, 0.01 ].asSpec).domainSpecs_(~plotterViewDomainSpecs);
~eqBufValues = 0 ! ~fftsize;
~eqbuf.loadCollection(~eqBufValues);
};
StaticText(w,***@20).string_("FFT bins--->");

// start synth
~syn = Synth(\fftEQ, [\out, 0, \fftsize, ~fftsize, \bufnum, ~eqbuf.bufnum ]);
~syn.run(true);

w.onClose = { ~syn.free; ~eqbuf.free };

};

// load the whole thing, when server booted
s.waitForBoot(loader);

)




Le Mercredi 8 octobre 2014 19h34, christophe lengelé <christophe.lengele-***@public.gmane.org> a écrit :



By trying the example in Plotter for domainSpecs and setting the editMode to true,
you can see the problem of "mismatch" and error generated :

a = { (40..300).scramble }.dup(2).plot;
a.domainSpecs = \freq.asSpec; a.refresh;
a.editMode_(true);

Thanks,
Christophe
haven't checked your code, but with exp mode never start from zero -
Thanks, Daniel,
That's right,
But I can't find a way to represent visually and act consistently with domainSpecs in an exponential way (that does not generate errors), with the previous code.
Maybe Plotter is not appropriate for that.
Maybe someone has a solution for a GUI that can act on each FFT bin (what the code does) but get a visual representation of frequencies (or the size of each bin slider) in an exponential way and not in a linear "bin" way ?
Hope it is clear,
Many thanks,
Christophe
felix
2014-10-09 14:26:01 UTC
Permalink
The default GridLines is linear

You can implement a subclass of GridLines called ExponentialGridLines

implement the methods .niceNum and .ideals

these each return an array of values where the lines should be.

or do one called FreqGridLines that knows to choose lines on common
frequencies like 440Hz and to space them by octaves etc.

each ControlSpec has a variable to hold its preferred grid:

\freq.asSpec.grid

// create a spec with the grid
fspec = ControlSpec(10, 44100, \exp, grid: FreqGridLines())

If its working nicely then the class can be added to Common and the
ControlSpec that is registered as \freq can use it, so it would work for
everyone


The plan was to create grid lines classes for each specific style.

a DbGridLines would be great too. lines every 3db is standard



On Thu, Oct 9, 2014 at 2:15 PM, christophe lengelé <
Post by christophe lengelé
Does someone know how to correct the horizontal gridline ?
DrawGrid.test( \freq.asSpec.grid, \amp.asSpec.grid );
--
..
http://soundcloud.com/crucialfelix
http://github.com/crucialfelix
.
Loading...