Friday 30 November 2012

Speaking Voice Processing

Sonic Field started life as an audio processing project - back to its roots!

The following script uses envelope followers to remove background rumble from the recording without taking out the lows from the voice. It also has a de-esser which is much the same thing but for high frequencies. Some light reverb is use via a very simple algorithm which folds the signal back on its self. This reverb' is seeded using a bit of Haas effect form the mono code.

The script also does some gating to remove noise between the words and compression of the over all signal to make the volume even through out. It does have a nasty habit of not catching very short audio spikes which end up left in the signal. I need to figure out how to fix this, but it is so rare that a manual tweak in Audacity does the trick.


(>left, 150,2,12)RBJPeaking  Normalise  !left
(>right,150,2,12)RBJPeaking  Normalise  !right


The above filters then make the voice sound deeper. The values would need tweaking for a female voice.

Here is a video where I used the script to process my voice:
http://youtu.be/7qhoXL7EKYs

Here is the script:
"temp/input.wav" ReadFile ^signal
?signal !orig

[Low peak cut]
(?signal,150,3)ButterworthLowPass  !lower
(?signal,150,3)ButterworthHighPass !upper
(>lower,60,2)ButterworthHighPass   !lower
(?lower Normalise,100,100)Follow           !shape
(?shape,(1,?shape MaxValue)/)NumericVolume !shape
(0.1,>shape dbs+48)DirectMix               !shape
(
    >lower,
    >shape 
)Divide !lower

(
    >lower,
    >upper 
)Mix  Normalise !signal

[ De-ess ]
(?signal,4000,5)ButterworthLowPass  !lower
(?signal,4000,5)ButterworthHighPass !upper
(?upper Normalise,100,100)Follow           !shape
(?shape,(1,?shape MaxValue)/)NumericVolume !shape
(0.1,>shape dbs+48)DirectMix               !shape
(
    >upper,
    >shape 
)Divide !upper

(
    >lower,
    >upper dbs+3
)Mix  Normalise !signal


(
    (?signal Reverse,1,50)Follow Reverse,
    (?signal        ,1,50)Follow,
)Mix !shape    
(?shape,(2,?shape MaxValue)/)NumericVolume   !shape
(0.04,>shape)DirectMix Clip                  !shape
(>signal,?shape)Multiply Normalise           !signal

(
    (?signal Normalise,25,25)Follow,
    (?signal Normalise Reverse,25,25)Follow Reverse,
)Mix !shape
(?shape,(1,?shape MaxValue)/)NumericVolume !shape
(0.3,>shape dbs+24)DirectMix               !shape
(
    >signal,
    >shape 
)Divide Normalise !signal 

[ Reverb ]
(15 Silence,?signal)Concatenate !note-left
?signal                         !note-right

(>note-left ,1000,0.25)RBJLowPass !note-left
(>note-right,1000,0.25)RBJLowPass !note-right
(
    1,2,
    {    
        !outer
        (
            1,4,
            {
                !t
                {((30,(?t,(24,?outer)*)*)+ Prime Silence,?note-left )Concatenate} Do !nlTask
                {((45,(?t,(15,?outer)*)*)+ Prime Silence,?note-right)Concatenate} Do !nrTask
            
                {((>nlTask Done, -15)Volume,(700,(?t,3)*)-,1)ButterworthLowPass}  Do  !nlTask
                {((>nrTask Done, -15)Volume,(700,(?t,3)*)-,1)ButterworthLowPass}  Do  !nrTask
            
                {(>nlTask Done, ?note-left )Mix Normalise}                        Do !nlTask 
                {(>nrTask Done, ?note-right)Mix Normalise}                        Do !nrTask
                
                ?nlTask Done !note-left
                ?nrTask Done !note-right
            }
        )Repeat
    }
)Repeat
(
    >note-left dbs-20,
    ?signal
)Mix Normalise !left
(
    >note-right dbs-20,
    >signal
)Mix Normalise !right

(>left ,3000,2,6)RBJPeaking Normalise   !left
(>right,3000,2,6)RBJPeaking Normalise   !right
(>left, 150,2,12)RBJPeaking  Normalise  !left
(>right,150,2,12)RBJPeaking  Normalise  !right

(
    (
        >left,
        >right
    )StereoMonitor,"temp/tone.wav"
)WriteFile32


Tuesday 27 November 2012

Working With The Sonic Field Console


Having A Console Makes A Huge Difference To Productivity And Creativity

Up until now the productivity of Sonic Field has been severely limited by the need to re-run a patch every time it is edited; this make playing around with sound a very slow process indeed. The addition of the Console processor opens up a whole new arena of rapid sound development from Sonic Field. It also opens up lots of possibilities for fun.

