An installation in a gallery has a screen with a grid of slowly pulsing circles. When a visitor waves a hand near a sensor, the circles nearest the sensor brighten and one of them emits a short, high tone. The tone is not a musical note and not a sound effect in the game sense. It is a signal that something the visitor did was registered, and it needs to be short enough that a hundred waves in a minute do not turn the space into a beeping room.
This is the exact problem that blip sounds solve. A blip in the 50 to 80 millisecond range is long enough for the ear to register a pitch but short enough that it does not interfere with the next signal. It reads as digital, which fits the aesthetic of most interactive art, and it does not require the visitor to interpret any musical content. The blip is a signal and nothing more.
Processing is a natural fit for this kind of work because it was designed for exactly this purpose: bringing computation and interaction together for artists. Its Sound library gives enough synthesis capability for real-time blip generation, and its interaction model maps cleanly onto the sensor-driven triggers that installations use. This article covers both approaches to blips in Processing — real-time synthesis and pre-rendered playback — and the specific interaction patterns that make blips work in a space where the visitor's attention is on the visuals.
Why do blips fit interactive art better than other sound categories?
Interactive installations have three properties that make them different from games or apps, and each one favors blips over longer sounds.
The visitor's attention is on the visual. A visitor to an installation is looking at the screen or the projection, not at any interface. Sound that carries narrative content — a voice, a musical phrase, a notification — competes for attention in a way that distracts from the visual. A blip registers as feedback without competing, because there is nothing in a blip for the visitor to interpret.
The trigger rate is variable and unpredictable. A visitor might wave a hand once and then stand still for a minute. Two visitors might wave at the same time. Five might. A game sound design can assume a predictable sequence of events; an installation cannot. Sounds that are short stay out of each other's way when they overlap, and blips overlap cleanly because their spectral content is narrow.
The installation runs for hours. A gallery piece runs from morning to evening, and every sound it makes is heard by dozens of visitors and by the staff who are in the room all day. Sounds that are pleasant for the first hour become intolerable by the fourth, and short blips are more tolerable than longer sounds because the silence between them is longer.
The design implications of these three properties come together in the same direction. The blip should be short, tonally neutral, and quiet enough that the ambient noise of the space is louder than the silence between blips. The blip sound design guide covers the specific parameter ranges; the installation context adds the requirement that the blip's aesthetic should feel like it belongs to the piece rather than being borrowed from a consumer interface.
What does the Processing Sound library actually provide for real-time synthesis?
The processing.sound library is a wrapper
around the Beads audio library, and it exposes a small
set of classes that cover the common synthesis needs.
The classes that matter for blip generation are the
oscillators, the envelope generators, and the file
players.
| Class | Purpose | Relevance to blips |
|---|---|---|
SinOsc |
Sine wave oscillator | Cleanest blip, the default choice |
TriOsc |
Triangle wave oscillator | Brighter blip, more harmonic content |
Pulse |
Pulse wave oscillator | Retro/stylized blip |
Env |
Breakpoint envelope | Shapes the blip's short attack and decay |
ADSR |
Four-stage envelope | Alternative to Env, useful for varied triggers |
SoundFile |
WAV/MP3/OGG player | Loads pre-rendered blips from disk |
Amplitude |
Envelope follower | Analyzes an existing sound's level |
The two synthesis paths are different in how they
generate the sound. Real-time synthesis uses an
oscillator that runs continuously, and the envelope
gates its amplitude so it only produces output when a
blip is triggered. Pre-rendered playback uses a
SoundFile that plays a WAV or OGG file
that was created in advance.
Both approaches produce a blip that works in an installation. The choice between them comes down to three factors: how much the blip needs to vary between playbacks, how much CPU the installation has available, and whether the artist wants to work with pre-recorded source material or with synthesis parameters.
How do you generate a blip at runtime with SinOsc and an envelope?
The synthesis approach uses two objects that are created
once at startup: a SinOsc that runs
continuously, and an Env that gates its
output. The oscillator is never stopped — it runs for
the entire duration of the sketch — but its output is
multiplied by the envelope, which is at zero except
during the brief window when a blip is playing.
import processing.sound.*;
SinOsc osc;
Env blipEnv;
void setup() {
size(800, 600);
// Oscillator at 1200 Hz — a neutral blip pitch
osc = new SinOsc(this);
osc.freq(1200);
osc.amp(0); // Start silent; the envelope controls level
// Envelope: attack 3 ms, decay 60 ms
blipEnv = new Env(this);
}
void triggerBlip() {
// Env.ads(attack, decay, sustainLevel, releaseTime)
// sustainLevel 0 means the sound is gone after the decay
blipEnv.play(osc, 0.003, 0.060, 0.0, 0.0);
}
void draw() {
// Trigger a blip when the mouse is clicked
if (mousePressed) {
triggerBlip();
}
}
The Env.play() method takes four parameters:
attack time in seconds, decay time in seconds, sustain
level as a fraction of full amplitude, and release time
in seconds. For a blip, the sustain level is zero,
because the sound should end as the decay completes. The
release time only matters if the sustain level is
non-zero, which is why it can be set to zero here.
The envelope values that produce a clean blip are tight. The attack should be between 1 and 5 milliseconds; below that, the sound starts with a click; above that, the blip begins to feel soft and loses the digital character. The decay should be between 40 and 100 milliseconds. The specific values that work for a neutral blip are 3 milliseconds attack and 60 milliseconds decay, which produces a total duration of 63 milliseconds. This is the same range that the Web Audio blip tutorial recommends; the envelope classes differ between languages but the perceptual thresholds do not.
The oscillator frequency determines the character of the blip. The range from 800 to 2500 Hz produces a sound that reads as digital. Below 800 Hz, the blip sounds tonal. Above 2500 Hz, it becomes piercing on installation speakers, which are usually small and often have a resonance in that range. A neutral blip sits at around 1000 Hz, a confirmation at around 1400 Hz, and an alert at around 1800 Hz.
The oscillator's amplitude is set to zero at startup, and
the envelope controls the amplitude during playback. The
two are not in conflict because the envelope's
play() method takes over the amplitude for
the duration of the envelope and returns it to zero when
the envelope completes. Between blips, the oscillator is
still running, but its amplitude is zero, so nothing is
heard.
When should you load a pre-rendered blip instead of synthesizing one?
The synthesis approach has two limits that matter for installations. The first is that the envelope gate can only produce one sound character — the sine wave at a fixed frequency — and varying that character at runtime requires creating additional oscillators or changing the frequency between triggers. The second is that a running oscillator consumes CPU continuously, even between triggers, and on a low-powered installation machine that cost is not negligible.
The pre-rendered approach loads a WAV file that was created in a browser tool or a DAW, and plays it on trigger. The file contains the entire blip, including its envelope, so no synthesis is happening at runtime.
import processing.sound.*;
SoundFile[] blipFiles = new SoundFile[3];
int lastPlayed = -1;
void setup() {
size(800, 600);
blipFiles[0] = new SoundFile(this, "blip_neutral.wav");
blipFiles[1] = new SoundFile(this, "blip_confirm.wav");
blipFiles[2] = new SoundFile(this, "blip_alert.wav");
}
void triggerBlip(int index) {
SoundFile file = blipFiles[index];
// Randomize pitch slightly by resampling
float rate = 0.96 + random(0.08);
file.rate(rate);
// Slight gain variation
file.amp(0.7 + random(0.15));
file.play();
}
void draw() {
if (mousePressed && lastPlayed != 0) {
triggerBlip(0);
lastPlayed = 0;
} else if (!mousePressed) {
lastPlayed = -1;
}
}
The SoundFile.rate() method changes the
playback rate, which affects pitch and duration together
the way a tape machine does. For a blip in the 60 to 80
millisecond range, a rate between 0.96 and 1.04 produces
a variation that is audible as difference but not as a
different sound. The
variation system guide
covers the perceptual thresholds in detail.
The lastPlayed variable in the example is a
guard against the installation triggering the same blip
on every frame while the mouse is held down. In an
installation with a sensor trigger, this guard is even
more important, because sensor noise can produce
continuous triggering that would turn a blip into a
buzzing sound.
The pre-rendered approach is the right choice when the
installation needs several distinct blips with different
characters, when the machine is underpowered, or when
the artist wants to design the blips outside of
Processing using a tool that gives more control. The
free sound generator guide
covers the tools that produce the WAV files; the files
then drop into the Processing data folder
and load with a single line of code.
How do you map installation interaction to blip triggers without making the space noisy?
The hardest problem in an interactive installation is not generating the blip. It is deciding when a blip should play and when it should not. A sensor that fires on every reading produces a continuous stream of blips, and the installation becomes a machine that beeps at the visitor rather than a space the visitor can interact with.
The patterns that work for installation triggers are borrowed from interaction design, and each one solves a specific problem.
Cooldown timers. After a blip plays, a minimum time must pass before the same trigger can fire another blip. The minimum is usually 100 to 300 milliseconds for a blip, which is long enough that rapid triggering becomes a rapid series of distinct sounds rather than a continuous buzz. A cooldown of 200 milliseconds produces at most five blips per second, which is on the edge of what the ear can distinguish as separate events.
Threshold-based triggers. A sensor reading of 0.4 does not need to produce a blip any more than a reading of 0.42 does. The trigger fires when the reading crosses a threshold from below, not when the reading is above the threshold. This is a hysteresis pattern: fire on the rising edge, do not fire again until the reading drops below a lower threshold and rises again.
Interaction state. If the installation has multiple interaction modes, only one mode should be triggering blips at any given time. A visitor who is browsing a menu should not also be triggering sounds by moving through a sensor field. The mode determines which triggers are active, and the mode transitions themselves are quiet.
Global rate limiting. Even with all the above, a busy moment can produce more blips than the space can tolerate. A global counter that caps the total number of blips in the last second — say, at ten — provides a final ceiling. When the cap is reached, additional triggers are silently ignored until the second rolls over.
The specific values that work depend on the space, the audience, and the aesthetic of the piece. A busy festival installation can tolerate more blips per second than a quiet gallery piece. What matters is that the rates are set deliberately rather than by whatever the sensor happens to output, and that the code enforces them rather than relying on visitor behavior.
The UI sound design guide covers the broader set of patterns for interaction-driven sounds, including the distinction between sounds that respond to continuous input and sounds that respond to discrete events. For installations, the discrete-event pattern is almost always the right one, because continuous-input sounds become the buzzing problem that the cooldown patterns are designed to avoid.
What changes when the installation runs for hours or days?
A gallery installation is not a game session. It runs unattended for hours, days, or weeks. The audio system has to survive this without glitching, without consuming more CPU over time, and without producing sounds that become irritating after repeated exposure.
The three changes that matter most in practice are:
Sound file loading. The processing Sound
library loads files synchronously, which is fine at
startup but causes a stutter if it happens during
interaction. All SoundFile objects should be
created in setup(), and the code should not
attempt to load files from within draw() or
event handlers.
Garbage collection. Processing's memory
management is Java-based, and the garbage collector runs
periodically. The synthesis approach creates envelope
objects on every trigger, which adds to the GC pressure.
The pre-rendered approach reuses the same
SoundFile object, which does not add to GC
pressure because the object is created once. For a long-
running installation, the pre-rendered approach is more
stable from a memory perspective.
Frequency fatigue. A blip that sounds fine in a ten-minute test becomes irritating after four hours of exposure. The specific frequencies that cause fatigue fastest are above 2000 Hz, because the ear is most sensitive in that range and small speakers have a peak there. An installation that is going to run for hours should keep its blips in the 800 to 1500 Hz range, even if the piece's other sounds use higher frequencies for other purposes.
The other consideration specific to installations is volume. The blip should be audible in the space's ambient noise without being the loudest sound in the room. Ambient noise in a gallery is usually around 45 to 55 dB, and the blip should sit just above that, at around 55 to 65 dB at the visitor's typical distance from the speakers. A blip that is dramatically louder than the ambient noise will feel aggressive; a blip that is quieter than the ambient noise will be missed entirely. The playback environment guide covers the general considerations for matching a sound to its listening context; the installation case is similar but with a different noise floor.
The Blip sound library for installations is not a
specific package that the artist installs. It is the set
of blips that the artist creates and the code that
triggers them, both shaped by the specific requirements
of the installation. The two approaches covered here —
real-time synthesis with SinOsc and
pre-rendered playback with SoundFile — are
both valid, and the choice depends on whether the piece
needs variation at the level of the waveform or variation
at the level of the parameters.
For most interactive art pieces, the pre-rendered approach is the right one. The artist designs the blips in a browser tool or a DAW with more control than the Processing envelope class provides, exports them as WAV files, and writes simple code in Processing to load and play them. The result is a small number of files on disk and a few dozen lines of Processing code that turn the visitor's interaction into sound.
Generate Blip WAV Files for a Processing Sketch
Open the SfxMaker blip generator and create the
three blips that most installations need: a neutral
feedback blip, a confirmation blip, and an alert
blip. Export each as a WAV file, place them in the
sketch's data folder, and load them
with new SoundFile() in the sketch's
setup() function.