Monday 29 October 2012

Amazingly Handy Document - RBJ EQ CookBook


A Huge thanks to Robert Bristow-Johnson for having written released this VERY useful document!

         Cookbook formulae for audio EQ biquad filter coefficients
----------------------------------------------------------------------------
           by Robert Bristow-Johnson  <rbj@audioimagination.com>


All filter transfer functions were derived from analog prototypes (that
are shown below for each EQ filter type) and had been digitized using the
Bilinear Transform.  BLT frequency warping has been taken into account for
both significant frequency relocation (this is the normal "prewarping" that
is necessary when using the BLT) and for bandwidth readjustment (since the
bandwidth is compressed when mapped from analog to digital using the BLT).

First, given a biquad transfer function defined as:

            b0 + b1*z^-1 + b2*z^-2
    H(z) = ------------------------                                  (Eq 1)
            a0 + a1*z^-1 + a2*z^-2

This shows 6 coefficients instead of 5 so, depending on your architechture,
you will likely normalize a0 to be 1 and perhaps also b0 to 1 (and collect
that into an overall gain coefficient).  Then your transfer function would
look like:

            (b0/a0) + (b1/a0)*z^-1 + (b2/a0)*z^-2
    H(z) = ---------------------------------------                   (Eq 2)
               1 + (a1/a0)*z^-1 + (a2/a0)*z^-2

or

                      1 + (b1/b0)*z^-1 + (b2/b0)*z^-2
    H(z) = (b0/a0) * ---------------------------------               (Eq 3)
                      1 + (a1/a0)*z^-1 + (a2/a0)*z^-2


The most straight forward implementation would be the "Direct Form 1"
(Eq 2):

    y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2]
                        - (a1/a0)*y[n-1] - (a2/a0)*y[n-2]            (Eq 4)

This is probably both the best and the easiest method to implement in the
56K and other fixed-point or floating-point architechtures with a double
wide accumulator.



Begin with these user defined parameters:

    Fs (the sampling frequency)

    f0 ("wherever it's happenin', man."  Center Frequency or
        Corner Frequency, or shelf midpoint frequency, depending
        on which filter type.  The "significant frequency".)

    dBgain (used only for peaking and shelving filters)

    Q (the EE kind of definition, except for peakingEQ in which A*Q is
        the classic EE Q.  That adjustment in definition was made so that
        a boost of N dB followed by a cut of N dB for identical Q and
        f0/Fs results in a precisely flat unity gain filter or "wire".)

     _or_ BW, the bandwidth in octaves (between -3 dB frequencies for BPF
        and notch or between midpoint (dBgain/2) gain frequencies for
        peaking EQ)

     _or_ S, a "shelf slope" parameter (for shelving EQ only).  When S = 1,
        the shelf slope is as steep as it can be and remain monotonically
        increasing or decreasing gain with frequency.  The shelf slope, in
        dB/octave, remains proportional to S for all other values for a
        fixed f0/Fs and dBgain.



Then compute a few intermediate variables:

    A  = sqrt( 10^(dBgain/20) )
       =       10^(dBgain/40)     (for peaking and shelving EQ filters only)

    w0 = 2*pi*f0/Fs

    cos(w0)
    sin(w0)

    alpha = sin(w0)/(2*Q)                                       (case: Q)
          = sin(w0)*sinh( ln(2)/2 * BW * w0/sin(w0) )           (case: BW)
          = sin(w0)/2 * sqrt( (A + 1/A)*(1/S - 1) + 2 )         (case: S)

        FYI: The relationship between bandwidth and Q is
             1/Q = 2*sinh(ln(2)/2*BW*w0/sin(w0))     (digital filter w BLT)
        or   1/Q = 2*sinh(ln(2)/2*BW)             (analog filter prototype)

        The relationship between shelf slope and Q is
             1/Q = sqrt((A + 1/A)*(1/S - 1) + 2)

    2*sqrt(A)*alpha  =  sin(w0) * sqrt( (A^2 + 1)*(1/S - 1) + 2*A )
        is a handy intermediate variable for shelving EQ filters.


Finally, compute the coefficients for whichever filter type you want:
   (The analog prototypes, H(s), are shown for each filter
        type for normalized frequency.)


LPF:        H(s) = 1 / (s^2 + s/Q + 1)

            b0 =  (1 - cos(w0))/2
            b1 =   1 - cos(w0)
            b2 =  (1 - cos(w0))/2
            a0 =   1 + alpha
            a1 =  -2*cos(w0)
            a2 =   1 - alpha



HPF:        H(s) = s^2 / (s^2 + s/Q + 1)

            b0 =  (1 + cos(w0))/2
            b1 = -(1 + cos(w0))
            b2 =  (1 + cos(w0))/2
            a0 =   1 + alpha
            a1 =  -2*cos(w0)
            a2 =   1 - alpha



BPF:        H(s) = s / (s^2 + s/Q + 1)  (constant skirt gain, peak gain = Q)

            b0 =   sin(w0)/2  =   Q*alpha
            b1 =   0
            b2 =  -sin(w0)/2  =  -Q*alpha
            a0 =   1 + alpha
            a1 =  -2*cos(w0)
            a2 =   1 - alpha


BPF:        H(s) = (s/Q) / (s^2 + s/Q + 1)      (constant 0 dB peak gain)

            b0 =   alpha
            b1 =   0
            b2 =  -alpha
            a0 =   1 + alpha
            a1 =  -2*cos(w0)
            a2 =   1 - alpha



notch:      H(s) = (s^2 + 1) / (s^2 + s/Q + 1)

            b0 =   1
            b1 =  -2*cos(w0)
            b2 =   1
            a0 =   1 + alpha
            a1 =  -2*cos(w0)
            a2 =   1 - alpha



APF:        H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1)

            b0 =   1 - alpha
            b1 =  -2*cos(w0)
            b2 =   1 + alpha
            a0 =   1 + alpha
            a1 =  -2*cos(w0)
            a2 =   1 - alpha



peakingEQ:  H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1)

            b0 =   1 + alpha*A
            b1 =  -2*cos(w0)
            b2 =   1 - alpha*A
            a0 =   1 + alpha/A
            a1 =  -2*cos(w0)
            a2 =   1 - alpha/A