The implementation of Console at the time of writing this is about as simple as it is possible to be. In agile style, I got something working and will use it to find out ways to improve it.

How It Works
At any point in a patch the Processor Console can be used. This will start interacting with the console. It simply reads from Standard Input. This works OK with the Eclipse console which Sonic Field gets when run under Eclipse. The console accepts lines of input. If a line consist of just:
%end%
then the console processor stops and the next processor in the patch is run.

The Console accumulates a patch. Each line of input is added to the patch. When an line consisting of :
%
and nothing else is entered, the current accumulated patch is parsed and run. This allows for complex patches to be either typed or pasted into the console window and then run. The patch runs in the context (same store values) as the patch which contained the original Console processor. However, there is a difference.

When a patch launched from the command line (or Eclipse) causes an error Sonic Field shuts down. Patches entered in the Console to not cause Sonic Field to shut down in this way. If you make a mistake in the Console Sonic Field will tell you something about the mistake and then just start reading from Standard Input again.

One Small Issue:
At the time of writing there is a slight issue in that if there is a layout problem with code inside a code block which is entered into the Console Sonic Field gets the code block tracking system a bif stuffed up. If, after a patch layout problem, you keep getting 'unmatched brace' errors, then enter
}
%

An Example:
Below is a slightly abridged example form the Eclipse console of me working on a bass/rhythm line in Sonic Field

SFPL: [3]1 >> Sonic Field Thread Factory:
SFPL: [3]1 >> ---------------------------
SFPL: [3]1 >> Found CPUs: 8
SFPL: [3]1 >> Initial Max Threads: 16
Parsing: scripts/play/FastBass.sfpl size: 866
SFPL: [532]1 >> Sonic Field Version 0.2 Starting Processing
SFPL: [532]1 >> ============================================
?play invoke
%
(
(0,2.0),
((?bt,2)*,0),
((?bt,4)*,2)
)NumericShape !qEnv
%
?play invoke
%
{
((?bt,4)*,?pitch)SinWave MakeSawTooth dbs+3 Saturate Normalise !signal
(?qEnv,4)DirectRelength !qsEnv
(?qsEnv,?qsEnv,?qsEnv,?qsEnv,?qsEnv)Concatenate !qsEnv
(0,?signal Length,>qsEnv)Cut !qsEnv
(?pitchEnv,4)DirectRelength !psEnv
(?psEnv,?psEnv,?psEnv,?psEnv,?psEnv)Concatenate !psEnv
(0,?signal Length,>psEnv)Cut !psEnv
(>signal,?psEnv,?qsEnv)ShapedLadderLowPass Normalise !signal
>signal Normalise !signal
(>signal,2)Power Normalise !signal
(>signal,?pitch,1,24)RBJPeaking Normalise !signal Monitor
}!play
%
?play invoke
%
"A2" Note !pitch
?play invoke
%
com.nerdscentral.sfpl.SFPL_RuntimeException: Runtime Exception at key word Invoke
operand: '109.99999987361397'
at line: 0, colum 30 in Console
at com.nerdscentral.sfpl.SFPL_Runner.Invoke(SFPL_Runner.java:103)
at com.nerdscentral.audio.io.SF_Console.Interpret(SF_Console.java:57)
at com.nerdscentral.sfpl.SFPL_Runner.Invoke(SFPL_Runner.java:87)
at com.nerdscentral.sfpl.SFPL_Runner.Invoke(SFPL_Runner.java:64)
at com.nerdscentral.sfpl.RenderRunnerImp.runParser(RenderRunnerImp.java:163)
at com.nerdscentral.sfpl.RenderRunnerImp.render(RenderRunnerImp.java:65)
at com.nerdscentral.sfpl.RenderRunner.main(RenderRunner.java:25)
Caused by: com.nerdscentral.sfpl.SFPL_RuntimeException: Failed to resolve type: class java.lang.Double
at com.nerdscentral.sfpl.Caster.describeSFPLType(Caster.java:55)
at com.nerdscentral.sfpl.Caster.throwConversion(Caster.java:49)
at com.nerdscentral.sfpl.Caster.makeBunch(Caster.java:68)
at com.nerdscentral.sfpl.SFPL_Parser$cInvoke.Interpret(SFPL_Parser.java:1166)
at com.nerdscentral.sfpl.SFPL_Runner.Invoke(SFPL_Runner.java:87)
... 6 more
"A2" Note !pitch

