Sunday 29 December 2013

Killing Off Spring

Glad to see the back of Spring.

Sonic Field Is Now Stand Alone Core Java

About a year ago I moves Sonic Field over to being a Spring based application. I had all sorts of ideas about making a UI using html etc etc. Whilst the exercise of converting to Spring was good for the clean structure of Sonic Field, the weight of the Spring framework is huge.

I am much happier now that Sonic Field just requires the Core JDK to work. It can be compiled down to a single jar file and run.

The next step is to make a standard release script which creates an executable jar file, then Sonic Field will be a very simple program to execute indeed.


Friday 27 December 2013

What Is ADSR

I made a short video tutorial

Downloading Sonic Field

Sonic Field Is Open Source

It always has been open source under the AGPL 3.0 license. For a while I had a dedicated website for Sonic Field. To be honest, the combination of Google Drive and blogger makes more sense now.

Sonic Field can be downloaded from here:

https://drive.google.com/folderview?id=0BwiW6ZSSu_DEVmZfbW1Qa1o5Q1U&usp=sharing


I hope to add a good examples section in the near future.

Thursday 26 December 2013

Phase Modulation Synthesis Explanation And Example

We here a lot about FM for synthesis - but the truth is that most 'FM' is not Frequency Modulation at all - it is Phase Modulation.

...The full example patch is at the bottom of this post...

The reason is simply that Phase Modulation can produce much the same effects as Frequency Modulation but it is much easier to get correct. Let us look into why this by first having a quick look at what Frequency and Phase modulation actually are. I am going to start at the well read amateur level here.
  • As we know - a note has a pitch.
  • Another word for pitch is (ish) frequency. Frequency is more precise in its usage than pitch so we shall use it instead.
  • So, A4 is 440Hz which is a frequency.
  • A pure note is a sine wave. This means the pressure waves in air for that note follow a sinusoidal shape. Equally, the voltage in an amplifier or synthesiser circuit will follow a sinusoidal shape (again - ish).
  • A pure note has just one frequency in it.
  • However, we want to create non pure tones (as pure ones are boring in general). If you don't believe me that a pure note is boring and that something like a flute makes a pure note - think again http://www.soundonsound.com/sos/oct03/articles/synthsecrets.htm. Even a flute has a very complex tone.
  • We can make rich tones in many ways, but Frequency Modulation of a pure tone is one of the more interesting.
Frequency Modulation Step By Step So we have a pure tone and we slowly move its frequency down a bit and then up a bit and back to the middle. What we get is vibrato (tremolo being the amplitude equivalent). Vibrato is technically frequency modulation but not in the sense that syntheses nerds talk about FM. The interesting stuff happens when we modulate the frequency of a tone up and down as a rate similar to that frequency of the tone its self. In other words, the tone (carrier) and modulation are both in the audible range.

