[PATCH v2] SCClassLibrary: cross-platform FreqScope implementation
Tim Blechmann <
tim@...>
2011-05-01 12:29:56 GMT
hi all,
second version of the original patch. this version is still compatible with
swingosc, since it still uses the redirection mechanism.
will commit this version, unless someone objects ...
cheers, tim
>8-----------
the old FreqScope was implemented for each platform separately. this
is not necessarily needed, since it can be implemented based on ScopeView.
the implementation has also been cleaned up, making it more robust by replacing
explicit delay with callbacks.
Signed-off-by: Tim Blechmann <tim@...>
---
.../Control/FreqScope.sc} | 222 +++++------
.../Common/GUI/PlusGUI/Control/scopeResponse.sc | 44 ++-
SCClassLibrary/Common/GUI/ViewRedirect.sc | 2 +-
.../Platform/osx/scide_scapp/CocoaGUI.sc | 4 +-
SCClassLibrary/QtCollider/QFreqScope.sc | 424 --------------------
SCClassLibrary/QtCollider/QtGUI.sc | 5 +-
6 files changed, 126 insertions(+), 575 deletions(-)
rename SCClassLibrary/Common/GUI/{osx/scide_scapp/SCFreqScope.sc =>
PlusGUI/Control/FreqScope.sc} (59%)
delete mode 100644 SCClassLibrary/QtCollider/QFreqScope.sc
diff --git a/SCClassLibrary/Common/GUI/osx/scide_scapp/SCFreqScope.sc b/SCClassLibrary/Common/GUI/PlusGUI/Control/FreqScope.sc
similarity index 59%
rename from SCClassLibrary/Common/GUI/osx/scide_scapp/SCFreqScope.sc
rename to SCClassLibrary/Common/GUI/PlusGUI/Control/FreqScope.sc
index cf52674..d8fda7b 100644
--- a/SCClassLibrary/Common/GUI/osx/scide_scapp/SCFreqScope.sc
+++ b/SCClassLibrary/Common/GUI/PlusGUI/Control/FreqScope.sc
<at> <at> -1,40 +1,37 <at> <at>
-// SCFreqScope and FreqScope
+// PlusFreqScope and PlusFreqScopeWindowVew
// by Lance Putnam
+// cross-platform port by Tim Blechmann
-SCFreqScope : SCScope {
+PlusFreqScope {
+ classvar <>server;
- classvar <server;
- var <scopebuf, <fftbuf;
- var <active, <node, <inBus, <dbRange, dbFactor, rate, <freqMode;
+ var <scope;
+ var <scopebuf;
+ var <active, <synth, <inBus, <dbRange, dbFactor, rate, <freqMode;
var <bufSize; // size of FFT
var <>specialSynthDef, <specialSynthArgs; // Allows to override the analysis synth
- *viewClass { ^SCScope }
-
- *initClass { server = Server.internal }
+ *initClass {
+ server = Server.internal; // FIXME: Some systems don't have an internal server
+ this.initSynthDefs;
+ }
*new { arg parent, bounds;
- ^super.new(parent, bounds).initSCFreqScope
+ ^super.new.initFreqScope (parent, bounds)
}
- initSCFreqScope {
- active=false;
- inBus=0;
- dbRange = 96;
- dbFactor = 2/dbRange;
- rate = 4;
- freqMode = 0;
- bufSize = 2048;
-
- node = server.nextNodeID;
- }
+ *initSynthDefs {
+ Class.initClassTree(SynthDef);
+ Class.initClassTree(SynthDescLib);
+ Class.initClassTree(Server);
+ UGen.allSubclasses.do(Class.initClassTree(_));
- sendSynthDefs {
// dbFactor -> 2/dbRange
// linear
- SynthDef("freqScope0", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
+ SynthDef("freqScope0", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
var signal, chain, result, phasor, numSamples, mul, add;
+ var fftbufnum = LocalBuf(fftBufSize, 1);
mul = 0.00285;
numSamples = (BufSamples.kr(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048)
signal = In.ar(in);
<at> <at> -44,11 +41,12 <at> <at> SCFreqScope : SCScope {
phasor = LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, numSamples, numSamples + 2);
phasor = phasor.round(2); // the evens are magnitude
ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
+ }).storeOnce;
// logarithmic
- SynthDef("freqScope1", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
+ SynthDef("freqScope1", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
var signal, chain, result, phasor, halfSamples, mul, add;
+ var fftbufnum = LocalBuf(fftBufSize, 1);
mul = 0.00285;
halfSamples = BufSamples.kr(fftbufnum) * 0.5;
signal = In.ar(in);
<at> <at> -57,35 +55,14 <at> <at> SCFreqScope : SCScope {
phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize
phasor = phasor.round(2); // the evens are magnitude
ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
-
-// SynthDef("freqScope2", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
-// var signal, chain, result, phasor, numSamples, mul, add;
-// mul = 0.00285;
-// numSamples = (BufSamples.kr(fftbufnum)) - 2;
-// signal = In.ar(in);
-// chain = FFT(fftbufnum, signal);
-// chain = PV_MagSmear(chain, 1);
-// phasor = ((LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5).squared * numSamples)+1).round(2);
-// ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
-// }).send(server);
-//
-// SynthDef("freqScope3", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
-// var signal, chain, result, phasor, numSamples, mul, add;
-// mul = 0.00285;
-// numSamples = (BufSamples.kr(fftbufnum)) - 2;
-// signal = In.ar(in);
-// chain = FFT(fftbufnum, signal);
-// chain = PV_MagSmear(chain, 1);
-// phasor = ((LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5).cubed * numSamples)+1).round(2);
-// ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
-// }).send(server);
+ }).storeOnce;
// These next two are based on the original two, but adapted by Dan Stowell
// to calculate the frequency response between two channels
- SynthDef("freqScope0_magresponse", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1,
dbFactor = 0.02, in2=1;
+ SynthDef("freqScope0_magresponse", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4,
phase=1, dbFactor = 0.02, in2=1;
var signal, chain, result, phasor, numSamples, mul, add;
var signal2, chain2, divisionbuf;
+ var fftbufnum = LocalBuf(fftBufSize, 1);
mul = 0.00285;
numSamples = (BufSamples.kr(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048)
signal = In.ar(in);
<at> <at> -100,11 +77,12 <at> <at> SCFreqScope : SCScope {
phasor = LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, numSamples, numSamples + 2);
phasor = phasor.round(2); // the evens are magnitude
ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
+ }).storeOnce;
- SynthDef("freqScope1_magresponse", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1,
dbFactor = 0.02, in2=1;
+ SynthDef("freqScope1_magresponse", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4,
phase=1, dbFactor = 0.02, in2=1;
var signal, chain, result, phasor, halfSamples, mul, add;
var signal2, chain2, divisionbuf;
+ var fftbufnum = LocalBuf(fftBufSize, 1);
mul = 0.00285;
halfSamples = BufSamples.kr(fftbufnum) * 0.5;
signal = In.ar(in);
<at> <at> -118,84 +96,70 <at> <at> SCFreqScope : SCScope {
phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize
phasor = phasor.round(2); // the evens are magnitude
ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
+ }).storeOnce;
+ }
- "SCFreqScope: SynthDefs sent".postln;
+ initFreqScope { arg parent, bounds;
+ scope = ScopeView(parent, bounds);
+
+ active = false;
+ inBus = 0;
+ dbRange = 96;
+ dbFactor = 2/dbRange;
+ rate = 4;
+ freqMode = 0;
+ bufSize = 2048;
}
- allocBuffers {
+ allocBuffersAndStart {
+ Buffer.alloc(server, bufSize/4, 1, { |sbuf|
+ scope.bufnum = sbuf.bufnum;
+ ("FreqScope: Buffer allocated ("
+ ++ sbuf.bufnum.asString ++ ")").postln;
- scopebuf = Buffer.alloc(server, bufSize/4, 1,
- { arg sbuf;
- this.bufnum = sbuf.bufnum;
- fftbuf = Buffer.alloc(server, bufSize, 1,
- { arg fbuf;
- ("SCFreqScope: Buffers allocated ("
- ++ sbuf.bufnum.asString ++ ", "
- ++ fbuf.bufnum.asString ++ ")").postln;
- });
- });
+ scopebuf = sbuf;
+ this.start;
+ });
}
freeBuffers {
- if( scopebuf.notNil && fftbuf.notNil, {
- ("SCFreqScope: Buffers freed ("
- ++ scopebuf.bufnum.asString ++ ", "
- ++ fftbuf.bufnum.asString ++ ")").postln;
+ if( scopebuf.notNil, {
+ ("FreqScope: Buffer freed (" ++ scopebuf.bufnum.asString ++ ")").postln;
scopebuf.free; scopebuf = nil;
- fftbuf.free; fftbuf = nil;
});
}
start {
-
- // sending bundle messes up phase of LFSaw in SynthDef (????)
-// server.sendBundle(server.latency,
-// ["/s_new", "freqScope", node, 1, 0,
-// \in, inBus, \mode, mode,
-// \fftbufnum, fftbuf.bufnum, \scopebufnum, scopebuf.bufnum]);
-
- node = server.nextNodeID; // get new node just to be safe
- server.sendMsg("/s_new", specialSynthDef ?? {"freqScope" ++ freqMode.asString}, node, 1, 0,
- \in, inBus, \dbFactor, dbFactor, \rate, 4,
- \fftbufnum, fftbuf.bufnum, \scopebufnum, scopebuf.bufnum, *specialSynthArgs);
+ var defname = specialSynthDef ?? {"freqScope" ++ freqMode.asString};
+ var args = [\in, inBus, \dbFactor, dbFactor, \rate, 4, \fftBufSize, bufSize,
+ \scopebufnum, scopebuf.bufnum] ++ specialSynthArgs;
+ synth = Synth.new(defname, args, server.asGroup);
}
kill {
- this.eventSeq(0.5, {this.active_(false)}, {this.freeBuffers});
- }
-
- // used for sending in order commands to server
- eventSeq { arg delta ... funcs;
- Routine.run({
- (funcs.size-1).do({ arg i;
- funcs[i].value;
- delta.wait;
- });
- funcs.last.value;
-
- }, 64, AppClock);
+ this.active_(false);
+ this.freeBuffers;
}
active_ { arg bool;
if(server.serverRunning, { // don't do anything unless server is running
- if(bool, {
- if(active.not, {
- CmdPeriod.add(this);
- if((scopebuf.isNil) || (fftbuf.isNil), { // first activation
- this.eventSeq(0.5, {this.sendSynthDefs}, {this.allocBuffers}, {this.start});
- }, {
- this.start;
+ if(bool, {
+ if(active.not, {
+ CmdPeriod.add(this);
+ if(scopebuf.isNil) { // first activation
+ this.allocBuffersAndStart;
+ } {
+ this.start;
+ };
+ });
+ }, {
+ if(active, {
+ synth.free;
+ CmdPeriod.remove(this);
});
});
- }, {
- if(active, {
- server.sendBundle(server.latency, ["/n_free", node]);
- CmdPeriod.remove(this);
- });
- });
- active=bool;
+ active=bool;
});
^this
<at> <at> -204,7 +168,7 <at> <at> SCFreqScope : SCScope {
inBus_ { arg num;
inBus = num;
if(active, {
- server.sendBundle(server.latency, ["/n_set", node, \in, inBus]);
+ synth.set(\in, inBus);
});
^this
}
<at> <at> -213,15 +177,14 <at> <at> SCFreqScope : SCScope {
dbRange = db;
dbFactor = 2/db;
if(active, {
- server.sendBundle(server.latency, ["/n_set", node, \dbFactor, dbFactor]);
+ synth.set(\dbFactor, dbFactor);
});
}
freqMode_ { arg mode;
freqMode = mode.asInteger.clip(0,1);
if(active, {
- server.sendMsg("/n_free", node);
- node = server.nextNodeID;
+ synth.free;
this.start;
});
}
<at> <at> -231,7 +194,6 <at> <at> SCFreqScope : SCScope {
if(active == true, {
CmdPeriod.remove(this);
active = false;
- node = server.nextNodeID;
// needs to be deferred to build up synth again properly
{ this.active_(true) }.defer( 0.5 );
});
<at> <at> -240,7 +202,7 <at> <at> SCFreqScope : SCScope {
specialSynthArgs_ {|args|
specialSynthArgs = args;
if(args.notNil and:{active}){
- server.sendMsg("/n_set", node, *specialSynthArgs);
+ synth.set(*specialSynthArgs);
}
}
<at> <at> -248,8 +210,7 <at> <at> SCFreqScope : SCScope {
this.specialSynthDef_(defname);
this.specialSynthArgs_(extraargs);
if(active, {
- server.sendMsg("/n_free", node);
- node = server.nextNodeID;
+ synth.free;
this.start;
});
}
<at> <at> -258,9 +219,13 <at> <at> SCFreqScope : SCScope {
^this.new(parent, bounds).inBus_(bus1.index)
.special("freqScope%_magresponse".format(freqMode), [\in2, bus2])
}
+
+ doesNotUnderstand { arg selector ... args;
+ ^scope.performList(selector, args);
+ }
}
-SCFreqScopeWindow { //was FreqScope
+PlusFreqScopeView {
classvar <scopeOpen;
var <scope, <window;
<at> <at> -319,38 +284,38 <at> <at> SCFreqScopeWindow { //was FreqScope
});
};
- window = SCWindow("Freq Analyzer", rect.resizeBy(pad[0] + pad[1] + 4, pad[2] + pad[3] + 4), false);
+ window = Window("Freq Analyzer", rect.resizeBy(pad[0] + pad[1] + 4, pad[2] + pad[3] + 4), false);
freqLabel.size.do({ arg i;
- freqLabel[i] = SCStaticText(window, Rect(pad[0] - (freqLabelDist*0.5) + (i*freqLabelDist),
pad[2] - 10, freqLabelDist, 10))
+ freqLabel[i] = StaticText(window, Rect(pad[0] - (freqLabelDist*0.5) + (i*freqLabelDist),
pad[2] - 10, freqLabelDist, 10))
.font_(font)
.align_(0)
;
- SCStaticText(window, Rect(pad[0] + (i*freqLabelDist), pad[2], 1, rect.height))
+ StaticText(window, Rect(pad[0] + (i*freqLabelDist), pad[2], 1, rect.height))
.string_("")
.background_(scopeColor.alpha_(0.25))
;
});
dbLabel.size.do({ arg i;
- dbLabel[i] = SCStaticText(window, Rect(0, pad[2] + (i*dbLabelDist), pad[0], 10))
+ dbLabel[i] = StaticText(window, Rect(0, pad[2] + (i*dbLabelDist), pad[0], 10))
.font_(font)
.align_(1)
;
- SCStaticText(window, Rect(pad[0], dbLabel[i].bounds.top, rect.width, 1))
+ StaticText(window, Rect(pad[0], dbLabel[i].bounds.top, rect.width, 1))
.string_("")
.background_(scopeColor.alpha_(0.25))
;
});
- scope = SCFreqScope(window, rect.moveBy(pad[0], pad[2]));
+ scope = FreqScope(window, rect.moveBy(pad[0], pad[2]));
scope.xZoom_((scope.bufSize*0.25) / width);
setFreqLabelVals.value(scope.freqMode, 2048);
setDBLabelVals.value(scope.dbRange);
- SCButton(window, Rect(pad[0] + rect.width, pad[2], pad[1], 16))
+ Button(window, Rect(pad[0] + rect.width, pad[2], pad[1], 16))
.states_([["Power", Color.white, Color.green(0.5)], ["Power", Color.white, Color.red(0.5)]])
.action_({ arg view;
if(view.value == 0, {
<at> <at> -363,12 +328,12 <at> <at> SCFreqScopeWindow { //was FreqScope
.canFocus_(false)
;
- SCStaticText(window, Rect(pad[0] + rect.width, pad[2]+20, pad[1], 10))
+ StaticText(window, Rect(pad[0] + rect.width, pad[2]+20, pad[1], 10))
.string_("BusIn")
.font_(font)
;
- SCNumberBox(window, Rect(pad[0] + rect.width, pad[2]+30, pad[1], 14))
+ NumberBox(window, Rect(pad[0] + rect.width, pad[2]+30, pad[1], 14))
.action_({ arg view;
view.value_(view.value.asInteger.clip(0, Server.internal.options.numAudioBusChannels));
scope.inBus_(view.value);
<at> <at> -377,11 +342,11 <at> <at> SCFreqScopeWindow { //was FreqScope
.font_(font)
;
- SCStaticText(window, Rect(pad[0] + rect.width, pad[2]+48, pad[1], 10))
+ StaticText(window, Rect(pad[0] + rect.width, pad[2]+48, pad[1], 10))
.string_("FrqScl")
.font_(font)
;
- SCPopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+58, pad[1], 16))
+ PopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+58, pad[1], 16))
.items_(["lin", "log"])
.action_({ arg view;
scope.freqMode_(view.value);
<at> <at> -391,11 +356,11 <at> <at> SCFreqScopeWindow { //was FreqScope
.font_(font)
;
- SCStaticText(window, Rect(pad[0] + rect.width, pad[2]+76, pad[1], 10))
+ StaticText(window, Rect(pad[0] + rect.width, pad[2]+76, pad[1], 10))
.string_("dbCut")
.font_(font)
;
- SCPopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+86, pad[1], 16))
+ PopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+86, pad[1], 16))
.items_(Array.series(12, 12, 12).collect({ arg item; item.asString }))
.action_({ arg view;
scope.dbRange_((view.value + 1) * 12);
<at> <at> -421,5 +386,4 <at> <at> SCFreqScopeWindow { //was FreqScope
^this.newCopyArgs(scope, window)
});
}
-
}
diff --git a/SCClassLibrary/Common/GUI/PlusGUI/Control/scopeResponse.sc b/SCClassLibrary/Common/GUI/PlusGUI/Control/scopeResponse.sc
index 439a091..b5c5341 100644
--- a/SCClassLibrary/Common/GUI/PlusGUI/Control/scopeResponse.sc
+++ b/SCClassLibrary/Common/GUI/PlusGUI/Control/scopeResponse.sc
<at> <at> -25,6 +25,11 <at> <at> Slew.scopeResponse
var bus1, bus2, synth, win, fs;
server = server ?? {GUI.stethoscope.defaultServer};
+ if (server != FreqScope.server) {
+ "Function-scopeReponse: resetting Freqscope.server".warn;
+ FreqScope.server = server;
+ };
+
// Create two private busses
bus1 = Bus.audio(server, 1).postln;
bus2 = Bus.audio(server, 1).postln;
<at> <at> -33,28 +38,33 <at> <at> Slew.scopeResponse
// Also, onClose must free the synth and the busses
win = GUI.window.new(label, Rect(100, 100, 511, 300));
- fs = GUI.freqScopeView.response(win, win.view.bounds, bus1, bus2, freqMode);
- win.onClose_{
+ fs = FreqScope.response(win, win.view.bounds, bus1, bus2, freqMode);
+
+ win.onClose_ {
fs.kill;
- server.bind{[synth, bus1, bus2].do(_.free)};
+ synth.release;
};
+
win.front;
fs.active_(true);
- Task{
- 1.5.wait;
- server.sync;
- // Create a synth using this function and the busses
- synth = {
- var noise = PinkNoise.ar;
- var filtered = this.value(noise);
- if (not(mute)) {
- Out.ar(0, (filtered * 0.1) ! 2); // filter only
- };
- Out.ar(bus1, noise);
- Out.ar(bus2, filtered);
- }.play(Node.basicNew(server, fs.node), addAction: \addBefore);
- }.play;
+ // Create a synth using this function and the busses
+ synth = { |gate = 1|
+ var noise = PinkNoise.ar;
+ var filtered = this.value(noise);
+ var env = EnvGen.kr(Env.asr(0.1, 1, 0.1, \sine), gate, 0.1, doneAction: 2);
+ if (not(mute)) {
+ Out.ar(0, (filtered * env) ! 2); // filter only
+ };
+ Out.ar(bus1, noise);
+ Out.ar(bus2, filtered);
+ }.play(fs.synth.asTarget, addAction: \addBefore);
+ synth.register;
+ synth.onFree {
+ {
+ [bus1, bus2].do(_.free);
+ }.defer;
+ }
^fs
}
diff --git a/SCClassLibrary/Common/GUI/ViewRedirect.sc b/SCClassLibrary/Common/GUI/ViewRedirect.sc
index 786c9fc..71b894f 100644
--- a/SCClassLibrary/Common/GUI/ViewRedirect.sc
+++ b/SCClassLibrary/Common/GUI/ViewRedirect.sc
<at> <at> -68,7 +68,7 <at> <at> Stethoscope : ViewRedirect {
ScopeView : ViewRedirect { *key { ^\scopeView }}
FreqScopeView : ViewRedirect { *key { ^\freqScopeView }} // redirects to SCFreqScope
-FreqScope : ViewRedirect { // redirects to SCFreqScopeWindow
+FreqScope : ViewRedirect { // redirects to FreqScopeWindow
*new { arg width=512, height=300, busNum=0, scopeColor, bgColor;
busNum = busNum.asControlInput;
^this.implClass.new(width, height, busNum, scopeColor)
diff --git a/SCClassLibrary/Platform/osx/scide_scapp/CocoaGUI.sc b/SCClassLibrary/Platform/osx/scide_scapp/CocoaGUI.sc
index 8dc2c94..1652d36 100644
--- a/SCClassLibrary/Platform/osx/scide_scapp/CocoaGUI.sc
+++ b/SCClassLibrary/Platform/osx/scide_scapp/CocoaGUI.sc
<at> <at> -27,8 +27,8 <at> <at> CocoaGUI {
///////////////// Common -> GUI /////////////////
- *freqScope { ^SCFreqScopeWindow }
- *freqScopeView { ^SCFreqScope }
+ *freqScope { ^PlusFreqScope }
+ *freqScopeView { ^PlusFreqScopeView }
*scopeView { ^SCScope }
*stethoscope { ^SCStethoscope }
diff --git a/SCClassLibrary/QtCollider/QFreqScope.sc b/SCClassLibrary/QtCollider/QFreqScope.sc
deleted file mode 100644
index 4af226d..0000000
--- a/SCClassLibrary/QtCollider/QFreqScope.sc
+++ /dev/null
<at> <at> -1,424 +0,0 <at> <at>
-// QFreqScope and QFreqScopeWindow
-// by Lance Putnam
-// modified by Jakob Leben and Lucas Samaruga for GUI.qt scheme
-
-QFreqScope : QScope {
-
- classvar <server;
- var <scopebuf, <fftbuf;
- var <active, <node, <inBus, <dbRange, dbFactor, rate, <freqMode;
- var <bufSize; // size of FFT
- var <>specialSynthDef, <specialSynthArgs; // Allows to override the analysis synth
-
- *initClass { server = Server.internal }
-
- *new { arg parent, bounds;
- ^super.new(parent, bounds).initSCFreqScope
- }
-
- initSCFreqScope {
- active=false;
- inBus=0;
- dbRange = 96;
- dbFactor = 2/dbRange;
- rate = 4;
- freqMode = 0;
- bufSize = 2048;
-
- node = server.nextNodeID;
- }
-
- sendSynthDefs {
- // dbFactor -> 2/dbRange
-
- // linear
- SynthDef("freqScope0", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
- var signal, chain, result, phasor, numSamples, mul, add;
- mul = 0.00285;
- numSamples = (BufSamples.kr(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048)
- signal = In.ar(in);
- chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1);
- chain = PV_MagSmear(chain, 1);
- // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist)
- phasor = LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, numSamples, numSamples + 2);
- phasor = phasor.round(2); // the evens are magnitude
- ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
-
- // logarithmic
- SynthDef("freqScope1", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
- var signal, chain, result, phasor, halfSamples, mul, add;
- mul = 0.00285;
- halfSamples = BufSamples.kr(fftbufnum) * 0.5;
- signal = In.ar(in);
- chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1);
- chain = PV_MagSmear(chain, 1);
- phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize
- phasor = phasor.round(2); // the evens are magnitude
- ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
-
-// SynthDef("freqScope2", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
-// var signal, chain, result, phasor, numSamples, mul, add;
-// mul = 0.00285;
-// numSamples = (BufSamples.kr(fftbufnum)) - 2;
-// signal = In.ar(in);
-// chain = FFT(fftbufnum, signal);
-// chain = PV_MagSmear(chain, 1);
-// phasor = ((LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5).squared * numSamples)+1).round(2);
-// ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
-// }).send(server);
-//
-// SynthDef("freqScope3", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1, dbFactor = 0.02;
-// var signal, chain, result, phasor, numSamples, mul, add;
-// mul = 0.00285;
-// numSamples = (BufSamples.kr(fftbufnum)) - 2;
-// signal = In.ar(in);
-// chain = FFT(fftbufnum, signal);
-// chain = PV_MagSmear(chain, 1);
-// phasor = ((LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5).cubed * numSamples)+1).round(2);
-// ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
-// }).send(server);
-
- // These next two are based on the original two, but adapted by Dan Stowell
- // to calculate the frequency response between two channels
- SynthDef("freqScope0_magresponse", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1,
dbFactor = 0.02, in2=1;
- var signal, chain, result, phasor, numSamples, mul, add;
- var signal2, chain2, divisionbuf;
- mul = 0.00285;
- numSamples = (BufSamples.kr(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048)
- signal = In.ar(in);
- signal2 = In.ar(in2);
- chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1);
- divisionbuf = LocalBuf(BufFrames.ir(fftbufnum));
- chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1);
- // Here we perform complex division to estimate the freq response
- chain = PV_Div(chain2, chain);
- chain = PV_MagSmear(chain, 1);
- // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist)
- phasor = LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, numSamples, numSamples + 2);
- phasor = phasor.round(2); // the evens are magnitude
- ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
-
- SynthDef("freqScope1_magresponse", { arg in=0, fftbufnum=0, scopebufnum=1, rate=4, phase=1,
dbFactor = 0.02, in2=1;
- var signal, chain, result, phasor, halfSamples, mul, add;
- var signal2, chain2, divisionbuf;
- mul = 0.00285;
- halfSamples = BufSamples.kr(fftbufnum) * 0.5;
- signal = In.ar(in);
- signal2 = In.ar(in2);
- chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1);
- divisionbuf = LocalBuf(BufFrames.ir(fftbufnum));
- chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1);
- // Here we perform complex division to estimate the freq response
- chain = PV_Div(chain2, chain);
- chain = PV_MagSmear(chain, 1);
- phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.kr(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize
- phasor = phasor.round(2); // the evens are magnitude
- ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum);
- }).send(server);
-
- "SCFreqScope: SynthDefs sent".postln;
- }
-
- allocBuffers {
-
- scopebuf = Buffer.alloc(server, bufSize/4, 1,
- { arg sbuf;
- this.bufnum = sbuf.bufnum;
- fftbuf = Buffer.alloc(server, bufSize, 1,
- { arg fbuf;
- ("SCFreqScope: Buffers allocated ("
- ++ sbuf.bufnum.asString ++ ", "
- ++ fbuf.bufnum.asString ++ ")").postln;
- });
- });
- }
-
- freeBuffers {
- if( scopebuf.notNil && fftbuf.notNil, {
- ("SCFreqScope: Buffers freed ("
- ++ scopebuf.bufnum.asString ++ ", "
- ++ fftbuf.bufnum.asString ++ ")").postln;
- scopebuf.free; scopebuf = nil;
- fftbuf.free; fftbuf = nil;
- });
- }
-
- start {
-
- // sending bundle messes up phase of LFSaw in SynthDef (????)
-// server.sendBundle(server.latency,
-// ["/s_new", "freqScope", node, 1, 0,
-// \in, inBus, \mode, mode,
-// \fftbufnum, fftbuf.bufnum, \scopebufnum, scopebuf.bufnum]);
-
- node = server.nextNodeID; // get new node just to be safe
- server.sendMsg("/s_new", specialSynthDef ?? {"freqScope" ++ freqMode.asString}, node, 1, 0,
- \in, inBus, \dbFactor, dbFactor, \rate, 4,
- \fftbufnum, fftbuf.bufnum, \scopebufnum, scopebuf.bufnum, *specialSynthArgs);
- }
-
- kill {
- this.eventSeq(0.5, {this.active_(false)}, {this.freeBuffers});
- }
-
- // used for sending in order commands to server
- eventSeq { arg delta ... funcs;
- Routine.run({
- (funcs.size-1).do({ arg i;
- funcs[i].value;
- delta.wait;
- });
- funcs.last.value;
-
- }, 64, AppClock);
- }
-
- active_ { arg bool;
- if(server.serverRunning, { // don't do anything unless server is running
-
- if(bool, {
- if(active.not, {
- CmdPeriod.add(this);
- if((scopebuf.isNil) || (fftbuf.isNil), { // first activation
- this.eventSeq(0.5, {this.sendSynthDefs}, {this.allocBuffers}, {this.start});
- }, {
- this.start;
- });
- });
- }, {
- if(active, {
- server.sendBundle(server.latency, ["/n_free", node]);
- CmdPeriod.remove(this);
- });
- });
- active=bool;
-
- });
- ^this
- }
-
- inBus_ { arg num;
- inBus = num;
- if(active, {
- server.sendBundle(server.latency, ["/n_set", node, \in, inBus]);
- });
- ^this
- }
-
- dbRange_ { arg db;
- dbRange = db;
- dbFactor = 2/db;
- if(active, {
- server.sendBundle(server.latency, ["/n_set", node, \dbFactor, dbFactor]);
- });
- }
-
- freqMode_ { arg mode;
- freqMode = mode.asInteger.clip(0,1);
- if(active, {
- server.sendMsg("/n_free", node);
- node = server.nextNodeID;
- this.start;
- });
- }
-
- cmdPeriod {
- this.changed(\cmdPeriod);
- if(active == true, {
- CmdPeriod.remove(this);
- active = false;
- node = server.nextNodeID;
- // needs to be deferred to build up synth again properly
- { this.active_(true) }.defer( 0.5 );
- });
- }
-
- specialSynthArgs_ {|args|
- specialSynthArgs = args;
- if(args.notNil and:{active}){
- server.sendMsg("/n_set", node, *specialSynthArgs);
- }
- }
-
- special { |defname, extraargs|
- this.specialSynthDef_(defname);
- this.specialSynthArgs_(extraargs);
- if(active, {
- server.sendMsg("/n_free", node);
- node = server.nextNodeID;
- this.start;
- });
- }
-
- *response{ |parent, bounds, bus1, bus2, freqMode=1|
- ^this.new(parent, bounds).inBus_(bus1.index)
- .special("freqScope%_magresponse".format(freqMode), [\in2, bus2])
- }
-}
-
-QFreqScopeWindow {
- classvar <scopeOpen;
- var <scope, <window;
-
- *new { arg width=512, height=300, busNum=0, scopeColor, bgColor;
- var rect, scope, window, pad, font, freqLabel, freqLabelDist, dbLabel, dbLabelDist;
- var setFreqLabelVals, setDBLabelVals;
- var nyquistKHz;
- if(scopeOpen != true, { // block the stacking up of scope windows
- //make scope
-
- scopeOpen = true;
-
- if(scopeColor.isNil, { scopeColor = Color.green });
- if(bgColor.isNil, { bgColor = Color.green(0.1) });
-
- rect = Rect(0, 0, width, height);
- pad = [30, 38, 14, 10]; // l,r,t,b
- font = QFont("Monaco", 9);
- freqLabel = Array.newClear(12);
- freqLabelDist = rect.width/(freqLabel.size-1);
- dbLabel = Array.newClear(17);
- dbLabelDist = rect.height/(dbLabel.size-1);
-
- nyquistKHz = Server.internal.sampleRate;
- if( (nyquistKHz == 0) || nyquistKHz.isNil, {
- nyquistKHz = 22.05 // best guess?
- },{
- nyquistKHz = nyquistKHz * 0.0005;
- });
-
-
- setFreqLabelVals = { arg mode, bufsize;
- var kfreq, factor, halfSize;
-
- factor = 1/(freqLabel.size-1);
- halfSize = bufsize * 0.5;
-
- freqLabel.size.do({ arg i;
- if(mode == 1, {
- kfreq = (halfSize.pow(i * factor) - 1)/(halfSize-1) * nyquistKHz;
- },{
- kfreq = i * factor * nyquistKHz;
- });
-
- if(kfreq > 1.0, {
- freqLabel[i].string_( kfreq.asString.keep(4) ++ "k" )
- },{
- freqLabel[i].string_( (kfreq*1000).asInteger.asString)
- });
- });
- };
-
- setDBLabelVals = { arg db;
- dbLabel.size.do({ arg i;
- dbLabel[i].string = (i * db/(dbLabel.size-1)).asInteger.neg.asString;
- });
- };
-
- window = QWindow("Freq Analyzer", rect.resizeBy(pad[0] + pad[1] + 4, pad[2] + pad[3] + 4), false);
-
- freqLabel.size.do({ arg i;
- freqLabel[i] = QStaticText(window, Rect(pad[0] - (freqLabelDist*0.5) + (i*freqLabelDist),
pad[2] - 10, freqLabelDist, 10))
- .font_(font)
- .align_(0)
- ;
- QStaticText(window, Rect(pad[0] + (i*freqLabelDist), pad[2], 1, rect.height))
- .string_("")
- .background_(scopeColor.alpha_(0.25))
- ;
- });
-
- dbLabel.size.do({ arg i;
- dbLabel[i] = QStaticText(window, Rect(0, pad[2] + (i*dbLabelDist), pad[0], 10))
- .font_(font)
- .align_(1)
- ;
- QStaticText(window, Rect(pad[0], dbLabel[i].bounds.top, rect.width, 1))
- .string_("")
- .background_(scopeColor.alpha_(0.25))
- ;
- });
-
- scope = QFreqScope(window, rect.moveBy(pad[0], pad[2]));
-
- scope.xZoom_((scope.bufSize*0.25) / width);
-
- setFreqLabelVals.value(scope.freqMode, 2048);
- setDBLabelVals.value(scope.dbRange);
-
- QButton(window, Rect(pad[0] + rect.width, pad[2], pad[1], 16))
- .states_([["Power", Color.white, Color.green(0.5)], ["Power", Color.white, Color.red(0.5)]])
- .action_({ arg view;
- if(view.value == 0, {
- scope.active_(true);
- },{
- scope.active_(false);
- });
- })
- .font_(font)
- .canFocus_(false)
- ;
-
- QStaticText(window, Rect(pad[0] + rect.width, pad[2]+20, pad[1], 10))
- .string_("BusIn")
- .font_(font)
- ;
-
- QNumberBox(window, Rect(pad[0] + rect.width, pad[2]+30, pad[1], 14))
- .action_({ arg view;
- view.value_(view.value.asInteger.clip(0, Server.internal.options.numAudioBusChannels));
- scope.inBus_(view.value);
- })
- .value_(busNum)
- .font_(font)
- ;
-
- QStaticText(window, Rect(pad[0] + rect.width, pad[2]+48, pad[1], 10))
- .string_("FrqScl")
- .font_(font)
- ;
- QPopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+58, pad[1], 16))
- .items_(["lin", "log"])
- .action_({ arg view;
- scope.freqMode_(view.value);
- setFreqLabelVals.value(scope.freqMode, 2048);
- })
- .canFocus_(false)
- .font_(font)
- ;
-
- QStaticText(window, Rect(pad[0] + rect.width, pad[2]+76, pad[1], 10))
- .string_("dbCut")
- .font_(font)
- ;
- QPopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+86, pad[1], 16))
- .items_(Array.series(12, 12, 12).collect({ arg item; item.asString }))
- .action_({ arg view;
- scope.dbRange_((view.value + 1) * 12);
- setDBLabelVals.value(scope.dbRange);
- })
- .canFocus_(false)
- .font_(font)
- .value_(7)
- ;
-
- scope
- .background_(bgColor)
- .style_(1)
- .waveColors_([scopeColor.alpha_(1)])
- .inBus_(busNum)
- .active_(true)
- .canFocus_(false)
- ;
-
- window.onClose_({ scope.kill;
- scopeOpen = false;
- }).front;
- ^this.newCopyArgs(scope, window)
- });
- }
-
-}
diff --git a/SCClassLibrary/QtCollider/QtGUI.sc b/SCClassLibrary/QtCollider/QtGUI.sc
index 3750157..4d7001b 100644
--- a/SCClassLibrary/QtCollider/QtGUI.sc
+++ b/SCClassLibrary/QtCollider/QtGUI.sc
<at> <at> -35,8 +35,9 <at> <at> QtGUI {
*listView { ^QListView }
*popUpMenu { ^QPopUpMenu }
*textView { ^QTextView; }
- *freqScope { ^QFreqScopeWindow }
- *freqScopeView { ^QFreqScope }
+
+ *freqScope { ^PlusFreqScope }
+ *freqScopeView { ^PlusFreqScopeView }
*scopeView { ^QScope }
*stethoscope { ^QStethoscope }
*soundFileView { ^QSoundFileView }
--
--
1.7.4.1
_______________________________________________
sc-dev 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-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/