%
?play println
%
com.nerdscentral.sfpl.SFPL_Runner@c6824d9
?play println
%
com.nerdscentral.sfpl.SFPL_Runner@c6824d9
?play invoke
%
{
((?bt,4)*,?pitch)SinWave MakeSawTooth dbs+3 Saturate Normalise !signal
(?qEnv,4)DirectRelength !qsEnv
(?qsEnv,?qsEnv,?qsEnv,?qsEnv,?qsEnv)Concatenate !qsEnv
(0,?signal Length,>qsEnv)Cut !qsEnv
(?pitchEnv,4)DirectRelength !psEnv
(?psEnv,?psEnv,?psEnv,?psEnv,?psEnv)Concatenate !psEnv
(0,?signal Length,>psEnv)Cut !psEnv
(>signal,?psEnv,?qsEnv)ShapedLadderLowPass Normalise !signal
>signal Normalise !signal
(>signal,2)Power Normalise !signal
(>signal,?pitch,1,24)RBJPeaking Normalise dbs+3 Saturate Normalise !signal
?bt WhiteNoise MakeTriangle Normalise !signalb
(
>signal,>signalb
)Concatenate !signal Monitor
}!play
%
?play invoke
%

?play invoke
%

{
((?bt,4)*,?pitch)SinWave MakeSawTooth dbs+3 Saturate Normalise !signal
(?qEnv,4)DirectRelength !qsEnv
(?qsEnv,?qsEnv,?qsEnv,?qsEnv,?qsEnv)Concatenate !qsEnv
(0,?signal Length,>qsEnv)Cut !qsEnv
(?pitchEnv,4)DirectRelength !psEnv
(?psEnv,?psEnv,?psEnv,?psEnv,?psEnv)Concatenate !psEnv
(0,?signal Length,>psEnv)Cut !psEnv
(>signal,?psEnv,?qsEnv)ShapedLadderLowPass Normalise !signal
>signal Normalise !signal
(>signal,2)Power Normalise !signal
?bt WhiteNoise MakeSawTooth !signalb
(?signalb,(?pitch,4)*,24,1.5)RBJLowShelf !signalb
(
((0,0),(100,1),(?signalb Length,0))NumericShape,
>signalb
)Multiply Normalise !signalb
(
>signal,>signalb
)Concatenate !signal
(>signal,?pitch,1,24)RBJPeaking Normalise dbs+3 Saturate Normalise !signal Monitor
}!play
%
?play invoke
%

{
((?bt,4)*,?pitch)SinWave MakeSawTooth dbs+3 Saturate Normalise !signal
(?qEnv,4)DirectRelength !qsEnv
(?qsEnv,?qsEnv,?qsEnv,?qsEnv,?qsEnv)Concatenate !qsEnv
(0,?signal Length,>qsEnv)Cut !qsEnv
(?pitchEnv,4)DirectRelength !psEnv
(?psEnv,?psEnv,?psEnv,?psEnv,?psEnv)Concatenate !psEnv
(0,?signal Length,>psEnv)Cut !psEnv
(>signal,?psEnv,?qsEnv)ShapedLadderLowPass Normalise !signal
>signal Normalise !signal
(>signal,2)Power Normalise !signal
?bt WhiteNoise MakeSawTooth !signalb
(?signalb,(?pitch,4)*,1.5,24)RBJLowShelf !signalb
(
((0,0),(100,1),(?signalb Length,0))NumericShape,
>signalb
)Multiply Normalise !signalb
(
>signal,>signalb
)Concatenate !signal
(>signal,?pitch,1,24)RBJPeaking Normalise dbs+3 Saturate Normalise !signal Monitor
}!play
%
?play invoke
%
{
((?bt,4)*,?pitch)SinWave MakeSawTooth dbs+3 Saturate Normalise !signal
(?qEnv,4)DirectRelength !qsEnv
(?qsEnv,?qsEnv,?qsEnv,?qsEnv,?qsEnv)Concatenate !qsEnv
(0,?signal Length,>qsEnv)Cut !qsEnv
(?pitchEnv,4)DirectRelength !psEnv
(?psEnv,?psEnv,?psEnv,?psEnv,?psEnv)Concatenate !psEnv
(0,?signal Length,>psEnv)Cut !psEnv
(>signal,?psEnv,?qsEnv)ShapedLadderLowPass Normalise !signal
>signal Normalise !signal
(>signal,2)Power Normalise !signal
?bt WhiteNoise MakeSawTooth !signalb
(?signalb,(?pitch,2)*,1.5,24)RBJLowShelf !signalb
(
((0,0),(100,1),(?signalb Length,0))NumericShape,
>signalb
)Multiply Normalise !signalb
(
>signal,>signalb dbs+12
)Concatenate !signal
(>signal,?pitch,1,24)RBJPeaking Normalise dbs+3 Saturate Normalise !signal Monitor
}!play
%
?play invoke
%
?signal monitor
%
((?signal),"temp/tone.wav")WriteFile32
%



