Scoring an animation with Orca
In this post, I’ll demonstrate how to score an animation using Orca.
- What is Orca?
- The final score
- What is a score?
- Learning how to wait
- Wiring up sounds
- Timers in practice
- Conclusion
What is Orca?
Orca is an esoteric programming language for composing music. An Orca program is somewhere between a circuit diagram and an ASCII roguelike. But you don’t need to know either of those things to get started— in an interview with its creator Devine Lu Linvega of the programming duo Hundred Rabbits:
I was always kind of aiming, I guess, at children. I was like, if you can just open the page and put that in front of a kid, could they figure it out? It wouldn’t take that many keystrokes until they figure out which… like [the operator]
E
will start moving, and through the act of playing they’ll find their way without having to read the documentation.
Some resources to get started:
- Orca Sequencer Intro (Experimental Livecoding!) by Allieway Audio on YouTube: This is how I got interested in Orca. It’s an excellent introduction— jumps to the good stuff without getting lost in the details. Note: Some of the operators have changed since this video was made, but the core principles haven’t.
- Official Documentation
- Making a song in 1h: Beginning with a blank canvas, I try to learn Orca and make a tune in an hour.
The final score
The completed score, consisting of all the techniques described in this post.
Although it might seem complicated— especially if you’re not familiar with Orca— this program is actually the result of building on a few core ideas. As you read this, I hope it will feel like a natural progression to go from one step to the next.
Ok, now let’s start at the beginning.
What is a score?
Scoring an animation requires timing sounds to events on screen. For example, when a piece of glass shatters in the animation, there should be a crash sound. Let’s say this happens on frame 21. Using Orca, how do you play a sound on the 21st frame and then never again?
The answer to this was not obvious to me. Most Orca compositions, at the time
of writing this, consisted of loops. I could not find any examples that did
what I wanted. But since we have access to the clock frame using the C
operator, this feels like it should be possible.
Here’s one way to do it:
Learning how to wait
Note: Throughout this post, I will refer to hexadecimal numbers using the
prefix 0x
. For example, 0x10
is decimal 16.
Note 2: I will refer to the last digit in a hexadecimal number as the
“ones’ digit” and the second-to-last digit as the “sixteens’ digit.” For
example, 0x10
‘s ones’ digit is 0
and its sixteens’ digit is 1
.
Ok, let’s begin.
First, use a pair of hexadecimal clocks Cf
and fCf
:
- The frame count is at the bottom right, a monotonically increasing number.
Cf
mods the frame count by0xf
, or 16, to output the ones’ digit, a number from0x0
to0xe
.fCf
also divides the frame count by0xf
, or 16, to output the sixteens’ digit.
A hexadecimal clock in
Orca— written Cf
— that outputs an increasing number from 0x0
to
0xe
. Upon reaching 0xe
, it starts over from 0x0
. Also, a second clock
written fCf
that produces a similar output, but which increases at 1/16
the rate of the first clock.
Next, check the outputs using F
. The F
operator will output
a bang (*
) if their inputs on either side are equal.
There are now two `F`s. The first `F` compares the sixteens' digit and outputs a `*` if it is `1`. The second `F` checks if the ones' digit is `5`.
Finally, AND
the outputs of both the F
s into a single *
:
Y
, the ‘yumper’ operator, just copies the input horizontally.f
here is a lowercaseF
that only operates on a bang.
On frame 0x15
, the f
outputs a bang.
Note: If the f
were uppercase, it would incorrectly output a bang when
both inputs are empty (i.e. when neither ones’ nor sixteens’ digits matched.)
A `Y` carries the output of the sixteens' match to the right. A `f` compares both the outputs and bangs on frame 15 when both digits match.
At this point, I posted my timer to the Orca thread on lines, asking the community if there was a simpler way to do this. Devine responded, suggesting this condensed version that uses one fewer operator.
A rearranged version of the previous timer. Now, the ones' output is connected directly to the `f` (lowercase), skipping the `F` (uppercase) entirely.
Limitations
Here, it is important to note that this timer does not actually “bang once and
then never again” as originally promised. Since the timer only checks the ones’
and sixteens’ digits of the frame number, it will bang at 0x015
, 0x115
,
0x215
, …— every 0x100
or 256 frames. This ends up being about 25
seconds at 120 bpm.
My animation happens to be 15s long, so this was not a problem for me. If anyone finds an elegant solution to the original problem as stated, I’d love to see it.
Wiring up sounds
Now, the fun part. Use this timer to schedule different sounds.
Playing a note
This can be used to play a single midi note.
Like the previous video, but with a midi note (`:01a`) next to bang. It's triggered at frame `0x15`.
Toggling a loop
First, consider a simple drum loop.
A simple drum loop, consisting of a `D` wired up to a midi note (`:01a`).
Then, use an X
to set the note’s velocity, effectively turning the loop
on or off. Here, it sets the velocity to 0x7
.
It’s a bit silly to use X
to set a constant value like this, but it should
make sense in the next step.
The same drum loop, but there is now an `X` operator that sets the velocity of the midi note to `0x7`.
Finally, automate this using timers:
- The drum loop begins muted, its velocity
0x0
. - The first timer at frame
0x15
turns on the drum loop by setting its velocity to0xa
. - The second timer at frame
0x28
turns it off again by setting the velocity to0x0
.
There are two timers. Each activates a lowercase `x` operator to set the velocity as described.
Timing a sequence of notes
Play a sequence of notes by combining operators Z
and T
:
- The
Z
counts up from 1 to 5, exactly once. - This determines the note output by
T
. - The output of
T
is fed to:
, the midi operator.
The `Z` counts up from 1 to 5. This is fed to `T`, which chooses notes `a`, `b`, `c`, `d`, and a blank, in that order. The output of `T` is finally fed to a midi operator, which is powered by a `*` held down by `H`.
Use a timer to control when the sequence plays:
Z
starts at5
, unlike the previous example, so it doesn’t immediately play.- The timer fires at frame
0x15
to activatex
. x
sets theZ
back to 0 and causes it to play.
A timer fires at frame `0x15`, which activates the `x`, which sets the output of `Z` to `1`, causing it to restart. Then, the sequence plays a note as with the previous example.
Timers in practice
At this point, if you go back to the beginning and see the final composition, you may notice some differences from the examples. I omitted details to keep the examples small and easy to understand:
- Instead of repeating
fCf
andCf
, the sixteens’ and ones’ digits are stored in variablesa
andb
and read usingVa
andVb
, respectively. - I often use a timer triggered at frame
0x00
to reset the initial state of timed sequences or loops. This allows me to easily replay the composition from the beginning usingCtrl+R
.
Conclusion
Here’s the completed looping animation:
A hand reaches to water a plant but drops the cup, which shatters. The plant droops, the mug pieces rise and hover in the air above the plant, before falling into the pot which we now see contains a worm. The worm is sliced in half by a piece of mug, its worm blood spreading around the dirt, before gathering and traveling up the stalk of the plant. Zooming in, we see a new stem emerge. Its bud sprouts, revealing it has grown pieces of the same mug fragments. Zooming out all the way, we see the plant is standing up once again. It has an extra stem, which the hand plucks. A worm squirms out of the pot and offscreen, and the entire animation loops.
(If you want to see more of my art, please follow my instagram.)
This is only a small taste of what Orca’s capable of doing, but I hope it’s a fun read. If you notice any mistakes in this article or want to share feedback, please reach out. I’d like to do more of these in the future.