Thursday 21 August 2014

Black Knight

An auto soundscape describing the Black Knight Satellite transmitting over the last 13 000 years.




Thursday 14 August 2014

Code Behind Cold

I am very found of this piece because it was the start of my work with granular reverberation for 'following' sounds. Also, I just love the effect. I heard something similar from the son's guitar pedal and just had to be able to do that myself!

import random
import math
sf.SetSampleRate(192000)

# Single threaded for debug
#def sf_do(toDo):
#   return toDo()

def granularReverb(signal,ratio,delay):
    def granularReverbInner():
        out=[]
        for grain in sf.Granulate(signal,50,10):
            (signal_i,at)=grain
            signal_i=sf.DirectRelength(signal_i,ratio-0.01+(0.02*random.random()))
            for x in range(0,50):
                out.append(
                    (
                        +signal_i,
                        at + (random.random()+random.random())*delay
                    )
                )
            -signal_i
        return sf.Normalise(sf.MixAt(out))
    return sf_do(granularReverbInner)

def reverbInner(signal,convol,grainLength):
    def reverbInnerDo():
        mag=sf.Magnitude(+signal)
        if mag>0:
            signal_=sf.Concatenate(signal,sf.Silence(grainLength))
            signal_=sf.FrequencyDomain(signal_)
            signal_=sf.CrossMultiply(convol,signal_)
            signal_=sf.TimeDomain(signal_)
            newMag=sf.Magnitude(+signal_)
            signal_=sf.NumericVolume(signal_,mag/newMag)        
            # tail out clicks due to amplitude at end of signal 
            return signal_
        else:
            -convol
            return signal
            
    return sf_do(reverbInnerDo)

def reverberate(signal,convol):
    def reverberateDo():
        grainLength = sf.Length(+convol)
        convol_=sf.FrequencyDomain(sf.Concatenate(convol,sf.Silence(grainLength)))
        signal_=sf.Concatenate(signal,sf.Silence(grainLength))
        out=[]
        for grain in sf.Granulate(signal_,grainLength):
            (signal_i,at)=grain
            out.append((reverbInner(signal_i,+convol_,grainLength),at))
        -convol_
        return sf.Realise(sf.Normalise(sf.MixAt(out)))
    return sf_do(reverberateDo)

# Get IRs
violinIRs = sf.ViolinBodyIRs(())
#violaIRs  = sf.ViolaBodyIRs(())
celloIRs  = sf.CelloBodyIRs(())
bassIRs   = sf.BassBodyIRs(())

def createSawTooth(length,pitch):
    signals=[]
    v=1
    opitch=pitch
    it=1.0
    phase=random.random()
    while pitch<18000:
        signals.append(sf.NumericVolume(sf.PhasedSineWave(length,pitch,phase),1.0/it))
        pitch+=opitch
        it+=1
    return sf.Clean(sf.FixSize(sf.Mix(signals)))

def rawString(length,pitch):
    def rawStringA(l,p):
        def rawStringAIn():
            return createSawTooth(l,p)
        return sf_do(rawStringAIn)
    pitch=float(pitch)
    #pitch=pitch+pitch*random.random()*0.0001
    s1=rawStringA(length,pitch)
    s2=rawStringA(length,pitch*2.0)
    s3=rawStringA(length,pitch*4.0)
    s4=sf.WhiteNoise(length)
    signal=sf.Normalise(
        sf.Mix(
            sf.Pcnt20(s4),
            sf.Pcnt50(s1),
            sf.Pcnt20(s2),
            sf.Pcnt10(s3)
        )
    )
    signal=sf.Clean(sf.ResonantFilter(signal,0.95,0.15,sf.Period(pitch)))
    multi=sf.Normalise(
        sf.DirectRelength(
            sf.ButterworthLowPass(sf.WhiteNoise(length/500.0),2500,6),
            0.001
        )
    )
    multi=sf.Cut(0,sf.Length(+signal),multi)
    signal=sf.Resample(
        sf.DirectMix(1,sf.NumericVolume(multi,0.001)),
        signal
    )
    return sf.Realise(sf.Normalise(sf.Clean(signal)))


def playStringClean(a,length,pitch,whiteAmount):
    def rsd():
        return rawString(length,pitch)
    
    signal=0
    if(pitch>500):
        signal=sf.Normalise(sf.Mix(sf_do(rsd),sf_do(rsd),sf_do(rsd)))
    else:
        signal=sf.Normalise(sf.Mix(sf_do(rsd),sf_do(rsd)))
    if(pitch>440):    
        signal=sf.ButterworthHighPass(signal,pitch*0.5,6)
        signal=sf.ButterworthHighPass(signal,2000,1)
        signal=sf.ButterworthLowPass(signal,8000,1)
    if(pitch<128):
        signal=sf.ButterworthHighPass(signal,pitch*0.5,1)
        signal=sf.ButterworthHighPass(signal,500,1)
        signal=sf.ButterworthLowPass(signal,2000,1)
    else:
        signal=sf.ButterworthHighPass(signal,pitch*0.5,3)
        signal=sf.ButterworthHighPass(signal,1500,1)
        signal=sf.ButterworthLowPass(signal,4000,1)

    signal=sf.ButterworthLowPass(signal,pitch*10.0,1)
    signal=sf.Mix(
        sf.Pcnt25(+signal),
        sf.Pcnt75(sf.RBJNotch(signal,pitch,0.5))
    )    
    white=sf.WhiteNoise(length)
    white=sf.ButterworthHighPass(white,pitch*2.0,2)
    white=sf.ButterworthLowPass(white,pitch*6.0,1)
    white=sf.Normalise(white)
    white=sf.Multiply(white,+signal)
    white=sf.NumericVolume(white,whiteAmount)
    signal=sf.NumericVolume(signal,1.0-whiteAmount)
    signal=sf.Normalise(sf.Mix(signal,white))

    sq=sf.Mix(
        sf.PhasedSineWave(length,pitch*0.95,random.random()),
        sf.PhasedSineWave(length,pitch*1.05,random.random())
    )
    envb=sf.NumericShape((0,0.25),(a,0),(length,0))
    sq=sf.Multiply(envb,sf.FixSize(sq))

    enva=sf.NumericShape((0,0.75),(a,1),(length,1))
    signal=sf.Multiply(enva,signal)

    signal=sf.Mix(sq,sf.FixSize(signal))
    sigs=[]
    bodies=[]
    if(pitch<128):
        bodies=bassIRs
    elif(pitch<440):
        bodies=celloIRs
    else:
        bodies=violinIRs
    
    for body in violinIRs:
        sigs.append(reverberate(+signal,+body))  
    -signal
    signal=sf.Normalise(sf.Mix(sigs))
    return signal