Monday 26 November 2012

All Current Processors

All SFPL Processors As Of 27 November 2012

This is constant work in progress - I am working my way down the list as I get chance - and updating as stuff gets added/updated. Please note that some times the descriptions says 'change the volume...' for example. This is just to make reading easier; SFPL has 'immutable' types so it is not possible to change the volume of a signal or trim white space off a string. What actually happens is that a new one is made and the old one left unchanged.

December 2013 - this is quite out of data, I will work on it over the next few days...
  • MakeSawTooth
    Convert a signal into a saw tooth using center crossing
  • MakeSquare
    Convert a signal into a square wave using center crossing
  • SubOctave
    Make a sin wave the period of which is half the rate of center crossing.
  • MakeTriangle
    Make a signal into a triangle wave using centre crossing
  • Saturate
    Distortion effect using 1-(1/x) law
  • ShapedThreshold
    Convert a signal into a pulse wave using a threshold based on a shape
  • Threshold
    Convert a signal into a pulse wave using a fixed threshold
  • WaveShaper
    Distort a wave using a 6th order polynomial transfer function
  • ClipToSafe
    Use DC removal and fadeout to attempt to get rid of clicks entering and leaving a audio signal
  • Concatenate
    Join two or more audio signals end to end 
  • Convolve
    Convolve one signal with another. Convolution is forwards and backwards, i.e. the convolving signals centre is placed at the current sample on the main signal.
  • ConvolveDelay
    Mix a signal with a delayed version of its self where the delayed version is actually mixed with the original via convolution via a second convolving signal.
  • ConvolveForward
    Convolve one signal with another. Convolution is forwards only (see Convolve).
  • CrossFadeSplit
    Create a bunch of subsections of a signal where the sub sections are overlapping and are pre-faded.
  • Cut
    Take a subsection of a signal.
  • Divide
    Sample my sample division of one signal by another.
  • Mix
    Mix two or more signals together using direct sample addition.
  • MixAt
    Mix two or more signals together using direct sample addition and with defined offsets for each.
  • Multiply
    Sample by sample multiplication of one signal by another.
  • GaussianShape
    Generate a signal which follows a Gaussian shape.
  • HammingShape
    Generate a signal which follows a Hamming shape.
  • HannShape
    Generate a signal which follows a Hann shape.
  • Note
    Take a string representation of a note in equal temperament and forward the frequency in Hz based on A4 being 440Hz. It uses a post fix of b or # for flat and sharp. E.g. "C5#" "E2b". 
  • NumericShape
    Takes a bunch of time and magnitude values and creates a signal from the linear interpolation of the values.
  • PhasedSinWave
    Create a sin wave of a given length and frequency and starting at a given phase.
  • ShapedSinWave
    Create a sin wave the frequency of which is continuously set by a shape signal. This effectively is an infinitely variable sin wave generator and can create things like FM.
  • Silence
    Generate a given length of silence.
  • SimpleShape
    Generate a shape signal from a series of decible and time values.
  • SinWave
    Generate a sin wave of a given length and frequency.
  • SincShape
    Generate a Sinc shape signal with a given period and width.
  • Slide
    Generate a sin wave which continuously in frequency varies based on a series of time and frequency values.
  • WhiteNoise
    Generate pure white noise of a given length.
  • ToJSON
    Convert a SFPL data type (signal, number, bunch etc) into a JSON string.
  • CreateBesselBandPass
    Create a Bessel based band pass filter which can be passed to another processor.
  • CreateButterworthBandPass
    Create a Butterworth based band pass filter which can be passed to another processor.
  • CreateButterworthHighPass
    Create a Butterworth based high pass filter which can be passed to another processor.
  • CreateButterworthLowPass
    Create a Butterworth based low pass filter which can be passed to another processor.
  • DirectRelength
    Change the length of an audio signal by a fixed ratio via decimation and / or interpolation resulting in a new sample of different length and changing all the frequencies.
  • DirectResample
    The same as DirectRelength except the resulting signal is cut or padded with silence to result in it being the same length as the original.
  • FrequencyModulate
    Use an shape signal to continuously resample another signal so as to modulate its frequency. This is different from Resample in that the change in frequency is symmetric about zero for the modulating waveform. A positive value of the modulator will increase the frequency of the modulated and a negative modulator value decreases the frequency of the modulated. This method is centre frequency stable for stable modulation frequencies. The centre frequency of the modulate signal will shift if the frequency of the modulator signal shifts overall throughout the modulation period. For complex waveforms, things are more complex.
  • ShapedLadderFilter
    A classic synthesiser low pass filter. This is loosely similar to something like the low pass on a  minimoog but it is not as fruity. It acts as a low pass with variable cut off and variable resonance.
  • ButterwothBandPass
    Use a Butterworth filter for band pass filtering up to 5 poles.
  • BesselBandPass
    Use a Bessel filter for band pass filtering up to 5 poles.
  • ButterworthHighPass
    Use a Butterworth filter for high pass filtering up to 11 poles.
  • BesselHighPass
    Use a Bessel filter for high pass filterring up to 11 poles.
  • ButterworthLowPass
    Use a Butterworth filter for low pass filtering up to 11 poles.
  • BesselLowPass
    Use a Bessel filter for low pass filtering up to 11 poles.
  • RBJLowPass
    Use a Robert Bristow-Johnson filter for 2 pole low pass variable Q filtering.
  • RBJHighPass
    Use a Robert Bristow-Johnson filter for 2 pole high pass variable Q filtering.
  • RBJBandPass
    Use a Robert Bristow-Johnson filter for 2 pole band pass filtering with variable Q.
  • RBJPeaking
    Use a Robert Bristow-Johnson filter for 2 pole filter as a peaking resonator with variable Q and gain.
  • RBJBandReject
    Use a Robert Bristow-Johnson filter for 2 pole notch filter with variable Q.
  • RBJLowShelf
    Use a Robert Bristow-Johnson filter for 2 pole low shelf filter with variable Q.
  • RBJHighShelf
    Use a Robert Bristow-Johnson filter for 2 pole high shelf filter with variable Q.
  • Resample
    Resample a signal at a rate determined by a second signal. Unlike FrequencyModulate, the next sample rate is simply the modulation signal value. 
  • ShapedButterworthBandPass
    Use a Butterworth filter as a band pass filter up to 5 poles but make the low and high frequency shoulders controlled by two other signals allowing continuously variable filter width.
  • Mixer
    Chooses a Java Audio mixer given a description.
  • LineWait
    Waits for a Java Audio line to finish.
  • Mixers
    Produces a bunch of description of the available Java Audio mixers.
  • Monitor
    Plays a single audio signal on the default output device using Java Audio.
  • PlayFile
    Plays the contents of a file on the default output device using Java Audio.
  • ReadFile
    Reads a wav file into a bunch of signals. Forwards a bunch with one signal per audio channel in the file.
  • Semitone
    Forwards a number representing the twelfth root of 2.
  • SpeedOfSound
    Forwards a number giving the approximate speed of sound at sea level in meters per second.
  • StereoMonitor
    Plays a stereo sound on the default audio device using Java Audio. Takes a bunch of two signals and plays them.
  • WriteFile16
    Take a bunch of audio signals and write them out to a 16 bit wav file with one channel per element in the bunch.
  • WriteFile32
    Take a bunch of audio signals and write them out to a 16 bit wav file with one channel per element in the bunch.
  • WriteFileString
    Write a string to a file.
  • DirectResonate
  • FilterResonate
  • ResonantFilter
    Filter via feedback resonance. Note that this is nothing at all like an IIR peaking resonator. 
  • Resonate
  • FilteredResonantFilter
    Filter via feedback resonance with an IIR filter in the feedback loop (see ResonantFilter). 
  • Reverse
    Reverse the direction of an audio signal.
  • ShapedResonantFilter
    Filter via feedback resonance where the feedback delay time is varied according to the value of a shaping signal. The shaping signal alters the delay in a simple multiplication way; e.g. a value of 2 will double the delay, a value of 0.5 will halve it (see ResonantFilter). 
  • Frequency
    Convert a period for a single cycle in milliseconds into a frequency in Hz.
  • Length
    Forward the length of the passed audio signal in milliseconds.
  • Period
    Convert a frequency in Hz into a period for a single cycle in milliseconds.
  • ValueAt
    Forward the numeric value of a signal at a point in time in milliseconds.
  • Normalise
    Remove DC from an audio signal and make set the magnitude so the maximum excursion from zero is 1.
  • NormaliseArea
    Scale an audio signal so that the area between the signal and zero sums to 1.
  • RemoveDC
    Remove an DC component from an audio signal.
  • ShapedPower
    Raise all the values of a signal to the power of an equivalent length shaping signal. E.g. if the shaping signal as a value of 2 at 10 milliseconds, then the value of the forwarded audio signal at 10 milliseconds will be the square of the input signal at that point.
  • DoneAll
    Perform Done on a bunch of Do Tasks in order and forward a bunch holding the results.
  • DoAll
    Do a bunch of code blocks, then accumulate the Done result in a bunch in order of the code blocks in to input bunch, Forward the resulting in a bunch of the same order.
  • Max
    Forward the greatest (closest to positive infinity) numerical value from a bunch of numbers.
  • Min
    Forward the lowest (closest to negative infinity) numeric value from a bunch of numbers.
  • Prime
    Forward the closest prim number which is larger than the passed number.
  • Random
    Forward a random number between 0 and 1.
  • Truncate
    Forward a number with any decimal part removed. E.g. 1.57 will forward to 1.
  • Clip
    Set any value in an audio signal which is above 1 to 1 and any below -1 to -1.
  • DirectMix
    Add a constant value to every value in an audio signal and forward the result.
  • Invert
    Invert an audio signal about zero.
  • Power
    Raise every value in an audio signal to a index.
  • Rectify
    Convert all negative values in an audio signal to positive values of the same magnitude.
  • Volume
    Scale the volume of an audio signal by a value given in db.
  • NumericVolume
    Scale the volume of an audio signal by a value given as a linear number (2 will double etc).
  • FromDBs
    Convert a number passed in dbs to a linear number and forward that number.
  • ToDBs
    The oposite of FromDBs.
  • MaxValue
    Find the largest (closest to positive infinity) value of an audio signal.
  • PrintLn
    Send a string to standard out and append a new line.
  • |
    Forward the modulus of two numbers.
  • -
    Forward the different of two numbers.
  • /
    Forward one number divided by another.
  • GT
    Forward TRUE if the first passed number is greater than the second, otherwise forward false.
  • LT
    Forward TRUE if the first passed number is less than the second, otherwise forward false.
  • EQ
    Forward TRUE if the first passed number is equal to the second, otherwise forward false.
  • NOT
    If passed TRUE forward FALSE, if passed FALSE forward TRUE.
  • OR
    Forward the Boolean OR of the passed bunch of Booleans.
  • AND
    Forward the Boolean AND of the passed bunch of Booleans.
  • XOR
    Forward the Boolean XOR of the bassed bunch of Booleans.
  • StrCat
    Concatenate all the members of the passed bunch of string and forward the result.
  • StrIndex
    Forward the index (zero based) of a string in another string. -1 if not found.
  • String
    Convert any operand into a string representation of its self.
  • StrLen
    Forward the length of the passed string.
  • StrToUpper
    Forward the a string based on the passed string where all the characters are turned to upper case using the current locale.
  • StrToLower
    Forward the a string based on the passed string where all the characters are turned to upper case using the current locale.
  • StrTrim
    Forward a string with all the white space at the start and end of the passed string removed.
  • Integer
    Round a number to the nearest integer using the Java default rounding rules.
  • Follow
    Create an envelop signal from the magnitude of the passed audio signal with settable attack and release rates.
  • Console
    Cause patch execution to pause the move over to interactive console working.
  • Granulate
    Split an audio signal into tapered (fade in and fade out) grains of a given length with an optionally given random variation up from that length.
  • AutoCorrelate
    Create a signal which is the direct auto-correlation of the passed signal.
  • DBs-100 DBs-99 DBs-98 ... DBs+98 DBs+99 DBs-100
    Change the volume of the passed audio signal by an amount in dbs and forward the result.
  • Pcnt-100 Pcnt-99 Pcnt-98 ... Pcnt+98 Pcnt+99 Pcnt+100
    Change the volume of the passed audio signal by an amount in linear numbers as a percent and forward the result.

