Showing posts with label compression. Show all posts
Showing posts with label compression. Show all posts

Friday, 3 January 2014

Simple But Very Effective Envelope Compressor Patch

Further Experiments In Extreme Synthesis
Sometimes over engineering is a killer - strip something down and it works better.
I have worked a lot on compression (dynamic range compression) in Sonic Field. I have tried granular compression and wave limiting. These can be quite exciting things but they have not been as musical as I would like. It turns out that a simple 3 band envelope compressor is just the ticket.
This section splits the signal into three bands. The roll off does not need to be steep so I use Bessel filters to help avoid too great an amount of phase rotation:
{
    {(?signal ,200,2000,4)BesselBandPass}Do !signal-m 
    {(?signal     ,2000,4)BesselHighPass}Do !signal-h 
    {(?signal     , 200,4)BesselLowPass}Do  !signal-l 
    >signal-m !signal
    ?envelope-compress Do !signal-m
    >signal-h !signal
    ?envelope-compress Do !signal-h
    >signal-l !signal
    ?envelope-compress Do !signal-l
    (
        ({>signal-l pcnt+50}Do,10),
        ({>signal-m pcnt+30}Do,0),
        ({>signal-h pcnt+20}Do,0)
    )MixAt Normalise 
}!do-it 
On recombination I delay the bass a little which is a psychoacoustic trick to make the bass sound more present and sit better in the rest of the mix. Now - the usual number is around 2.5 ms but I am using 10 - the project does have the word 'extreme' in it.
Then the compressor it self uses an envelope generated from follow the signal in both the forward and reverse directions. This avoids 'pumping' due to note attacks. Pumping can be cool - it that is what you want. But when you need a sharp compression attack (think piano) and don't want everything to go quiet as a distinct dip after transients - the reverse trick is just great:
(
        {(?signal Reverse,1,50)Follow Reverse},
        {(?signal        ,1,50)Follow}
    )DoAll Mix !shape   
I do the compression twice. Once with the above sharp attack and slower decay then a second smoothing run which uses symmetrical attack and decay.
(
        {(?signal Normalise,25,25)Follow},
        {(?signal Normalise Reverse,25,25)Follow Reverse}
    )DoAll Mix !shape
And here is the whole thing.
{

    (1,?compress)- !offset
    (
        {(?signal Reverse,1,50)Follow Reverse},
        {(?signal        ,1,50)Follow}
    )DoAll Mix !shape   

    {(?shape,(1,?shape MaxValue)/)NumericVolume}Do          !shape
    {(?offset,(>shape, ?compress)NumericVolume)DirectMix}Do !shape
    {
        (
            >signal,
            >shape 
        )Divide Normalise
    }Do !signal 
    
    (
        {(?signal Normalise,25,25)Follow},
        {(?signal Normalise Reverse,25,25)Follow Reverse}
    )DoAll Mix !shape
    
    {(?shape,(1,?shape MaxValue)/)NumericVolume}Do          !shape
    {(?offset,(>shape, ?compress)NumericVolume)DirectMix}Do !shape
    
    {
        (
            >signal,
            >shape 
        )Divide Normalise
    }Do 
}!envelope-compress

{
    {(?signal ,200,2000,4)BesselBandPass}Do !signal-m 
    {(?signal     ,2000,4)BesselHighPass}Do !signal-h 
    {(?signal     , 200,4)BesselLowPass}Do  !signal-l 
    >signal-m !signal
    ?envelope-compress Do !signal-m
    >signal-h !signal
    ?envelope-compress Do !signal-h
    >signal-l !signal
    ?envelope-compress Do !signal-l
    (
        ({>signal-l pcnt+50}Do,10),
        ({>signal-m pcnt+30}Do,0),
        ({>signal-h pcnt+20}Do,0)
    )MixAt Normalise 
}!do-it 

"temp/input.wav" ReadFile ^left ^right

[
    As compression happens in two phases - 0.5 is actually
    a lot - more gets silly - 0.9 makes stuff sound all crunchy
    and old school.
]
0.5 !compress

>left  !signal
?do-it Do !left
>right !signal
?do-it Do !right

((>left Done,>right Done),"temp/done.wav")WriteFile32

To demonstrate, here are two pieces. The first does not use the compressor and the second does (at a setting of 0.5). The first has had some work done on the base to bring it out which was not needed on the second as the compressor did it.

Saturday, 29 December 2012

Follow

Follow is a processor for following the volume envelope of a signal.

(?signal,50,50)Follow !envelope

In the above example, an envelope is created using a rise (attack) and fall (release) time of 50 milliseconds. The first number is the rise and the second the fall.

An envelope is a signal which moves between 0 (for silence) and X (the loudest part of the incoming signal).

One issue with envelopes is that they should not be normalised because their common mode of operation is for the entire envelope to be above zero. The following patch sets an envelope to be between 0 and 1.

((1,?envelope MaxValue)/,>envelope)DirectMix !envelope

Please note that the above will fail if the envelope is silence.

Dividing a signal by its envelope will compress the volume range.

Multiplying a signal by its envelope will expand the volume range.

Wednesday, 19 December 2012

Vocoder Fun

Ether uses a complex vocoder to perform some interesting effects mixing generative a performed music.


Music and technology have always gone hand in hand. We think of technology in music as related to electronic and computational music; however, if we consider, just for a moment, the technology behind the valves in a trumpet or the wood in a violin we can start to see that music and technology are like a hand in a glove. Sonic Field is both a synthesis engine and an audio processor. In Ether, it is acting as a bit of both. I took audio recorded as the output from an outboard processor chain starting with Garage Band (of all things) doing a piano type sound. The sound from Garage Band is nothing special, but it was pretty heavily processed before I captured it with the USB audio interface and recorded it in Audacity.

Garage Band --- EQ --- Reverb --- Compressor --- USB Digitiser --- WAV File
Then
WAV File --- 256 Envelope Followers --- Generative Engine[256 Signal Generators]
--- Reverberation --- WAV File
Then
WAV File --- Valve emulation --- Compression --- Valve Emulation --- Wave File

In the middle step the vocoder part (in red and underlined) is the separation of the signal into 256 frequency specific envelopes using envelope followers and resonant filters. The the generative engine alters the parameters by which the signal generators form new sounds from the envelopes. The metallic other worldly sound of the output from the vocoder is achieved by frequency modulating each of the sin waves used to recreate the audio. This moves the signal in and out of harmonic match with the original.

The challenge from the point of view of Sonic Field was memory. The 256 separate components of the system simply exhausted the existing ways in which Sonic Field could manage its storage. It now has a fully automatic swap system which stores audio in memory as a high speed cache but moves it to disk storage as needed to prevent running out of memory in the JVM. This replaces the partly manual system it had before.

Here is the end result on Youtube And Sound-cloud: http://youtu.be/kOo-2OpSq2E
\


Here is the vocoder patch:

"temp/input.wav" ReadFile ^signal1 ^signal2
(
    >signal1,
    >signal2
)Mix !signal

?signal Length !length
(?length,0.5)* !offset
1.025 !step
  256 !bands
   25 !pitch
bunch !m-channels
(
    1,?bands,
    {
        {
            ("Scanning channel ",?pitch)Println
            (?signal,?pitch,0.1,18)RBJPeaking    !signal
            (?signal,?pitch,0.1,18)RBJPeaking    !signal
            (?signal,?pitch,0.1,18)RBJPeaking    !chan-sig
            (?pitch period,10)/                 !p
            (
                (?chan-sig,?p,?p)Follow pcnt+50,
                (>chan-sig,?p,?p)Follow pcnt+50
            )Mix   dbs+6 WaveLimit               !chan-sig
            >chan-sig 
        }Do !job
        (>job,>m-channels)AddEnd                 !m-channels
        (>pitch,?step)* !pitch
    }
)Repeat

bunch !final
1 !swap
0 !position
-10 !shifter
 -5 !shifter-shift
(
   1,32,
   {
        !x
        ("***** Encoding ", ?x," Shift is ",?shifter,"*****")Println
        (25,?shifter)+ !pitch-in
        (
           (?shifter,10)Gt,
           {-5 !shifter-shift},
           {}
        )Choose Invoke
        (
           (?shifter,-10)lt,
           { 5 !shifter-shift},
           {}
        )Choose Invoke
        (>shifter,?shifter-shift)+ !shifter
        
        (
               (>swap,1)eq,
               {
                   0 !swap
               },
               {
                   1 !swap
               }
        )Choose Invoke
        
        {
            1 Silence !output-l !output-r
            [25 !pitch-in]
            1 Silence !output
            1 !c
            (
                ?m-channels,
                {
                    !chan-sig
                    ?pitch-in !pitch 
                    (>c,1)+ !c
                    (
                        >output,
                        (
                            (
                                (?length,?pitch)SinWave,
                                (
                                    ?length,
                                    (
                                        0.1,
                                        (Random,0.1)*
                                    )+
                                )SinWave pcnt+1
                            )FrequencyModulate,
                            ?chan-sig
                        )Multiply !signal
                    )Mix !output
                                    
                    >output RemoveDc RoundOff !output Length !len
                    (>output,(?pitch,2)*,4)ButterworthLowPass !output
                    {
                        ((0,?swap),(?len,(1,?swap)-))NumericShape !shape
                        (
                            (?output,>shape)Multiply,
                            >output-l
                        )Mix RemoveDc
                    }Do !output-l
                    {
                        ((0,(1,?swap)-),(?len,?swap))NumericShape !shape                
                        (
                            (>output,>shape)Multiply,
                            >output-r
                        )Mix RemoveDc
                    }Do !output-r
                    >output-l Done !output-l
                    >output-r Done !output-r
                    (>pitch-in,?step)* !pitch-in                              
                }
            )InvokeAll
            [ The left and right record ready for splitting and
              sending to MixAt
            ]
            ((>output-l,?position),(>output-r,?position))  
        }Do !job            
        (
            >job,
            >final
        )AddEnd !final
        (>position,?offset)+ !position
    }
)Repeat

bunch !final-l !final-r
(
    >final,
    {
        ^l ^r
        (>l,>final-l)AddEnd !final-l
        (>r,>final-r)AddEnd !final-r
    }
)InvokeAll
>final-l MixAt normalise !left
>final-r MixAt normalise !right 

[(?left,?right)StereoMonitor]

{
    ("Resonant Filtering")Println
    (?signal,64,64)Follow Normalise           !shape
    ((1,>shape)DirectMix,0.5)Power            !shape
    (>shape,15000)NumericVolume               !cut
    (?signal length WhiteNoise,1,2)RBJLowPass !q
    (?q,1,2)RBJLowPass Normalise    pcnt+75   !q
    (?signal,>cut,>q)ShapedLadderLowPass      !new
    (>new pcnt+75,>signal pcnt+25)Mix Normalise
}!res-filter
>left  !signal ?res-filter Do !left
>right !signal ?res-filter Do !right
>left  Done !left
>right Done !right
(>left, 3000,2,12)RBJPeaking !left
(>right,3000,2,12)RBJPeaking !right

