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.
Monday, 29 October 2012
Amazingly Handy Document - RBJ EQ CookBook
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 |
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 here. Please 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.
Now we have a sound the timbre of which varies over time. The envelope (shape) for these filters is generated thus:
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:
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.
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.
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.
(>signal,15,2)DirectHighPass !signal (>signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal (>signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal (>signal,>low-shape,>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:
( >signal, ( ( ?length, (?pitch,1.2)* )SinWave, ?modulation-index )Volume )FrequencyModulate !signal (( (?a,?b,?c,?d,?e)NumericShape, >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 ( >wet, ?signal Invert )Mix !wet ( >signal, >wet Normalise )Mix Normalise !signal (>signal,?post-cut-low,3 )DirectLowPass Normalise !signal (>signal,?post-cut-high,2)DirectHighPass Normalise !signal >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 (>signal,15,2)DirectHighPass !signal (>signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal (>signal,?low-shape,?high-shape,?order)ShapedBandPass Normalise !signal (>signal,>low-shape,>high-shape,?order)ShapedBandPass Normalise !signal ( >signal, ( ( ?length, (?pitch,1.2)* )SinWave, ?modulation-index )Volume )FrequencyModulate !signal (( (?a,?b,?c,?d,?e)NumericShape, >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 ( >wet, ?signal Invert )Mix !wet ( >signal, >wet Normalise )Mix Normalise !signal (>signal,?post-cut-low,3 )DirectLowPass Normalise !signal (>signal,?post-cut-high,2)DirectHighPass Normalise !signal >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 ( (>1 Done dbs+6 !1,?time), (>2 Done !2,(?beat,>time)+ !time), (>3 Done !3,(?beat,>time)+ !time), (>4 Done !4,(?beat,>time)+ !time) )MixAt !low-rhyth ( 1,400, { ( (>low-rhyth,0), (?1,(?beat,>time)+ !time), (?2,(?beat,>time)+ !time), (?3,(?beat,>time)+ !time), (?4,(?beat,>time)+ !time) )MixAt !low-rhyth } )Repeat >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 ( (>centre,0), (>b1 Done dbs-6 !b1,(>time,(?beat,8)*)+ !time) )MixAt !centre ( 1,200, { ( (>centre,0), (?b1, (>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, { ( (>centre,0), (?b2,(>time,(?beat,8)*)+ !time) )MixAt !centre ( (>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, { ( (>centre,0), (?b3,(>time,(?beat,8)*)+ !time) )MixAt !centre ( (>right,0), (?b3,?time) )MixAt !right } )Repeat (>b3,0.75)DirectRelength !b3 (?beat,62.75)* !time ( 1,200, { ( (>centre,0), (?b3 dbs-3,(>time,(?beat,8)*)+ !time) )MixAt !centre ( (>right,0), (?b3 dbs+3,(?time,30)-) )MixAt !right } )Repeat [ high dong in middle ] (?b1,1.5)DirectReLength !b4 (?beat,40)* !time ( 1,20, { ( (>centre,0), (?b4,(>time,(?beat,8)*)+ !time) )MixAt !centre } )Repeat (?b1,(5,3)/)DirectReLength !b5 (?beat,49)* !time ( 1,200, { ( (>centre,0), (?b5 dbs-6,(>time,(?beat,8)*)+ !time) )MixAt !centre ( (>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 (>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, { ( (>right,0), (?b6 dbs-6,(>time,(?beat,8)*)+ !time) )MixAt !right ( (>left,0), (?b6,(?time,30)+) )MixAt !left ( (>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, { ( (>centre,0), (?b7 ,(>time,(?beat,8)*)+ !time) )MixAt !centre } )Repeat (>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, { ( (>right,0), (?b8 dbs-6,(>time,(?beat,8)*)+ !time) )MixAt !right ( (>centre,0), (?b8,(?time,30)+) )MixAt !centre } )Repeat [ Stich it all together ] ( (>left,0), (?signal,50), (?centre,0) )MixAt Normalise !left ( (>right,0), (>signal,0), (>centre,0) )MixAt Normalise !right (>left,>right) } !play 750 !beat ?play Do !750 760 !beat ?play Do !800 >750 Done !bus1 >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 ((>left,>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
>channels GetRest GetStart !right
(
(?left !lefto,1500,1)DirectLowPassBessel,
>left dbs-3
)Mix Normalise !left
(
(?right !righto,1500,1)DirectHighPassBessel,
>right dbs-3
)Mix Normalise !right
(
(>right,0),
(?lefto dbs-18,80),
(?lefto dbs-18,260),
(?lefto dbs-18,340)
)MixAt !right
(
(>left,0),
(?righto dbs-18,120),
(?righto dbs-18,250),
(?righto dbs-18,330)
)MixAt !left
(
(
(1000 Silence,>left Normalise)Concatenate,
(1000 Silence,>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
>channels GetRest GetStart !right
?wavFile ReadFile !channels
?channels GetStart !left
>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,
>left dbs-3
)Mix Normalise !left
(
(?right !righto,1500,1)DirectHighPassBessel,
>right dbs-3
)Mix Normalise !right
(?left !lefto,1500,1)DirectLowPassBessel,
>left dbs-3
)Mix Normalise !left
(
(?right !righto,1500,1)DirectHighPassBessel,
>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!
(
(>right,0),
(?lefto dbs-18,80),
(?lefto dbs-18,260),
(?lefto dbs-18,340)
)MixAt !right
(
(>left,0),
(?righto dbs-18,120),
(?righto dbs-18,250),
(?righto dbs-18,330)
)MixAt !left
(>right,0),
(?lefto dbs-18,80),
(?lefto dbs-18,260),
(?lefto dbs-18,340)
)MixAt !right
(
(>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,>left Normalise)Concatenate,
(1000 Silence,>right Normalise)Concatenate
),
"temp/parted-2.wav"
)WriteFile32
(
(1000 Silence,>left Normalise)Concatenate,
(1000 Silence,>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
(>s,>samples)AddEnd !samples
}
)Repeat
>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:
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.
?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:
- Make and envelope
- At 0 milliseconds have -99 decibels which is near silence
- Increase till
- At 1 second have 0 decibels which is full volume
- Decrease till
- At 2 seconds have -6 decibels which is half the amplitude
- Decrease till
- At 5 seconds have -8 decibels
- Decrease till
- 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 |
Sonic Field is an audio processor and synthesis engine written and conceived by Dr Alexander J Turner.
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.
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
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:
Subscribe to:
Posts (Atom)