7.9.6. AUDIO-06 — Streaming Audio
This tutorial covers real-time PCM streaming — generating and feeding audio data in small chunks while it plays. It also introduces the collected audio system for long-running applications.
7.9.6.1. PCM Streaming
Previous tutorials used play_sound_from_pcm, which requires all
samples up front. play_sound_from_pcm_stream creates an open channel
that you feed incrementally with append_to_pcm. This is essential for:
Real-time synthesis (generating audio on the fly)
Network audio (receiving chunks over time)
Procedural music (composing while playing)
let sid = play_sound_from_pcm_stream(MA_SAMPLE_RATE, 1)
The returned sound ID is immediately valid — the audio engine starts reading from the stream as soon as data is available.
7.9.6.2. Generating Chunks
Feed audio by calling append_to_pcm repeatedly, passing the sound ID
and an array<float> of samples. Each chunk can be any size; the audio
engine buffers them internally. Maintain phase continuity between chunks
to avoid clicks at chunk boundaries:
var phase = 0.0
for (i in range(num_chunks)) {
let freq = 440.0
var samples <- [for (x in range(chunk_samples));
sin(phase + 2.0 * PI * freq * float(x) / float(MA_SAMPLE_RATE)) * 0.5
]
phase += 2.0 * PI * freq * float(chunk_samples) / float(MA_SAMPLE_RATE)
append_to_pcm(sid, samples)
sleep(uint(chunk_duration * 1000.0))
}
7.9.6.3. Frequency Sweep
The tutorial demonstrates streaming with a sine wave that sweeps from 220 Hz to 880 Hz over 3 seconds. The frequency is interpolated across 30 chunks of 100 ms each, and phase is accumulated so the waveform remains continuous:
let start_freq = 220.0
let end_freq = 880.0
for (i in range(num_chunks)) {
let t = float(i) / float(num_chunks)
let freq = start_freq + (end_freq - start_freq) * t
// ... generate chunk at `freq`, advance phase ...
append_to_pcm(sid, samples)
}
When the sweep is finished, stop(sid, 0.1) fades out and releases the
stream.
7.9.6.4. Collected Audio System
with_audio_system is the simplest way to initialise audio, but for
long-running applications (games, tools) where sounds are created and
destroyed over time, with_collected_audio_system adds garbage collection
for audio resources. When using it, call audio_system_collect
periodically to process deferred cleanup:
with_collected_audio_system() {
let sid = play_sound_from_pcm_stream(MA_SAMPLE_RATE, 1)
for (i in range(10)) {
var samples <- [for (x in range(chunk_samples));
sin(2.0 * PI * 440.0 * float(x) / float(MA_SAMPLE_RATE)) * 0.4
]
append_to_pcm(sid, samples)
audio_system_collect()
sleep(100u)
}
stop(sid, 0.1)
audio_system_collect()
}
7.9.6.5. Running the Tutorial
Run from the project root:
daslang.exe tutorials/dasAudio/06_streaming.das
The tutorial plays a 3-second frequency sweep (220 Hz to 880 Hz), printing the current frequency every 10 chunks, then demonstrates the collected audio system with a short ascending tone sequence.