Book Image

Mapping and Visualization with SuperCollider

By : Marinos Koutsomichalis
Book Image

Mapping and Visualization with SuperCollider

By: Marinos Koutsomichalis

Overview of this book

SuperCollider is an environment and programming language used by musicians, scientists, and artists who work with audio-files SuperCollider has built-in graphical features which are used in conjunction with the sound synthesis server to create audio-visual mapping and sound visualization. If you wish to create data visualizations by acquiring data from audio and visual sources, then this book is for you.Digital sound artists need to analyze, manipulate, map, and visualize data when working on a scientific or an artistic project. As an artist, this book, by means of its numerous code examples will provide you with the necessary knowledge of SuperCollider's practical applications, so that you can extract meaningful information from audio-files and master its visualization techniques. This book will help you to prototype and implement sophisticated visualizers, sonifiers, and complex mappings of your data.This book takes a closer look at SuperCollider features such as plotting and metering functionality to dispel the mysterious aura surrounding the more advanced mappings and animation strategies. This book also takes you through a number of examples that help you to create intelligent mapping and visualization systems. Throughout the course of the book, you will synthesize and optimize waveforms and spectra for scoping as well as extract information from an audio signal. The later sections of the book focus on advanced topics such as emulating physical forces, designing kinematic structures, and using neural networks to enable you to develop a visualization that has a natural motion with structures that respect anatomy and which come with an intelligent encoding mechanism. This book will teach you everything you need to work with intelligent audio-visual systems to extract and visualize audio-visual data.
Table of Contents (16 chapters)

Scoping signals


Plotter and SoundFileView can be exploited in several ways, but they are not really efficient for scoping real-time audio signals. SuperCollider features dedicated built-in visualizers that we use to easily scope signals in both time and frequency domains.

Scoping waveforms

As far as signals are concerned, we can easily plot their waveforms in real time by means of simply invoking scope on UGen graphs and instances of Bus or Server. The scopemethod is a convenient one too, which creates an instance of Stethoscope in the background; the latter being a fully featured virtual oscilloscope. An example of this is shown in the following code:

( // Stethoscope Example
Server.default.waitForBoot({ // wait for server to boot
  {SinOsc.ar}.scope;  // scope a UGen graph
});
)

An instance of Stethoscope features dedicated controls so that we can configure its display ranges; select which and how many instances of Bus to plot; and switch between overlay, non-overlay, or Lissajous (that is X/Y) representational modes. We can design custom oscilloscopes through ScopeView, which is a powerful, highly parameterized waveform visualizer on its own. However, at the time of writing, and in defiance of Stethoscope being fully functional on both kinds of servers, ScopeView cooperated only with the internal one. Other than this, its use involves linking it with a manually allocated instance of Buffer whose contents are to be constantly updated using a ScopeOut UGen (and not with an Out UGen). In the following code, we have implemented a custom waveform/phase scope:

(  // a custom dual oscilloscope
Server.default = Server.internal;  // make internal the default server
Server.default.waitForBoot({

  var waveScope, phaseScope; // the two scopes
  
  // allocate two audio buffers
  var bufferA = Buffer.alloc(Server.default, 1024,2);
  var bufferB = Buffer.alloc(Server.default, 1024,2);

  // a stereo signal
  var sound = {
    var signal = Resonz.ar(
      [ ClipNoise.ar(1.7), ClipNoise.ar(1.8) ],
      SinOsc.ar(1000).range(100,500)); // a stereo signal
    ScopeOut.ar(signal, bufferA); // update first buffer
    ScopeOut.ar(signal, bufferB); // update second buffer
    Out.ar(0,signal); // write to output
  }.play;

  // create the main Window
  var window = Window("Dual Oscilloscope", 640@320).front
  .onClose_({ // on close stop sound and free buffers
    sound.free;
    bufferA.free;
    bufferB.free;
  });
  window.addFlowLayout; // add a flowLayout to the window 

  // create the ScopeViews and set their buffers
  waveScope = ScopeView(window,314@310).bufnum_(bufferA.bufnum);
  phaseScope = ScopeView(window,314@310).bufnum_(bufferB.bufnum);

  // customize waveScope
  waveScope.style_(1)   // overlay channels
  .waveColors_([Color.red, Color.yellow]).background_(Color.magenta(0.4))
  .xZoom_(1.7).yZoom_(1.2);   // scaling factors
  
  // customize phaseScope
  phaseScope.style_(2)   // lissajous mode
  .waveColors_([Color.magenta]).background_(Color.cyan(0.3))
  .xZoom_(1.2).yZoom_(1.2);   // scaling factors
})
)

Our custom scope is shown in the following screenshot:

Note

Lissajous curves, named after the 19th century French mathematician Jules Antoine Lissajous, represent the ratio between two different signals and are typically used as phase scopes to visualize the phase differences between the left and right channels of a stereo signal.

Scoping spectra

Frequency domain refers to the representation of signals where the frequency is mapped to the horizontal dimension and amplitude to the vertical dimension. As far as real-time plotting in the frequency domain is concerned, much like waveform scoping, we can either use FreqScope to globally scope the default output of Server; the scopeResponse method to scope UGen graphs on the fly; or the more sophisticated FreqScopeView method to design custom frequency visualizers. Yet, in spite of them being very similar in spirit, there are a couple of major differences between the latter and ScopeView, as illustrated in the following code:

(  // a custom Frequency Analyzer
Server.default = Server.local; // set local as the default server
Server.default.waitForBoot({
  // create the parent window
  var window = Window("Frequency Analyzer", 640@480).front
  .onClose_({ // on close
    sound.free;  // stop sound
    scope.kill;  // kill the analyzer
  });

  // the bus to scope
  var bus = Bus.audio(Server.default,2);  
  
  // a stereo signal
  var sound = {
    var signal = Resonz.ar(
      [ ClipNoise.ar(1.7), ClipNoise.ar(1.8) ],
      SinOsc.ar(1000).range(100,500)); // a stereo signal
    Out.ar(bus,signal); // update bus for scoping
    Out.ar(0,signal);   // write to output
  }.play;

  // the frequency scope
  var scope = FreqScopeView(window,640@480).active_(true); 
// activate it
  scope.background_(Color.red).waveColors_([Color.yellow]); 
// set colors
  scope.dbRange_(120);  // set amplitude range (in decibels)
  scope.inBus_(bus); // select Bus to scope
})
)

Here, we read the signal directly from an instance of Bus, rather than Buffer. Moreover, we have to explicitly set the active variable of FreqScope to true, else no scoping will occur. Ironically enough, as of this writing, FreqScopeView will only collaborate with instances of the localhost Server, thereby making it impossible to have both ScopeView and FreqScopeView based visualizers scoping the very same signal (although we can do so using Stethoscope instead).