Rendering 1 Second of Audio Data

Yesterday’s python script rendered 1 frame of a rudimentary additive synthesizer. Today’s script renders 1 second. You can download the complete example at textsnip or at snipt.

To render multiple frames of audio, I added two classes: Mixer and Run.

class Mixer:
    '''A simple mixer.'''
    
    def __init__(self, source1, source2):
        self.s1 = source1
        self.s2 = source2
    
    def __iter__(self):
        self.index = 0
        self.iter_1 = (i for i in self.s1)
        self.iter_2 = (i for i in self.s2)
        return self
    
    def next(self): 
        if self.index >= ksmps:
            raise StopIteration

        self.index += 1
        return self.iter_1.next() + self.iter_2.next()
    
class Run:
    '''Render frames over time.'''
    
    def __init__(self, dur=1.0):
        self.dur = dur  
    
    def __iter__(self):
        self.index = 0
        return self
    
    def next(self): 
        if self.index >= (self.dur * sr) / ksmps:
            raise StopIteration

        self.index += 1
        return self.index

Mixer is an iterator class that takes two iterator objects as its input. The values yielded by the inputs are summed together. Yesterday’s method was only good for one frame; A Mixer object does not have this restriction.

The Run iterator class is designed to loop through the iterator/audio graph over a user-defined duration of time, creating multiple frames of audio data.

The follow snippet of code resembles yesterday’s example as it creates a graph of two sine waves (a1 & a2) being fed into a mixer (amix.) The Run object is given a duration of 1 second, which produces 4410 frames (sr / ksmps) and 44100 samples (10 samples per frame.)

if __name__ == "__main__":
    a1 = Sine(0.5, 440)
    a2 = Sine(0.5, 440 * 2 ** (7 / 12.0))
    amix = Mixer(a1, a2)
    
    for frame in Run(1.0):
        print frame, ':'
        for sample in amix:
            print 't', sample

Still no output to an audio file. What it does output is a printed list of frames and samples. Here’s frame 4276:

4276 :
    0.128148365438
    0.138541849949
    0.14709747835
    0.153592896452
    0.157826911985
    0.15962183375
    0.158825589584
    0.155313602303
    0.148990404968
    0.139790979215

BTW, I’m trying a new service, textsnip.com, for storing and sharing my scripts online. If you have a better recommendation, let me know. Update: textsnip seems to add a couple of gremlins to the autodocs, so I’m trying out snipt.org as well.

Python Iterator as a Sine Oscillator

I wrote a sine oscillator as a Python iterator class. Not the fastest digital oscillator in the world. Though for now, doing prototype work in pure Python will do just fine, even if it means slow render times. In the long run, Slipmat will require a powerhouse of an engine for real-time audio synthesis and DSP, probably written in C. All in good time.

Here’s the script:

#!/usr/bin/env python
import math
import itertools

class Sine:
    '''A sine wave oscillator.'''
    
    sr = 44100
    ksmps = 10    
    
    def __init__(self, amp=1.0, freq=440, phase=0.0):
        self.amp = amp
        self.freq = float(freq)
        self.phase = phase
        
    def __iter__(self):
        self.index = 0
        return self
    
    def next(self):
        if self.index >= self.ksmps:
            raise StopIteration

        self.index += 1
        v = math.sin(self.phase * 2 * math.pi)
        self.phase += self.freq / self.sr
        return v * self.amp

if __name__ == "__main__":
    a1 = Sine(1, 4410, 0.25)
    a2 = Sine(0.5, 8820)
    amix = (i + j for i, j in itertools.izip(a1, a2))
    
    for i in amix:
        print i

Currently, it produces the same sound as a tree falling in the woods with no one around to hear it; It doesn’t write to a DAC or sound file. At least we can still view the results:

1.0
1.28454525252
0.602909620521
-0.602909620521
-1.28454525252
-1.0
-0.333488736227
-0.0151243682287
0.0151243682287
0.333488736227

Near the bottom of the code is a very simple graph, where two sine wave generators (a1 & a2) are patched into a mixer generator (amix), creating a very rudimentary additive synthesizer. The signals aren’t generated until the for-block at the very end. The script only prints one control-block’s worth of data, 10 samples, which coincides with the value of ksmps found in class Sine. The sample rate and control rate is built right into class Sine, and needs to be moved out.

