# Boodler: Building Packages

Say you've created a `bootest` directory which contains a working soundscape called `Example`. (And if you followed the previous chapter of this manual, you do.) How do you turn it into a .boop package? Easy:

    boodle-mgr.py --import create bootest

Type that, and you'll see this output:

    Package created: /home/zarf/com.example.bootest.1.0.boop

(The .boop file will be created in the same directory as you put the `bootest` folder, actually.)

The `boodle-mgr.py` script is for package management, and its "create" command scans a package directory, figures out what's in it, and creates a .boop package.

(The `--import` option is necessary, for security reasons. Not-yet-implemented security, at that. See the documentation for the create command. Or, just use it and don't fret about why.)

This newly-created .boop file can be installed, same as any .boop that you download:

    boodle-mgr.py install /home/zarf/com.example.bootest.1.0.boop

(Fill in the actual location of the .boop you created, of course.)

You can now play the `Example` soundscape without using the `--external` option:

    boodler.py com.example.bootest/Example

Now that you've installed it, Boodler is able to locate the package in your collection. It is no longer relying on the contents of the `bootest` directory. You could even delete the `bootest` directory if you wanted. But you shouldn't, because we're going to keep updating it throughout this manual.

## Metadata

The creation process figured out that the package name was `com.example.bootest`. How? By looking in the `Metadata` file that you created. That contained a line of the form:

    boodler.package: com.example.bootest

You can add other lines to specify other information about your package. For example, if you added this line:

    boodler.version: 1.1

...then you would be defining version 1.1 of your package. The "create" command would then create a file named `com.example.bootest.1.1.boop`.

You will usually want to specify your own name in the `Metadata` file, and perhaps other bibliographic information. You would add lines like these:

    dc.creator: Andrew Plotkin
    dc.title: Example plinking module

The "dc." prefix refers to "Dublin Core", a common standard for metadata. (In contrast, the "boodler." lines are information that control Boodler's behavior.)

These are the most common "dc." terms:

- `dc.creator`: the name of the package's creator
- `dc.title`: the title
- `dc.description`: a longer explanation of the package
- `dc.created`: the creation date
- `dc.modified`: the last modification date
- `dc.source`: your home page URL, or where people can find you
- `dc.license`: the terms under which people can use the package
- `dc.rights`: information about who owns the package material (if not you)

There are many more Dublin Core metadata terms, but the ones listed here are most useful for Boodler packages.

(A future version of the Boodler web site will display this metadata information when you are browsing through available packages.)

## Resources

You've defined a title for your package. But you should also define a title for each soundscape in the package. You do this by creating a `Resources` file in your `bootest` directory. Create a file with that name, containing these lines:

    :Example
    dc.title: Example soundscape

`Resources` is rather like `Metadata`, except that it's divided into sections, one for each resource you want to describe. (A resource is a sound or a soundscape that will go into the package.) A line beginning with a colon is the start of a section. In this case, we have just one section, giving the `Example` soundscape a title.

Try running the soundscape:

    boodler.py --external bootest com.example.bootest/Example

We've gone back to using the `--external` option, because we want to pick up the changes you just made to the `bootest` directory. You'll see this output:

    16:20:43 (root) located external package: com.example.bootest 1.0
    16:20:44 (root) Running "Example soundscape"

Boodler displays your soundscape title, instead of "unnamed agent".

(Yes, you could put any Dublin Core metadata terms into a `Resources` file. But you usually only need the `dc.title`. That's because, usually, all the soundscapes have the same `dc.creator` and so on. If you don't specify a term in the `Resources` file, the value in the `Metadata` file is assumed to apply. If you want to put a different modification date on each soundscape, or some such, feel free.)

## Building a package with sound resources

You can put sounds, as well as soundscapes, into packages. (You've probably figured this out, given all the sound packages you've installed.) Boodler's native sound formats are AIFF, WAV, and AU.

(Yes, MP3 and Ogg would be nice. But Python doesn't support those formats out of the box, so decoding them would make Boodler harder to build. It would also be slow. Maybe a future version of Boodler will support them.)

It's generally best practice to keep sounds and soundscapes in separate packages. That way, another package can import your sounds without worrying about your soundscapes -- or vice versa.

So, create a second package directory named `bootest2`. Give it a `Metadata` file with only this line:

    boodler.package: com.example.bootest2

You don't want a `boodler.main` line, because that defines the location of a Python source file, and this package won't have one.

Now copy some AIFF or WAV files into `bootest2`.

You have to be careful about filenames, though. A Boodler sound resource must have a Python-legal name. That means letters, digits, and underscores only (and it can't begin with a digit). No other punctuation, except for the ".aiff", ".wav", or ".au" suffix.

Say you've found a `foop.aiff` file that you want to incorporate into Boodler. Copy it into `bootest2`.

You now have a valid Boodler package directory. You can use the standard sound-playing tool, `org.boodler.play/OneSound`, to play it. Type this (all on one line):

    boodler.py --external bootest2 org.boodler.play/OneSound
        com.example.bootest2/foop

Notice what's going on here. We use the `--external` option to load in the `com.example.bootest2` package. That's not where the `OneSound` agent is -- just where the `foop` resource can be found. `OneSound` comes from the `org.boodler.play` package, which you should have installed already (from the Boodler site).

The argument to `OneSound` is the full name of the sound resource we want to play: `com.example.bootest2/foop`. That's available because of the `--external` option. So it works; the sound plays.

You can define a `Resources` file for sounds, just as you can for soundscapes:

    :foop
    dc.title: A foop-like noise

If you put several sounds in the package (which you typically will), you'd have one section per sound resource, each beginning with a line beginning with a colon.

## A package with both sounds and soundscapes

I said you generally don't want to do this. But let's pretend that you do, for the sake of documentation.

Copy your `foop.aiff` into the `bootest` directory. We'll make that sound directly accessible from the Python code in `main.py`.

    from boopak.package import *
    from boodle import agent

    bexport()

    class Example(agent.Agent):
        def run(self):
            self.sched_note(foop)

The new feature here is the `bexport()` call. What this means is, look through the sound files in the package directory, and make each one a sound resource in the package. Each one also becomes a variable in the code itself. In this case, we have a resource `com.example.bootest/foop` which can be referred to from other packages, and a value `foop` that can be used inside the package. (Which the `sched_note` call does.)

In sound-only packages -- packages with no Python source -- this resource-exporting process is automatic. You only need the `bexport()` call when you have Python code and sound files in the same package.

(In fact, you can use `bexport()` to control which sound files get turned into resources. But we don't need to worry about that here.)

## Next...

Tricks with soundscape channels.

Designing Soundscapes

Return to Boodler docs index