Playing live
By the end of this chapter, your kit plays live with the least delay your machine allows, and no clicks.
The project so far
The project from Recording on one machine, playing on another: the machine that plays, its library in the folder it shares with the machine that records, with the maps and kits as the chapters before left them. Only the configuration matters here:
mkdir kitchen-kit
cd kitchen-kit
subsample --init
recorder:
enabled: false
audio:
input: [3, 4]
audio_format: flac
bit_depth: 24
player:
midi_map: midi-map.yaml
watch_midi_map: true
enabled: true
virtual_midi_port: Subsample Virtual MIDI
audio:
channels: 4
library:
directory: /home/keanu/Sync/captures
max_memory_mb: 512
watch: true
similarity:
weight_timbre_onset: 2
detection:
release_threshold_db: 4
retrigger_threshold_db: 15
min_peak_db: -45
tempo:
bpm: 120
source: midi
osc:
enabled: true
receive_enabled: true
Where the delay comes from
Between your hitting a pad and hearing it, the sound is held up in four places:
- The MIDI message reaching Subsample, which is quick.
- Subsample choosing the sound, which is quick too, since the choice for each note is worked out ahead, whenever the library changes, rather than when the note arrives.
- One buffer's wait before the sound starts. Each note plays one buffer after it arrives, from the very frame it arrived on, so notes keep the spacing you played them with: two hits a few milliseconds apart stay that far apart rather than sounding together. It costs half a buffer on average, and one at most.
- The sound going out through the audio buffer to the interface, which is usually the largest part, and what you hear as a steady delay against a hardware instrument.
The last two are the ones to tune, and one setting tunes both.
The buffer
Subsample hands the interface its sound a buffer at a time, and the interface plays one buffer while Subsample fills the next. A smaller buffer means less waiting:
player:
audio:
buffer_frames: 128
player.audio.buffer_frames is how many frames of audio each buffer holds, a power of two, and a frame lasts one tick of the sample rate: 128 frames at 48 kHz is 2.7 ms. Left out, the system chooses. An interface that refuses the size you ask for gets its own instead, and Subsample logs an error saying so.
The delay on the way out is several buffers long, not one, so Subsample works it out for you: when the player starts, it logs a line such as PortAudio output latency: 8.0 ms. Tune against that line rather than your own sums, remembering that the wait before a note starts comes on top of it: up to one more buffer, 2.7 ms at 128 frames and 48 kHz.
Setting the machine up
How small a buffer your machine can keep filled depends on two of its settings as well as its speed. Set them before you tune, so that the buffer you settle on is the least the machine allows, not the least it allows as it happens to be set.
Real-time priority, on Linux. Subsample asks for it for the audio, and for the MIDI and OSC that bring its notes in, so that other programs cannot hold them up. Linux gives it only where it has been allowed, which on most machines it has not. When the player starts, it says which it got, as in Audio runs at real-time priority (70), so other programs cannot delay it. Where it got none, it says the audio runs at ordinary priority, and what to do: allow real-time priority to the audio group, and be in that group:
Example not checked: it is not run when this site is built.
echo '@audio - rtprio 95' | sudo tee -a /etc/security/limits.d/audio.conf
sudo usermod -aG audio "$USER"
Then log out and in again, since an account's limits are read as it logs in, and start Subsample to see the line change. On macOS, audio already runs at real-time priority, so there is nothing to do.
A power mode that does not save power. A CPU set to save power can make the audio drop out at small buffer sizes. When the player starts on a CPU set that way, it warns, and says what to change: on a Linux desktop, the power mode to Balanced or Performance; on a Mac, Low Power Mode off, in System Settings, under Battery.
Clicks, and stepping back
A buffer too small for your machine to keep filled runs dry, and the sound breaks up in clicks. Subsample notices, and warns, at most every few seconds:
Audio xrun: 3 output underflow(s) - buffer_frames=64 is too low for this machine to sustain; raise it if you hear clicks.
Where either setting above still costs the audio time, the warning goes on to name it, and putting that right may let the smaller buffer hold after all:
Also costing time on this machine: the CPU is set to save power.
So lower buffer_frames a power of two at a time, playing hard at each, until the warnings come or you hear clicks, and then step back up one. That is the least delay this machine allows.
A sequencer on the same machine
A sequencer on the same machine, playing Subsample through its MIDI port, keeps time as Subsample does, and the two compete for the machine. On a modern machine with several cores that is rarely a problem; on a smaller one, it can bring clicks, or timing that drifts. Stepping back works the other way from tuning: a larger buffer, in Subsample or in the sequencer, gives each more room.
The recorder is work too. The machine that plays in Recording on one machine, playing on another has it off already, and on a machine that records as well, turning it off with recorder.enabled while you play live makes the most room of all.
Loud passages
When many sounds play at once, they add up, and too many at full velocity would pass full scale and clip. Subsample plays each sound at a share of full level, so that a number of them at full velocity together only reach it:
player:
max_polyphony: 12
player.max_polyphony is that number. More sounds than that still play rather than being cut off, so raise it when dense passages clip, and lower it for louder single notes.
What still passes full scale meets the limiter at the end of the output, which rounds it off rather than clipping it hard. player.limiter_threshold_db is where it starts, in dBFS, and player.limiter_ceiling_db the highest level it lets through. A threshold of 0 turns it off.
That is the project whole: a kit cut from the sounds of one room, your own map choosing and shaping them, a keyboard played by one held note, a tapped rhythm kept on the beat, two kits played together or switched between, other software playing along, and all of it quick enough to play live.