Deep Synth — Dynamically Generated Oscillators

The situation — You want an instrument that can play any number of oscillators, determined by a p-field value in the score. The problem — Unit generators cannot be dynamically created in an instrument with a simple loop. One possible solution — Multiple events can be generated in a loop, with each event triggering an oscillator-based instrument.

Download: Deep_Synth.csd
Listen: Deep_Synth.mp3

The Csound file Deep_Synth.csd provides an example of how to dynamically generate oscillators using the compound instrument technique. A compound instrument is two or more instruments that operate as a single functioning unit. This particular compound instrument is built from two instruments: DeepSynth and SynthEngine. SynthEngine is, you guessed it, the synth engine, while DeepSynth is a player instrument that generates multiple events for SynthEngine using the opcodes loop_lt and event_i:

i_index = 0
loop_start:
    ...
    event_i "i", $SynthEngine, 0, idur, iamp, ipch, iattack, idecay, ipan,
            irange, icps_min, icps_max, ifn
loop_lt i_index, 1, ivoices, loop_start

If you are wondering why we can’t just place a unit generator, such as oscil, inside of a loop, read Steven Yi’s articles Control Flow Pt I and Pt II. Pay special attention to the section IV. Recursion – Tecnical Explanation near the end of Pt. II. Not only does Mr. Yi do an excellent job explaining these technical reasons, but he also provides another applicable solution for creating multiple unit generator instances utilizing recursion and user-defined opcodes.

Sound Design

The instrument SynthEngine uses a single wavetable oscillator, an amplitude envelope and the jitter opcode to randomly modulate frequency. A single instance of DeepSynth can generate multiple instances of SynthEngine. DeepSynth can generate a single instance, or 10,000+. Users have control over the depth of frequency modulation, as well as the rate in which jitter ramps from one random value to the next. Panning between instances of SynthEngine is evenly distributed.

“Turn it up!” – Abe Simpson

The name DeepSynth is a homage to Dr. James A. Moorer‘s piece Deep Note, also known as the infamous THX Logo Theme. Very early in the design, it became evident that DeepSynth is capable of making very Deep Note like drones. This is due to the fact that it does utilize some of the defining techniques used in Dr. Moorer’s piece.

I highly recommend reading Recreating the THX Deep Note by Batuhan Bozkurt at EarSlap. The author conveniently walks readers through each step of the process, providing both audio and Supercollider code examples. If you have ever yearned to create that amazing sound for yourself, here’s your opportunity.

The Backlog

I’m reposting all the Csound Blog posts from the original site.  The write-ups are stored within the Csound files themselves.  I’m really looking forward to posting new content, and will hopefully have something up by the end of the week.  Without further ado:

Beginning Csound @ NYC Resistor

Beginning Csound

Beginning Csound
July 28, 2008 @ NYC Resistor
1 Session, 3 hours, with personalized post-session project with instructor via email.
Cost $75

Csound is the most powerful computer music language in the world, with a direct lineage to Max Mathews’ original Music-N languages. The focus of this class will be a synthesis of three topics: The Csound language, synthesizer theory, and composing weird alien music.

Together, we will demystify the assembly-like syntax of the Csound language. We will cover the fundamentals of synthesizer theory, including: oscillators, filters, envelopes, amplifiers and modulation. Finally, we’ll tie it all together by composing sounds in the vein of classic Sci-Fi movies.

Taught by Jacob Joaquin (that’s me.) Click here to enroll.

Csound and the OLPC

OLPC

Flickr photo by me

Since friday, I’ve been learning the ins and outs of my XO computer. I finally got to a point this morning where I can start writing csound-based activities for it.

Using the csndsugui toolkit, I slapped together a primitive step-sequencer in about five hours. It features: An 8-step pitch slider array, two oscillators for notes, AD envelope for amplitude, tempo control, volume control, 8-step kick row and an 8-step snare row. So while it might not do much at the moment, I can certainly see myself fixing it up to a point where it’ll be a fun musical toy in the near future. I’ll post a pic in a few days, once it shapes up a bit.