Friday 23 November 2012

Sonic Field 0.2 Released

Sonic Field 0.2 Has Been Released Under AGPL 3.0

The .zip of all the source and class files is here: http://www.sonicfield.co.uk/downloads/SonicField-0-2.zip

This download contains all the dependancy jars and the information of the licensing for them as well.

From the VERSION.txt file:


Version 0.2
===========

This version of Sonic Field has many enhancements including but not limited to:
1)  Granular synthesis
2)  RBJ IIR Filers (high,low,high-shelf,low-shelf,peaking)
3)  Cleaner implementation of resonance synthesis
4)  Better error handling - fix the line number bug
5)  System hang on error in paralleliser bug fixed
6)  Envelope follower.
7)  Fix to numerous bugs in shaped
8)  Addition of shaped butter worth and bessel bandpass filters
9)  Improved FM signal modulation and addition of fm signal generator
10) Addition of shaped power

Saturday 17 November 2012

Site Update

Just added two tracks to the examples page

Eat Bass and megaphone-1 are now available form this examples page.



Current:


Sonic Field Of Dreams: 
Dreams: A growing collection of perforances exploring the generation of digital sounds using inspiration from the analogue world.
Synthesis And Processing Examples: 
Eat Bass: A demonstration of granular synthesis for bass effects and pitch shifting.
Megaphone-1: A demonstration of granular synthesis, envelope following and eveloped filtering to make a stylophone sound like a church organ.
Early Stuff: 
Somme: 4 ab-initio synthesised saxophones with abinito rain and sampled drums. This piece also has fully spatialised reverberation.   
Romance Electric: 2 ab-initio clean tone electric guitars playing Romance.   
Romance Semi-Acoustic: 4 ab-initio semi-acoustic guitars playing Romance.   
Theme Of Four: An ab-initio rendering of hand played drums with variations around 4/4 time.   

