Synth {
// Primitives expect to find sampleRate
& defaultBlockSize in the first two classvars,
// so dont define any other classvars
before them.
classvar <sampleRate=44100.0;
classvar <>defaultBlockSize=64;
//classvar <newSynth; // this
is the synth being built with Synth.new
var <ugens; // Array of UGens in this Synth in the order
they will be executed.
var <outputs; // a single UGen or an Array of UGens which
are the output(s) of this Synth
var <>parent; // the enclosing Synth, or nil if the top level
Synth
// the following 3 may only be set from
within the ugenGraphFunc
var <>blockSize;
var <>releaseTime;
var <>channelOffset = 0;
var schedQueue; // private queue for the time based scheduler
var bSchedQueue; // private queue for the tempo based scheduler
*new { arg ugenGraphFunc;
// creates a Synth, evaluates
the function and compiles the resulting ugen graph.
// If the function returns nil
instead of a ugen graph, then the new Synth is
// discarded and we return nil.
_Synth_New
^this.primitiveFailed
}
*stop {
_Synth_Stop
^this.primitiveFailed
}
*playWithFadeOut { arg ugenGraphFunc,
duration = 60.0, fadeout = 5.0;
var newsynth, env;
env = Env.new(#[1, 1, 0],[duration
- fadeout, fadeout], -2);
newsynth = this.new({ arg synth;
var outputs;
outputs = ugenGraphFunc.value(synth);
outputs * EnvGen.kr(env);
});
if (newsynth.notNil, { newsynth.play(duration) });
^newsynth
}
*play { arg ugenGraphFunc, duration;
var newsynth;
newsynth = this.new(ugenGraphFunc);
if (newsynth.notNil, { newsynth.play(duration) });
^newsynth
}
*bench { arg ugenGraphFunc, duration,
yield=true;
var newsynth;
newsynth = this.new(ugenGraphFunc);
if (newsynth.notNil, { newsynth.bench(duration, yield) });
^newsynth
}
*collect { arg ugenGraphFunc,
duration = 0.01;
var newsynth;
newsynth = this.new(ugenGraphFunc);
^if (newsynth.notNil, { newsynth.collect(duration) });
}
*plot { arg ugenGraphFunc, duration
= 0.01, name, bounds;
var res;
res = this.collect(ugenGraphFunc,
duration);
name = name ? "plot";
bounds = bounds ? Rect.new(40,50,600,475);
^SignalWindow.new(name,
bounds, res);
}
*scope { arg ugenGraphFunc, duration
= 0.01, name, bounds;
var wind;
this.play({ arg synth;
var scopeData, signalSize,
view, ugenGraph;
ugenGraph = ugenGraphFunc.value(synth);
name = name ? "scope";
bounds = bounds ? Rect.new(40,60,600,475);
signalSize = duration * sampleRate;
if (ugenGraph.isKindOf(Array),
{
// create data for
signal widgets :
scopeData = Array.fill(ugenGraph.size,
{ Signal.newClear(signalSize) });
// make window
wind = SignalWindow.new(name,
bounds, scopeData, sampleRate);
// wrap outputs with
Scope ugens
ugenGraph = ugenGraph.collect({ arg ugen, i;
view = wind.at(i+1);
// Scope requires
that the SignalView has an additional signal for
// double buffering.
view.scopeSignal = Signal.newClear(signalSize);
Scope.ar(view,
ugen)
});
},{
// create data for
signal widget :
scopeData = Signal.newClear(signalSize);
// make window
wind = SignalWindow.new(name,
bounds, scopeData, sampleRate);
view = wind.at(1);
// Scope requires
that the SignalView has an additional signal for
// double buffering.
view.scopeSignal = Signal.newClear(signalSize);
// wrap output with
Scope ugen
ugenGraph = Scope.ar(view,
ugenGraph)
});
});
wind.close;
}
*fftScope { arg ugenGraphFunc,
name, bounds, fftsize=4096;
var wind, fftWindow, cosineTable;
fftWindow = Signal.hanningWindow(fftsize); // make a signal analysis window
cosineTable = Signal.fftCosTable(fftsize); // make cosine table required for FFT
this.play({ arg synth;
var scopeData, view,
ugenGraph, fft;
ugenGraph = ugenGraphFunc.value(synth);
name = name ? "scope";
bounds = bounds ? Rect.new(40,60,600,475);
if (ugenGraph.isKindOf(Array),
{
// create data for
signal widgets :
scopeData = Array.fill(ugenGraph.size,
{ Signal.newClear(fftsize) });
// make window
wind = SignalWindow.new(name,
bounds, scopeData, sampleRate);
// wrap outputs with
Scope ugens
ugenGraph = ugenGraph.collect({ arg ugen, i;
view = wind.at(i+1);
view.minval = -150; view.maxval = 0;
// Scope requires
that the SignalView has an additional signal for
// double buffering.
view.scopeSignal = Signal.newClear(fftsize);
fft = FFT.ar(fftsize,
0, cosineTable, fftWindow, nil,
ugen, 0.0);
Scope.ar(view,
(fft/fftsize).magnitudeApx.max(1e-10).ampdb);
ugen
});
},{
// create data for
signal widget :
scopeData = Signal.newClear(fftsize);
// make window
wind = SignalWindow.new(name,
bounds, scopeData, sampleRate);
view = wind.at(1);
view.minval = -150; view.maxval = 0;
// Scope requires
that the SignalView has an additional signal for
// double buffering.
view.scopeSignal = Signal.newClear(fftsize);
fft = FFT.ar(fftsize,
0, cosineTable, fftWindow, nil,
ugenGraph, 0.0);
// wrap output with
Scope ugen
Scope.ar(view,
(fft/fftsize).magnitudeApx.max(1e-10).ampdb);
ugenGraph
});
});
wind.close;
}
*dualScope { arg ugenGraphFunc,
duration = 0.01, name, bounds, fftsize=4096;
var wind, fftWindow, cosineTable;
fftWindow = Signal.hanningWindow(fftsize); // make a signal analysis window
cosineTable = Signal.fftCosTable(fftsize); // make cosine table required for FFT
this.play({ arg synth;
var scopeData, fftscopeData,
view, ugenGraph, fft, mixout, signalSize;
ugenGraph = ugenGraphFunc.value(synth);
mixout = if (ugenGraph.isKindOf(Array),
{ Mix.ar(ugenGraph) },{ ugenGraph
});
name = name ? "scope";
bounds = bounds ? Rect.new(40,60,600,475);
signalSize = duration * sampleRate;
// create data for signal
widgets :
fftscopeData = Signal.newClear(fftsize);
scopeData = Signal.newClear(signalSize);
// make window
wind = SignalWindow.new(name,
bounds, [scopeData, fftscopeData], sampleRate);
view = wind.at(1);
view.scopeSignal = Signal.newClear(signalSize);
Scope.ar(view, ugenGraph);
view = wind.at(2);
view.minval = -150; view.maxval = 0;
view.scopeSignal = Signal.newClear(fftsize);
fft = FFT.ar(fftsize,
0, cosineTable, fftWindow, nil,
mixout, 0.0);
// wrap output with Scope
ugen
Scope.ar(view, (fft/fftsize).magnitudeApx.max(1e-10).ampdb);
ugenGraph
});
wind.close;
}
*record { arg ugenGraphFunc,
duration, pathName,
headerFormat = 'AIFF',
sampleFormat = '16 big endian signed';
var file, z, newsynth;
newsynth = this.new({ arg synth;
var ugenGraph;
ugenGraph = ugenGraphFunc.value(synth).asArray;
file = SoundFile.new;
file.headerFormat = headerFormat;
file.sampleFormat = sampleFormat;
file.numChannels = ugenGraph.size;
if (file.writeHeader(pathName), {
file.prepareRecord;
DiskOut.ar(file,
32768, ugenGraph)
},{
file = nil;
nil
});
});
if (newsynth.notNil, {
newsynth.play(duration);
file.endRecord
});
^file
}
*recordMonoFiles { arg ugenGraphFunc,
duration, pathName,
headerFormat = 'AIFF',
sampleFormat = '16 big endian signed';
var files, z, newsynth;
files = List.new;
newsynth = this.new({ arg synth;
var ugenGraph;
ugenGraph = ugenGraphFunc.value(synth).asArray;
// ugenGraph is an array
of UGens.
// size of array is number
of outputs
ugenGraph.do({ arg
channel, i;
var file;
file = SoundFile.new;
file.headerFormat = headerFormat;
file.sampleFormat = sampleFormat;
file.numChannels = 1;
if (file.writeHeader(pathName ++ "." ++ (i+1).asString), {
file.prepareRecord;
files.add(file);
DiskOut.ar(file,
32768, [channel])
});
channel
});
});
if (newsynth.notNil, {
newsynth.play(duration);
files.do({ arg file;
file.endRecord; });
});
^files
}
// *writeMonoFiles { arg ugenGraphFunc,
duration, pathName,
// headerFormat = 'AIFF', sampleFormat
= '16 big endian signed';
// var files, z, newsynth;
//
// files = List.new;
// newsynth = this.new({ arg synth;
// var ugenGraph;
//
// ugenGraph = ugenGraphFunc.value(synth).asArray;
//
// // ugenGraph is an array
of UGens.
// // size of array is number
of outputs
// ugenGraph.do({ arg channel,
i;
// var file;
// file = SoundFile.new;
// file.headerFormat
= headerFormat;
// file.sampleFormat
= sampleFormat;
// file.numChannels
= 1;
// if (file.writeHeader(pathName
++ "." ++ (i+1).asString), {
// file.prepareRecord;
// files.add(file);
// DiskOut.ar(file,
32768, [channel])
// });
// channel
// });
// });
//
// if (newsynth.notNil, {
// newsynth.bench(duration);
// files.do({ arg file; file.endRecord;
});
// });
// ^files
// }
*write { arg ugenGraphFunc, duration,
pathName,
headerFormat = 'AIFF',
sampleFormat = '16 big endian signed';
var synth, file;
synth = Synth.new(ugenGraphFunc);
^if (synth.notNil, {
file = SoundFile.new;
file.headerFormat = headerFormat;
file.sampleFormat = sampleFormat;
file.numChannels = synth.numChannels;
if (file.writeHeader(pathName), {
synth.write(file, duration);
},{
"Write header failed.".error;
});
file
});
}
*sampleRate_ { arg newSampleRate=44100.0;
if (Synth.isPlaying, {
error("cannot change sample
rate while playing\n");
},{
sampleRate = newSampleRate;
});
}
collect { arg duration = 0.01;
// returns a Signal or Array of
Signals representing the
// output of the synth for the
given duration
_SynthCollect
^this.primitiveFailed
}
play { arg duration;
_SynthPlay
^this.primitiveFailed
}
bench { arg duration = 5.0, yield=true;
_SynthBench
^this.primitiveFailed
}
debug { arg numBlocks = 12;
_SynthDebug
^this.primitiveFailed
}
write { arg soundFile, duration
= 2.0;
_SynthWrite
^this.primitiveFailed
}
numChannels {
if (outputs.isKindOf(Array),
{ ^outputs.size },{ ^1 })
}
// status
time {
// returns the amount of time
in seconds that the Synth has been playing.
_Synth_ElapsedTime
^this.primitiveFailed
}
beats {
// returns the number of beats
that the Synth has been playing.
_Synth_ElapsedBeats
^this.primitiveFailed
}
sampleCount {
// returns the number of samples
that the Synth has played.
_Synth_ElapsedSamples
^this.primitiveFailed
}
release {
// releases envelope generators
_Synth_Release
^this.primitiveFailed
}
steal {
// steals envelope generators
_Synth_Steal
^this.primitiveFailed
}
tsched { arg timeFromNow, func;
_Synth_SchedSecs
^this.primitiveFailed
}
trepeat { arg start, period,
userFunc;
var count = 0;
this.tsched(start.value,
{ arg synth, now, repeatFunc;
userFunc.value(synth, now, count);
count = count + 1;
this.tsched(period.value,
repeatFunc);
});
}
trepeatN { arg start, period,
maxRepeats, userFunc, completionFunc;
var count = 0;
if (maxRepeats > 0, {
this.tsched(start.value,
{ arg synth, now, repeatFunc;
userFunc.value(synth, now, count);
count = count + 1;
if (count < maxRepeats, {
this.tsched(period.value,
repeatFunc);
},{
if (completionFunc.notNil, {
this.tsched(period.value,
{ completionFunc.value(synth, now) });
});
});
});
});
}
sched { arg beatsFromNow, func;
_Synth_SchedBeats
^this.primitiveFailed
}
repeat { arg start, period, userFunc;
var count = 0;
this.sched(start.value,
{ arg synth, now, repeatFunc;
userFunc.value(synth, now, count);
count = count + 1;
this.sched(period.value,
repeatFunc);
});
}
repeatN { arg start, period,
maxRepeats, userFunc, completionFunc;
var count = 0;
if (maxRepeats > 0, {
this.sched(start.value,
{ arg synth, now, repeatFunc;
userFunc.value(synth, now, count);
count = count + 1;
if (count < maxRepeats, {
this.sched(period.value,
repeatFunc);
},{
if (completionFunc.notNil, {
this.sched(period.value,
{ completionFunc.value(synth, now) });
});
});
});
});
}
task { arg start, func, stackSize = 512, seed = -1;
var task;
task = Task(func, this, stackSize, seed);
this.sched(start.value,
{ task.next });
}
*hardwareName {
_SynthGetHardware
^this.primitiveFailed
}
*setInputRouting { arg routingArray;
_SynthSetInRouting
^this.primitiveFailed
}
*setOutputRouting { arg routingArray;
_SynthSetOutRouting
^this.primitiveFailed
}
*normalRouting {
this.setInputRouting(Array.series(64,1,1));
this.setOutputRouting(Array.series(64,1,1));
}
// tempo support
newTempoBase { arg tempo;
_Synth_NewTempoBase
}
tempo_ { arg tempo;
_Synth_SetTempo
}
tempo {
_Synth_GetTempo
}
*newSynth {
"CHANGE: Use 'thisSynth' instead
of 'Synth.newSynth'".postln;
^thisSynth
}
}
This page was created by SimpleText2Html 1.0.3 on 22-Feb-100.