def playString(pitch,e,a,d,dat,s,sat,r,whiteAmount,vibStart,vibMiddle,vibAmount,vibRate=2.0):
    print ("Performing Note: ",pitch,e,a,d,dat,s,sat,r,whiteAmount,vibStart,vibMiddle,vibAmount,vibRate)
    def playStringInner():
        envA=sf.SimpleShape(
            (0,-60),
            (e,0),
            (d,0),
            (s,0),
            (r,0)
        )
        envB=sf.NumericShape(
            (0,0),
            (a,1),
            (d,dat),
            (s,sat),
            (r,0)
        )
        env=sf.Multiply(envA,envB)
        sigs=[]
        for x in range(0,5):
            sigs.append(playStringClean(a,r,pitch,whiteAmount))
        signal=sf.Normalise(sf.Mix(sigs))
        signal=sf.Multiply(signal,env)
        if(vibAmount>0):
            l=sf.Length(+signal)
            env=sf.NumericShape((0,0),(vibStart,0),(vibMiddle,1),(r,0.75),(l,0))
            env=sf.NumericVolume(env,vibAmount)
            trem=sf.SineWave(l,2.0+random.random())
            trem=sf.Multiply(env,trem)
            vib=+trem
            trem=sf.DirectMix(1,sf.Pcnt50(trem))
            signal=sf.Multiply(trem,signal)
            vib=sf.DirectMix(1,sf.NumericVolume(vib,0.01))
            signal=sf.Resample(vib,signal)
        
        if(pitch>128):
            signal=sf.ButterworthHighPass(signal,pitch*0.75,6)
            signal=sf.BesselLowPass(signal,pitch,1)
        else:
            signal=sf.ButterworthHighPass(signal,pitch*0.75,3)
            
        return sf.Realise(sf.Normalise(sf.Clean(signal)))
    return sf_do(playStringInner)

def playStringInitial(pitch,length,volume):
    def playStringInitialInner():
        sig=playString(
            pitch,
            64,                 # e
            128,                # a
            length*0.5,         # d
            0.75,               # d at
            length*0.75,        # s
            1.0,                # s at
            length,             # r
            0.75,               # white amount  
            length*0.75,        # vib start
            length*0.75,        # vib middle
            0.5                 # vib amount
        )
        envH=sf.NumericShape((0,1),(length*0.25,0.25),(length,0.25))
        envL=sf.NumericShape((0,0),(length*0.25,0.75),(length,0.75))
        sig=sig.get()
        sigLow=sf.ButterworthLowPass(+sig,pitch*2.0,2)
        sigHi =sf.ButterworthHighPass(sig ,pitch*2.0,2)
        sigLow=sf.Multiply(sigLow,envL)
        sigHi =sf.Multiply(sigHi ,envH)
        env   =sf.NumericShape((0,0),(length*0.25,0.25),(length*0.5,1),(length,1))
        sig   =sf.Mix(sigLow,sigHi)
        sig   =sf.FixSize(sf.Multiply(env,sig))
        return sf.Clean(sf.NumericVolume(sig,volume))
    return sf_do(playStringInitialInner)
    
def playStringSuperSoft(pitch,length,volume):
    def playStringSoftSuperInner():
        if(pitch<256):
            w=0.75
        else:
            if(pitch<720):
                w=0.33
            else:
                w=0.25
        sig = sf.NumericVolume(
            playString(
                pitch,
                64,                 # e
                length*0.25,        # a
                length*0.50,        # d
                1.0,                # d at
                length*0.75,        # s
                1.0,                # s at
                length,             # r
                w,                  # white amount  
                length*0.50,        # vib start
                length*0.75,        # vib middle
                0.5                 # vib amount
            ),
            volume
        )
        env   = sf.NumericShape((0,0),(length*0.25,1),(length,1))
        return sf.Clean(sf.FixSize(sf.Multiply(env,sig)))
    return sf_do(playStringSoftSuperInner)

def playStringSoftShort(pitch,length,volume):
    def playStringSoftShortInner():
        if(pitch<256):
            w=0.5
        else:
            if(pitch<720):
                w=0.25
            else:
                w=0.15
        return sf.Clean(sf.NumericVolume(
            playString(
                pitch,
                32,                 # e
                64,                 # a
                length*0.15,        # d
                1.0,                # d at
                length*0.5,         # s
                0.5,                # s at
                length,             # r
                w,                  # white amount  
                length*0.50,        # vib start
                length*0.75,        # vib middle
                0.5                 # vib amount
            ),
            volume
        ))
    return sf_do(playStringSoftShortInner)

