boodler
Reference Manual
The boodler
script plays soundscapes from your package collection. (To install soundscapes and data in your collection, see boodle-mgr.)
boodler [ options ] package/Agent [ data ... ]
You must usually supply the name of a soundscape (Agent class) to play, in the form package.name/Agent.
Normally, this loads the most current version of the package which is installed. To specify a particular version, you can say package.name:X.Y/Agent, where X and Y are numbers. This locates a version with major version exactly X, and minor version Y or later. (For other ways to specify versions, see this wiki page.) The assumption is that if you want version 3.1 of a package, then 3.2 or 3.10 will be acceptable, but 4.0 is too big a change. To choose an exact version of a package, use two colons: package.name::3.1.37a/Agent
Any arguments after the soundscape are passed along to that soundscape as data. See Soundscape Arguments for the format of these arguments. (If a soundscape argument begins with a minus sign, precede it with --
, so that it is not grabbed as a script argument instead.)
This special form:
boodler --testsound
...plays a test melody. This is always available; it does not have to be loaded from your collection.
Type boodler --help
or boodler -h
for a complete list of options.
--rate soundrate
--master volume
--hardware
--define opt
--define opt=val
--verbose
--verbose
, Boodler will print out the entire Python stack trace. Log messages are also more detailed in --verbose
mode; you will see the entire log channel name, instead of a summary.--log level
debug
, info
, warning
, error
, critical
. The default is warning
, meaning that messages of that severity or worse are printed. (In other words, by default, debug
and info
messages are suppressed.) Set this to debug
to see lots of picayune detail about sound generation.--stats interval
--data directory
~/Library/Application Support/Boodler
. On Linux or Windows, it will be a ~/.boodler
folder.--collection directory
Collection
subdirectory of the --data
folder (given above). There is generally no reason to change this.--external directory
--external
directories if you wish.) This is generally useful only if you are developing a soundscape, and want to test it without packaging it up first.--listen
--port port
--listen
is used, this causes Boodler to listen on the given port number (instead of the default port 31863). The port may also be an absolute pathname (beginning with "/"), in which case Boodler uses a Unix domain socket instead of a network socket.--stdinevents
--prop=opt
--prop=opt=val
All of these environment variables are optional. You can set all of this information with command-line arguments. (And command-line arguments override environment variables, if provided.)
$BOODLER_DATA
--data
option.$BOODLER_COLLECTION
--collection
option.$BOODLER_PROPERTIES
--prop
option. To set several properties, set this variable to a comma-separated list of opt
or opt=val
.Boodler currently offers these drivers:
stdout
-- write raw sample output to stdoutStreams data to stdout containing raw PCM sound sample data, two channels, 16 bits per sample, signed (centered at 0), little endian.
The stdout
driver, like the file
driver,
generates sound data as quickly as possible. This will probably
be much faster than real time! If you pipe the output to a file,
you will have a very large file very soon. This driver is intended
to be piped to an application that can regulate its input, such as
Ices.
Boodler soundscape arguments are specified in a slightly addled S-expression syntax. (S-expressions are the building blocks of Lisp. (Expect parentheses.))
The first thing to remember is that Boodler wants to parse all of the argument data itself. (We're not talking about the arguments to boodler
itself -- those begin with dashes, and are handled in the usual Unix way. We're talking about the soundscape and the options passed to it.)
Unix command-line tools usually get their arguments pre-split into words, but Boodler isn't interested in that, so it will jam all its arguments together and then do its own splitting. That is, the following command lines are exactly equivalent:
boodler pkg/Agent arg boodler " pkg/Agent arg " boodler pkg/Agent " " arg
In all but the simplest cases, it's easiest to slap quotes around all of the argument data. That prevents the Unix shell from interpreting the parentheses to mean shell-language. However, in this section, we will ignore that and write all of our S-expressions without shell-quotes.
Which is to say, the syntax of Boodler's S-expressions, which aren't really S-expressions, but I don't have a better term handy.
An expression is a string, or a parenthesized list of expressions. The following are all strings:
abc 123 "string with four words"
The following are all lists:
() (abc 123 "string with four words") (() 123 (list with four strings))
A list can also contain named entries. Examples:
(x=y) (pitch=1.0 pan=0.5) (abc bcd cde one=1 two=() three=(list of (lists)))
That last example contains three positional (ordinary) entries plus three named entries. This extension will look very odd to Lisp habitués, but it's just what we need to specify the argument of a Python function.
The other tedious-but-necessary details: a string can contain any characters, but you have to quote it if you want to include whitespace, single or double quotes, parentheses, backslash, or equals sign. You can quote a string with either single or double quotes, as long as you backslash any of that sort of quote inside it. Backslash backslashes, too.
Boodler interprets its soundscape and following arguments as a single S-expression, with the parentheses implied. The command
boodler org.boodler.play/OneSound org.boodler.old.clock/clock_cuckoo pitch=1.5 pan=1
...assembles itself as the S-expression
(org.boodler.play/OneSound org.boodler.old.clock/clock_cuckoo pitch=1.5 pan=1)
The first entry, of course, is interpreted as a soundscape agent to look up. The following entries (and named entries) are interpreted as whatever type the soundscape is expecting for that argument.
This is important, because S-expressions don't themselves have type information (except for "list" and "not a list"). 1
is parsed simply as a string. But the OneSound
agent declares that its pan
argument needs to be a float. So the 1
is passed to it as the Python float value 1.0. If that argument needed to be an int, it would be passed in as the integer 1; if it needed to be a string, it would be the Python string "1".
This is all straightforward for int, float, and string arguments. Bools aren't much harder; you can enter true
or false
, yes
or no
, or single-letter abbreviations of these -- or 1
or 0
-- and they will be interpreted as booleans in the obvious way.
List or tuple arguments are assembled out of S-expression lists. If an argument expects a list of integers, (1 23 456)
will become a Python list of length three. Types are checked carefully; (1 xyzzy)
in the same place would raise an exception, because the string xyzzy
cannot be interpreted as a Python integer.
A sound argument must be a string in the usual form package/resource. In the examples above, org.boodler.old.clock/clock_cuckoo
becomes a sound argument to OneSound
. (If that package is available!) You can also use the forms package:versionspec/resource or package::exactversion/resource.
Finally, we have soundscape arguments. If an argument expects a soundscape, you can fill in a package.name/Agent string, as usual. You can also fill in a list, of the form (package.name/Agent argument argument...). This creates a soundscape with its own arguments, and passes the entire thing along as the original arguments. The inner arguments are checked in their turn, and so the whole thing is tidily recursive.
Just a couple more special cases. If a soundscape is expected, you can enter a string beginning with a slash. This is looked up with Python's standard module system, rather than the Boodler package collection. You could use /boodle.builtin.TestSoundAgent
to locate the class TestSoundAgent
in the boodle.builtin
module. (This part of the core Boodler engine; it's the agent invoked when you use the --testsound
option.)
Finally, if a soundscape is expected, you can also enter the empty list ()
. This is interpreted as a soundscape which plays nothing and ends immediately. It is, in fact, the same as /boodle.builtin.NullAgent
.