Skip to content

The Prototype

passivist edited this page Sep 5, 2016 · 13 revisions

The Prototype

The SuperCollider patch this plugin is based on grew out of a longer occupation with granular synthesis and more specifically the lecture of Curtis Roads book "Microsound". It was at first developed without a GUI completely relying on SuperColliders pattern system. In preperation for a workshop on granular synthesis with SuperCollider I gave in 2015 it was developed and given more or less it's current form.

A semi-short overwiev

The prototype is split into four files: INIT_GRNLR.scd, GRNLR_GUI.scd, GRNLR_ENGINE.scd, grnlr_synth.scd. The files are seperated by task they to keep the code more readable.

INIT_GRNLR.scd contains general setup and initalization of variables and loads and executes the contents of GRNLR_GUI.scd and grnlr_synth.scd which holds the SynthDef a SuperCollider Class that is responible for defining the function that produces the sound in the end (that explanation is of course is criminaly oversimplified).

GRNLR_GUI handles as the name implies all the GUI related operations. That specifically means setting up the window and handling all the interaction the user has with GUI elements such as sliders and buttons. All the variables are stored in a dictionary we initialize at the top of the file. This dictionary is (in classic SuperCollider style) "sort of global". More precicely it's an environment variable that is in the namespace of the current environment.

GRNLR_ENGINE.scd contains the main routine (a Tdef or Task definition which is basically a named routine). This routine is responible for getting the values of all the GUI elements and other variables and triggering grains with those values. Later in the handling of MIDI data is defined.

Concept

In this paragraph I will try to lay out my initial concept which went into writing the prototype and when necessary point out differences to the finished plugin.

Parameters of granular synthesis

When developing the prototype especially while playing around with it before I implemented the GUI a number of parameters concerning the single grains that seemed useful started to emerge:

  • duration (or: inter onset-time between grains could also be described as frequency of grain creation but I felt that would have been to closely associated with pitch)
  • length
  • volume (or amplitude)
  • transposition
  • grain-envelope
  • timbre
Inter Onset Time / Duration

The length of time between the creation of one grain and the next is called duration in my implementation. It interacts with the next parameter "density" to also define the length of a grain making this a "quasisynchronous" granular synthesizer.

Length / Density

The length of the grains is defined as duration * density. In practice density defines the average number of grains playing no matter if the duration is short or long. This represents a level of abstraction from the low level parameters of length and duration which aren't necessarily meaningful in the context of real time use. The definition of length in that way also simplifies the management of the grains in the implementation because we know roughly how many grains will be playing at any moment. Because of this I was able to set the boundaries for the two parameters "duration" and "density" much more freely than otherwise.

Imagine we trigger grains for 1 second. A new grain is created every 1ms (the smallest possible value in my implementation) and each grain is 2000ms long (much larger values are possible in GRNLR when the duration is greater). After the 1 second we have 1000 grains playing. My implementation is certainly not efficient enough (or my computer fast enough) to handle that amount of playing grains. When the length is defined as a multiple of the duration however we know even for edge cases that we won't be producing far to many grains. This enables us to set the boundaries for the parameters much more generously. By testing I determined that a density of 80 (the length of of the grain is 80 times the duration) worked fairly well and didn't limit the sonic flexibility of the plugin too much.

Pitch / Chords

The pitch of the grains can be manipulated in two ways. With the "transposition" control the pitch can be changed from down 2 octaves to up 2 octaves continuously. The pitch can also be controlled with MIDI Note input.

Using MIDI input it is also possible to play polyphonically. The processing however isn't done in parallel. When more then one note is pressed on the keyboard the plugin creates grains with a pitch value randomly chosen from the pressed keys. This way of handling "polyphony" ensures that the amount of grains (and thus the density of the sound) doesn't change when playing different amount of notes at once. As a side effect low settings for the density control and medium setting for the duration result in randomly arpeggiated grains and high values for density result in a very full chord sound.

Envelope

Rather than implementing a specific kind of envelope (like a hanning or cosine window) standard for granular synthesis I wanted for the synthesizer to have a variable grain envelope. In the SuperCollider version the envelope is a 4-point envelope function. The first and the last point are set to a fixed position (start and end) and amplitude (zero) while the points in the middle can be freely set in amplitude or position (as long as they don't pass each other).

In the JUCE version I decided to implement the envelope in a way that is a bit faster to control and easier to program (not needing a fancy GUI). This envelope has three parameters: center, sustain and curve. sustain controls how much of the envelope the level is held at 1 (so for example at a sustain of 0.5 the envelope would have the level 1 for half of the duration of the grain). center governs the relationship between the attack, release and sustain of the envelope. The attack of the envelope is defined as (1 - sustain) * center and the release as sustain + attack. The curve parameter sets the curvature of the attack and release segments: negative values curve the segments upward, positive values curve them downward.

Here are some examples of different envelope settings and their resulting envelopes:

center 0.5, sustain: 0, curve: 0: env cent:0.5 sus:0 cur:0

center 0.5, sustain: 0.5, curve 0:

Clone this wiki locally