Monday, May 19, 2014

23. Phase Modulation Example


A Phase Modulation example is presented.




Instead of using the function that was named add() in our csound module, it will be renamed as addTag(), to make its meaning clear. Further, there are checks to see if the first and last character are the angle brackets.


# moduleCsound.py

from os import system
from time import sleep

L = []

startSyn,stopSyn='<CsoundSynthesizer>','</CsoundSynthesizer>'
startOpt,stopOpt='<CsOptions>','</CsOptions>'
startIns,stopIns='<CsInstruments>','</CsInstruments>'
startSco,stopSco='<CsScore>','</CsScore>'

def addTag(*b):
    """
    Adding Tag terms to csd file
    """
    for s in b:
        if s[0]!='<' or s[-1]!='>':
            raise Exception("AddTag only adds Tags")
    L.extend(b)
    return

def rem(remark):
    """
    Generates one line of comment
    """
    L.append('; %s' % remark)

def header(sr=44100,ksmps=10,nch=1,amp=1):
    """
    Generates 4 headers in the orchesta section
    """
    L.append('sr = %d' % sr)
    L.append('ksmps = %d' % ksmps)
    L.append('nchnls = %d' % nch)
    L.append('0dbfs = %d' % amp)
    return

def instrument(rem,instr,S):
    """
    Generates instrument code given a String
    in the orchestra section
    """
    tL = S.split('\n')
    if tL[0]!='' or tL[-1]!='' : raise Exception("Instr Str")
    tL = [' '*2 + tl for tl in tL]
    tL[0] = 'instr %d' % instr # (3)
    tL[-1] = 'endin'
    if rem!='': L.append('; ' + rem)
    L.extend(tL)
    return

def table(rem,tabNum,tabTime,tabSize,tabGEN,*tab):
    """
    Generates f line inside score section
    """
    tup = (tabNum,tabTime,tabSize,tabGEN)
    String = 'f %s %s %s %s' % tup
    LString1=[' ' + str(i) for i in tab]
    String1 = "".join(LString1)
    if rem!='': L.append('; ' + rem)
    L.append(String+String1)
    return

def score(instr,start,dur,*p):
    """
    Generates i line inside score section
    """
    String = 'i %s %s %s' % (instr,start,dur)
    LString1=[' ' + str(pf) for pf in p]
    String1 = "".join(LString1)
    L.append(String+String1)
    return
    
def writeRun(fname):
    """
    Write out the csd file and perform it
    """
    OutL=[Lu + '\n' for Lu in L]
    out = open('%s.csd' % fname,'w')
    out.writelines(OutL)
    out.close()
    sleep(1)
    cmd = 'csound -o %s.wav %s.csd' % (fname,fname)
    status=system(cmd)
    if status!=0: raise Exception ('Could not write wav file')
    return



This equation shows what we are trying to do. In the csound program we have to prefix each variable with the letter a to indicate that it is an audio rate variable. First y3 is found as the output of an oscil with a frequency of f3. Then y2p is found, as a sum of phasor, of frequency f2, and the signal y3. The variable y2p, is a phase term. Using the table opcode, y2p, is decoded, to y2. Finally yp is found, which is the sum of a phasor of frequency f1, and the signal y2. Finally we decode the yp with the table opcode to get the y output.




These steps are indicated in this Instrument String Template. There are 3 placeholders representing f3, f2 and f1. We have fixed the values of A, and B. After getting y, two envelopes are created for the left and right channels. There is a fast attack, and then the signal slowly decays, with fade-out, at the end.




The ten instruments are created such that f3 equals 5 Hz, f2 equals 20 Hz, and f1 is going from 2200 Hz to 1300 Hz in steps of minus 100 Hz. Python knows we have a multi-line statement if there is a starting delimiter such as square brackets, until it finds a matching closing delimiter. The indentation level of a multi-line statement is that of the line that started the delimiter.




Now the sine table is created and 10 scores are written, one for each instrument.


# PhaseEx.py

from moduleCsound import *
addTag(startSyn,startOpt,stopOpt,startIns)
header(nch=2)

# *** Instrument String Template ***
PhaseExTemplate="""
ay3 oscil .5, %s, 1 ; f3 (B=.5)
ay2p phasor %s ; f2
ay2p = ay2p + ay3
ay2 table ay2p, 1, 1, 0, 1
ay2 = ay2*2 ; A=2
ayp phasor %s; f1
ayp = ayp + ay2
ay table ayp, 1, 1, 0, 1
aenvL linseg 0,.01,.5,.19,.2,p3-.3,.2,.1,0
aenvR linseg 0,.01,.6,.19,.2,p3-.3,.2,.1,0
aL = ay*aenvL
aR = ay*aenvR
out aL, aR
"""

N = 10

PhaseExStr=[
  PhaseExTemplate % (5,20,2200-100*i)
    for i in range(N)]
for i in range(N):
  instrument('HaHa',
             i+1,
             PhaseExStr[i])

addTag(stopIns,startSco)

# *** Table ***
table('1. Sine wave',1,0,8192,10,1)

# *** Score ***
rem('Phase Mod Score')
for i in range(N): score(i+1,0.4*i,0.4)

addTag(stopSco,stopSyn)
writeRun('Tut23')



The wav file shows the effect of the envelope.




This is the frequency spectrum of the first score using the first instrument.




You will find additional information at pythonaudio.blogspot.com, including the source code.



This is the video of Tutorial 23:



1 comment:

About Me

I have used Python for the last 10+ years. I have a PhD in Electrical Engineering. I have taught Assembly Language programming of Intel-compatible chips as well as PC hardware interfacing. In my research, I have used Python to automate my calculations in physics and chemistry. I also use C++ and Java, often with Python.