Oscillator Experiment Update: Piecewise Sine

After matrixsynth.com picked up “My Sine Oscillator Experiment,” doktor future started a discussion about different ways of emulating analog oscillators in digital. Adam S mentioned that he thought the Plan B sine looked like a piecewise quadratic to him and provided the following function:

y=
-(4/pi^2)[x – (pi/2)]^2+1, x from 0 to pi
(4/pi^2)[x-(3pi/2)]^2-1, x from pi to 2pi

After having checked it out in grapher.app myself, and confirmed it did look similar to the Plan B sine, I implemented this as a wave table in Csound. See piecewise.csd.

Piecewise + Plan B Model 15

In this image, I have superimposed Adam’s recommended piecewise function over the Plan B’s Model 15 sine wave. As you can see, their contours are not quite identical, though very, very similar.

After listening to both waves side-by-side, the harmonic distortion in the piecewise sine example is a tad louder, and the frequencies are just slightly off. At least to my ears. However, I consider it to be a wonderful approximation of the Model 15.

Oh, the Irony

Peter Grenader, the principle designer at Plan B, has this written in his bio:

“In 2001 , Peter returned to analog after a 22 year hiatus because he tired of trying to force digital instruments to behave in like manner.”

I’m finding this whole discussion a bit humorous as the three of us are doing exactly this, trying to force digital instruments to sound like analog. In this case, Mr. Grenader’s analog oscillator.

My Sine Oscillator Experiment

Over the weekend, I recorded/generated four sine waves of different synthesizer modules and compared the results. Each of the four oscillators are tuned to approximately to 440Hz, close enough to get a sense of each wave shape.

This is a very casual observation of contour and contour only, so please do not read too much into my findings. Here are the results:

Csound Digital Oscillator

This first graph shows a digital sine wave generated within the computer music language Csound. This is what I used as my test reference. Being that this is a purely mathematical construct, I figured this would be the perfect wave to compare against its analog counterparts.

Doepfer A-110 Standard VCO

Upon casual observation, you may notice that the sine isn’t the most accurate in the world. In fact, you might go as far to say this isn’t a sine wave at all. One noticable feature of this oscillator is that little glitch you see at 90º. This is consistent among every cycle at the stated frequency. I have two of these modules, and there were no significant differences when compared to each other.

Now it might sound like I’m completely down on this module. The truth is, I’m actually quite happy with this dirtiness of this unit, as it adds character. It is sometimes the imperfections that make something great.

Plan B Model 15

This unit has the smoothest contour of the three analog examples. Though the shape doesn’t adhere completely to the perfectly generated Csound test reference, it certainly gets close. The peak and the dip seem to be a bit rounder, almost as if they are slightly compressed.

Cwejman D-LFO

Now, I must say that it probably isn’t fair that I’m comparing a device designed specifically for low frequencies. With that being said, the contour fared noticeably better than the Doepfer. You might notice that the peak and the dip are both a little on the sharp side. The D-LFO comes with two oscillators, both of which I tested. I found both to be consistent with one another.

All Examples Compared

For fun, I thought it would be nice to superimpose each example over one another so we can better observe how much variation can exist between sine wave oscillators.

Other Variables in the Equation

Since I recorded the three analog signals, there were at least two extra variables that may have introduced distortion to the resulting wave shapes. The first would be the recording device, an Apogee Ensemble with the soft limit feature set to off. The second is the cable. I used the same cable for all the recordings. I always patched directly from the sine wave outputs to the Ensemble input.

I did go the extra step and recorded the Csound sine wave with the Ensemble and cable. I found there were no significant differences, in terms of contour, between the original generated wave and the recorded version.

My Methods

Last, I want to share the methods I used to collect and present the data. I recorded the three analog signals with the Apogee Ensemble, and with the software Peak. I took screen captures of peak, and then processed them in Photoshop. In Photoshop, I removed the dotted zero line, and replaced it with a solid line. I also resized each image so the waves would have matching periods. Though I compressed the width of each waveform, the contours of the waves were not affected.

And like I said, this experiment is just the casual observations of one guy, and completely non-scientific.