Additive Synthesis

In this example we see how to create a harmonic spectrum using additive synthesis. The code is displayed first in full, then it is explained in detail.

 1from pdpy_lib import PdPy, Obj                  # necessary imports
 2fund = 110                                  # fundamental frequency in Hz
 3partials = 8                                # number of partials
 4mypatch = PdPy(name="additive", root=True)  # initialize a patch
 5dac = Obj('dac~')                           # instantiate a ``dac~`` object
 6mypatch.create(dac)                         # creates the dac on the canvas
 7for i in range(1, partials):                # loop through all partials
 8  objects = [                               # put objects on a list
 9    Obj("osc~").addargs(fund * i),          # a sinusoid at the partial's freq
10    Obj("*~").addargs(1 / partials)         # brute normalization
11  ]
12  mypatch.create(*objects)                  # create the objects list
13  mypatch.connect(*objects)                 # connect it
14  mypatch.connect(objects[-1], [dac, 0, 1]) # connect ``*~`` to dac chans 1,2
15mypatch.write()                             # write the patch out

First, we import the library so we can use it:

from pdpy_lib import PdPy, Obj

Variables

Now, we can define some variables. fund will have the fundamental frequency in Hz, and npartials will store the number of partials to create:

fund = 110
npartials = 8

dac~ Object

The next three lines define a PdPy patch and creates a dac~ object:

mypatch = PdPy(name="additive", root=True)
dac = Obj('dac~')
mypatch.create(dac)

Note

We create a dac~ object first so we can connect all the partials to it.

Partials

Each partial will be made of a single sinusoid. For this, we need an oscillator object osc~ connected to a multiplier *~. Since we need npartials number of partials, in this case 8, we iterate:

for i in range(1, npartials):

Within this iteration, we build an objects list with the two objects:

objects = [
  Obj("osc~").addargs(fund * i),
  Obj("*~").addargs(1 / npartials)
]

Note

  1. The addargs() function of the osc~ object is passed the fund variable multiplied by the partial number i, which is the required for a harmonic spectrum.

  2. The addargs() function of the *~ object is passed the coefficient to normalize (average) n number of partials, ie. 1 / n.

Then, still in the loop, we create and connect the objects together:

mypatch.create(*objects)
mypatch.connect(*objects)

Before exiting the loop, we connect the last object *~ to both inlets of the dac~:

mypatch.connect(objects[-1], [dac, 0, 1])

To finish this patch, you need to write it to disk:

mypatch.write()

You should now see an additive.pd patch on the working directory.