lowShelf: H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1)

            b0 =    A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha )
            b1 =  2*A*( (A-1) - (A+1)*cos(w0)                   )
            b2 =    A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha )
            a0 =        (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha
            a1 =   -2*( (A-1) + (A+1)*cos(w0)                   )
            a2 =        (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha



highShelf: H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A)

            b0 =    A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha )
            b1 = -2*A*( (A-1) + (A+1)*cos(w0)                   )
            b2 =    A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha )
            a0 =        (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha
            a1 =    2*( (A-1) - (A+1)*cos(w0)                   )
            a2 =        (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha





FYI:   The bilinear transform (with compensation for frequency warping)
substitutes:

                                  1         1 - z^-1
      (normalized)   s  <--  ----------- * ----------
                              tan(w0/2)     1 + z^-1

   and makes use of these trig identities:

                     sin(w0)                               1 - cos(w0)
      tan(w0/2) = -------------           (tan(w0/2))^2 = -------------
                   1 + cos(w0)                             1 + cos(w0)


   resulting in these substitutions:


                 1 + cos(w0)     1 + 2*z^-1 + z^-2
      1    <--  ------------- * -------------------
                 1 + cos(w0)     1 + 2*z^-1 + z^-2


                 1 + cos(w0)     1 - z^-1
      s    <--  ------------- * ----------
                   sin(w0)       1 + z^-1

                                      1 + cos(w0)     1         -  z^-2
                                  =  ------------- * -------------------
                                        sin(w0)       1 + 2*z^-1 + z^-2


                 1 + cos(w0)     1 - 2*z^-1 + z^-2
      s^2  <--  ------------- * -------------------
                 1 - cos(w0)     1 + 2*z^-1 + z^-2


   The factor:

                    1 + cos(w0)
                -------------------
                 1 + 2*z^-1 + z^-2

   is common to all terms in both numerator and denominator, can be factored
   out, and thus be left out in the substitutions above resulting in:


                 1 + 2*z^-1 + z^-2
      1    <--  -------------------
                    1 + cos(w0)


                 1         -  z^-2
      s    <--  -------------------
                      sin(w0)


                 1 - 2*z^-1 + z^-2
      s^2  <--  -------------------
                    1 - cos(w0)


   In addition, all terms, numerator and denominator, can be multiplied by a
   common (sin(w0))^2 factor, finally resulting in these substitutions:


      1         <--   (1 + 2*z^-1 + z^-2) * (1 - cos(w0))

      s         <--   (1         -  z^-2) * sin(w0)

      s^2       <--   (1 - 2*z^-1 + z^-2) * (1 + cos(w0))

      1 + s^2   <--   2 * (1 - 2*cos(w0)*z^-1 + z^-2)


   The biquad coefficient formulae above come out after a little
   simplification.

Sunday 28 October 2012

Direct Filters

DirectLowPass, DirectBandPass, DirectHighPass, DirectLowPassBessel, DirectBandPassBessel, DirectHighPassBessel


These six processors represent the work horse of subtractive synthesis and general filtering. They are non resonant infinite impulse response filters with variable cut-off rates. The versions which do not end in Bessel are Butterworth filters. The Bessel ones are Bessel filters. The difference in use is that the Bessel filters introduce hardly any phase distortion in the pass band but are much shallower than the Butterworth filters. The Butterworth filtes do introduce some phase distortion but are much steeper. At the time of writing Sonic Field does not have steeper IIR filters than Butterworth because the lobes in the pass and reject bands of such filters tend to make their use problematic. For a true 'brick wall' style filter convolution is the solution. However, as the Butterworth filters will (under some conditions) go up to 10 or even 11 order and still be stable, it is hard to see why one might want a sharper filter.

High and Low Pass Layout:
(?signal,?frequency,?order)DirectXXXPass !new-signal

Band Pass:
(?signal,?low-frequency,?high-frequency,?order)DirectXXXPass !new-signal

Where XXX is Low,High or Band. Put Bessel on the end of the processor name to get the equivalent Bessel Filter. Frequency is in Hz and order can be from 1 to 11 for low and high or 1 to 5 for band. However, sometimes these filters go unstable and produce non numbers or infinities in the outgoing signal. This is more likely with high pass filters with low frequency cut-offs or band pass where the upper frequency is low or where the two frequencies are very close (closer than 10%). Reducing the order makes it less likely for a filter to go unstable. Low pass filters are almost always stable. High pass are OK at 6 orders down to around 100 Hz and order 2 and 12 Hz (usually). Band pass is less stable and order 4 is only useful for frequencies over 200 Hz. These are all approximate values, experimentation is required.

Note: the higher the order, the steeper the filter. The cut-off frequencies are the -6db points.
 

Sunday 21 October 2012

Caverns Of Ganymede

Based upon the same generative framework as Oceans Of Europa, this is a very much more complex composition. It is only 10 minutes long because beyond that, without some considerable enhancements to Sonic Field, my computer runs out of memory!

The generative framework is slow enough in this piece to create a single theme which moves through the entire composition as a single piece. The sounds are a combination of string type effects, bells (using FM synthesis - see Bells Of Time) and simple oscillator effects. It is the use of resonance synthesis which gives the sounds complexity.

This piece employs some of the multi-dimensional stereo effects I first had real success with in Parted. Not only does it use left/center/right and Haas method to give left/right position and width but it uses carefully placed early reflections and long running reverberation to open out the sound stage infront and behind the listener.

Tuesday 16 October 2012

Jam In A Junk Yard Beginning


Pump up the volume!
Copyright: Dr Alexander J Turner All Rights Reserved
To try out the new and shiny (well - newly working) shaped band pass filter I have started to work on a series of ideas I call "Jam In A Junk Yard". The idea being to synthesise highly metallic sounds which are close to but not quite notes and use them to drive rhythms.

Check out music on sonic-field:
Jam In A Junk Yard Beginning

I am a big believer in creativity being derived form limitation. Given the near infinite pallet of sound creating techniques which a blank Sonic Field patch offers I just sit and think 'what should I do'. To create Jam In A Junk Yard Beginning I gave myself one sound generating patch and said 'you can only make sounds with this by altering its controls, stereo placement or resampling'. That much more restrictive environment lead to the creation of an interesting set of very metallic sounds (I hope).

To see and hear the piece on Youtube go herePlease listen/view in HD for get good quality. Also note that this piece uses some seriously low notes so laptop speakers will not play it properly.



So - what is this sub-patch from hell? It is a simple enough additive  subtractive, FM thing with some feedback delay. Really, it is not that complex so lets have a look at it:

(
        (?length,?pitch)SinWave MakeTriangle dbs+6,
        (?length,(?pitch,2)/)SinWave MakeTriangle dbs-6,
        (?length,(?pitch,4)/)SinWave MakeTriangle dbs-6,
        (?length,(?pitch,8)/)SinWave MakeTriangle
    )Mix Normalise !signal
    
This is the source of the sound; it is a simple addition of triangle waves which are in unusual magnitudes. Effectively, it contains sub-harmonics because the lower signals we much weaker then the high. Triangle waves only have odd harmonic overtones and I added even sub-harmonics; this thickens out the sound without creating any even harmonics from overlaying. The result in a big fat sound which is just right for subtraction and frequency modulation.

Some of those sub-harmonics become infra-sound for low notes so I filter out that then apply a band pass filter which is shaped. This means the lower and upper shoulders of the filter vary over time using two envolopes. I apply the filter three times to make it really sharp. This is numerically more stable than trying to apply a very steep filter in one go.

(&gt;signal,15,2)DirectHighPass !signal
    
    (&gt;signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal
    (&gt;signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal
    (&gt;signal,&gt;low-shape,&gt;high-shape,?order)ShapedBandPass Normalise !signal

Now we have a sound the timbre of which varies over time. The envelope (shape) for these filters is generated thus:

(?pitch,8)/ !bass
    ((0,?bass),(?wide-point,?bass),(?narrow-point,(?pitch,?narrow-amount)*),(?length,(?pitch,0.95)*))NumericShape !low-shape
    ((0,1000) ,(?wide-point,1000) ,(?narrow-point,(?pitch,?narrow-amount)/),(?length,(?pitch,0.95)*))NumericShape !high-shape

So the sound starts with very little filtering and then narrows to one width and then narrows again to a very tight filter. That is at least the way I use it; the patch is complex enough to allow the filter to widen towards the end if that effect was desired. The width and positioning of these points are parameters for the patch.

Next I hit it with frequency modulation and overdrive. This makes it sound like a mike over loading listening to a piece of metal being hit - which is where the junk yard sound comes from:

(
        &gt;signal,
        (
            (
                ?length,
                (?pitch,1.2)*
            )SinWave,
            ?modulation-index
        )Volume
    )FrequencyModulate !signal 
    ((
        (?a,?b,?c,?d,?e)NumericShape,
        &gt;signal
    )Multiply Normalise,?over-drive)Volume Saturate Normalise !signal

Finally some feed back delay (like guitarists use but with more layers) is applied to give resonance to the sound and some post filtering to help control the brilliance (to give dull thuds and sharper clangs) and cut low rumble is added.

(?length,2000)/ !res-scale
    (
        (?signal,4000 Silence)Concatenate,
        (
            (-14,((160,?pitch Period)+,?res-scale)* Prime),
            (-15,((190,?pitch Period)+,?res-scale)* Prime),
            (-14,((320,?pitch Period)+,?res-scale)* Prime),
            (-15,((355,?pitch Period)+,?res-scale)* Prime),
            (-17,((380,?pitch Period)+,?res-scale)* Prime)
        )
    ) DirectResonate Normalise !wet
    (
        &gt;wet,
        ?signal Invert
    )Mix !wet
    (
        &gt;signal,
        &gt;wet Normalise
    )Mix Normalise !signal
    
    (&gt;signal,?post-cut-low,3 )DirectLowPass Normalise !signal
    (&gt;signal,?post-cut-high,2)DirectHighPass Normalise !signal
    &gt;signal ClipToSafe

All this processing can result in the zero point of the signal moving away from true zero. ClipToSafe removes any annoying clicks which this would produce in the mix.

The result of the patch creates sounds to make a rhythm. With some suggestions form my wonderful wife, this version of Jam In A Junk Yard messes with that rhythm. The piece is generated twice with very slightly different beats. One is at 750 milliseconds and the other at 760. The stereo mix is inverted in the two versions. It is the result of this which is passed into a simple and slightly claustrophobic reverb' effect. My messing with the rhythm timing this way, the two generations move through one another. Listening to the sounds produces (in me) the interesting effect that just as I think I am getting used to it the rhythms move enough to create a noticeably different pattern and I am drawn back into the piece. I would not say it captures my attention for all 21 minutes (hardly!) but as something in the background which reaches forward into the foreground every so often - it is quite surprising. The most obvious place to hear this effect is around 15 minutes in where the two rhythms line up and the Haas effect makes the sounds appear wide instead of distinct left and right channels; then, over the next minute or so the rhythms slowly separate.

I hope to make a release of Sonic Field which has the newly working filter in it later this week.


Note that this patch and the music its creates is Copyright Dr Alexander J Turner 2012 and I license it under theCreative Commons Attribution 3.0 license. To use the patch or any music derived from it etc, please attribute Sonic Field, myself and this original work.

{
    (?pitch,8)/ !bass
    ((0,?bass),(?wide-point,?bass),(?narrow-point,(?pitch,?narrow-amount)*),(?length,(?pitch,0.95)*))NumericShape !low-shape
    ((0,1000) ,(?wide-point,1000) ,(?narrow-point,(?pitch,?narrow-amount)/),(?length,(?pitch,0.95)*))NumericShape !high-shape
    (
        (?length,?pitch)SinWave MakeTriangle dbs+6,
        (?length,(?pitch,2)/)SinWave MakeTriangle dbs-6,
        (?length,(?pitch,4)/)SinWave MakeTriangle dbs-6,
        (?length,(?pitch,8)/)SinWave MakeTriangle
    )Mix Normalise !signal
    
    (&gt;signal,15,2)DirectHighPass !signal
    
    (&gt;signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal
    (&gt;signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal
    (&gt;signal,&gt;low-shape,&gt;high-shape,?order)ShapedBandPass Normalise !signal
    
    (
        &gt;signal,
        (
            (
                ?length,
                (?pitch,1.2)*
            )SinWave,
            ?modulation-index
        )Volume
    )FrequencyModulate !signal 
    ((
        (?a,?b,?c,?d,?e)NumericShape,
        &gt;signal
    )Multiply Normalise,?over-drive)Volume Saturate Normalise !signal
    (?length,2000)/ !res-scale
    (
        (?signal,4000 Silence)Concatenate,
        (
            (-14,((160,?pitch Period)+,?res-scale)* Prime),
            (-15,((190,?pitch Period)+,?res-scale)* Prime),
            (-14,((320,?pitch Period)+,?res-scale)* Prime),
            (-15,((355,?pitch Period)+,?res-scale)* Prime),
            (-17,((380,?pitch Period)+,?res-scale)* Prime)
        )
    ) DirectResonate Normalise !wet
    (
        &gt;wet,
        ?signal Invert
    )Mix !wet
    (
        &gt;signal,
        &gt;wet Normalise
    )Mix Normalise !signal
    
    (&gt;signal,?post-cut-low,3 )DirectLowPass Normalise !signal
    (&gt;signal,?post-cut-high,2)DirectHighPass Normalise !signal
    &gt;signal ClipToSafe
} !clang

{
    0   !time
    2000        !length
    2           !order
    "e0b" note  !pitch
     200        !wide-point
     600        !narrow-point
    0.7         !narrow-amount
    (1.0,0)     !a
    (1,500)     !b
    (1000,0.5)  !c
    (1850,0.25) !d
    (?length,0) !e
    "e4b" Note  !post-cut-low
    15          !post-cut-high
    0           !modulation-index 
    
    24          !over-drive
    ?clang Do   !1
    
    36          !over-drive
    "e1b" note  !pitch
    0.99        !narrow-amount
    ?clang Do   !2
    ?clang Do   !3
    
    0.9         !narrow-amount
    "b1b" note  !pitch
    12          !modulation-index 
    ?clang Do   !4
    (
        (&gt;1 Done dbs+6 !1,?time),
        (&gt;2 Done !2,(?beat,&gt;time)+ !time), 
        (&gt;3 Done !3,(?beat,&gt;time)+ !time), 
        (&gt;4 Done !4,(?beat,&gt;time)+ !time)
    )MixAt !low-rhyth
    
    (
        1,400,
        {
            (
                (&gt;low-rhyth,0),
                (?1,(?beat,&gt;time)+ !time),
                (?2,(?beat,&gt;time)+ !time), 
                (?3,(?beat,&gt;time)+ !time), 
                (?4,(?beat,&gt;time)+ !time)
            )MixAt !low-rhyth
        }
    )Repeat
    &gt;low-rhyth Normalise !signal
    
    [ Dong low ]
    1000        !length
    3           !order
    "g4" note   !pitch
     500        !wide-point
     600        !narrow-point
    0.8         !narrow-amount
    (1.5,0)     !a
    (1,2000)     !b
    (750,0.5)   !c
    (950,0.25)  !d
    (?length,0) !e
    24          !modulation-index 
    24          !over-drive
    ?clang Do   !b1
    
    0 Silence !left !right !centre
    
    (?beat,4)* !time
    (
        (&gt;centre,0),
        (&gt;b1 Done dbs-6 !b1,(&gt;time,(?beat,8)*)+ !time)
    )MixAt !centre
    
    (
        1,200,
        {
            (
                (&gt;centre,0),
                (?b1,       (&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre
        }
    )Repeat
    
    [ clang medium ]
    750         !length
    3           !order
    "b6b" note  !pitch
     200        !wide-point
     500        !narrow-point
    0.7         !narrow-amount
    (1,0)       !a
    (1,2000)     !b
    (300,0.5)   !c
    (400,0.25)  !d
    (?length,0) !e
    12          !modulation-index 
     3          !over-drive
     2500       !post-cut-low
    "b4b" Note  !post-cut-high 
    ?clang Do Done !b2
    (
        (?b2,0),
        (?b2,50)
    )MixAt Normalise dbs-18 !b2
    
    (?beat,21)* !time
    (
        1,200,
        {
            (
                (&gt;centre,0),
                (?b2,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre
            
            (
                (&gt;left,0),
                (?b2,?time)
            )MixAt !left
        }
    )Repeat
    
    [ clang high ]
    750         !length
    3           !order
    "b6b" note  !pitch
     100        !wide-point
     200        !narrow-point
    0.9         !narrow-amount
    (1,0)       !a
    (1,2000)     !b
    (300,0.5)   !c
    (400,0.25)  !d
    (?length,0) !e
    12          !modulation-index 
     3          !over-drive
     5000       !post-cut-low
    "b6b" Note  !post-cut-high 
    ?clang Do Done !b2
    (
        (?b2,0),
        (?b2,50)
    )MixAt Normalise dbs-24 !b3
    
    (?beat,29.5)* !time
    (
        1,200,
        {
            (
                (&gt;centre,0),
                (?b3,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre
            
            (
                (&gt;right,0),
                (?b3,?time)
            )MixAt !right
        }
    )Repeat

    (&gt;b3,0.75)DirectRelength !b3
    (?beat,62.75)* !time
    (
        1,200,
        {
            (
                (&gt;centre,0),
                (?b3 dbs-3,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre
            
            (
                (&gt;right,0),
                (?b3 dbs+3,(?time,30)-)
            )MixAt !right
        }
    )Repeat
    
    [ high dong in middle ]
    (?b1,1.5)DirectReLength !b4
    (?beat,40)* !time
    (
        1,20,
        {
            (
                (&gt;centre,0),
                (?b4,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre    
        }
    )Repeat
    
    (?b1,(5,3)/)DirectReLength !b5
    (?beat,49)* !time
    (
        1,200,
        {
            (
                (&gt;centre,0),
                (?b5 dbs-6,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre
            (
                (&gt;left,0),
                (?b5,?time)
            )MixAt !left
            
        }
    )Repeat
    
    [ ting te te te high ]
    8000        !length
    2           !order
    "b1b" note  !pitch
    1000        !wide-point
    1500        !narrow-point
    0.9         !narrow-amount
    (1.5,0)     !a
    (1,1000)    !b
    (5000,0.5)  !c
    (7000,0.25) !d
    (?length,0) !e
    18          !modulation-index 
     6          !over-drive
     5000       !post-cut-low
     32         !post-cut-high 
    ?clang Do Done !b6
    (&gt;b6,16)DirectRelength !b6 !b6-source
    (?beat,4)/ !qbeat
    (
        (?b6 dbs+6,0),
        (?b6      ,?qbeat),
        (?b6      ,(?qbeat,2)*),
        (?b6      ,(?qbeat,3)*)    
    )MixAt Normalise dbs-12 !b6 
    
    (?beat,58.1)* !time
    (
        1,200,
        {
            (
                (&gt;right,0),
                (?b6 dbs-6,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !right
            (
                (&gt;left,0),
                (?b6,(?time,30)+)
            )MixAt !left
            (
                (&gt;centre,0),
                (?b6,?time)
            )MixAt !centre
            
        }
    )Repeat
    
    [ Dong massive ]
    (?beat,62.9)* !time
    1500        !length
    3           !order
    "f3" note   !pitch
    1000        !wide-point
    1300        !narrow-point
    0.95        !narrow-amount
    (2.5,0)     !a
    (1,500)     !b
    ( 750,0.25) !c
    (1400,0.25) !d
    (?length,0) !e
    12          !modulation-index 
    36          !over-drive
    "f5"  Note  !post-cut-high
    "f1"  Note  !post-cut-low
    ?clang Do  Done !b7
    (
        1,200,
        {
            (
                (&gt;centre,0),
                (?b7 ,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !centre
        }
    )Repeat
    
    (&gt;b6-source,(2,3)/)DirectRelength !b8
    (?beat,4)/ !qbeat
    (
        (?b8 dbs+6,0),
        (?b8      ,?qbeat),
        (?b8      ,(?qbeat,2)*),
        (?b8      ,(?qbeat,3)*)    
    )MixAt Normalise dbs-12 !b8 
    (?beat,(60,16)+)* !time
    (
        1,200,
        {
            (
                (&gt;right,0),
                (?b8 dbs-6,(&gt;time,(?beat,8)*)+ !time)
            )MixAt !right
            (
                (&gt;centre,0),
                (?b8,(?time,30)+)
            )MixAt !centre
            
        }
    )Repeat
    
    
    [ Stich it all together ]
    (
        (&gt;left,0),
        (?signal,50),
        (?centre,0)
    )MixAt Normalise !left
    
    (
        (&gt;right,0),
        (&gt;signal,0),
        (&gt;centre,0)
    )MixAt Normalise !right
    (&gt;left,&gt;right)
    
} !play
750 !beat
?play Do !750
760 !beat
?play Do !800

&gt;750 Done !bus1
&gt;800 Done !bus2

(
    ?bus1 GetStart,
    ?bus2 GetRest GetStart
)Mix Normalise !left

(
    ?bus1 GetRest GetStart,
    ?bus2 GetStart
)Mix Normalise !right

[
(
    ((48,?beat)*,?left  length,?left)Cut,
    ((48,?beat)*,?right length,?right)Cut
)StereoMonitor
]

(
    1,12,
    {
        !t
        {((30,(?t,10)*)+ Silence,?left)Concatenate } Do !nlTask
        {((40,(?t,10)*)+ Silence,?right)Concatenate} Do !nrTask
    
        {((?nlTask Done, -18)Volume,2000,1)DirectLowPass} Do  !nlTask
        {((?nrTask Done, -18)Volume,2000,1)DirectLowPass} Do  !nrTask
    
        {(?nlTask Done, ?left) Mix Normalise} Do !nlTask 
        {(?nrTask Done, ?right)Mix Normalise} Do !nrTask
        
        ?nlTask Done !left
        ?nrTask Done !right
    }
)Repeat

    
((&gt;left,&gt;right),"temp/tone.wav")WriteFile32

Wednesday 10 October 2012

Parted-2 Post Processing

Messing With Stereo And Reflections

Recently I posted over on Nerds-Central a piece called Parted. This render was done in two stages. The first patch produced the basic sounds however, the post processing step added stereo depth.
"temp/parted-1.wav"      !wavFile
?wavFile ReadFile          !channels
?channels GetStart         !left
&gt;channels GetRest GetStart !right
(
    (?left !lefto,1500,1)DirectLowPassBessel,
    &gt;left dbs-3
)Mix Normalise !left
(
    (?right !righto,1500,1)DirectHighPassBessel,
    &gt;right dbs-3
 )Mix Normalise !right

(
    (&gt;right,0),
    (?lefto dbs-18,80),
    (?lefto dbs-18,260),
    (?lefto dbs-18,340)
)MixAt !right
 
(
    (&gt;left,0),
    (?righto dbs-18,120),
    (?righto dbs-18,250),
    (?righto dbs-18,330)
)MixAt !left
 
(
    (
        (1000 Silence,&gt;left Normalise)Concatenate,
        (1000 Silence,&gt;right Normalise)Concatenate
    ),
    "temp/parted-2.wav"
)WriteFile32
 The first bit takes a stereo (2 channel) wav file and reads it into two separate audio signals:

"temp/parted-1.wav"      !wavFile
?wavFile ReadFile          !channels
?channels GetStart         !left
&gt;channels GetRest GetStart !right

The input here was pure stereo; the render was effectively done twice, one for each channel. As quite a lot of the detailing in the piece comes from random numbers, the two channels were subtly different, especially in the reverb. However, the effect was a little cold and artificial. The next steps helped sort that out.

(
    (?left !lefto,1500,1)DirectLowPassBessel,
    &gt;left dbs-3
)Mix Normalise !left
(
    (?right !righto,1500,1)DirectHighPassBessel,
    &gt;right dbs-3
 )Mix Normalise !right 

These gave left and right very slightly different tonal differences. More highs on the right and more lows on the left. I used Bessel filters to avoid 'phasing' effects when mixing back with the original otherwise the result might have sounded like a 1970 pop song!

(
    (&gt;right,0),
    (?lefto dbs-18,80),
    (?lefto dbs-18,260),
    (?lefto dbs-18,340)
)MixAt !right
   
(
    (&gt;left,0),
    (?righto dbs-18,120),
    (?righto dbs-18,250),
    (?righto dbs-18,330)
)MixAt !left

These added a few early reflections to the audio which already had reverberation in it. The effect of this it to add a really etherial sound and completely confuse the brain. It is not possible to properly imagine a space which would have this audio structure to it, so the sound just becomes 'other worldly'.

(
    (
        (1000 Silence,&gt;left Normalise)Concatenate,
        (1000 Silence,&gt;right Normalise)Concatenate
    ),
    "temp/parted-2.wav"
)WriteFile32

It is always important to put some silence before a piece starts to allow the audio player (itunes, youtube or what ever) to get started. Here I added 1 second. Actually, I think this is a little too little and should have added 2 seconds.

ValueAt

ValueAt

Sometimes it can be handy to find the numeric value of an audio signal at a point in time. Bells Of Time uses this technique to get timing from sin waves to produce complex and non repeating sequences of pitch, timbre, volume and timing. Visualisation is another area where this technique is very important. ValueAt provides the signal value at a point in milliseconds.

(1000,1)SinWave !signal
Bunch !samples
(
    1,100,
    {
        !x
        (?signal,(?x,10)*)ValueAt !s
        (&gt;s,&gt;samples)AddEnd  !samples
    }
)Repeat
&gt;samples ToJson Println

The patch above produces this:
[0.06279052048921585,0.12533323466777802,0.187381312251091,0.24868988990783691,0.30901700258255005,0.3681245446205139,0.4257792830467224,0.4817536771297455,0.5358268022537231,0.5877852439880371,0.6374239921569824,0.6845471262931824,0.728968620300293,0.7705132365226746,0.80901700258255,0.8443279266357422,0.8763066530227661,0.9048270583152771,0.9297764897346497,0.9510565400123596,0.9685831665992737,0.9822872281074524,0.9921147227287292,0.9980267286300659,1.0,0.9980267286300659,0.9921147227287292,0.9822872281074524,0.9685831665992737,0.9510565400123596,0.9297764897346497,0.9048270583152771,0.8763066530227661,0.8443279266357422,0.80901700258255,0.7705132365226746,0.728968620300293,0.6845471262931824,0.6374239921569824,0.5877852439880371,0.5358268022537231,0.4817536771297455,0.4257792830467224,0.3681245446205139,0.30901700258255005,0.24868988990783691,0.187381312251091,0.12533323466777802,0.06279052048921585,1.2246468525851679E-16,-0.06279052048921585,-0.12533323466777802,-0.187381312251091,-0.24868988990783691,-0.30901700258255005,-0.3681245446205139,-0.4257792830467224,-0.4817536771297455,-0.5358268022537231,-0.5877852439880371,-0.6374239921569824,-0.6845471262931824,-0.728968620300293,-0.7705132365226746,-0.80901700258255,-0.8443279266357422,-0.8763066530227661,-0.9048270583152771,-0.9297764897346497,-0.9510565400123596,-0.9685831665992737,-0.9822872281074524,-0.9921147227287292,-0.9980267286300659,-1.0,-0.9980267286300659,-0.9921147227287292,-0.9822872281074524,-0.9685831665992737,-0.9510565400123596,-0.9297764897346497,-0.9048270583152771,-0.8763066530227661,-0.8443279266357422,-0.80901700258255,-0.7705132365226746,-0.728968620300293,-0.6845471262931824,-0.6374239921569824,-0.5877852439880371,-0.5358268022537231,-0.4817536771297455,-0.4257792830467224,-0.3681245446205139,-0.30901700258255005,-0.24868988990783691,-0.187381312251091,-0.12533323466777802,-0.06279052048921585,0.0]

Which is a full cycle of a 1Hz sin wave sampled every 10 milliseconds represented as a JSON (a useful format for communicating between systems) list.

Friday 5 October 2012

Comments

SFPL Comments

Tomorrow I will forget how something I wrote today works. This is why we have comments.

SFPL has a carefully designed commenting system which goes beyond those of many other languages (which, in effect SFPL is). However, they are also really simple.

To create a comment just use [ write something here ]

Anything between square brackets will be ignored by SFPL. Also, comments can be placed inside comments (unlike /* */ comments in C for example) and comments can span many lines:

[ this is a comment]
[ this is a comment [ with a comment inside it ]]
[
  this
  ===
  is
  a
  multi-line comment
]

One thing which is not a comment is  this

Monitor[ monitor the singal ]

SFPL will think we are trying to use a processor called Monitor[ ; the correct layout is:

Monitor [ monitor the singal ]

If you are a language minded sort of person then we could say "comments must start with a new token"

Why do we have comments inside comments? Sometimes we want to be able to turn off chunks of patch whilst we are working on a performance. For example
?make-tuneA Do !tune-a-do
?make-tuneB Do !tune-b-do
(
    >tune-a-do,
    >tune-b-do
)DoAll Mix !signal
?reverberate Do Done !signal [ add reverb - this takes a long time ]
>signal Monitor
If we are just working on the tune, running the reverberation each time we want to listen to the result might be a waste of time so we can just 'comment out' that bit:


?make-tuneA Do !tune-a-do
?make-tuneB Do !tune-b-do
(
    >tune-a-do,
    >tune-b-do
)DoAll Mix !signal
[?reverberate Do Done !signal [ add reverb - this takes a long time ]]
>signal Monitor

Because comments can be nested, it does not matter that we have a comment inside a comment. This is a very powerful and easy to use trick in SFPL.

Applying An Envelope - Simple and Numeric Shapes

SimpleShape NumericShape

Making sounds - like the sinwave - is the start of synthesis. However, any real sounding note will also have a volume envelope. Sonic Field uses the same sort of signal for controls like envelopes as it does for audio signals. This means that all the processors which work on audio signals will also work as control signals.

Volume envelopes are easiest to make using the SimpleShape and NumericShape processors:

(
    (0,-99),
    (1000,0),   [attack]
    (2000,-6),  [decay]
    (5000,-8),  [sustain]
    (6000,-99) [release] )SimpleShape !envelope (     (6000,440)SinWave,     ?envelope )Multiply Monitor

Here we make a classic envelope with an attack/decay/sustain/release cycle. The bunches in the input to the SimpleShape processor give time in milliseconds and volume in decibels. So we can read it as saying:

  1. Make and envelope
  2. At 0 milliseconds have -99 decibels which is near silence
  3. Increase till
  4. At 1 second have 0 decibels which is full volume
  5. Decrease till
  6. At 2 seconds have -6 decibels which is half the amplitude
  7. Decrease till
  8. At 5 seconds have -8 decibels
  9. Decrease till
  10. At 6 seconds have -99 decibels which is near silence again


Using SimpleEnvelope defines the shape of the signal is decibels. This is a natural approach because human hearing approximates to perceiving volume on a decibel scale. However, sometimes we want to define envelopes based on a linear scale. This is useful for creating more artificial sounding sustain and also (as we will see elsewhere) for using envelopes for other things than just volume.


(
    (0,0),
    (1000,1),    [attack]
    (2000,0.5),  [decay]
    (5000,0.4),  [sustain]
    (6000,0) [release] )NumericShape !envelope (     (6000,440)SinWave,     ?envelope )Multiply Monitor


This produces an envelop with the same timings as the previous but with linear interpolation between the points rather than logarithmic.

The names SimpleShape and NumericShape come from the history of SFPL. Initially it did not even have NumericShape. 


Wednesday 3 October 2012

Making Sin Waves

SinWave

The simplest thing we need to be able to do in synthesis is to create sin waves:

(10000,300)SinWave

The above achieves this. It will create a 10 second long signal at 300Hz. If we want to listen to the result we can do the following:


(10000,300)SinWave Monitor


The above patch will play the sin wave on the computer's default sound output system.

How it works:


(10000,300)


This creates a bunch with two elements. The first element is the number 10000 and the second is the number 300.


SinWave


This takes a bunch of two numbers as its input and forwards a signal containing the appropriate sin wave moving between -1 and 1. The first number from the bunch is the time in milliseconds and the second is the frequency in Hz.


Monitor


This takes a signal as the input and plays it on the computer's default sound output.

Sonic Field Released Under AGPL

A visualisation of Sonic Field's rendering 'Bells Of Time'
Sonic Field has stabilised enough to be released under AGPL-3. It is still very rough, but can do some very complex programmatic compositions, synthesises and audio processes. It is time to let others see the code I have written (gulp).
It is true that there are many software, programming language based audio processing systems out there already. Supercollider is a famous example of the genre. However, I do feel that the area of arbitrary complexity non real time processing and synthesis is neglected. Further, the current batch of such systems are largely written in C or C++ and come from a single threaded, non distributed computational paradigm. Sonic Field has a full multi-threaded, parallel programming model and is written entirely in cross platform, pure Java. Sonic Field uses the Spring Framework for services and it is my aim to create a web/html5 based UI for it using Spring MVC (work in progress as we speak).
For more information on Sonic Field, check out the blog I have create for it! This will become the main place for documentation for Sonic Field. There is no point supporting a full documentation system and useful commenting system (even if anyone uses it) when blogger does it all for you! You can download Sonic Field from the main Sonic Field website:


So what can Sonic Field Really Do?
My favourite piece from Sonic Field (so far) is Acceptance. I like it because I hand crafted each note rather than use some form of automatic envelope and pitch system based on lists of notes as I have in other compositions. 
So, to finish this post, here is the patch which creates Acceptance:
[Absolute brick wall at 20KHz]
(20000 Period,50)SincShape NormaliseArea !brick
{
    (>signal,>brick)Convolve Normalise 
}!brick-wall-filter

{
    (>length,2)* !length
    (?length,(?pitch,2)-)SinWave !signal1 
    (?length,(?pitch,2)+)SinWave !signal2 
    (?length,(?pitch,1.2)*)SinWave dbs+48 !fm1
    (?length,(?pitch,1.3)*)SinWave dbs+12 !fm2
    
    (
        (
            ?signal1,
            >fm1
        )FrequencyModulate,
        (
            >signal2 dbs-24,
            >fm2
        )FrequencyModulate,
    )Mix Normalise !signal
    
    (
        >signal,
        (
            (100 WhiteNoise,?pitch,2)DirectLowPass,
            (
                (0,0),
                (20,1),
                (100,0)
            )NumericShape
        )Multiply
    )Mix Normalise !signal
    
    (
        (0,-99),
        (50,0),
        (?length,-99)
    )SimpleShape !env
    (
        >signal,
        >env
    )Multiply !signal
    
    (>signal,(?pitch,2)*,2)DirectHighPass !signal
    (>signal,(?pitch,1)*,?dullness)DirectlowPass  !signal
}!play-bell

{
    (?sample,1000,5)DirectLowPass  !sampleL
    (?sample,3000,2)DirectLowPass  !sampleN
    (?sample,1000,4)DirectHighPass !sampleH
    (>sampleH,5000,2)DirectLowPass !sampleH
    (?sample,((?first ,?offset)+ Prime Silence,(?sample,-13)Volume)Concatenate)Mix    !wet
    (
        1,2,
        {
            !z
            (>first,1.2)* Prime !first
            (>wet,(((?first,30)-,?offset)- Silence,(?sampleL,(-10,?z)-)Volume)Concatenate)Mix   !wet
            (>wet,(((?first,30)+,?offset)- Silence,(?sampleN,(-6, ?z)-)Volume)Concatenate)Mix   !wet
            (>wet,((?first      ,?offset)- Silence,(?sampleH,(-10,?z)-)Volume)Concatenate)Mix   !wet
        }
    )Repeat
    (?sampleL,1000,1)DirectLowPass  !sampleL
    (?sampleN,1000,1)DirectLowPass  !sampleN
    (?sampleH,2000,1)DirectLowPass  !sampleH
    (
        (0,0),
        ((?wet Length,3)/,1),
        (?wet Length,0)
    )NumericShape !env
    (
        3,20,
        {
            !z 
            (?z,2)/ !z
            (>first,1.1)* Prime !first
            (>wet,(((?first,30)-,?offset)- Silence,((?sampleL,(-7,?z)-)Volume,?env)Multiply)Concatenate)Mix    !wet
            (>wet,(((?first,30)+,?offset)- Silence,((?sampleN,(-4,?z)-)Volume,?env)Multiply)Concatenate)Mix    !wet
            (>wet,((?first      ,?offset)- Silence,((?sampleH,(-7,?z)-)Volume,?env)Multiply)Concatenate)Mix    !wet
        }
    )Repeat
    (
        20,40,
        {
            !z 
            (?z,3)/ !z
            (>first,1.05)* Prime !first
            (>wet,(((?first,30)-,?offset)- Silence,(((?sampleL,(-7,?z)-)Volume,?env)Multiply,500,2)DirectLowPass)Concatenate)Mix    !wet
            (>wet,(((?first,30)+,?offset)- Silence,(((?sampleN,(-4,?z)-)Volume,?env)Multiply,500,2)DirectLowPass)Concatenate)Mix    !wet
            (>wet,((?first      ,?offset)- Silence,(((?sampleH,(-7,?z)-)Volume,?env)Multiply,500,2)DirectLowPass)Concatenate)Mix    !wet
        }
    )Repeat
    >wet
} !reflector


{
    (?length,(?pitch,((Random,0.5)-,5)*)-,Random)PhasedSinWave !signal
    ?wave-shape Do Done !signal
    (((?length,500)/ WhiteNoise,2500,6)DirectLowPass,0.001)DirectRelength Normalise !multi
    (0,?signal Length,>multi)Cut  !multi
    (
        (1,>multi pcnt+2 )DirectMix,
        >signal
    )Resample !signal
    (>signal,(?pitch,4)*,1)DirectLowPass Normalise
} !string

{ >signal MakeTriangle } !triangle-shape
{ >signal MakeSawTooth } !saw-tooth-shape

{
    {
        (?pitch,4)/  !pitch
        (?length,4)* !length
        ( 
            { ?triangle-shape  !wave-shape ?string Do Done },
            { ?triangle-shape  !wave-shape ?string Do Done },
            { ?triangle-shape  !wave-shape ?string Do Done },
            { ?triangle-shape  !wave-shape ?string Do Done },
            { ?saw-tooth-shape !wave-shape ?string Do Done },
            { ?saw-tooth-shape !wave-shape ?string Do Done },
            { ?saw-tooth-shape !wave-shape ?string Do Done }
        )DoAll Mix Normalise !base
        (>base,4)DirectRelength Normalise
    } Do Done !sample
      
    (>sample,(?pitch,5)*,2)DirectLowPass !sample 
    
    ((?length WhiteNoise,500,6)DirectLowPass,0.01)DirectResample Normalise !multi
    (>multi,(?pitch,2)/,6)DirectHighPass Normalise !multi
    (
        (0.5,?multi pcnt+5)DirectMix,
        >sample
    )Multiply Normalise  !sample 
    
    (>sample,(?pitch,2)/,6)DirectHighPass Normalise !sample
    (
        (
            (0,-99),
            (150,0),
            ((?sample Length,2)/,0),
            (?sample Length,-99)
        )SimpleShape,
        >sample
    )Multiply Normalise
    
} !play-strings
[ Parameters for play-strings
  ===========================
  length
  pitch
  
  Forwards
  ========
  A signal
]

{ 
    {
        (?pitchLocal,((Random,0.5)-,6)*)+                      !pitch
        (?lengthLocal,?pitch,Random)PhasedSinWave MakeSawTooth !signal
        [?brick-wall-filter Do Done !signal]
        (
            (
                (?signal Length,1.5)* WhiteNoise,
                (500,?over-sample)/,
                6
            )DirectLowPass,
            0.01
        )DirectResample Normalise                 !multi
        (0,?signal Length,>multi)cut              !multi 
        (0.5,>multi Normalise pcnt+45)DirectMix   !shape
        ?brick-wall-filter Do Done !signal
        (>signal,>shape)ShapedThreshold Normalise !signal
        (>signal,(10000,?over-sample)/,6)DirectLowPass 
    }!horn
    (1,(?pitch,100)/)Min !over-sample
    (?pitch,?over-sample)/  !pitchLocal
    (?length,?over-sample)* !lengthLocal
    (
        ?horn,
        ?horn,
        ?horn,
        ?horn,
        ?horn,
        ?horn,
        ?horn,
        ?horn
    )DoAll Mix Normalise                !signal
    (>signal,?over-sample)DirectRelength Normalise !signal
    ?signal Length !length
    (
        (0,0.1),
        ((?length,2)/,0.5),
        (?length,0.1)
    )NumericShape !resonance
    (
        (0,?pitch),
        ((?length,2)/,(?pitch,4)*),
        (?length,?pitch)
    )NumericShape !cutoff
    (
        >signal,
        >cutoff,
        >resonance
    )ShapedLadderFilter                !signal
    (
        (0,0),
        (?attack,(1,?softness)-),
        (
            ((?attack,4)*,(?length,2)/)Min,
            -10
        ),
        (
            ((?attack,4)*,(?length,0.8)*)Min,
            -10
        ),
        (?length,0)
    )NumericShape !envelope
    (>signal,12,1)DirectHighPass Normalise  !signal
    (
        >signal,
        >envelope
    )Multiply Normalise !signal-horn
    
    [Add softness]
    (
        (0,      (?pitch,8)/),
        (?attack,(?pitch,4)/),
        (?length,12)
    )NumericShape !cutoff

    (
        (0,0.25),
        (?attack,0.5),
        (?length,0)
    )NumericShape !resonance
        
    (
        (?length WhiteNoise,(?pitch,1)*,(?pitch,4)*,?filter-factor)DirectBandPass,
        >cutoff,
        >resonance
    )ShapedLadderFilter !signal-soft

    (
        (0,-60),
        ((?attack,4)/,-6),
        (?attack,0),
        (
            ((?attack,4)*,(?length,2)/)Min,
            -10
        ),
        (?length,-60)
    )SimpleShape !envelope    

    (?signal-soft,0.95,0.15,?pitch Period)ResonantFilter Normalise !signal-soft
     
 
    (>signal-soft,(?pitch,1)*,1)DirectLowPass !signal-soft    
    (>signal-soft,12,1)DirectHighPass Normalise  !signal-soft
    (
        >signal-soft,
        >envelope
    )Multiply !signal-soft

    (>signal-soft,?softness)NumericVolume     !signal-soft
    
    (
        >signal-horn,
        >signal-soft
    )Mix Normalise
    
} !play-horn

[ Parameters for play-horn:
  =========================
  length
  pitch
  softness [0 to 1]
  attack
  filter-factor [1 to 4]
  
  Forwards
  ========
  A signal
]

{
    (((?signal, ?drive-left )NumericVolume,?delay-left ))MixAt !left
    (((?signal, ?drive-right)NumericVolume,?delay-right))MixAt !right
    
    (
        (?left  pcnt+40,0),
        (?right pcnt+2,(?room-size,0.5)*),
        (?right pcnt+2,(?room-size,0.75)*),
        (?right pcnt+2,?room-size)
    )MixAt !left

    (
        (?right pcnt+90,0),
        (?left  pcnt+2,(?room-size,0.5)*),
        (?left  pcnt+2,(?room-size,0.75)*),
        (?left  pcnt+2,?room-size)
    )MixAt !right

    (
        (?right pcnt+5,(?room-size,2)/),
        (?left  pcnt+5,(?room-size,2)/)
    )MixAt !middle
    
    (
        ?left,
        ?middle
    )Mix Normalise !left
    
    (
        ?right,
        ?middle
    )Mix Normalise !right
    [ Remove any initial click ]
    (
        (
            (0,-99),
            (100,0),
            (?right Length,0)
        )SimpleShape,
        >right
    )Multiply !right

    (
        (
            (0,-99),
            (100,0),
            (?left Length,0)
        )SimpleShape,
        >left
    )Multiply !left

    
    (>left,>right)
}!place-in-room
[ Parameters For place-in-room
  ============================
  delay-left
  drive-left
  delay-right
  drive-right
  room-size
  signal
 
  Forwards
  ========
  left right bunch
]
[
(100000,(10,(2,0.5)**)* )SinWave !sqrt2-samples 
(100000,(10,(3,0.5)**)* )SinWave !sqrt3-samples 
(100000,(10,(5,0.5)**)* )SinWave !sqrt5-samples
(100000,(10,(7,0.5)**)* )SinWave !sqrt7-samples
]

{
    ?place-in-room Do Done !bus  
    ?bus GetStart          !leftTone
    >bus GetRest GetStart  !rightTone
    ((>left, 0),((>leftTone,?volume)Volume, ?pos))MixAt !left
    ((>right,0),((>rightTone,?volume)Volume,?pos))MixAt !right
}!mix-in

1 Silence !left !right
0    !pos
1500 !beat
0    !volume
[ 
    Start
  -=======-   
]

[ Note  1  Bar 1 Beat 1]
    (?beat,2)/ !length
     "e4b" Note !pitch
      0.8  !softness
      250  !attack
        2  !filter-factor
    ?play-horn Do Done Normalise !signal
    (>signal,?pitch,(?pitch,2)*,4)DirectBandPass !signal
    
    500    !room-size
    50     !drive-left !drive-right
     0     !delay-left
     0     !delay-right
    
    ?mix-in invoke

(?pos,?beat)+ !pos

[ Note 2 Bar 1 Beat 2]
    (?beat,0.8)*   !length
     "e4b" Note !pitch
      0.2  !softness
      50   !attack
        4  !filter-factor
    ?play-horn Do Done Normalise !signal
    (>signal,?pitch,(?pitch,3)*,4)DirectBandPass !signal
    
    [ Room as above ]
    ?mix-in invoke

(?pos,?beat)+ !pos

[ Note 3 Bar 1 Beat 3-6]
    (?beat,2.9)* !length
     "e4b" Note !pitch
      0.5  !softness
      500  !attack
        4  !filter-factor
    ?play-horn Do Done Normalise !signal
    (>signal,(?pitch,2)/,(?pitch,4)*,2)DirectBandPass !signal
    
    [ Room as above ]
    ?mix-in invoke

(?pos,(?beat,4)*)+ !pos [6 beats]

[ Note 4 Bar 2 Beat 1-4]
    (?beat,2.9)* !length
     "D4" Note !pitch
      0.5  !softness
      500  !attack
        4  !filter-factor
    ?play-horn Do Done Normalise !signal
    (>signal,(?pitch,1)/,(?pitch,2)*,4)DirectBandPass !signal
    (
        (
            0.75,
            ((0,1),(?signal length,3))Slide pcnt+25
         )DirectMix,
        >signal
    )Multiply Normalise !signal

    [ As Above ]    
    ?mix-in invoke

(?pos,(?beat,4)*)+ !pos [6 beats]

[First Strong Note - third bar]
[ Note 5 Bar 3 Beat 1-4
  Reverse pattern long-short-short
]
     (?beat,2.9)* !length 
     "G4" Note !pitch
      0.5  !softness
      500  !attack
        4  !filter-factor
    ?play-horn Do Done Normalise !signal
    (
        (
            0.75,
            ((0,1),(?signal length,3))Slide pcnt+25
         )DirectMix,
        >signal
    )Multiply Normalise !signal
    
    500    !room-size
    25     !drive-left 
    75     !drive-right
    50     !delay-left
     0     !delay-right
    
    ?mix-in invoke

(?pos,(?beat,4)*)+ !pos 
[ Note 6 Bar 3 beat 5 ]
    (?beat,0.66)* !length
    "F4" Note !pitch
     0.0  !softness
     100  !attack
       4  !filter-factor
    ?play-horn Do Done Normalise !signal
    
    500    !room-size
    75     !drive-left 
    25     !drive-right
     0     !delay-left
    50     !delay-right
    
    ?mix-in invoke

(?pos,(?beat,1)*)+ !pos

[ Note 7 Bar 3 beat 6 ]
     (?beat,0.66)* !length
     "F4" Note !pitch
      0.0  !softness
      100  !attack
        4  !filter-factor
    ?play-horn Do Done Normalise !signal
        
    [ As Above ]
    ?mix-in invoke

(?pos,(?beat,1)*)+ !pos

[ Note 8 Bar 4 beat 1-6 ]
     (?beat,2.9)* !length
     "E4b" Note !pitch
      0.5  !softness
     1000  !attack
        2  !filter-factor
    ?play-horn Do Done Normalise !signal
    (
        (
            0.75,
            ((0,1),(?signal length,3))Slide pcnt+25
         )DirectMix,
        >signal
    )Multiply Normalise !signal
    
    500    !room-size
     5     !drive-left 
    95     !drive-right
    50     !delay-left
     0     !delay-right

    ?mix-in invoke

(?pos,(?beat,6)*)+ !pos

[Next Bar - enter strings]
[ Note 9 Bar 5 beat 1 ]
    "e5b" note   !pitch
    (?beat,1.0)* !length
    ?play-strings Do Done !signal
    
    99     !room-size
     5     !drive-left 
    95     !drive-right
    50     !delay-left
     0     !delay-right
    -6     !volume
    ?mix-in invoke

(?pos,(?beat,1)*)+ !pos

[ Note 9 Bar 5 beat 1 ]
    "e5b" note   !pitch
    (?beat,1.0)* !length
    ?play-strings Do Done !signal
    [ As Above ]
    ?mix-in invoke

(?pos,(?beat,1)*)+ !pos

[ Note 10 Bar 5 beat 3-6 ]
    "d5" note   !pitch
    (?beat,3.0)* !length
    ?play-strings Do Done !signal
    (>signal,((0,-24),(?beat,0),((?beat,3)*,-24))SimpleShape)Multiply !signal

    [ As Above ]
    ?mix-in invoke

(?pos,(?beat,4)*)+ !pos

[Next Bar - continue strings]
[ Note 11 Bar 6 beat 1 ]
    "f5" note   !pitch
    -3 !volume
    (?beat,1.0)* !length
    ?play-strings Do Done !signal

    [ As Above ]
    ?mix-in invoke

(?pos,(?beat,1)*)+ !pos

[ Note 12 Bar 6 beat 2 ]
    "f5" note   !pitch
    (?beat,1.0)* !length
    ?play-strings Do Done !signal

    [ As Above ]
    ?mix-in invoke

(?pos,(?beat,1)*)+ !pos

[ Note 13 Bar 6 beat 3-6 ]
    "e5b" note   !pitch
    (?beat,3.0)* !length
    ?play-strings Do Done !signal
    (>signal,((0,-24),(?beat,0),((?beat,3)*,-24))SimpleShape)Multiply !signal

    [ As Above ]
    ?mix-in invoke

(?pos,(?beat,4)*)+ !pos

[ Notes 14-19 (triplets) Bar 6 beats 1-2 ]
    (?beat,3.5)/ !length
       0  !volume
     0.8  !softness
     200  !attack
       1  !filter-factor
    500   !room-size
    25    !drive-left 
    75    !drive-right
    50    !delay-left
     0    !delay-right
    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,4)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,3)/)+ !pos
    }!fffupoot
    
    "e4b" Note !pitch
    ?fffupoot  Invoke
    "f4"  Note !pitch
    ?fffupoot  Invoke
    "g4"  Note !pitch
    ?fffupoot  Invoke
    "f4"  Note !pitch
    ?fffupoot  Invoke
    "e4b" Note !pitch
    ?fffupoot  Invoke
    "d4"  Note !pitch
    ?fffupoot  Invoke

[ Note 20 Bar 6 beats 3-6 ]
    "e4b" Note !pitch
    (?beat,3.5)* !length
     0.5  !softness
     250  !attack
       4  !filter-factor

    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,1)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,4)*)+ !pos
    }!fpoot4

    ?fpoot4  Invoke

[ Note1 21 Bar 7 beats 1-2 ]
    "f4" Note !pitch
    (?beat,1.7)* !length
     0.5  !softness
     250  !attack
       4  !filter-factor

    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,1)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,2)*)+ !pos
    }!fpoot2
    
    ?fpoot2  Invoke

[ Note1 22 Bar 7 beats 3-5 ]
[ Make it seem more distance and spacy ] 
    (?beat,2.5)* !length
     0.9  !softness
     500  !attack
       1  !filter-factor
    900   !room-size
    25    !drive-left 
    75    !drive-right
    99    !delay-left
     0    !delay-right

    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,4)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,3)*)+ !pos
    }!fffupoot3
    
    "g4" Note !pitch
    ?fffupoot3  Invoke

[ Note1 23 Bar 7 beat 6 ]

    ?beat !length
     0.8  !softness
     200  !attack
       1  !filter-factor
    500   !room-size
    25    !drive-left 
    75    !drive-right
    50    !delay-left
     0    !delay-right
    -3    !volume
    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,1)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,1)*)+ !pos
    }!fpoot1
    
    "f4" Note !pitch
    ?fpoot1  Invoke

[ Note 24 Bar 8 beats 1-4 ]
    "d4" Note !pitch
     0    !volume 
    (?beat,3.5)* !length
     0.5  !softness
     250  !attack
       4  !filter-factor

    ?fpoot4  Invoke   

[ Note1 25 Bar 8 beats 5-6 ]
    "e4b" Note !pitch
    (?beat,1.7)* !length
       4  !filter-factor
 
    ?fpoot2  Invoke

[ Note1 26 Bar 9 beats 1-3 ]
[ Also start drone rhythum ]

[   100000 !length
    (?length,32)SinWave !signal
    (0.5,>signal)DirectMix !signal
    
    (   >signal dbs+6,
        (?length,(1,6)/,0.25)PhasedSinWave Normalise
    )Mix !signal
    >signal saturate  !signal
    >signal normalise !signal
    (>signal,128,4)DirectLowPass Normalise !signal
    ((0,0),(6000,1),(?signal Length,1))NumericShape !env
    (>env,>signal)Multiply !signal
    (?signal,0.99,0.15,48 Period)ResonantFilter Normalise !signalR
    (
        >signal,
        >signalR
    )Mix Normalise !signal
    500   !room-size
    50    !drive-left 
    50    !drive-right
     0    !delay-left
    99    !delay-right
    >volume !v-tmp
    -12 !volume
    ?mix-in invoke
    >v-tmp !volume
]    

    500   !room-size
    25    !drive-left 
    75    !drive-right
    50    !delay-left
     0    !delay-right
     
    (?beat,2.5)* !length
    
    "f4" Note !pitch
    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,1)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,3)*)+ !pos
    }!fpoot3
    ?fpoot3  Invoke