Clips And Effects

Flute Dry A classical harp and flute clip unprocessed.
Flute Reverb' The flute clip with spatialised reverberation added.   

Sunday 11 November 2012

Granulate

Granulate - the gateway to granular synthesis

Granulate takes a signal and breaks it up into a series of sound grains. The over all length of the grain is passed into granulate:


(?signal,50)granulate !new


In the above, signal is broken up into 50ms grains. The grains are faded in and out so that the first 25 milliseconds (in the above) are fading in and the second are fading out.

The result of Granulate is a bunch of bunches. Each inner bunch consists of a sample as the grain and the time in milliseconds from which it came. Passing the output of Granulate into MixAt will exactly reproduce exactly the original signal appart from the first half and last half of a grain which are missing causing a short fade in and fade out section.

Here is a test case for Granulate:


[ Granulates a singal so that the middle section when reconstructed and mixed
  with the orignal should be within rounding error of silent
]
(10000,440)SinWave !signal
(?signal,50)granulate !new
>new MixAt Normalise !dog
(>dog,>signal Invert)Mix !dog
0 !zero
(
   1000,2000,
   {
      !x
      (>zero,((?dog,>x)ValueAt,2)**)+ !zero
   }
)Repeat
(?zero,0.1)LT Println

Thursday 1 November 2012

