ag = FadeOutAgent(3)This creates an instance of an agent class, but it passes in an argument as it does so.
FadeOutAgenthas a (mandatory) argument, which is the duration of the fade-out that occurs before the channel stops.
This is a nice trick, and you will sometimes want to create your own agents that take arguments. You do this by adding a constructor method to your class.
class Example2(Agent): name = 'repeat example' def __init__(self, pitch, reptime): Agent.__init__(self) self.pitch = float(pitch) self.reptime = float(reptime) def run(self): self.sched_note('environ/droplet-plink.aiff', self.pitch) self.resched(self.reptime) class Example(Agent): name = 'repeat example' def run(self): ag = Example2(1.5, 0.5) self.sched_agent(ag) ag = Example2(1, 1.21) self.sched_agent(ag)The
Exampleagent creates two instances of
Example2. The first has a high pitch (1.5) and a short repeat time (half a second). The other has a lower pitch and a longer repeat time (1.21 seconds). Both are scheduled to start immediately, so you hear a quick high plinking interspersed with a low, slower sound.
Here is how the constructor in
In Python, the constructor is always called
The first argument is
self; it is followed by any arguments
you want the caller to pass in.
Agent.__init__(self)The first line of
__init__()must be this call. It calls the general agent setup code. If you neglect this line, you will get a
ScheduleError: agent is uninitializedexception.
The remainder of the constructor is yours to do with as you will.
But remember that
__init__() is called when the agent instance
is created. This is before the agent is scheduled,
placed in a channel, or set running. Therefore, the
schedule notes or agents, or create channels, or do anything else
that affects the stream of sound.
(If you think you want to do these things, you probably really
want to create a separate agent class that does them in its
Most often, your
__init__() method will just take its
arguments and store them away for
run() time. In the example,
we take the
pitch argument and attach it to the agent instance,
self.pitch. We do the same with
Note that we call
reptime to convert
them to real numbers. It is not obvious why this is necessary -- after all,
Python automatically converts integers to real numbers when needed.
The reason is so that you can type this command:
python boodler.py bootest.Example2 1.25 0.75When you run Boodler, all command-line arguments after the class name are passed on to the class as constructor arguments. However, they are passed as strings. (The Boodler startup mechanism cannot know that they are meant to be interpreted as numbers, so it can't convert them automatically.) If you think your agent might ever be run from the command line, it is polite to accept string values for your numeric arguments, by using the
int()functions to convert them.
An optional argument is easy to arrange:
class Example2(Agent): name = 'repeat example' def __init__(self, pitch=1, reptime=1): Agent.__init__(self) self.pitch = float(pitch) self.reptime = float(reptime) def run(self): self.sched_note('environ/droplet-plink.aiff', self.pitch) self.resched(self.reptime)The line
def __init__(self, pitch=1, reptime=1):gives default values for both arguments, making them optional. If you run the
Example2agent from the command line without parameters, or do
ag = Example2()in Python code, the agent will default to pitch 1.0 and a one-second repeat time. If you supply just one argument, it will be taken as the pitch, and the repeat time will default to 1.
sched_note_pan()method instead of
sched_note(). This method has an extra argument (after the sound), which indicates how far left or right to play the sound.
self.sched_note_pan('environ/droplet-plink.aiff', 1.0) self.sched_note_pan('environ/droplet-plink.aiff', -1.0, 1, 1, 0.5)The value -1.0 indicates a sound played entirely in the left channel; 1.0 means the right channel; 0.0 is center, the normal position.
(The usual optional arguments of pitch, volume, delay, and channel can follow the pan location. The second line above plays a note in the left channel, normal pitch, normal volume, and 0.5 seconds after the first note.)
Just as a channel can modify the volume of every sound within it, a channel can modify the stereo location of every sound within it.
chan = self.new_channel_pan(0.5)This creates a channel shifted halfway to the right. A sound played in this channel with
sched_note()would be played at position 0.5, instead of the default (center) position. A sound played at location -1.0 would come out at position -0.5.
You can control the stereo location of a channel more precisely using
the functions in the
stereo module. For example:
from boodle import stereo chan = self.new_channel_pan(stereo.fixed(0.5))This channel renders all sounds within it, no matter where they think they're going, at location 0.5.
See the Programming Reference for more
stereo module. You can use these functions
to shift a channel, or compress it into a narrow range, or even swap
the left and right channels. I leave the details to your enjoyment.
Return to Boodler docs index