def playStringHardLong(pitch,length,volume):
    def playStringHardLong():
        if(pitch<256):
            w=0.1
        else:
            if(pitch<720):
                w=0.1
            else:
                w=0.05
        return sf.Clean(sf.NumericVolume(
            playString(
                pitch,
                32,                 # e
                64,                 # a
                length*0.25,        # d
                1.0,                # d at
                length*0.75,        # s
                0.75,               # s at
                length,             # r
                w,                  # white amount  
                length*0.25,        # vib start
                length*0.75,        # vib middle
                0.5                 # vib amount - no vib in this case
            ),
            volume
        ))
    return sf_do(playStringHardLong)

def playStringHardShort(pitch,length,volume):
    def playStringHardShortInner():
        if(pitch<256):
            w=0.1
        else:
            if(pitch<720):
                w=0.1
            else:
                w=0.05
        return sf.Clean(sf.NumericVolume(
            playString(
                pitch,
                32,                 # e
                64,                 # a
                length*0.125,       # d
                1.0,                # d at
                length*0.75,         # s
                0.75,               # s at
                length,             # r
                w,                  # white amount  
                length*0.25,        # vib start
                length*0.75,        # vib middle
                0                   # vib amount - no vib in this case
            ),
            volume
        ))
    return sf_do(playStringHardShortInner)

def playStringPluck(pitch,length,volume):
    def playStringPluckInner():
        sig=playString(
                pitch,
                8,                  # e
                16,                 # a
                32,                 # d
                0.5,                # d at
                length*0.75,        # s
                0.25,               # s at
                length,             # r
                0,                  # white amount  
                length*0.50,        # vib start
                length*0.90,        # vib middle
                1                   # vib amount - no vib in this case
            )
        envH=sf.NumericShape((0,0),(32,1),(length,0))
        envL=sf.NumericShape((0,1),(32,0),(length,1))
        sig=sig.get()
        sigL=sf.ButterworthLowPass(+sig,pitch,1)
        sigL=sf.ButterworthLowPass(sigL,pitch*3,1)
        sigH=sf.Multiply(sig,envH)
        sigL=sf.Multiply(sigL,envL)
        sig=sf.Mix(sigL,sigH)
        sig=sf.NumericVolume(sig,volume)
        return sig
        
    return sf_do(playStringPluckInner)

def makeClick(formant):
    clickA=sf.Multiply(
        sf.SimpleShape((0,0),(500,-30),(512,-60)),
        sf.NumericShape((0,0),(100,1),(-300,-1),(400,0)),
        sf.FixSize(sf.Power(sf.WhiteNoise(512),8))
    )
    clickA=sf.BesselLowPass(clickA,440,1)
    clickA=formant(clickA)

    for i in range(0,4):
        clickB=sf.BesselLowPass(+clickA,440,1)
        clickB=formant(clickB)
        clickA=sf.MixAt(
            (clickA,0),
            (clickB,beat/8)
        )
    return sf.Normalise(clickA)

def doFormant(sig,f1,f2,f3):
    def doFormantInner(a,b,c,d):
        def doFII():
            return sf.RBJPeaking(a,b,c,d)
        return sf_do(doFII)
    sig1=doFormantInner(+sig,f1,1,40)
    sig2=doFormantInner(+sig,f2,2,20)
    sig3=doFormantInner( sig,f3,1,40)
    x=sf.Mix(sig1,sig2,sig3)
    x=sf.Normalise(x)
    return sf.Realise(x)

#beat
def doFormant1(sig):
    return doFormant(sig,300,2800,3300)

#bit
def doFormant2(sig):
    return doFormant(sig,430,2500,3100)

#bet
def doFormant3(sig):
    return doFormant(sig,600,2350,3000)

#bat
def doFormant4(sig):
    return doFormant(sig,860,2050,2850)

#part
def doFormant5(sig):
    return doFormant(sig,850,1200,2800)

#pot 
def doFormant6(sig):
    return doFormant(sig,590,900,2700)

#boat
def doFormant7(sig):
    return doFormant(sig,470,1150,2700)

#boat
def doFormant8(sig):
    return doFormant(sig,470,1150,2700)

#book
def doFormant9(sig):
    return doFormant(sig,370,950,2650)

#but
def doFormant10(sig):
    return doFormant(sig,760,1400,2800)

#pert
def doFormant11(sig):
    return doFormant(sig,500,1650,1950)

# oddness
#pert
def doFormant12(sig):
    return doFormant(sig,550,1800,2050)

formants=[
    doFormant1,
    doFormant2,
    doFormant3,
    doFormant4,
    doFormant5,
    doFormant6,
    doFormant7,
    doFormant8,
    doFormant9,
    doFormant10,
    doFormant11,
    doFormant12
]

# Very slow indeed
beat = 1024*2.0

