/ Examples / Control / Box2D

Projects .. AudioIO .. Control
NoteStreams .. Instruments
Filters .. Effects .. LiCK Effects
Plot .. Utility .. Pure ChucK


Wherein we explore the use of classical mechanics to generate control events for use in your musical compositions.

Right-click to copy these examples to your workspace.

Setting the Stage

Physical simulation engines have played an important role in science and entertainment for as long as there have been computers. The Box2D node builds atop the DbBox2D chugin and the Box2D engine to bring the power of physical simulation to your music compositional fingertips.

Imagine assigning a musical role to each of these bouncing shapes. Let's say we trigger a note when a yellow square hits a blue circle. Next, when a note is triggered, perhaps we could assign a note frequency according to its current rotation. The velocity of the particle at the point of contact could control, for example, the volume of note. We could also place the sound in the stereo field according to its location in space. The options are nearly limitless.

To give you an idea of what would this might sound like:

A Recipe for success or disaster

  1. Create a Box2D node and choose parameters:
    • assign a worldbuilder script. Re-use one or develop your own.
    • define the collision behaviors.
    • sample other physical aspects of your world to produce CCs.
    • enable visualization via the Plot parameter.
  2. Connect the Box2D node to instruments and effects.
    • values can be renamed and remapped to match your target.

So the key takeaway for simulations is:

Running a simulation doesn't intrinsically or automatically produce any sound. Rather, you must design responses to simulation steps and collisions and then route these events into instruments and effects.

Testbed Example

Here is the graph we used to make the intro movie for this example.

As you see, only two nodes are required to get simulatin'. The Box2D node controls the parameters of our simulation and the TimeKeeper node merely establishes the time duration over which to operate. The most important parameter of the Box2D is WorldGen and specifies the name of an external world-builder script (more details below). In this example we've used tumbler.ck which contains world-construction code slightly more elaborate than this:

DbBox2D b;
#(0, 50) => complex center;
#(50, 50) => complex size;
b.worldBegin(#(0, -10)); // gravity is down
b.newRoom(center, size, 5.0, b.dynamicType) => int roomId;
b.newRectangle(#(0, 20), #(.5, .5),
    Math.random2f(0, pi), 1., b.dynamicType) => id;
b.worldEnd();

The important worldbuilding take-aways are:

Mobile example

The Mobile example models a wind-chime. Here's the node-graph:

As you'd expect, when two bars collide they produce a note that is performed by the Stk TubeBell instrument.

On Contact

Notice that each chime produces a consistent pitch. This assignment of rectangle to note is the responsibility of the OnContact mode and ruleset. As mentioned previously, each simulated contact involves two bodies. As we see above, the id of each chime is present in the plot and their values range between 1 and 15. These ids are used as indexes into the OnContact ruleset. For example, body 4 can be seen to produce MIDI note 92. When more bodies are present than the number of rules in the ruleset we recycle them "circularly". So with these 5 rules, bodies 0, 5, 10, 15 all produce MIDI note 50. Bodies 1, 6, 11, 16 produce 85 and so on. A note request of -1 signals Box2D to prevent note events for the associated body.

ContactMode allows you to choose how to apply the OnContact ruleset:

On Notes

Upon construction, our mobile has enough internal energy to produce a number of collisions. Soon thereafter things settle down, the simulation stabilizes and we may wish to "kick" some energy back into the system. This explains the presence of the Euclid node in this graph. Euclid's role is to produce a rhythmic assortment of NoteOn/NoteOff events. These trigger evaluation of Box2D's OnNotes ruleset.

So when Euclid produces a note 60 event, the effect is that body 14 will receive an impulse of energy in the X direction. Similarly note 61 kicks body 5 by -20 in X. The units of force are Newtons and the effects of an impulse depend upon the size and density of a body. Typical values for an impulse kick range from 10 to 100 newtons. When you play with this example, locate the Box2D plot and try to identify when kicks occur. See how the effect changes with kick sizes of 200 and 2. Note that the note velocity contributes to the strength of the impulse. Changing Euclid's note-velocity range can have a big impact on the simulation.

For our mobile, a horizontal kick is easy to understand and produces a predictable result. In more complex scenarios it's often desirable to specify impulse directions dynamically. ImpulseMode offers two options: Static which applies the impulse in the X, Y directions given and Velocity which applies the impulse in the direction of the body's current velocity scaled by the magnitude of given values. If you need more precise control over your kicks, you can program an EventHandler to kick bodies around wantonly.

Pendulum Example

So far our focus has been contact, or collision, events. Many interesting simulations may involve no collisions an this raises the question of how to leverage these conditions toward our music-making endeavors.

Let's consider a simple double-pendulum for this discussion. Start by imagining the sound of a pendulum in a cartoon world. The question is, how can we realize the imagined sound?

One observation is that pendula have a characteristic motion. In physics, motion is characterized by velocity and acceleration and these properties have an instantaneous direction and amplitude. If we can periodically sample the motion of bodies in our simulation we could convert these samples into control signals for arbitrary use.

On Step

The On Step ruleset allows us to generate CCs associated with the dynamic state of bodies in the 2D simulated world. This ruleset is evaluated after each simulation step and the resulting CCs are delivered via the Ctrl1 output port (Ctrl0 emits NoteOn events).

Here we see 4 rules that sample properties of bodies 3 and 4 in our pendulum scene. The tooltip for OnStep reveals this list of available fields:

Referring to the pendulum node graph, we see that the Box2D.Ctrl1 is routed to both CCPlot and CCRelayer. Note, too, that there are some Remapper nodes assisting Box2D.

We leave it as an exercise to the reader to explore this graph to learn how all the pieces fit together. The following plot (produced by th CCPlot node) is quite helpful in understanding the role and remapped ranges of CCs in this scene.

Right-click to copy these examples to your workspace.

Box2D Node

Controller input port for control. Typically you might connect a TimeKeeper here to signal end of simulation.

WorldGen the name of a world-generator script.

TimeStep the time step in seconds that the simulator sees as representing real-time. 16::ms is 60 fps and is a typical value used in game engines and other realtime applications.

TimeScale a multiplier for the time step. When > 1 you go into "slo-mo" mode. Values < 1 speed up the simulation but may also incroach upon the simulation time-budget and shouldn't generally be needed.

ContactMode one of BodyId, Cycle, Random, selects how to index into the OnContact array. If OnContact is empty this has no effect.

OnContact controls which notes to emit when Box2D contact occurs. Because contacts are very short-lived we don't emit NoteOff events. Rather you should select instruments with "pluck-like" behavior (ie: short-attack and long-ish decay, and no release requirements). The choice of the MIDI note depends on the ContactMode setting. Values represent fractional MIDI note numbers between 0 and 127. 60 is Middle C (aka C3) and adjacent integers represent a semitone. When set to -1 the note for that slot is held back. In all modes, all incoming object ids are modulo-ed by this array size to ensure successful lookup.

OnNotes you can "kick" the simulation by connecting Euclid or MidiCC to our Controller input. A kick is an instantaneous 2D force (impulse) applied to matching rules in this ruleset. The kick units are Newtons and their effect depends on the the mass of your shapes. Values from 10-100 are typical. Impulses can either be applied in an arbitrary direction or along the direction of current movement. This is controlled by ImpulseMode. For an additional dimension of control, the size of the impulse is multiplied by the incoming note velocity.

ImpulseMode selects the interpretation of the OnNote XKick, YKick values. When set to Static, impulses are applied in the direction of the Kick. When set to Velocity, impulses are applied in the current body direction and according to the magnitude of [XKick, YKick]. This approach allows you to easily switch between two modes.

OnStep describes which control events we generate on each simulation step. For each rule in this list we emit a CC for the field of the identified body. CC names are constructed by combining the field and body id, eg. Vmag3. You can remap CC values via Remap connections or CC names and values with the Relayer node.

Remap connect Remapper nodes here to modify the values of OnStep CCs.

Plot, PlotCtx requests that the simulation be delivered to the Box2D Plot surface.

Pause controls whether the simulation is paused.

Mute controls whether the simulation is muted. If not paused, the simulation continues to step but triggers no contact or step events.

See Also

Example Worlds

WorldBuilding with Box2D API

home .. topics .. interface .. reference .. examples .. tipjar