[ Note1 27 Bar 9 beat 4 ]

    ?beat !length
    -6    !volume 
     0.9  !softness
     250  !attack
       1  !filter-factor
    "e4b" Note !pitch
     {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)/,(?pitch,3)*,4)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,1)*)+ !pos
    }!fffpoot1
    ?fffpoot1  Invoke

[ Note 28 Bar 9-10 beats 5-2 ]
    "c4" Note !pitch
     0    !volume 
    (?beat,3.5)* !length
     0.5  !softness
     250  !attack
       4  !filter-factor
    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,3)/,(?pitch,4)*,2)DirectBandPass !signal
        ?mix-in invoke
        (?pos,(?beat,4)*)+ !pos
    }!low-fpoot4

    ?low-fpoot4  Invoke   

[ Note1 29 Bar 10 beats 3-4 ]
    "d4" Note !pitch
    (?beat,1.7)* !length
     0.2  !softness
     125  !attack
       4  !filter-factor
    {
        ?play-horn Do Done Normalise !signal
        ?mix-in invoke
        (?pos,(?beat,2)*)+ !pos
    }!low-poot2
 
    ?fpoot2  Invoke

[ Note1 30 Bar 10-11 beats 4-1 ]
    (?beat,2.5)* !length
    
    "e4b" Note !pitch
    {
        ?play-horn Do Done Normalise !signal
        ?mix-in invoke
        (?pos,(?beat,3)*)+ !pos
    }!low-poot3
    ?low-poot3  Invoke

