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.