def phrase1():
    print "Phrase 1"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("G6")
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 1
    at+=beat*1
    pitch=sf.Note("G6")
    pitch+=10
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 2
    at+=beat*1
    pitch=sf.Note("G6")
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    at+=beat*0.5
    pitch=sf.Note("G6")
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 3
    at+=beat*0.5
    pitch=sf.Note("G6")
    length=beat*0.2
    sigl.append((playStringPluck(pitch,length,0.25),at))
    sigr.append((playStringPluck(pitch,length,0.75),at))

    at+=beat*0.25
    pitch=sf.Note("G6")
    pitch+=10
    length=beat*0.15
    sigl.append((playStringPluck(pitch,length,0.75),at))
    sigr.append((playStringPluck(pitch,length,0.25),at))

    # 4
    at+=beat*0.75
    pitch=sf.Note("G6")
    length=beat*2.0
    sigl.append((playStringSoftShort(pitch,length,0.15),at))
    sigr.append((playStringSoftShort(pitch,length,0.15),at))
    
    pitch=sf.Note("G7")
    length=beat*0.15
    pitch*=1.01
    sigl.append((playStringPluck(pitch,length,0.05),at))
    pitch=sf.Note("G7")
    pitch*=0.99
    sigr.append((playStringPluck(pitch,length,0.05),at))
       
    print "Compiling Phrase1"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))

    wleft  = granularReverb(+left,0.5,1000)
    wright = granularReverb(+right,0.5,1000)
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt50(wleft),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt50(wright),0),
        (sf.Pcnt50(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-1.wav")

def phrase2():
    print "Phrase 2"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("G6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 1
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 2
    at+=beat*1
    pitch=sf.Note("G6")
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    at+=beat*0.5
    pitch=sf.Note("G6")
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 3
    at+=beat*0.5
    pitch=sf.Note("G6")
    pitch+=10
    length=beat*0.2
    sigl.append((playStringPluck(pitch,length,0.75),at))
    sigr.append((playStringPluck(pitch,length,0.25),at))

    at+=beat*0.25
    pitch=sf.Note("G6")
    length=beat*0.15
    sigl.append((playStringPluck(pitch,length,0.25),at))
    sigr.append((playStringPluck(pitch,length,0.75),at))

    # 4
    at+=beat*0.75
    pitch=sf.Note("F6")
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
       
    print "Compiling Phrase2"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))

    wleft  = granularReverb(+left,0.5,1000)
    wright = granularReverb(+right,0.5,1000)
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt50(wleft),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt50(wright),0),
        (sf.Pcnt50(right),0)
    ))    
    
    sf.WriteFile32([left,right],"temp/phrase-2.wav")