[ Note1 31 Bar 11 beat 2 ]

    ?beat !length
      -3  !volume
     0.5  !softness
     250  !attack
       3  !filter-factor
    "d4" Note !pitch
    {
        ?play-horn Do Done Normalise !signal
        ?mix-in invoke
        (?pos,(?beat,1)*)+ !pos
    }!low-fpoot1
    
    ?low-fpoot1  Invoke

[ Note 32 Bar 11 beats 3-6 ]
       0  !volume
    (?beat,9.5)* !length
     0.0  !softness
     125  !attack
       4  !filter-factor
    {
        ?play-horn Do Done Normalise !signal
        [(?signal,(1,(?signal Length,2)SinWave dbs-12)DirectMix)Multiply !signal
        >signal dbs+3 Saturate Normalise !signal]
        ?mix-in invoke
        (?pos,(?beat,6)*)+ !pos
    }!low-brass-poot6

[ Start string chord]
    "Starting chord" Println
    "e5b" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
    
    (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-12 !signal
     -12  !volume
    {
        99     !room-size
         5     !drive-left 
        95     !drive-right
        50     !delay-left
         0     !delay-right
    }!string-room
    
    ?mix-in invoke

   "f5#" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
     (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-12 !signal
    ?mix-in invoke

   "b5b" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
     (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-9 !signal
    ?mix-in invoke
 
    {
        500   !room-size
        25    !drive-left 
        75    !drive-right
        50    !delay-left
         0    !delay-right
    }!horn-room Invoke

[ Note 32 Bar 12 ]
    "Note 32 Bar 12" Println
    0 !volume
    "b3b" Note !pitch
    (?beat,5)* !length
    ?low-brass-poot6  Invoke   

[ Notes 33-69 (triplets) Bars 13-14]
    (?beat,3.5)/ !length
       0  !volume
     0.5  !softness
     100  !attack
       3  !filter-factor
    500   !room-size
    25    !drive-left 
    75    !drive-right
    50    !delay-left
     0    !delay-right
    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)*,3)DirectLowPass !signal
        ?mix-in invoke
        (?pos,(?beat,3)/)+ !pos
    }!fpoot
    
    "Notes 33-69" Println
    "b3b" Note !pitch
    ?fpoot  Invoke
    "c4"  Note !pitch
    ?fpoot  Invoke
    "d4"  Note !pitch
    ?fpoot  Invoke
    "c4"  Note !pitch
    ?fpoot  Invoke
    "b3b" Note !pitch
    ?fpoot  Invoke
    "a3"  Note !pitch
    ?fpoot  Invoke
    
    "Block 2" Println
    "a3" Note !pitch
    ?fpoot  Invoke
    "b3b"  Note !pitch
    ?fpoot  Invoke
    "c4"  Note !pitch
    ?fpoot  Invoke
    "b3b"  Note !pitch
    ?fpoot  Invoke
    "a3" Note !pitch
    ?fpoot  Invoke
    "g3"  Note !pitch
    ?fpoot  Invoke

    "Block 3" Println
    "g3" Note !pitch
    ?fpoot  Invoke
    "a3"  Note !pitch
    ?fpoot  Invoke
    "b3b"  Note !pitch
    ?fpoot  Invoke
    "a3"  Note !pitch
    ?fpoot  Invoke
    "g3" Note !pitch
    ?fpoot  Invoke
    "f3"  Note !pitch
    ?fpoot  Invoke