Implementing RBJ Filters In Java

A flare for simplicity.
Image From NASA Solar Observatory.
Infinite Impulse Response filters a super useful in many application but especially so for audio work where very large numbers of samples need to be filtered. 

IIR filters are sometimes called recursive filters. They work by feeding some of their signal back into the incoming signal. This means that even though for each sample of the incoming signal they only need to make a few calculations, they implicitly use the entire length of preceding signal. The limit to this model is only the numerical accuracy of the mathematics being used.

There is something of a down side to the seemingly magical properties of IIR filters - the mathematics used to create what are called the 'coefficients' is a bit tricky. I guess, given enough time, I could get my head around it, but I have other things to do and I doubt I would be that good at it anyhow! What we need is someone very much better at maths than I am who can make a simple cookbook of how to compute the coefficients for a set of general purpose filters which sit in the sweet spot between not filtering enough and going unstable.

Most pipe dreams do not come true but this one seems to have done so! Robert Bristow-Johnson created just such a cook book. It is called the Audio EQ Cookbook and it does just what we want. It shows how to compute the coefficients for the 'bi-quad' variants for IIR filters for all the handy filters we normally need.

package com.nerdscentral.audio.pitch.algorithm;

import com.nerdscentral.audio.SFConstants;

/*
 * RBJ Filters from C++ version by arguru[AT]smartelectronix[DOT]com based on eq filter cookbook by Robert Bristow-Johnson
 * <rbj@audioimagination.com> This code is believed to be public domain and license free after best efforts to establish its
 * licensing.
 */
public class SFRBJFilter
{

    // filter coeffs
    double b0a0, b1a0, b2a0, a1a0, a2a0;

    // in/out history
    double ou1, ou2, in1, in2;

    public SFRBJFilter()
    {
        // reset filter coeffs
        b0a0 = b1a0 = b2a0 = a1a0 = a2a0 = 0.0;

        // reset in/out history
        ou1 = ou2 = in1 = in2 = 0.0f;
    }

    public double filter(double in0)
    {
        // filter
        final double yn = b0a0 * in0 + b1a0 * in1 + b2a0 * in2 - a1a0 * ou1 - a2a0 * ou2;

        // push in/out buffers
        in2 = in1;
        in1 = in0;
        ou2 = ou1;
        ou1 = yn;

        // return output
        return yn;
    }

    public enum FilterType
    {
        LOWPASS, HIGHPASS, BANDPASS_SKIRT, BANDPASS_PEAK, NOTCH, ALLPASS, PEAK, LOWSHELF, HIGHSHELF
    }

    public void calc_filter_coeffs(final FilterType type, final double frequency, final double q, final double db_gain)
    {
        boolean q_is_bandwidth;
        final double sample_rate = SFConstants.SAMPLE_RATE;
        switch (type)
        {
        case ALLPASS:
        case HIGHPASS:
        case LOWPASS:
        case LOWSHELF:
        case HIGHSHELF:
            q_is_bandwidth = false;
            break;
        default:
            q_is_bandwidth = true;
            break;
        }
        // temp pi
        final double temp_pi = 3.1415926535897932384626433832795;

        // temp coef vars
        double alpha, a0 = 0, a1 = 0, a2 = 0, b0 = 0, b1 = 0, b2 = 0;

        // peaking, lowshelf and hishelf
        if (type == FilterType.PEAK || type == FilterType.HIGHSHELF || type == FilterType.LOWSHELF)
        {
            final double A = Math.pow(10.0, (db_gain / 40.0));
            final double omega = 2.0 * temp_pi * frequency / sample_rate;
            final double tsin = Math.sin(omega);
            final double tcos = Math.cos(omega);

            if (q_is_bandwidth) alpha = tsin * Math.sinh(Math.log(2.0) / 2.0 * q * omega / tsin);
            else
                alpha = tsin / (2.0 * q);

            final double beta = Math.sqrt(A) / q;

            // peaking
            if (type == FilterType.PEAK)
            {
                b0 = (1.0 + alpha * A);
                b1 = (-2.0 * tcos);
                b2 = (1.0 - alpha * A);
                a0 = (1.0 + alpha / A);
                a1 = (-2.0 * tcos);
                a2 = (1.0 - alpha / A);
            }

            // lowshelf
            if (type == FilterType.LOWSHELF)
            {
                b0 = (A * ((A + 1.0) - (A - 1.0) * tcos + beta * tsin));
                b1 = (2.0 * A * ((A - 1.0) - (A + 1.0) * tcos));
                b2 = (A * ((A + 1.0) - (A - 1.0) * tcos - beta * tsin));
                a0 = ((A + 1.0) + (A - 1.0) * tcos + beta * tsin);
                a1 = (-2.0 * ((A - 1.0) + (A + 1.0) * tcos));
                a2 = ((A + 1.0) + (A - 1.0) * tcos - beta * tsin);
            }

            // hishelf
            if (type == FilterType.HIGHSHELF)
            {
                b0 = (A * ((A + 1.0) + (A - 1.0) * tcos + beta * tsin));
                b1 = (-2.0 * A * ((A - 1.0) + (A + 1.0) * tcos));
                b2 = (A * ((A + 1.0) + (A - 1.0) * tcos - beta * tsin));
                a0 = ((A + 1.0) - (A - 1.0) * tcos + beta * tsin);
                a1 = (2.0 * ((A - 1.0) - (A + 1.0) * tcos));
                a2 = ((A + 1.0) - (A - 1.0) * tcos - beta * tsin);
            }
        }
        else
        {
            // other filters
            final double omega = 2.0 * temp_pi * frequency / sample_rate;
            final double tsin = Math.sin(omega);
            final double tcos = Math.cos(omega);

            if (q_is_bandwidth) alpha = tsin * Math.sinh(Math.log(2.0) / 2.0 * q * omega / tsin);
            else
                alpha = tsin / (2.0 * q);

            // lowpass
            if (type == FilterType.LOWPASS)
            {
                b0 = (1.0 - tcos) / 2.0;
                b1 = 1.0 - tcos;
                b2 = (1.0 - tcos) / 2.0;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // hipass
            if (type == FilterType.HIGHPASS)
            {
                b0 = (1.0 + tcos) / 2.0;
                b1 = -(1.0 + tcos);
                b2 = (1.0 + tcos) / 2.0;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // bandpass csg
            if (type == FilterType.BANDPASS_SKIRT)
            {
                b0 = tsin / 2.0;
                b1 = 0.0;
                b2 = -tsin / 2;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // bandpass czpg
            if (type == FilterType.BANDPASS_PEAK)
            {
                b0 = alpha;
                b1 = 0.0;
                b2 = -alpha;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // notch
            if (type == FilterType.NOTCH)
            {
                b0 = 1.0;
                b1 = -2.0 * tcos;
                b2 = 1.0;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // allpass
            if (type == FilterType.ALLPASS)
            {
                b0 = 1.0 - alpha;
                b1 = -2.0 * tcos;
                b2 = 1.0 + alpha;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }
        }

        // set filter coeffs
        b0a0 = (b0 / a0);
        b1a0 = (b1 / a0);
        b2a0 = (b2 / a0);
        a1a0 = (a1 / a0);
        a2a0 = (a2 / a0);
    }
}