Sculpting Sound with Boodler 2.0

244

Boodler LogoBoodler is a cross-platform audio tool with which you can construct and play back sound streams composed in a simple, Python-based syntax. Boodler uses “soundscape” to describe these creations, a term which is usually associated with re-creating naturalistic audio environments. Although you can do that with Boodler, creating immersive sound scenarios, you can do much more, including programming music, voice response systems, and sound servers that respond to events from other applications, local or over the network. All you need are a few audio samples.

icon for podpress
icon for podpress

Boodler is the creation of Andrew Plotkin; the current 2.0-series represents a major upgrade over previous versions, especially in ease-of-use and compatibility. The suite consists of three tools: the main audio player boodler.py, a utility for managing and inspecting Boodler packages called boodle-mgr.py, and a lightweight script named boodle-event.py used to send event signals to a running Boodler process.

Boodler currently runs as a stand-alone program, but that does not mean it has no application outside locally-generating audio. The code is extremely compact, as are the soundscape packages, yet together they can produce unlimited sound content–that could have implications for game design, animation and video, or any other creative task that makes use of audio components.

Installation and Setup

You can download the latest release in a source archive from the project’s site. The prerequisites are Python 2.3.5 or later (but not Python 3), and development packages for the various audio output methods you wish to enable. This version supports direct audio playback with OSS, ESD, ALSA, or PulseAudio on Linux, playback with CoreAudio on Mac OS X, creating Ogg Vorbis, MP3, or raw WAV files, writing raw samples to stdout, or generating a SHOUTcast/Icecast source stream. On a modern Linux system, for example, make sure you have libpulse-dev, libmp3lame-dev, and libvorbis-dev installed; Boodler will attempt to build output modules for all of them at install time, and issue a warning message if it fails to find the needed header files.

Unpack the source archive, then build with python setup.py build. Boodler will compile without support for missing output modules, so be sure to check the setup script’s output for warnings. When satisfied, executing sudo python setup.py install will copy Boodler into your Python directory.

You can test your installation with boodler.py –testsound, which plays a quick stereo sequence of simple tones. Boodler defaults to OSS for Linux sound output; if you need to use another you must specify it with the -o outputdriver flag. For a PulseAudio system, use boodler.py -o pulse –testsound.

Soundscapes

Once you hear the test sound, Boodler is successfully installed, but to really get any usage out of it, you will need to install some soundscape packages with boodle-mgr. Boodler packages use the extension .boop, and can contain individual audio samples, soundscape definitions, or both–some Boodler users prefer to package their sounds and soundscape definitions separately, to make sharing sounds easier. Packages are prefixed with their author’s domain name components and include version numbers, e.g., com.example.mynoises.1.0.boop.

The Boodler site maintains a public repository at www.boodler.org/lib/. If you are just getting started with Boodler, go ahead and install the entire set (at present about 50 packages, ranging in size from 1.5KB to 3.6MB)–many of the examples in the Boodler documentation and soundscaping tutorial make use of the packages in the library. You can download them directly, but it is easier to retrieve them with boodle-mgr.py install package_url. Boodler installs the packages into ~/.boodler/Collection/, after which any soundscape or individual sound sample can be played by name with boodler.py.

Although a soundscape could technically contain just a single sound sample, most are composed of a set of sounds blended together at different pitches, volumes, times, and stereo locations. For example, boodler.py com.eblong.zarf.crows/ParliamentOfCrows simulates a field of crows by repeating four different original samples at randomized intervals and volumes. ParliamentOfCrows will continue playing, indefinitely and without repeating, until you exit Boodler with Crtl-c. You can limit the play time by calling the special org.boodler.manage/Limit soundscape instead, and passing ParliamentOfCrows to it as an argument: boodler.py org.boodler.manage/Limit com.eblong.zarf.crows/ParliamentOfCrows will play for the default length of 30 seconds.

icon for podpress
icon for podpress

Boodler’s ability to generate non-repeating sequences of continually blended sounds certainly sets it apart from other audio tools, but that is only the beginning. Soundscapes don’t have to contain any randomization or repetition, and they can still do useful and interesting things. boodler.py com.eblong.zarf.timespeak/Time retrieves the local system time and speaks it out loud using human voice samples.

icon for podpress
icon for podpress

Soundscape Authoring