[ Bar 14 ]

    "Block 4 bar 14" Println

    "Starting chord" Println
    "b5b" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
    
    (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-12 !signal
    -12  !volume
    ?string-room invoke
    
    ?mix-in invoke

   "c6#" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
     (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-12 !signal
    ?mix-in invoke

   "f6" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
     (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-9 !signal
    ?mix-in invoke

    0  !volume
    ?horn-room invoke
    (?beat,3.5)/ !length
    {
        ?play-horn Do Done Normalise !signal
        (>signal,(?pitch,2)*,1)DirectLowPass !signal
        ?mix-in invoke
        (?pos,(?beat,3)/)+ !pos
    }!fpoot
    
    "f3" Note !pitch
    ?fpoot  Invoke
    "g3"  Note !pitch
    ?fpoot  Invoke
    "a3"  Note !pitch
    ?fpoot  Invoke
    "g3"  Note !pitch
    ?fpoot  Invoke
    "f3" Note !pitch
    ?fpoot  Invoke
    "d3"  Note !pitch
    ?fpoot  Invoke

    "Block 5" Println
    "d3" Note !pitch
    ?fpoot  Invoke
    "e3b"  Note !pitch
    ?fpoot  Invoke
    "f3"  Note !pitch
    ?fpoot  Invoke
    "e3b"  Note !pitch
    ?fpoot  Invoke
    "d3" Note !pitch
    ?fpoot  Invoke
    "b2b"  Note !pitch
    ?fpoot  Invoke

    (?beat,3.5)/ !length
    {
        ?play-horn Do Done Normalise !signal
        ?mix-in invoke
        (?pos,(?beat,3)/)+ !pos
    }!fpoot

    "Block 6" Println
    "b2b" Note !pitch
    ?fpoot  Invoke
    "c3"  Note !pitch
    ?fpoot  Invoke
    "d3"  Note !pitch
    ?fpoot  Invoke
    "c3"  Note !pitch
    ?fpoot  Invoke
    "b2b" Note !pitch
    ?fpoot  Invoke
    "a2"  Note !pitch
    ?fpoot  Invoke

     500  !attack
    (?beat,6)* !length
    "b2b" Note !pitch
    2 !volume
   ?low-brass-poot6  Invoke

   ((?beat,6)*,>pos)+ !pos

    "Starting chord" Println
    "g4" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal    
    (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-12 !signal
    -12  !volume
    ?string-room invoke
    
    ?mix-in invoke

   "b5" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
     (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-12 !signal
    ?mix-in invoke

   "d5" note   !pitch
    (?beat,22.0)* !length
    ?play-strings Do Done !signal
     (((0,0),(6000,1),(?signal Length,1))NumericShape,>signal)Multiply dbs-9 !signal
    ?mix-in invoke

    "Bell 1" Println
    6000 !length 
    4    !dullness
    "g2" Note   !pitch
    ?play-bell Do Done !signal
    -6    !volume
    100   !room-size
    50    !drive-left 
    50    !drive-right
     0    !delay-left
     0    !delay-right
    ?mix-in invoke
    
    ((?beat,6)*,>pos)+ !pos
    
    "Bell 2" Println
    ?play-bell Do Done !signal
    ?mix-in invoke

    ((?beat,6)*,>pos)+ !pos
    0  !Volume
    "Bell 3" Println
    ?play-bell Do Done !signal
    ?mix-in invoke

    20000  !length 
    1      !dullness
    75    !delay-left
    "e2b" Note !pitch
    ?play-bell Do Done !sample
    120  !first
    50   !offset
    ?reflector Do Done !signal
    ?mix-in invoke


((500 Silence,>left)Concatenate,12,1 )DirectHighPass Normalise !left
((500 Silence,>right)Concatenate,12,1)DirectHighPass Normalise !right

"Injecting Rumble" Println
?left Length !length
{
    ?length WhiteNoise !signal
    (25,180,3)CreateDirectBandPass !filter
    (>signal,0.9,0.1,55 Period,?filter)FilteredResonantFilter Normalise !signal  
    (25,110,3)CreateDirectBandPass !filter
    (>signal,0.9,0.5,55 Period,?filter)FilteredResonantFilter Normalise
}!big
?big Do !leftLow
?big Do !rightLow

((2000 Silence,>left)Concatenate, >leftLow  Done)Mix Normalise !left
((2000 Silence,>right)Concatenate,>rightLow Done)Mix Normalise !right

    "Starting main reflector" Println
    80  !first
    0   !offset
    >left !sample
    ?reflector Do !left
    >right !sample
    ?reflector Do !right
    >left  Done Normalise !left
    >right Done Normalise !right

"Monitoring started" Println
(?left,?right) StereoMonitor
((2000 Silence,>left)Concatenate,(2000 Silence,>right)Concatenate)!bus
(?bus,"temp/tone.wav")WriteFile32

Monday 1 October 2012

Welcome To Sonic Field

Dreaming Of Sonic Fields
This blog is actually designed as a reference manual, patch example and discussion area for Sonic Field now that it is available under AGPL.


Sonic Field is an audio processor and synthesis engine written and conceived by Dr Alexander J Turner. 

I have no idea is anyone other than myself will want to use or contribute to Sonic Field. It would be great if some did, but not a problem otherwise. This blog still acts as a major resource for myself as a place to record how to create particular sounds and effects and the subtleties of the many processors which are contained in Sonic Field.

Sonic Field is 100% pure Java.


I personally use it on Windows, Linux (Ubuntu) and Mac (Mountain Lion). I see no reason it would not work on any platform which is Java 7 compliant. Sonic Field does not do anything very special and it does not rely on any native libraries. It does not have any platform specific code and should always run without any recompilation of its code or any alteration of Sonic Field patches.

Note: Sonic Field is not a release product or even in a release cycle. At any one time some of it will not work. However, I am slowly moving it over to a fully unit tested framework and once that is in place it should enter a "if it ain't broken now - it will continue to work" mode!

Some Links:
Sonic Field - the main website
Sonic Field Of Dreams - a collection of compositions
Sonic Field Examples - more examples including audio processing as well as synthesis
Sonic Field Download - the AGPL source code and compiled code (pending - later today!)
Nerds-Central - the my personal blog which has a load of stuff about Sonic Field on it
Nerds-Central On Youtube - many Sonic Field renderings are recorded here plus other audio and software related stuff.

Here is an introduction to Sonic Field Patch Layout: