Oscillators

Oscillators in Afterglow are a flexible way of turning the timing information tracked by metronomes into waveforms that can be used to make lights do interesting things. They can be related to the beats, bars, or phrases of the metronome, or multiples or fractions thereof, and can create sawtooth, triangle, square, or sine waves, or any custom shape you can dream up and code a shape function for.

Metronomes keep track of musical time relative to some starting point, in terms of beats, bars (by default four beats to a bar), and phrases (usually eight bars to a phrase). In addition to keeping track of the current beat, bar, and phrase, metronomes can also tell you the phase of that beat, bar, or phrase, which is a measurement of progress through the beat, bar, or phrase. The phase starts out at 0.0 at the very beginning of the interval, and grows towards, but never quite reaches, 1.0, because at that point you will be on to phase 0.0 of the following interval.

So, in a sense, by itself a metronome can give you a sawtooth wave related to its intervals, just by looking at the interval phase. The sawtooth oscillators build on that by letting you change the direction of oscillation, so it starts at 1.0 and slides downward, the speed of oscillation, so it ramps over multiples or fractions of an interval, and also let you shift the phase of the wave so it does not coincide with the interval itself.

So that all of the lighting effects created for a given frame of control output are synchronized and share the same notion of the current state of the metronome, Afterglow takes a snapshot of the metronome at the start of the frame, and the oscillators work from that.

Sawtooth Oscillators

(afterglow.effects.oscillators/sawtooth)

Returns an oscillator which generates a sawtooth wave relative to the phase of the current beat. At the start of the beat, the value will be 0.0, and at the end of the beat, the value will have grown linearly to 1.0.

Default Sawtooth Oscillator

You can change the nature of the wave by using optional keyword parameters, and the values you use with them can be be dynamic parameters:

Parameter Default Purpose

:down?

false

When true the wave starts at 1.0 and falls linearly to 0.0.

:interval

:beat

Change whether the oscillator cycles over each beat, bar, or phrase, by passing in the keyword :beat, :bar, or :phrase. There are graphs showing the other intervals below.

:interval-ratio

1

Runs the oscillator at the specified multiple or fraction of the interval (beat, bar, or phrase).

:phase

0.0

Offsets the oscillator from the interval boundary by the specified amount (where 1.0 is an entire interval, and so would have no visible effect).

As noted in the table, the direction of the wave can be reversed:

(afterglow.effects.oscillators/sawtooth :down? true)
Downward Sawtooth Oscillator

Ratios

All of the oscillators can be modified by supplying the :interval-ratio keyword argument. This argument specifies a fraction that adjusts the speed of the oscillator with respect to the interval it is oscillating over. For example a beat-oriented oscillator normally goes through its entire wave shape once per beat. If you supply an :interval-ratio of 2, it will run half as fast, taking two beats to go through its waveform.

Sawtooth Beat Oscillator with Beat Ratio 2

An :interval-ratio of 1/3 speeds it up so that it only takes one-third of a beat to go through its oscillation, and will finish three complete cycles each beat.

Sawtooth Oscillator with Interval Ratio 1/3

These can be combined, of course, so an :interval-ratio of 2/3 would complete three cycles every two beats.

Sawtooth Oscillator with Interval Ratio 2/3

Phase Shifting

All of the oscillators can be modified by supplying a :phase keyword argument, which offsets them from the actual phase of the interval that they are tracking. For example, if you supply a :phase value of 0.5, the oscillator will be pushed exactly halfway out-of-phase with the metronome interval, so that it will act as if a beat is starting halfway through the actual beat. A positive value shifts the oscillator ahead of the underlying interval, and a negative value delays it. Only values between -1.0 and 1.0 make sense, since shifting multiple intervals has no functional difference from staying within the current interval. In other words, passing in exactly 1.0 (or 2.0, etc.) is the same as passing in 0.0, and will have no effect on the oscillator.

Sawtooth Oscillator with Phase 0.25

As noted in the table above, to have the oscillator work with intervals other than beats, you use the optional keyword argument :interval. For example to have the sawtooth spread over each bar:

(afterglow.effects.oscillators/sawtooth :interval :bar)
Sawtooth Bar Oscillator

And to have it oscillate over each phrase:

(afterglow.effects.oscillators/sawtooth :interval :phrase)
Sawtooth Phrase Oscillator

Triangle Oscillators

(afterglow.effects.oscillators/triangle)

Returns an oscillator which generates a triangle wave relative to the phase of the current beat. At the start of the beat, the value will be 0.0, at the midpoint, the value will have grown linearly to 1.0, and at the end of the beat it will have returned to 0.0.

Default Triangle Oscillator

You can change the nature of the wave by using optional keyword parameters, and the values you use with them can be be dynamic parameters:

Parameter Default Purpose

:interval

:beat

Change whether the oscillator cycles over each beat, bar, or phrase, by passing in the keyword :beat, :bar, or :phrase. There are graphs showing the other intervals below.

:interval-ratio

1

Runs the oscillator at the specified multiple or fraction of the interval (beat, bar, or phrase).

:phase

0.0

Offsets the oscillator from the beat by the specified amount

The effects of the :interval-ratio and :phase parameters are discussed in more depth, and illustrated with graphs, in the documentation for the Sawtooth oscillator. You can jump to those sections using the links in the Purpose section of the table.

As noted in the table above, to have the oscillator work with intervals other than beats, you use the optional keyword argument :interval. For example to have the triangle spread over each bar:

(afterglow.effects.oscillators/triangle :interval :bar)
Triangle Bar Oscillator

And to have it oscillate over each phrase:

(afterglow.effects.oscillators/triangle :interval :phrase)
Triangle Phrase Oscillator

Sine Oscillators

Just like in musical synthesis, sine waves are the smoothest-feeling waves of all, and are good for creating gentle, subtle effects which ease in and out.

(afterglow.effects.oscillators/sine)

Returns an oscillator which generates a sine wave relative to the phase of the current beat. At the start of the beat, the value will be 0.0 and beginning to rise slowly, picking up speed as it goes, and slowing down again as it approaches the midpoint. At the midpoint, the value will reach 1.0 and begin falling slowly, again picking up speed, and at the end of the beat it will have returned to 0.0.

Default Sine Oscillator

You can change the nature of the wave by using optional keyword parameters, and the values you use with them can be be dynamic parameters:

Parameter Default Purpose

:interval

:beat

Change whether the oscillator cycles over each beat, bar, or phrase, by passing in the keyword :beat, :bar, or :phrase. There are graphs showing the other intervals below.

:interval-ratio

1

Runs the oscillator at the specified multiple or fraction of the interval (beat, bar, or phrase).

:phase

0.0

Offsets the oscillator from the beat by the specified amount

The effects of the :interval-ratio and :phase parameters are discussed in more depth, and illustrated with graphs, in the documentation for the Sawtooth oscillator. You can jump to those sections using the links in the Purpose section of the table.

As noted in the table above, to have the oscillator work with intervals other than beats, you use the optional keyword argument :interval. For example to have the sine wave spread over each bar:

(afterglow.effects.oscillators/sine :interval :bar)
Sine Bar Oscillator

And to have it oscillate over each phrase:

(afterglow.effects.oscillators/sine :interval :phrase)
Sine Phrase Oscillator

Square Oscillators

Square waves are good for abrupt transitions, like strobes, or switching between different effects.

(afterglow.effects.oscillators/square)

Returns an oscillator which generates a square wave relative to the phase of the current beat. At the start of the beat, the value will be 1.0. At the midpoint, it will instantly drop to 0.0, where it will stay until the end of the beat.

Square Beat Oscillator

You can change the nature of the wave by using optional keyword parameters, and the values you use with them can be be dynamic parameters:

Parameter Default Purpose

:width

0.5

Determines the phase at which the value changes from 1.0 to 0.0, and therefore the width of the 1.0 pulse

:interval

:beat

Change whether the oscillator cycles over each beat, bar, or phrase, by passing in the keyword :beat, :bar, or :phrase. There are graphs showing the other intervals below.

:interval-ratio

1

Runs the oscillator at the specified multiple or fraction of the interval (beat, bar, or phrase).

:phase

0.0

Offsets the oscillator from the beat by the specified amount

The effects of the :interval-ratio and :phase parameters are discussed in more depth, and illustrated with graphs, in the documentation for the Sawtooth oscillator. You can jump to those sections using the links in the Purpose section of the table.

Pulse Widths

As shown in the above graph, the square oscillator normally spends half its time in the “on” state (at the value one), and half its time “off” (at zero). You can adjust that by passing a value between 0.0 and 1.0 with the optional keyword argument :width. This tells the oscillator what fraction of the time to be on. For example, with the value 0.8, it is on 4/5 of the time:

(afterglow.effects.oscillators/square :width 0.8)
Square Oscillator with Width 0.8

Alternately, using a :width of 0.1 causes the oscillator to be on for only one tenth of each beat:

(afterglow.effects.oscillators/square :width 0.1)
Square Oscillator with Width 0.1

You can shift where within the beat the transitions take place using the :phase argument, as with all oscillators, in the manner described above.

The :width value must be greater than 0 and less than 1, or the oscillator does not oscillate at all. A value of 0 leaves it permanently off, and a value of 1 leaves it permanently on. Values outside that range are not accepted.

As noted in the table above, to have the oscillator work with intervals other than beats, you use the optional keyword argument :interval. For example to have the wave spread over each bar:

(afterglow.effects.oscillators/square :interval :bar)
Square Bar Oscillator

And to have it oscillate over each phrase:

(afterglow.effects.oscillators/square :interval :phrase)
Square Phrase Oscillator

Custom Oscillators

You can build your own oscillator with any shape waveform that you like by defining a shape function for it, and let Afterglow do all the hard work of hosting it within the oscillator framework by passing that shape function to afterglow.effects.oscillators/build-oscillator. All of the oscillators you have seen so far use this approach, and you can see how simple they actually are by looking at the source of one, for example triangle, which defines a the triangle wave oscillator. (Click on the view source button at the bottom of the linked documentation.)

As you will see, most of the function consists of its documentation, and its argument declaration, and those simply get passed on to build-oscillator, which supports the :interval, :interval-ratio, and :phase arguments you’ve seen in all the oscillator functions. The core of triangle is setting up its shape function to create the triangle wave which makes it a triangle oscillator.

Shape Functions

The shape function is the first argument to build-oscillator, and it is simply a function which is given the current phase of the oscillator, ranging from 0.0 to 1.0, and must return the value of the oscillator’s wave form when it is at that phase of oscillation. In the case of a triangle wave, it needs to ramp up from 0 to 1 during the first half of the oscillation (as the phase grows from 0 to 0.5), then back down to 0 during the second half. Here is how triangle implements that:

(fn [phase]
  (if (< phase 0.5)
    (* phase 2.0)
    (- 2.0 (* phase 2.0))))

The arguments to triangle are then passed along to build-oscillator after the phase function, and the result is the triangle oscillator behavior you can use in your shows.

Hopefully examining this example, as well as the source of the other oscillators, can inspire you to create your own interesting oscillator shapes.