def phrase3():
    print "Phrase 3"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("F6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 1
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 2
    at+=beat*1
    pitch=sf.Note("F6")
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    at+=beat*0.5
    pitch=sf.Note("F6")
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 3
    at+=beat*0.5
    pitch=sf.Note("F6")
    pitch+=10
    length=beat*0.2
    sigl.append((playStringPluck(pitch,length,0.75),at))
    sigr.append((playStringPluck(pitch,length,0.25),at))

    at+=beat*0.25
    pitch=sf.Note("G6")
    length=beat*0.15
    sigl.append((playStringPluck(pitch,length,0.25),at))
    sigr.append((playStringPluck(pitch,length,0.75),at))

    # 4
    at+=beat*0.75
    pitch=sf.Note("A6")
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
       
    print "Compiling Phrase3"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft  = granularReverb(+left,0.5,1000)
    wright = granularReverb(+right,0.5,1000)
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt50(wleft),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt50(wright),0),
        (sf.Pcnt50(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-3.wav")

def phrase4():
    print "Phrase 4"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("A6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
    
    # 1
    at+=beat*1
    pitch=sf.Note("B6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
           
    # 2
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 3
    at+=beat*1
    pitch=sf.Note("A6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 4
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 5
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    print "Compiling Phrase4"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,1000)
    wright1 = granularReverb(+right,0.5,1000)
    wleft2  = granularReverb(+left,0.75,1200)
    wright2 = granularReverb(+right,0.75,1200)
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt40(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt30(wright2),0),
        (sf.Pcnt50(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-4.wav")

def phrase5():
    print "Phrase 5"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("G0")
    pitch+=10
    length=beat*3
    sigl.append((playStringSuperSoft(pitch,length,0.5),at))
    sigr.append((playStringSuperSoft(pitch,length,0.5),at))
    
    # 1
    at+=beat*3
    pitch=sf.Note("D1")
    sigl.append((playStringSuperSoft(pitch,length,0.5),at))
    sigr.append((playStringSuperSoft(pitch,length,0.5),at))

    print "Compiling Phrase4"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left, 0.5,1000)
    wright1 = granularReverb(+right,0.5,1000)
    wleft2  = granularReverb(+left, 1.5,1200)
    wright2 = granularReverb(+right,1.5,1200)

    #6 -> #3 : boat to bat
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt40(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt30(wright2),0),
        (sf.Pcnt50(right),0)
    ))
    
    def doBoatBat(sig):
        l=sf.Length(+sig)
        envBoat=sf.NumericShape((0,1),(l,0))
        sigBoat=sf.Multiply(envBoat,+sig)
        sigBoat=doFormant6(+sig)  
        envBat  =sf.NumericShape((0,0),(l,1))
        sigBat =sf.Multiply(envBat,+sig)
        sigBat =doFormant3(sig)  
        sig    =sf.Mix(sigBat,sigBoat)
        return sf.Normalise(sf.ButterworthLowPass(sig,256,1))
    
    left = doBoatBat(left)    
    right= doBoatBat(right)
            
    sf.WriteFile32([left,right],"temp/phrase-5.wav")

def phrase6():
    print "Phrase 6"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("A6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    # 1
    at+=beat*1
    pitch=sf.Note("B6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
           
    # 2
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    # 3
    at+=beat*1
    pitch=sf.Note("A6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 4
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    # 5
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 6
    at+=beat*1
    pitch=sf.Note("D6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))


    print "Compiling Phrase6"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,800)
    wright1 = granularReverb(+right,0.5,8000)
    wleft2  = granularReverb(+left,0.25,1500)
    wright2 = granularReverb(+right,0.25,1500)
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt40(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt30(wright2),0),
        (sf.Pcnt50(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-6.wav")

def phrase7():
    print "Phrase 7"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("A6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 1
    at+=beat*1
    pitch=sf.Note("B6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
           
    # 2
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 3
    at+=beat*1
    pitch=sf.Note("A6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 4
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 5
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 6
    at+=beat*1
    pitch=sf.Note("D6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    print "Compiling Phrase7"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,800)
    wright1 = granularReverb(+right,0.5,800)
    wleft2  = granularReverb(+left,0.25,1500)
    wright2 = granularReverb(+right,0.25,1500)
        
    r=0.5*6.0/5.0    
    wleft3  = granularReverb(+left ,r,1000)
    wright3 = granularReverb(+right,r,1000)
    
    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt30(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt10(wleft3),0),
        (sf.Pcnt50(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt20(wright2),0),
        (sf.Pcnt20(wright3),0),
        (sf.Pcnt40(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-7.wav")

def phrase8():
    print "Phrase 8"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("G6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 1
    at+=beat*1
    pitch=sf.Note("A6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
           
    # 2
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 3
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 4
    at+=beat*1
    pitch=sf.Note("E6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 5
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 6
    at+=beat*1
    pitch=sf.Note("C6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    print "Compiling Phrase8"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,800)
    wright1 = granularReverb(+right,0.5,800)
    wleft2  = granularReverb(+left,0.25,1500)
    wright2 = granularReverb(+right,0.25,1500)
        
    r=0.5*6.0/5.0    
    wleft3  = granularReverb(+left ,r,1000)
    wright3 = granularReverb(+right,r,1000)
    
    wleft4  = granularReverb(+left,1.5,2000)
    wright4 = granularReverb(+right,1.5,2000)

    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt30(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt10(wleft3),0),
        (sf.Pcnt5(wleft4),0) ,
        (sf.Pcnt45(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt20(wright2),0),
        (sf.Pcnt20(wright3),0),
        (sf.Pcnt5(wright4),0) ,
        (sf.Pcnt35(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-8.wav")

def phrase9():
    print "Phrase 9"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("F6")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 1
    at+=beat*1
    pitch=sf.Note("G6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
           
    # 2
    at+=beat*1
    pitch=sf.Note("E6b")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 3
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 4
    at+=beat*1
    pitch=sf.Note("D6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 5
    at+=beat*1
    pitch=sf.Note("E6b")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 6
    at+=beat*1
    pitch=sf.Note("B5b")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    print "Compiling Phrase9"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,800)
    wright1 = granularReverb(+right,0.5,800)
    wleft2  = granularReverb(+left,0.25,1500)
    wright2 = granularReverb(+right,0.25,1500)
        
    r=0.5*6.0/5.0    
    wleft3  = granularReverb(+left ,r,1000)
    wright3 = granularReverb(+right,r,1000)
    
    wleft4  = granularReverb(+left,1.5,2000)
    wright4 = granularReverb(+right,1.5,2000)

    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt30(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt10(wleft3),0),
        (sf.Pcnt5(wleft4),0) ,
        (sf.Pcnt45(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt20(wright2),0),
        (sf.Pcnt20(wright3),0),
        (sf.Pcnt5(wright4),0) ,
        (sf.Pcnt35(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-9.wav")

def phrase10():
    print "Phrase 10"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("E6b")
    pitch+=10
    length=beat*0.5
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 1
    at+=beat*1
    pitch=sf.Note("F6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))
           
    # 2
    at+=beat*1
    pitch=sf.Note("D6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 3
    at+=beat*1
    pitch=sf.Note("E6b")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 4
    at+=beat*1
    pitch=sf.Note("C6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    # 5
    at+=beat*1
    pitch=sf.Note("D6")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    # 6
    at+=beat*1
    pitch=sf.Note("A5")
    sigl.append((playStringPluck(pitch,length,0.5),at))
    sigr.append((playStringPluck(pitch,length,0.5),at))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.25))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.25))

    pitch*=2
    length=beat*0.25
    sigl.append((playStringPluck(pitch,length,0.15),at+beat*0.50))
    sigr.append((playStringPluck(pitch,length,0.15),at+beat*0.50))

    print "Compiling Phrase10"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,800)
    wright1 = granularReverb(+right,0.5,800)
    wleft2  = granularReverb(+left,0.25,1500)
    wright2 = granularReverb(+right,0.25,1500)
        
    r=0.5*6.0/5.0    
    wleft3  = granularReverb(+left ,r,1000)
    wright3 = granularReverb(+right,r,1000)
    
    wleft4  = granularReverb(+left,1.5,2000)
    wright4 = granularReverb(+right,1.5,2000)

    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt30(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt10(wleft3),0),
        (sf.Pcnt5(wleft4),0) ,
        (sf.Pcnt45(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt20(wright1),0),
        (sf.Pcnt20(wright2),0),
        (sf.Pcnt20(wright3),0),
        (sf.Pcnt5(wright4),0) ,
        (sf.Pcnt35(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-10.wav")

def phrase11():
    print "Phrase 11"
    at   = 0
    sigl = []
    sigr = []

    pitch=sf.Note("G6")
    pitch+=10
    length=beat*4.0
    sigl.append((playStringSuperSoft(pitch,length,0.5),at))
    sigr.append((playStringSuperSoft(pitch,length,0.5),at))

    print "Compiling Phrase11"
    left=sf.FixSize(sf.MixAt(sigl))
    right=sf.FixSize(sf.MixAt(sigr))
    
    wleft1  = granularReverb(+left,0.5,800)
    wright1 = granularReverb(+right,0.5,800)
    wleft2  = granularReverb(+left,0.25,2400)
    wright2 = granularReverb(+right,0.25,2400)
        
    r=0.5*6.0/5.0    
    wleft3  = granularReverb(+left ,r,1600)
    wright3 = granularReverb(+right,r,1600)
    
    wleft4  = granularReverb(+left,0.125,3200)
    wright4 = granularReverb(+right,0.125,3200)

    wleft5  = granularReverb(+left,0.0625,3800)
    wright5 = granularReverb(+right,0.0625,3800)

    wleft5  = granularReverb(wleft5,1.0,3800)
    wright5 = granularReverb(wright5,1.0,3800)

    left=sf.Normalise(sf.MixAt(
        (sf.Pcnt10(wleft1),0),
        (sf.Pcnt10(wleft2),0),
        (sf.Pcnt10(wleft3),0),
        (sf.Pcnt20(wleft4),0) ,
        (sf.Pcnt20(wleft5),0) ,
        (sf.Pcnt30(left),0)
    ))
    
    right=sf.Normalise(sf.MixAt(
        (sf.Pcnt10(wright1),0),
        (sf.Pcnt10(wright2),0),
        (sf.Pcnt10(wright3),0),
        (sf.Pcnt20(wright4),0) ,
        (sf.Pcnt20(wright5),0) ,
        (sf.Pcnt30(right),0)
    ))
        
    sf.WriteFile32([left,right],"temp/phrase-11.wav")

#phrase1()
#phrase2()
#phrase3()
#phrase4()
#phrase5()
#phrase6()
#phrase7()
#phrase8()
#phrase9()
#phrase10()
phrase11()


(left1,right1)=sf.ReadFile("temp/phrase-1.wav")
left1  = sf.Swap(left1)
right1 = sf.Swap(right1)

(left2,right2)=sf.ReadFile("temp/phrase-2.wav")
left2  = sf.Swap(left2)
right2 = sf.Swap(right2)

(left3,right3)=sf.ReadFile("temp/phrase-3.wav")
left3  = sf.Swap(left3)
right3 = sf.Swap(right3)

(left4,right4)=sf.ReadFile("temp/phrase-4.wav")
left4  = sf.Swap(left4)
right4 = sf.Swap(right4)

(left5,right5)=sf.ReadFile("temp/phrase-5.wav")
left5  = sf.Swap(left5)
right5 = sf.Swap(right5)

(left6,right6)=sf.ReadFile("temp/phrase-6.wav")
left6  = sf.Swap(left6)
right6 = sf.Swap(right6)

(left7,right7)=sf.ReadFile("temp/phrase-7.wav")
left7  = sf.Swap(left7)
right7 = sf.Swap(right7)

(left8,right8)=sf.ReadFile("temp/phrase-8.wav")
left8  = sf.Swap(left8)
right8 = sf.Swap(right8)

(left9,right9)=sf.ReadFile("temp/phrase-9.wav")
left9  = sf.Swap(left9)
right9 = sf.Swap(right9)

(left10,right10)=sf.ReadFile("temp/phrase-10.wav")
left10  = sf.Swap(left10)
right10 = sf.Swap(right10)

(left11,right11)=sf.ReadFile("temp/phrase-11.wav")
left11  = sf.Swap(left11)
right11 = sf.Swap(right11)

left = sf.FixSize(
    sf.MixAt(
        ( sf.Pcnt50( left1),1000),
        
        ( sf.Pcnt50(+left2),1000+beat*6),
        
        ( sf.Pcnt50( left3),1000+beat*12),        

        ( sf.Pcnt50(+left4),1000+beat*18),
               
        ( sf.Pcnt50( left2),1000+beat*24),

        ( sf.Pcnt40(+left5),1000+beat*29),
        ( sf.Pcnt20( left4),1000+beat*30),
        
        ( sf.Pcnt20(+left6),1000+beat*36),
        ( sf.Pcnt40(+left5),1000+beat*35),

        ( sf.Pcnt40(+left7),1000+beat*42), # 8 time
        ( sf.Pcnt20(+left5),1000+beat*41),

        ( sf.Pcnt20(+left8),1000+beat*50),
        ( sf.Pcnt40(+left5),1000+beat*49),

        ( sf.Pcnt40(+left9),1000+beat*58),
        ( sf.Pcnt20(+left5),1000+beat*57),

        ( sf.Pcnt20(+left10),1000+beat*66),
        ( sf.Pcnt40(+left5) ,1000+beat*65),

        ( sf.Pcnt40( left7),1000+beat*74), 
        ( sf.Pcnt20(+left5),1000+beat*73),

        ( sf.Pcnt20( left8),1000+beat*82),
        ( sf.Pcnt40(+left5),1000+beat*81),

        ( sf.Pcnt40( left9),1000+beat*90),
        ( sf.Pcnt20(+left5),1000+beat*89),

        ( sf.Pcnt20( left10),1000+beat*98),
        ( sf.Pcnt40( left5) ,1000+beat*97),

        ( sf.Pcnt50( left11),1000+beat*106)

    )
)

right = sf.FixSize(
    sf.MixAt(
        ( sf.Pcnt50( right1),1000),
        
        ( sf.Pcnt50(+right2),1000+beat*6),

        ( sf.Pcnt50( right3),1000+beat*12),

        ( sf.Pcnt50(+right4),1000+beat*18),

        ( sf.Pcnt50( right2),1000+beat*24),
        
        ( sf.Pcnt20(+right4),1000+beat*30),
        ( sf.Pcnt40(+right5),1000+beat*29),
        
        ( sf.Pcnt40( right6),1000+beat*36),
        ( sf.Pcnt20(+right5),1000+beat*35),
        
        ( sf.Pcnt20(+right7),1000+beat*42), # 8 time
        ( sf.Pcnt40(+right5),1000+beat*41),
        
        ( sf.Pcnt40(+right8),1000+beat*50),
        ( sf.Pcnt20(+right5),1000+beat*49),
        
        ( sf.Pcnt20(+right9),1000+beat*58),
        ( sf.Pcnt40(+right5),1000+beat*57),

        ( sf.Pcnt40(+right10),1000+beat*66),
        ( sf.Pcnt20(+right5) ,1000+beat*65),
        
        ( sf.Pcnt20( right7),1000+beat*74),
        ( sf.Pcnt40(+right5),1000+beat*73),
        
        ( sf.Pcnt40( right8),1000+beat*82),
        ( sf.Pcnt20(+right5),1000+beat*81),
        
        ( sf.Pcnt20( right9),1000+beat*90),
        ( sf.Pcnt40(+right5),1000+beat*89),

        ( sf.Pcnt40( right10),1000+beat*98),
        ( sf.Pcnt20( right5) ,1000+beat*97),

        ( sf.Pcnt50( right11),1000+beat*106)
    )
)

sf.WriteFile32((+left,+right),"temp/temp.wav")

(convoll,convolr)=sf.ReadFile("temp/revb2.wav")

def procConvol(convol):
    env=sf.SimpleShape((0,0),(2048,0),(sf.Length(+convol),-40))
    convolH=sf.FixSize(sf.BesselHighPass(sf.Saturate(+convol),5000,6))
    convolL=sf.FixSize(sf.Multiply(env,convol))
    return sf.FixSize(sf.Mix(convolH,convolL))

convoll=procConvol(convoll)
convolr=procConvol(convolr)

wleft =reverberate(+left,convoll)
wright=reverberate(+right,convolr)

left_out=sf.Normalise(sf.MixAt(
    (sf.Pcnt50(wleft),0),
    (sf.Pcnt50(left),00)
))

right_out=sf.Normalise(sf.MixAt(
    (sf.Pcnt50(wright),0),
    (sf.Pcnt50(right),0)
))

sf.WriteFile32((left_out,right_out),"temp/temp_postb.wav")

Ethereal Reflections

Reverberation Like Effects With Enveloped White Noise 

About half way through The Chase there is a pause where the sound goes very much more quiet and distant. This was a pure 'I wonder if that will work' moment for me. The effect was done not by a change in synthesis parameters, or adding an effect in the traditional sense - it the sound is nothing but an effect. It was done using impulse response reverberation using an white noise envelope.

convoll=sf.Multiply(sf.WhiteNoise(beat*4.0),sf.NumericShape((0,0),(beat*0.5,1),(beat,0.1),(beat*4,0)))
convolr=sf.Multiply(sf.WhiteNoise(beat*4.0),sf.NumericShape((0,0),(beat*0.5,1),(beat,0.1),(beat*4,0)))
left13 =reverberate(+left12,convoll)
right13=reverberate(+right12,convolr)

The Chase:
Normally we think of capturing an impulse response. We do this from recording in a space (an abandoned factory for instance) or from the output of a classic reverberation unit. How about designing one from scratch to produce exactly the effect we want?

I have continued with these ideas. Maybe the most extreme example is the use of 'diamond shaped' white noise signals in convolution for the stretch effect in Invasion:

rLen=20480
ns=sf.NumericShape((0,0),(rLen/2,1),(rLen,0))
convoll=sf.Multiply(+ns,sf.WhiteNoise(rLen))
convolr=sf.Multiply( ns,sf.WhiteNoise(rLen))

wleft =reverberate(left,convoll)
wright=reverberate(right,convolr)

Invasion:

Audio Stretching Explaned

Picture out a train window
Sounds experienced at a different speed

What is stretching?

Take a sound, any sound, say a song, sound concrete or just voice and stretch it out. I guess you can think of playing a 78rpm record at 33 a sort of stretch but that is not what people mean. The key idea to stretching is to uncouple pitch and time so pitch stays constant but time dilates. What took one minute might take ten.

Why might we want to stretch?

There are many reasons. I guess the most common is to convert a short sound segment into an ambient background. There are issues with this though (like repeating artefacts). Another is to create completely new effects, for example to make ultra-long impulse responses.

What Methods can be employed to perform stretches?

Well, there three ( but actually, two of them end up the same ). The most obvious is using a segmenting approach. We can chop sound up into little segments of say 100 milliseconds. If we double up each one we get a 2:1 stretch. The hope is that the 10Hz introduced by the 100milisecond segments will not be noticed. The truth is that such a naive approach makes a sound a lot like shouting through a fan. Basically, it does not work well enough for anything but Dr Who style sound effects.

The second approach is to use the Fourier Transform to separate time and pitch. The human ear is insensitive to frequencies below 32Hz other than as pressure waves (we feel pressure on our ear drums but not actual pitch). So we can take a piece of music and window an FT across it. This is a bit like the segments, we take a lot of little pieces of the sound and transform them into just pitch and phase Information. Then we can 'randomise the phase'. This means that the variation in the position of each frequency within the sample is removed and converted to something random. We can then regenerate a longer segment with the same pitch information as the original but the different phases. This gets rid of the fan effect but has other issues. It is pretty powerful though. It is this approach which Paul Stretch uses.

The third approach is again to use little segments or grains (pretty much the same thing though grains are a concept which is more applicable to granular synthesis) but convolve them with white noise. This has a mathematically similar effect to the random phase thing although it also adds more randomness to the pitch magnitudes over time. Nevertheless, guess what, convolution is usually done in frequency space, i.e. After a Fourier Transform, so actually convolution with white noise ends up pretty much the same maths as randomising phases.

People might talk about converting between sound and pictures and stuff like that. But in reality, that is just a visually appealing form of FT based stretching for people who like pretty colours.

Invasion uses a subtly different stretch approach, how does that work?

Well, it is only an evolution of two of the existing approaches. Actually, it started with Sea Of Sound, Hadean Scream was 90% there but Invasion nailed it. The key idea is to employ both convolution with white noise and granular stretching (segment based but using granular concepts). But, more than that, it uses a dispersion approach to the granular stretch. I think it is the dispersion which makes it powerful and interesting.

What I mean by dispersion is best demonstrated by listening to 'Cold'. Here I take grains of the sound and duplicate them, making hundreds of copies of the grain. Then I mix them back together but at randomised times. In Cold they follow the original sound, the grains are delayed and randomised. As there are so many of them they form a cloud of sound which swells and fills in the gaps around it. By pitch shifting the grains ( simple resampling ) I got the effect of a huge number of instruments followng on from the lead at different pitches.

It occurred to me that if I were to space out the grains and get rid of the originals, then the random,grains would rise and swell to form a new, stretched sound. Hadean screen does exactly this. The approach gets rid of one issue with Paul Stretch which really frustrates me. The issue is that some low frequency artefacts end up repeated in the output at a regular pace producing annoying effects. The attack of a piano key or the vibrato of a singer can make a very annoying repeating pattern in the output of a phase randomised stretch. The time dispersed granular approach breaks up these patterns.

In Hadean Scream I used normal impulse response reverberation to smooth out the final product; that works nicely, but is not all that ambient. If you listen to some of Eno's ambient work you can quickly tell that a key idea is soft attack. Sounds slowly appear out of he background. How to create very slow, soft attacks? Normal impulse response reverberation is not going to do it because the pulse has a sharp attack which brings out the attacks in the processed sound.

My idea (which panned out) was to make diamond shape 'super grains' of white noise. In Invasion these are 20 seconds long. They linearly grown from zero to a peak magnitude at 10 seconds and the linearly die away to nothing at 20. Using these as the impulse response for the reverberator performs that 'convolution with white noise' stretch approach but with the super soft attack and decay.

Can this approach be taken further?

Well, yes. Indead, even in Invasion and Hadean Scream I used pitch shifting as well as stretch. This means we can produce harmonised ambience from stretched sound. However, so far the stretch amount and pitch shift amounts are all fixed. I would like to make them dynamic; eventually I would like them to change in response to the sound being stretched to produce a more organic, living sound.

Can other people try out your ideas?

Yes, naturally, Sonic Field is open source. Just contact me and I will be glad to help.

 

 

Sunday 10 August 2014

Really Simple Reverb' Script

This takes an impulse response wav (in this example I was using one called spring.wav) and and input.wav and it produces output.wav

This patch is part of my latest push to github.

def reverbInner(signal,convol,grainLength):
    def reverbInnerDo():
        mag=sf.Magnitude(+signal)
        if mag>0:
            signal_=sf.Concatenate(signal,sf.Silence(grainLength))
            signal_=sf.FrequencyDomain(signal_)
            signal_=sf.CrossMultiply(convol,signal_)
            signal_=sf.TimeDomain(signal_)
            newMag=sf.Magnitude(+signal_)
            signal_=sf.NumericVolume(signal_,mag/newMag)        
            # tail out clicks due to amplitude at end of signal 
            return signal_
        else:
            -convol
            return signal
            
    return sf_do(reverbInnerDo)

def reverberate(signal,convol):
    grainLength = sf.Length(+convol)
    convol_=sf.FrequencyDomain(sf.Concatenate(convol,sf.Silence(grainLength)))
    signal_=sf.Concatenate(signal,sf.Silence(grainLength))
    out=[]
    for grain in sf.Granulate(signal_,grainLength):
        (signal_i,at)=grain
        out.append((reverbInner(signal_i,+convol_,grainLength),at))
    -convol_
    return sf.Clean(sf.Normalise(sf.MixAt(out)))

    
(left,right)=sf.ReadFile("temp/input.wav")
(convoll,convolr)=sf.ReadFile("temp/spring.wav")

wleft =reverberate(+left,convoll)
wright=reverberate(+right,convolr)

left=sf.Normalise(sf.MixAt(
    (sf.Pcnt30(wleft),0),
    (sf.Pcnt70(left),00)
))

right=sf.Normalise(sf.MixAt(
    (sf.Pcnt30(wright),0),
    (sf.Pcnt70(right),0)
))


sf.WriteFile32((left,right),"temp/output.wav")