[ A very desnse reflector
  Which splits the reflected wave form into smaller chunkcs
  reflects them and then recombines the results. This is
  very parallel.
]
{
    {
        (?sample,1000,5)ButterworthLowPass   !sampleL
        (?sample,3000,2)ButterworthLowPass   !sampleN
        (?sample,1000,4)ButterworthHighPass  !sampleH
        (>sampleH ,5000,2)ButterworthLowPass  !sampleH
        (?sample,((?first ,?offset)+ Prime Silence,(?sample,-13)Volume)Concatenate)Mix    !wet
        (
            1,2,
            {
                !z
                "." Print
                (>first,1.05)* 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)ButterworthLowPass  !sampleL
        (?sampleN ,1000,1)ButterworthLowPass  !sampleN
        (?sampleH ,2000,1)ButterworthLowPass  !sampleH
        (
            (0,0),
            ((?wet  Length,3)/,1),
            (?wet   Length,0)
        )NumericShape !env
        (
            3,20,
            {
                !z
                (?z,4)/ !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
        0.99 !l
        (
            20,40,
            {
                !z
                "." Print
                (?z,6)/ !z
                (>first,1.025)* Prime !first
                (>wet ,(((?first,30)-,?offset)- Silence,(((?sampleL ,(-7,?z)-)Volume,?env)Multiply,500,2)ButterworthLowPass)Concatenate)Mix  !wet
                (>wet ,(((?first,30)+,?offset)- Silence,(((?sampleN ,(-4,?z)-)Volume,?env)Multiply,500,2)ButterworthLowPass)Concatenate)Mix  !wet
                (>wet ,((?first      ,?offset)- Silence,(((?sampleH ,(-7,?z)-)Volume,?env)Multiply,500,2)ButterworthLowPass)Concatenate)Mix  !wet
            }
        )Repeat
        >wet
    } !reflector
    
    bunch !dos
    (
        (>sample,?reflect-length)Granulate,
        {
            ^signal ^time
            "" Println
            ("Reverb at: ",?time)Println
            (?signal,>signal Length Silence)Concatenate !sample
            ?reflector Do !sample
            ((>sample,?time),>dos)AddEnd  !dos
        }
    )InvokeAll
    bunch !results
    (
        >dos,
        {
            ^signal ^time
            ((>signal Done,?time),>results)AddEnd  !results
        }
    )InvokeAll

    >results MixAt Normalise    
}!do-reflector

("Reverb")Println
  80 !first
  30 !offset
5000 !reflect-length
>left  !sample
?do-reflector Do !left
>right !sample
?do-reflector Do !right
(>left  Done,25,1)RBJHighPass Normalise !left
(>right Done,25,1)RBJHighPass Normalise !right

(>left  ,25,1)RBJHighPass Normalise !left
(>right ,25,1)RBJHighPass Normalise !right


(
    (
        (1000 Silence,>left  Normalise )Concatenate,
        (1000 Silence,>right Normalise)Concatenate
    ),
    "temp/tone.wav"
)WriteFile32

Here is the valve compressor patch:

"temp/input.wav" ReadFile ^left ^right

(>left ,10000,3)ButterworthLowPass !left
(>right,10000,3)ButterworthLowPass !right

{
    (
        (
            -0.03,0.2,0,-1,0.2,2,
            ?signal
        )WaveShaper pcnt+25,
        >signal pcnt+75
    )Mix Normalise !signal
    (
        {(?signal Reverse,1,50)Follow Reverse},
        {(?signal        ,1,50)Follow}
    )DoAll Mix !shape   
    
    (
        {(?signal Normalise,25,25)Follow},
        {(?signal Normalise Reverse,25,25)Follow Reverse}
    )DoAll Mix !shape
    
    (?shape,(1,?shape MaxValue)/)NumericVolume !shape
    (0.05,>shape dbs+6)DirectMix               !shape
    (
        >signal,
        >shape 
    )Divide Normalise !signal 
}!envelope-compress

{
    (?signal ,200,2000,4)BesselBandPass !signal-m 
    (?signal     ,2000,4)BesselHighPass !signal-h 
    (?signal     , 200,4)BesselLowPass  !signal-l 
    >signal-m !signal
    ?envelope-compress Invoke
    >signal !signal-m
    >signal-h !signal
    ?envelope-compress Invoke
    >signal !signal-h
    >signal-l !signal
    ?envelope-compress Invoke
    >signal !signal-l
    (
        (30 Silence,(>signal-l dbs+3 WaveLimit,200,6)BesselLowPass)Concatenate pcnt+50,
        (>signal-m dbs+3 WaveLimit,2000,6)BesselLowPass pcnt+30,
        >signal-h  dbs+3 WaveLimit pcnt+20
    )Mix Normalise 
}!do-it 
>left  !signal
?do-it Do !left
>right !signal
?do-it Do !right
((>left Done,>right Done),"temp/done.wav")WriteFile32


Thursday, 6 December 2012

Compression-102: Loudness Wars And Extreme Compression

Compression 102, how do we  boost loudness via dynamic range compression to catch people's attention. 

This is not about making audio sound better; it is about making it sound more striking. It is about capturing people's attention and hooking them into a radio program, or the background in a music store. It is about making sales of music, or in advert breaks. This is a fascinating area, though it is important to realise that we are not attempting to make stuff sound better in a classic sense, just louder.

Here is the video - I have put the compression patch used at the bottom of this post:

http://youtu.be/l_75rzdaxkg


Remember! This code is AGPL 3.0



"temp/step-1.wav" ReadFile ^left ^right
{
    (
        (?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 
}!envelope-compress

(?left ,2000,6)BesselHighPass         !signal-h 
(?left ,2000,6)BesselLowPass          !signal 
(>signal,150,1,3)RBJPeaking           !signal
?envelope-compress Invoke
(
    (30 Silence,(>signal dbs+6 WaveLimit,2000,6)BesselLowPass)Concatenate,
    >signal-h dbs+6 WaveLimit 
)Mix Normalise dbs+3 WaveLimit !left-new


(?right,2000,6)BesselHighPass         !signal-h 
(?right,2000,6)BesselLowPass          !signal 
(>signal,150,1,3)RBJPeaking           !signal
?envelope-compress Invoke
(
    (30 Silence,(>signal dbs+6 WaveLimit,2000,6)BesselLowPass)Concatenate,
    >signal-h dbs+6 WaveLimit
)Mix Normalise  dbs+3 WaveLimit !right-new

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

Wednesday, 5 December 2012

Compression 101

I have recently put up a video introducing the basics of audio compression (dynamic range compression) for voice:



The patch used in this video is this one (remember AGPL):



2 SetSwapLimit
"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 
}!envelope-compress

{
    (?signal,50,10)Granulate !grains
    Bunch !output
    (
        >grains,
        {
            ^grain ^time
            (                
                (?time,(?time,?grain length)+,?signal)Cut !sample
                (?grain Rectify MaxValue !v,?gate-point)Gt,
                {
                    (                    
                        (?v,?slam-point)Gt,
                        {
                            (>grain,(?slam-point,?v)/)NumericVolume !grain
                        },
                        {
                            [ Do nothing ]
                        }
                    )Choose Invoke
                }
                ,
                {
                    (>grain,(1,(?gate-point,?v)/)/)NumericVolume !grain
                }
            )Choose Invoke
            ((>grain swapout,>time),>output)AddEnd !output
        }
    )InvokeAll
    >output MixAt Normalise !signal
    
}!compress
{
    0.02 !gate-point
    0.50 !slam-point
    [ Do in pairs to avoid running out of memory ]
    (
        (
            ?compress,
        )DoAll Mix Swapout,
        (
            ?compress,
        )DoAll Mix Swapout,
        (
            ?compress,
        )DoAll Mix Swapout,
        (
            ?compress,
        )DoAll Mix Swapout,
    )Mix Normalise !signal
}!granular-compress

?envelope-compress Invoke

[ 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-12,
    ?signal
)Mix Normalise !left
(
    >note-right dbs-12,
    >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  !signal ?granular-compress Invoke
>signal dbs+6 WaveLimit !left
>right !signal ?granular-compress Invoke
>signal dbs+6 WaveLimit !right

(
    (
        >left,
        >right
    ),"temp/step-1.wav"
)WriteFile32