Frequency modulating (let's drop the caps for now) a tone of 1000Hz with a tone of 1100Hz will produce a tone with tones inside it rather than vibrato. In this case we will get 1000, 2100, 4200 and so on. There are also things which are called (sorry - I know it sounds confusing) negative frequencies. Now, negative frequencies cannot actually exist in sound though they are important in the mathematical modelling of sound. In real sound they are just frequencies.
A bit confused? Here is a simple way of looking at it:
  • We take a fundamental of frequency X.
  • We frequency modulate it with frequency Y.
  • We get new frequencies along side X, these are X+Y, X+Yx2, X+Yx3 etc.
  • We also get X-Y, X-Yx2, X-Yx3 etc.
  • However, the ones where we take some multiple Y away from X might end up negative.
  • So, X=1000 and Y=1100 then X-Y=-100Hz.
  • Negative frequencies don't exist in sound so we actually get the positive equivalent - e,.g. 100Hz.
This means that 1000Hz frequency modulated with 1100Hz will give:
  1. 100,
  2. 1000,
  3. 1200,
  4. 2100,
  5. 2300,
  6. 3200
  7. ...
Consequently, what we are left with is the original (fundamental) and a mixture of inharmonic overtones (and under-tones which we often remove via filtering).  We will also notice that the contribution of each inharmonic overtone reduces as the frequency goes up.

What does all this sound like?
Well, the 1000m1100 example will sound quite bell like. But, the truth is that, frequency modulation will make pretty much any tone you want (especially with a bit of filtering). This is why it is so powerful. Other techniques like wave shaping and distortion will produce just the harmonic overtones of the fundamental. Amplitude modulation will produce inharmonic over and under-tones but only one. Ring modulation is similarly more limited than FM. Nothing (other than additive synthesis which can do anything in theory) is quite as powerful at creating rich sounds.

But - why still using it when we have additive synthesis? I mentioned additive synthesis. As I say, this can produce any sound; so why bother with anything but additive synthesis. Why go to the effort of creating FM? The reasons are two fold. Firstly, to create a really complex rich sound with additive synthesis is very computationally complex and therefore still (even with modern technology) poses a major challenge to synthesis engines. Just creating a single waveform with additive synthesis is not so bad, but a complex evolving tone is quite a challenge. The second reason is very human: creativity is iterative. We make a sound we like it, we tweak it, we listen, we get inspired, we change it and we keep going. Frequency modulation gives an jaw dropping capacity to shape the resulting sound with only a few parameters to tweak, this makes it ideal for creative exploration.

From Bells To Clarinets
By controlling difference in frequency of the modulation and fundamental and the amount of modulation (sometimes called the modulation index) we get all sorts of different tones. Here are some example spectrograms. I have not filtered these so two have the low under-tones in them:
Modulation of fundamental of 440Hz with 880Hz producing the a spectrum similar to that of a clarinet. Because the negative frequencies coincide with the positive ones we do not seem them as separate lines on the spectrogram.
Modulation of 440Hz with 440.88Hz producing a spread harmonic spectrum similar to a low pitched piano note of a guitar string.
A classic bell tone modulating 440Hz with 528Hz.
The above notes all had an ADSR envelope applied which gives the characteristic intensity shape seen left to right.

From Frequency To Phase
My examples above are a cheat because they were not produced with frequency modulation; I used phase modulation. Here is the Sonic Field patch which created these tones:

{
    (
        (0,0),
        (?a,1),
        (?d,0.5),
        (?s,0.1)
        (?r,0.0)
    )NumericShape !env


    (
        ?frequency,
        (
            ((1,(?r,(?frequency,?frequency-spacing)*)ExactSinWave)DirectMix,?modulation-amount)NumericVolume
        )Mix
    )PhaseModulatedSinWave !signal
    
    (
        >signal,
        >env
    )   Multiply Normalise,
}!play-bell-inner

 64  !a
128  !d
2024 !s
4096 !r
440  !frequency

0.15 !modulation-amount
1.2  !frequency-spacing
((?play-bell-inner Do),"temp/bell-tone-example.wav")WriteFile32

0.35   !modulation-amount
1.002  !frequency-spacing
((?play-bell-inner Do),"temp/string-tone-example.wav")WriteFile32

0.5  !modulation-amount
2.0  !frequency-spacing
((?play-bell-inner Do),"temp/clarinet-tone-example.wav")WriteFile32

It really does not matter if that is meaningless to you! However, we can see some key points in there:
(
        ?frequency,
        (
            ((1,(?r,(?frequency,?frequency-spacing)*)ExactSinWave)DirectMix,?modulation-amount)NumericVolume
        )Mix
    )PhaseModulatedSinWave !signal

The above is the piece of the patch which actually does the modulation. It modulates the fundamental (given by the value ?frequency) by a sine wave at the modulation frequency which is given by ?frequency-spacing * ?frequency.

Also we have:
0.15 !modulation-amount
1.2  !frequency-spacing
((?play-bell-inner Do),"temp/bell-tone-example.wav")WriteFile32

0.35   !modulation-amount
1.002  !frequency-spacing
((?play-bell-inner Do),"temp/string-tone-example.wav")WriteFile32

0.5  !modulation-amount
2.0  !frequency-spacing
((?play-bell-inner Do),"temp/clarinet-tone-example.wav")WriteFile32

This is where the three tones are produced. Different spacing between fundamental and the modulation and different amounts of modulation are all that is required to produce completely different spectra and amazingly different sounding notes.

Frequency modulation is the moving of the fundamental frequency up and down. But that is quite hard to get right. The slightest numerical error and what we hear is the note being off pitch. To get frequency modulation correct, we need to exactly balance the up and down parts. This can prove quite hard to get right in practice. Fortunately, there is another property of a pure sine wave we can mess with which has the same effect for synthesis but is easier to work with.

Phase:
Again, this gets a little tricky to explain without a little mathematics. I will try really hard to make it as simple as possible! Let us look at the sine wave:
This image is Wiki Commons - see here: http://en.wikipedia.org/wiki/File:Sine_curve_drawing_animation.gif
If we imagine a spot of paint on a wheel at 3 o'clock and we roll that wheel along the ground, then just look at the hight of the spot we get a sine wave.

As the wheel rotates, we can see there is an angle between where the spot started,the centre of the wheel and where the spot is currently. For every value of this angle there is a value of the sin wave height.

This is effectively how the sine wave generator in a digital synthesiser works. It takes an angle which continually increases from 0 to 360 degrees (usually this is measured in radians but that is a detail) and for each tiny incremental step in the angle it looks up the value of a sine wave. Repeating this continuously produces a continuous sine wave which is what we call a 'Digital Oscillator'.

To phase modulate the digital oscillator we simply add a varying amount to the phase. This can change the instantaneous pitch but not the fundamental frequency. OK the mathematics here is a little more complex - feel free to stop reading this paragraph now.... Still here? OK, modulating the phase is the same as altering the first differential of the the wave form. But the first differential of a sine wave is a cosine wave which has the same shape. So, from the human perception point of view, except for instantaneous effects (transients - which I am not discussing here) phase and frequency modulation are exactly the same. The advantage is that if we get a slight asymmetry in the modulation it does not effect the fundamental as the rate of change asymmetry required to make the modulation asymmetrical cancels out the net effect. 

To prove phase modulation does not effect the fundamental even when the modulator is asymmetrical I will modulate 440Hz with a rectified sine wave.

The same 440 modulated by 528 tone as above but with the 528Hz sine wave rectified to make an asymmetric wave form.
We can clearly see that whilst the modulated signal now has many more, stronger inharmonics in it, the fundamental frequency has not changed. 

Here is an example of piece of music created using phase modulation:

[Here is the patch for the above]

{
    (
        (0,0),
        (?a,1),
        (?d,0.5),
        (?s,0.1)
        (?r,0.0)
    )NumericShape !env

    (
        (0,0),
        ((?a,2)/,1),
        (?d,0),
        (?r,0.0)
    )NumericShape !hitEnv
    
    (
        (?d WhiteNoise,(?d,?pitch)ExactSinWave MakeSquare)Mix pcnt+50,
        ?hitEnv
    )Multiply !hit
    (>hit,(?pitch,2)*,2)ButterworthLowPass !hit

    (
        ?pitch,
        (
            ((1,(?r,(?pitch,?pitch-spacing)*)ExactSinWave)DirectMix,?ring-amount)NumericVolume
        )Mix
    )PhaseModulatedSinWave !signal
    
    (
        (
            >signal,
            >env
        )   Multiply Normalise,
        ?hit
    )Mix Normalise 
}!play-bell-inner

{
    ?play-bell-inner Do        !s1
    (>pitch,1.005)*            !pitch
    ?play-bell-inner Do dbs-16 !s2
    (>s1,>s2)Mix Normalise !signal
    (
        (?dullness,0)gt,
        {
            (>signal,?pitch,?dullness)BesselLowPass  Normalise !signal
            (>signal,?pitch,2)ButterworthHighPass    Normalise !signal
        },{}
    )Choose Invoke
    >signal
}!play-bell

{
    (?velocity,1.5)**         !volume

    ?play-bell Do !signal
    (60000,?length)+ !length  
    {?length WhiteNoise}Do                                    !reverb
    {((>reverb,3.0)Power Normalise,10,1)ButterworthLowPass}Do !reverb
    {((0,-99),(50,0),(?length,-60))SimpleShape}Do             !renv
    {(>reverb Normalise,>renv)Multiply}Do                     !reverb
    
    {(>reverb,?r Silence)Concatenate}Do    !reverb
    {(>signal,?length Silence)Concatenate}Do !signal !signal-dry

    ?signal Magnitude !mag     
    {>signal FrequencyDomain}Do    !signal
    {>Reverb FrequencyDomain}Do    !reverb
    (?signal,?reverb)CrossMultiply !signal
    >signal TimeDomain !signal
    ?signal Magnitude !newMag 
    (>signal,(>mag,>newMag)/)NumericVolume !signal-wet 
    
    (>signal-wet,>signal-dry)Mix Normalise              !signal
    ((>signal,?pitch,1)ButterworthHighPass Normalise,(?volume,(0.25,Random)*)+)NumericVolume
     
}!reverb-bell

{
    Bunch !notes
    0     !count
    0     !prev-high
    (
        ?track,
        {
            ^tickOn ^tickOff ^note ^key ^velocity
            ("Note ",?count)Println
            (
                (?count,?notesToPlay)lt,
                {
                    [ Set up the note ]
                    (?tickOn,?beat)*                  !at
                    ((?tickOff,?tickOn)-,?beat)*      !length
                    (Semitone,?key)**                 !multi
                    (?baseSound,>multi)*              !pitch
                    (>pitch,2)/                       !pitch
                    (>velocity,100)/                  !velocity
                    
                    [ Play the note ]
                    ((?voice Do,?at),>notes)AddEnd    !notes
                },{}
             )Choose Invoke
             (>count,1)+ !count 
         }
     )InvokeAll
     >notes MixAt Normalise
}!play

128   !pitch
1.2   !pitch-spacing
  1   !dullness
0.15  !ring-amount
32    !a
128   !d
2048  !s
8192  !r

?reverb-bell !voice
"C0" Note    !baseSound
 48.00       !beat
 
"temp/chpn-p6.mid" ReadMidiFile 
^t1
^t2
^t3

?t3  !track
999  !notesToPlay

?play Do !left
?play Do !right


((?left,?right),"temp/bell-preb.wav")WriteFile32 

Saturday 21 December 2013

Chopin Prelude No 4

Below is a render of Chopin Prelude No 4 by Sonic Field.

It was done using much the same patch as that for Requiem For Peace; however, in this case the left hand notes were more gentle and this lead of the contamination of the attack with a slight high frequency click sound. To round this out I added from Bessel filtering just in the attach of the left hand notes (patch for this after the video). I used a Bessel filter to make sure there were not significant phase issues remixing the filtered and non filtered signals.


[ this patch removes clicks from the 
  attack phase of notes when soft-attack is true
]
    (
        ?soft-attack,
        {
            (
                (
                    (
                        (0,1),
                        (125,0)
                    )NumericShape,
                (?signal,(?pitch,7)*,6)BesselLowPass
                )Multiply,
                (
                    (
                        (0,0),
                        (125,1),
                        (?signal Length,1)
                    )NumericShape,
                   ?signal
                )Multiply
            )Mix !signal
        },{
        }
    )Choose Invoke

Friday 20 December 2013

Requiem For Peace

Here is another patch which I used to render the Moonlight Sonata.

This piece uses a similar percussive string sound to some of my other pieces. It has some very vague similarity to a piano (hence the silly name solar-piano) but in reality it sounds nothing like a piano. What it does have is a complex release. The signal is frequency and amplitude modulated by slow frequency noise. Whilst this produces a potentially pleasing and somewhat wistful sound for single notes, it effects on harmonies is to pain a complex sound scape just from the overlap of signals.

Because these sound generator is therefore good at filling space between the attacks of notes, it allowed me to slow the music down around 5:1. A hand made reverberation impulse response then helped further by smoothing everything into a near realistic but overly wet space.

The patch is below this video:


[
  Reverberator
  ============
]
{
    ?signal Magnitude !mag
    (>signal,?grain-length Silence)Concatenate !signal   
    (
        (?mag,0)Eq,
        {
        },
        {
            (>signal,?grain-length Silence)Concatenate !signal   
            >signal FrequencyDomain  !signal
            (>convol,>signal)CrossMultiply  !signal
            >signal TimeDomain !signal
            ?signal Magnitude !newMag
            (>signal,(>mag,>newMag)/)NumericVolume !signal
            [ tail out clicks due to amplitude at end of signal ]
            (
                (
                    (0,1),
                    (100,1),
                    ((?signal Length,100)-,1),
                    (?signal Length,0)
                )NumericShape,
                >signal
            )multiply !signal
        }
    )Choose Invoke
    >signal
}!reverb-inner

{
    ?convol Length !grain-length 

    (>convol,?grain-length Silence)Concatenate FrequencyDomain  !convol
    (>signal,?grain-length Silence)Concatenate !signal
    Bunch !out
    (
        (>signal,?grain-length)Granulate,
        {
                ^signal ^time
                ((?reverb-inner Do,>time),>out)AddEnd !out
        }
    )InvokeAll
    >out MixAt Normalise
}!reverb

{
    (100,?frequency)SinWave MakeSawTooth !filter
    (>filter,?length,1)ButterworthLowPass !filter
    ?length WhiteNoise !signal
    ((0,0),(?attack-a,0.25),(?attack-b,  1),((?length,0.8)*,  1),(?length,0))NumericShape !sinEnv
    (>signal,?sinEnv)Multiply                  !signal
    (>signal,>filter)Convolve Normalise        !signal
    (>signal,2000,5)ButterworthLowPass         !signal
    (>signal,?frequency,2)ButterworthHighPass  !signal
    (>signal,?frequency,1)ButterworthLowPass   !signal
    (((0,0),((?length,0.75)*,1),(?length,0.5))NumericShape,(?length,2.5)SinWave)Multiply !vvib
    (1,>vvib pcnt+50)DirectMix                 !vvib
    (>signal,?vvib)Multiply Saturate Normalise !signal
    (>signal,0.6,0.5,?frequency Period)ResonantFilter Normalise !wave
    (
        -0.03,0.2,0,-1,0.2,2,
        ?wave
    )WaveShaper Normalise      !signal
    (>signal,?sinEnv)Multiply  !signal
    ((0,64),((?length,0.25)*,?frequency),(?length,64))NumericShape                      !lower
    ((0,?frequency),((?length,0.25)*,(?frequency,4)*),(?length,?frequency))NumericShape !upper
    (>signal,>lower,>upper,2)ShapedButterworthBandPass Normalise !signal
    (>signal,?volume)Volume
} !flute

{
    ((?attack,2)*,?pitch)ExactSinWave MakeSquare !hit
    (?hit,(?pitch,2)*,4)ButterworthLowPass       !hit
    (
        (0,1),
        (45,0.5),
        (75,0)
    )NumericShape !hit-env
    (
        >hit,
        >hit-env
    )Multiply Normalise !hit 
    
    (>hit,?hit-strength)Volume !hit
    
    (?attack,?decay,?sustain,?release)+ !length
    (
       (?length,?pitch)ExactSinWave      dbs+3,
       (?length,(?pitch,2)*)ExactSinWave dbs-12, 
       (?length,(?pitch,3)*)ExactSinWave dbs-18
    )Mix                                !note
    
    (
        (0,0),
        (?attack,1),
        ((?attack,?decay)+,0.5),
        ((?attack,?decay,?sustain)+,0.1),
        (?length,0)
    )NumericShape !note-env
    (
        >note,
        ?note-env
    )Multiply Normalise !note 
    (
        1,
        0,
        1,
        1,
        4,
        10,
        >note
    ) WaveShaper Normalise !note
    (
        0,
        0,
        1,
        1,
        4,
        10,
        >note
    ) WaveShaper Normalise !note
    
    (>note,?pitch,1)ButterworthHighPass Normalise !note
    (>note,1500,2)ButterworthLowPass    Normalise !note
    
    (
        ((0,5),((?attack,?decay,?sustain)+,1))Slide,
        ?note-env
    )Multiply !twang
    (?twang,?release silence)Concatenate !twang
    
    ( 1,>twang  pcnt+20)DirectMix !twang
    (
        >twang,
        >note
    )Multiply !note
    
    (
        >hit dbs+6,
        >note
    )Mix !note
    
    (?note,((0,1.001),(?note length,0.999))NumericShape)Resample !note-1
    (?note,((0,0.999),(?note length,1.001))NumericShape)Resample !note+1
    (>note,>note-1 pcnt-50,>note+1 pcnt+50)Mix Normalise !note
    
    64 !base
    (
        (?note,110,2)ButterworthLowPass Normalise,
        (
            (-7,?base         Period),
            (-7,(?base,1.25)* Period),
            (-7,(?base,1.50)* Period),
            (-7,(?base,1.75)* Period)
        ),
        -20
    )MultipleResonantFilter Normalise !sounding-board
    (>sounding-board,110,2)ButterworthLowPass Normalise !sounding-board 
    ((0,0),(125,0),(500,1),((?note length,250)-,1),(?note length,0))NumericShape !damper
    (>sounding-board,25,4)ButterworthHighPass !sounding-board
    (
        >sounding-board,
        ?damper
    )Multiply Normalise !sounding-board 
    (>sounding-board,25,4)ButterworthHighPass !sounding-board
    (
        >sounding-board,
        ?damper
    )Multiply Normalise !sounding-board 
    (>sounding-board,?pitch,1)ButterworthHighPass !sounding-board
    (250,?sounding-board length,>sounding-board)Cut !sounding-board
   
    (
        >sounding-board,
        >note
    )Mix Normalise !note
    
    (
        (
            250 Silence,
            (?damper,?note)Multiply Saturate Normalise,
        )Concatenate,
        (
            (-3,(?pitch,0.05)* Period),
            (-6,(?pitch,0.2)* Period),
            (-8,(?pitch,0.25)* Period),
            (-8,(?pitch,0.333)* Period),
            (-9,(?pitch,0.5)* Period),
            (-6,(?pitch,1.5)* Period),
            (-6,(?pitch,2.0)* Period) 
        ),
        -80
    ) MultipleResonantFilter Normalise        !res
    (0,?length,>res)Cut               !res
    (
        0,
        0,
        1,
        1,
        4,
        10,
        >res
    ) WaveShaper Normalise !res    
    (
        >note,
        >res Normalise pcnt+15
    )Mix !note
    (?note,(?pitch,2)*,1)ButterworthLowPass Normalise !note    
    
    (>note,500 Silence)Concatenate !note
    
    [ Mix in the characteristic white noise ]
    (
        (
            1,
            (
                (
                    ?note length WhiteNoise,
                    ?pitch,
                    4
                )ButterworthHighPass
                ,(?pitch,1.25)*
                ,4
            )ButterworthLowPass Normalise pcnt+5
        )DirectMix,
        >note
    )Multiply !note
    (>note,15,2)ButterworthHighPass     !note

    (
        (0,0),
        (500,0),
        (1000,1),
        (?note length,1)
    )NumericShape !note-env
    
    (
        >note-env,
        ?note
    )Multiply !sample

    (>sample,25,4)ButterworthHighPass !sample
    ((?sample Length WhiteNoise,500,6)ButterworthLowPass,0.01)DirectResample Normalise !multi
    (>sample,(1,>multi)DirectMix)Multiply !sample

    >sample !signal
    
    [
    (
        (
            ((2000 WhiteNoise,2)Power,2000,1)ButterworthLowPass Normalise,
            ((0,0),(80,0),(90,1),(2000,0))NumericShape
        )Multiply,
        (
            ((5000 WhiteNoise,3)Power,1000,2)ButterworthLowPass Normalise,
            ((0,0),(125,0),(135,1),(5000,0))NumericShape
        )Multiply
    )Mix Normalise !convol
    ]
    
    (
        ?reverb Do pcnt+50,
        !sample
    )Mix

    ((?sample Length WhiteNoise,500,6)ButterworthLowPass,0.01)DirectResample Normalise !multi
    (>sample,(1,>multi dbs-6)DirectMix)Multiply !sample
    (
        0,
        0,
        1,
        1,
        4,
        10,
        >sample
    ) WaveShaper Normalise !sample
    (
        (((0,0.125),(4000,0.25),(?sample Length,1))NumericShape,>sample)Multiply,
        >note
    )Mix Normalise !note

    
    (
        ((?note,1000,4)ButterworthHighPass,0.87)Power dbs-6,
        >note
    )Mix Normalise !note

   ( >note,?volume)NumericVolume 
        
}!solar-piano

{
    (?velocity,1.5)**         !volume
    (((?velocity,1)+,2)**,1)- !velocity
    (
        (?velocity,0.5)lt,
        {
            120 !attack
            400 !decay
        },{
             50 !attack
            400 !decay
        }
    )Choose Invoke 
        
    (?decay,(?length,4.5)/)+   !sustain
        
    ?length        !release
    ?velocity      !hit-strength

    [bass boost]
    (
        (?pitch,220)lt,
        {
            (>hit-strength,0.5)+ !hit-strength
            (?volume,0.33)+      !volume
        },{
        }
    )Choose Invoke
    
    (
        "C",?count,
        "P",?pitch,
        "V",?volume,
        "H",?hit-strength,
        "A",?attack,
        "D",?decay,
        "S",?sustain,
        "R",?release
    )Println
    ?solar-piano Invoke !signal

    >signal
}!play-solar

{
    Bunch !notes
    0     !count
    0     !prev-high
    (
        ?track,
        {
            ^tickOn ^tickOff ^note ^key ^velocity
            (
                (?count,?notesToPlay)lt,
                {
                    [ Set up the note ]
                    (?tickOn,?beat)*                  !at
                    ((?tickOff,?tickOn)-,?beat)*      !length
                    (Semitone,?key)**                 !multi
                    (?baseSound,>multi)*              !pitch
                    [(>pitch,2)/                       !pitch]
                    [(>pitch,6)/                       !pitch]
                    (>velocity,100)/                  !velocity
                    (>length,1.5)*                    !length
                    [ Play the note ]
                    ((?play-solar Do,?at),>notes)AddEnd    !notes
                },{
                }
             )Choose Invoke
             (>count,1)+ !count 
         }
     )InvokeAll
     >notes MixAt Normalise
}!play

"C0" Note !baseSound
  8.00    !beat
2000      !shortCut
9999      !notesToPlay

"temp/ml1.mid" ReadMidiFile 
^t1
^t2

?t2 !track
"temp/Solar-Piano-Internal.wav" Readfile ^cLeft ^cRight

>cLeft !convol
?play Do !left

>cRight !convol
?play Do !right

[
   Post
   ===
]
"Post Processing" PrintLn
((?left,?right),"temp/moon-mix.wav")WriteFile32 

"temp/moon-impulse-b.wav" ReadFile ^revl ^revr
"temp/moon-mix.wav" ReadFile ^left ^right 

?left  !signal >revl !convol ?reverb Do Normalise !wleft
?right !signal >revr !convol ?reverb Do Normalise !wright
(
    >wleft,
    >left
)Mix Normalise !left
(
    >wright,
    >right
)Mix Normalise !right

((>left,>right),"temp/moon-post-b.wav")WriteFile32 

Wednesday 18 December 2013

Example: Liquid Sound

Here is the patch which produced Liquid Sound:



"temp/in.mid" ReadMidiFile 
^t1
^t2
^t3
^t4
^t5

?t1 Println
?t2 Println
?t3 Println
?t4 Println
?t5 Println


[
  Reverberator
  ============
]
{
    ?signal Magnitude !mag
    (>signal,?grain-length Silence)Concatenate !signal   
    (
        (?mag,0)Eq,
        {
        },
        {
            (>signal,?grain-length Silence)Concatenate !signal   
            >signal FrequencyDomain  !signal
            (>convol,>signal)CrossMultiply  !signal
            >signal TimeDomain !signal
            ?signal Magnitude !newMag
            (>signal,(>mag,>newMag)/)NumericVolume !signal
            [ tail out clicks due to amplitude at end of signal ]
            (
                (
                    (0,1),
                    (100,1),
                    ((?signal Length,100)-,1),
                    (?signal Length,0)
                )NumericShape,
                >signal
            )multiply !signal
        }
    )Choose Invoke
    >signal
}!reverb-inner

{
    ?convol Length !grain-length 

[    ("Convolving SignalLength:",?signal Length," ConvolutionLength:",?convol Length)Println ]

    (>convol,?grain-length Silence)Concatenate FrequencyDomain  !convol
    Bunch !out
    (
        (>signal,?grain-length)Granulate,
        {
                ^signal ^time
                ((?reverb-inner Do,>time),>out)AddEnd !out
        }
    )InvokeAll
    >out MixAt Normalise
}!reverb

{
    ?length         !outLen
    (?length,1.01)* !length
    {
        ?length Silence !signal
        1 !volume
        ?pitch !harmonic
        (
            (
                (1,1),
                (2.001, 0.5),
                (3.002, 0.1),
                (4.003, 0.25),
                (5.004, 0.05),
                (6.005, 0.125),
                (8.006, 0.0625),
                (9.007, 0.0125),
                (11.009,0.01),
                (13.01, 0.005),
                (15.011,0.0025),
                (19.013,0.0015)
            ),
            {
                ^harmonic ^volume
                ("Pitch",?pitch,"Harmonic",?harmonic,"Volume",?volume,"Length",?length)Println
                (>harmonic,?pitch)* !harmonic
                {
                    (?length,50)/ WhiteNoise          !wave
                    (>wave,100,4)ButterworthLowPass   !wave
                    (>wave, 10,1)ButterworthHighPass  !wave
                
                    (>wave,0.01)DirectRelength        !wave
                    (0,?length,>wave)Cut Normalise    !wave 
                    (1,>wave)DirectMix                !wave
                }!makeWaves

                ?makeWaves Do pcnt+25 !phase
                ?makeWaves Do pcnt+25 !volumeWave
                (>volumeWave,2)Power Normalise        !volumeWave
                (>volumeWave,2)Power Normalise        !volumeWave
                (
                    (
                        (
                            (?harmonic,>phase)PhaseModulatedSinWave,
                            ?volumeWave
                        )Multiply,
                        ?volume
                    )NumericVolume,
                    >signal
                )Mix !signal
                ?length WhiteNoise !noise
                
                (?noise,?pitch,2)ButterworthHighPass !noise
                (?noise,?pitch,2)ButterworthLowPass  !noise
                >noise Normalise !noise
                (?noise,?pitch,2)ButterworthHighPass !noise
                (?noise,?pitch,2)ButterworthLowPass  !noise
                (
                    >noise Normalise   pcnt+5,
                    >signal Normalise  pcnt+95
                )Mix !signal
                                
            }
        )InvokeAll
        >signal Normalise
    
    } !makeTriangle 
    
    ?makeTriangle Do !signal       !root
    (
        (?outlen,2100)gt,
        {
            1000 !point
            ((0,0),(?point,1),((?outLen,?point)-,1),(?outLen,0))NumericShape !venv
        },{
            (?outlen,0.5)* !point
            ((0,0),(100,1),((?outLen,?point)-,1),(?outLen,0))NumericShape   !venv
            
        }
    )Choose Invoke
    
    ((0,0),(?point,1),((?outLen,?point)-,1),(?outLen,0))NumericShape !venv
    (
        ?venv,
        >signal
    )Multiply !signal
    (
        >signal,
        >velocity
    )NumericVolume 
} !chord

{
    Bunch !notes
    0     !count
    (
        ?track,
        {
            ^tickOn ^tickOff ^note ^key ^velocity
            
            (
                (?count,?notesToPlay)lt,
                {
                    [ Set up the note ]
                    (?tickOn,?beat)*                  !at
                    ((?tickOff,?tickOn)-,?beat)*      !length
                    (Semitone,?key)**                 !multi
                    (?baseSound,>multi)*              !pitch
                    (>pitch,2)/                       !pitch
                    (>pitch,6)/                       !pitch
                    (>velocity,100)/                  !velocity
                    (>length,1000)+                   !length
                    ("Note at",?at) Println
                    [ Play the note ]
                    ((?chord Do,?at),>notes)AddEnd    !notes
                },{
                }
             )Choose Invoke
             (>count,1)+ !count 
         }
     )InvokeAll
     >notes MixAt Normalise
}!play

"C0" Note !baseSound
 75.00    !beat
2000      !shortCut
1000      !notesToPlay

?t2 !track

?play Do !left
?play Do !right
[(?left TrimSilence, ?right TrimSilence )StereoMonitor]
"temp/reverba.wav" ReadFile ^revl ^revr

?left  !signal >revl !convol ?reverb Do Normalise !wleft
?right !signal >revr !convol ?reverb Do Normalise !wright

"temp/reverbb.wav" ReadFile ^revl ^revr

?left  !signal >revl !convol ?reverb Do Normalise !vwleft
?right !signal >revr !convol ?reverb Do Normalise !vwright

{
    (
        >wleft  pcnt+50,
        >vwleft pcnt+20,
        >left   pcnt+30
    )Mix Normalise
} Do !left

{
    (
        >wright  pcnt+50,
        >vwright pcnt+20,
        >right   pcnt+30,
    )Mix Normalise
}Do !right

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

Saturday 7 December 2013

Where Is Sonic Field

I have been remiss in not posting at all for months.

Sonic Field is live and kicking. I did not bother renewing the website for it as the traffic was so woefully light. However, the project lives and the source is backed up into Google's Drive system.

Progress over the last few months:

1) The memory manager is working very much better indeed now and I found a near perfect set of GC settings to that Sonic Field no longer swaps out data which is about to be garbage collected anyway. I guess it still does this a bit - but nothing like as much as it did.

2) Better memory management has caused me to be able to go back to double precision mathematics throughout.

3) 2 was very important for the next big improvement which is the addition of a FFT engine. Now, I promised to never put FFT in Sonic Field because so many of the effects produced in the frequency domain are so artificial sounding; the whole thing of FFT processing breaks the analogue synth' model of Sonic Field. However, there are some effects which are just impractical in the time domain; most important of these is convolution. I have a granular convolution reverb system running now and it brings Sonic Field's reverbs up to leaders in the field for the first time.

4) More music: Now I am working only one contract (I had a time working 2 and that was exhausting) I am putting more time into composing. I also indulged in rendering someone else's music. That is not something I normally like to do any more. In this case, I did it as a challenge to learn more about how to handle classical music in Sonic Field and how to render string sounds better. The result is on youtube: