Showing posts with label full patch. Show all posts
Showing posts with label full patch. Show all posts

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")

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")

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.

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