Boodler soundscapes are written in Python. The key class is the Boodler Agent, which is responsible for scheduling sounds to be played in Boodler’s root audio channel. At its simplest, an Agent can call the sched_note() method for a sound sample to play it immediately, but sched_note can also be used to schedule sounds for playback after a delay, as well as to alter its pitch or volume. An Agent can also reschedule itself with resched(), and build more complex scenes by scheduling other Agents or spawning independent audio sub-channels.

For example, the com.eblong.zarf.clock/Tick soundscape contains the following:

 # com.eblong.zarf.clock

import random
from boopak.package import *
from boodle import agent, builtin

clock = bimport('org.boodler.old.clock')

class Tick(agent.Agent):
def init(self, pitch=1.0, pan=0.0):
self.pitch = pitch
self.pan = pan ### stereo argdef type
def run(self):
dur = self.sched_note_pan(clock.clock_tick, self.pan, self.pitch)
self.resched(dur)

Tick uses the sched_note_pan() method, which allows an Agent to specify the stereo location of the scheduled sound sample in addition to its other attributes, in the interval [-1,1]. By itself, Tick will play the org.boodler.old.clock.clock_tick sound sample at 100% volume in stereo center, then immediately reschedule itself–resulting in a steady stream of clock ticks. Other soundscapes, such as com.eblong.zarf.clock/VaryingTick from the same package, can pass pan and pitch arguments to Tick for variety:

 class VaryingTick(agent.Agent):
def run(self):
pitch = random.uniform(0.333, 1.666)
delay = random.uniform(8, 24)
self.sched_agent(builtin.FadeInOutAgent(Tick(pitch), delay-2, 2))
self.resched(delay)

Here, VaryingTick uses Python’s random package to randomize the pitch and play-length of each Tick. FadeInOutAgent is a utility Agent built in to Boodler to simplify repetitive tasks like fading a sample in or out–tweaks that make soundscapes considerably more pleasant to the ear than sharp stops and starts.

icon for podpress
icon for podpress

Boodler also includes a simple messaging system through which Agents can communicate. Boodler events, as they are known, are text strings that can be broadcast by Agents and picked up by other Agents that are specifically listening for them. Events are broadcast-only, and limited to a channel. In default Boodler usage, this would mean the root channel, but if a soundscape opens its own channels, Agents within them can use events to communicate without interfering with other channels.

An Agent broadcasts an event with send_event(‘message‘), where message is a Python string. In order for another agent to receive the event, though, the second agent must call listen(‘message‘) with a matching string. This can mean the same string, or a dotted prefix of the string. For example, if the listening agent calls listen(‘alert’), it would respond to both a send_event(‘alert’) or send_event(‘alert.redalert’)–thus allowing you to impose some light structure on your events if so desired.

Boodlin’ On

The Boodler documentation site hosts a far more comprehensive tutorial suite written by Plotkin detailing additional features like multiple channels and relaying events from external programs (including over the network) with boodle-event.py, as well as packaging soundscapes and samples into Boodler .boop packages.

Plotkin’s example soundscapes (which use the com.eblong.zarf.* namespace) are in the public domain, as are the sound samples within them. As you start to build your own soundscapes, you will need to acquire and package clean audio samples to which you have redistribution rights–either capturing them from field recordings, or through a Creative Commons-aware site like Freesound. Boodler currently supports clips in WAV, AIFF, and AU formats, because those are the formats natively supported by Python. AIFF holds interesting possibilities because of the three, it is the only format that supports in-file looping information.

Plotkin says his current focus is on upgrading the Boodler site and soundscape hosting functionality, after which he plans to work on building GUI tools for Boodler. There are technical enhancements slated for some time in the future, he adds, but for now improved ease-of-use through the site and graphical front-ends take priority.

In the meantime, Halloween is just around the corner… Why not grab a few spooky sound clips from Freesound.org, and assemble an experience appropriate to the season? You could start with material directly from the Boodler site, like Plotkin’s com.eblong.zarf.crows/ParliamentOfCrows, or atmospherics from com.eblong.zarf.basicwind/VaryingWind. Add to that whispers and voices from com.goob.secrets/Many or name.igo.bob.demons/Phrases, and top it off with com.eblong.zarf.heartbeat/ComingAndGoing. The possibilities are, well, endless.

{enclose http://podcasts.linux-foundation.org/mp3/sep_09/simultaneous.mp3 1 audio/mpeg}

icon for podpress
icon for podpress