Skip to main content

Module audio_player

Module audio_player 

Source
Available on target_os=none only.
Expand description

A device abstraction for playing audio clips over I²S hardware, with runtime sequencing and volume control.

This page provides the primary documentation for generated audio player types and clip utilities.

Audio clip sample data is defined at compile time as static values. At runtime, you select which clips to play and in what order. Playback runs in the background while the application does other work. Volume can be adjusted on the fly, and playback can be stopped or interrupted mid-clip. Audio samples are stored in flash. Only a small DMA buffer is used at runtime.

Supported audio formats

  • Any sample rate
  • 16-bit signed little-endian PCM audio data (s16le)
  • Mono input audio (duplicated to left/right on I²S output)

After reading the examples below, see also:

§Example: Play “Mary Had a Little Lamb” (Phrase) Once

This example plays the opening phrase (E D C D E E E) and then stops.

use device_envoy::{Result, audio_player::{AtEnd, Volume, audio_player, samples_ms, VOICE_22050_HZ}};

// Generate `AudioPlayer8`, a struct type with the specified configuration.
audio_player! {
    AudioPlayer8 {
        data_pin: PIN_8,
        bit_clock_pin: PIN_9,
        word_select_pin: PIN_10,
        sample_rate_hz: VOICE_22050_HZ, // Convenience constant for this example; any hardware-supported sample rate can be used.
        max_volume: Volume::percent(50),
    }
}

async fn example(spawner: embassy_executor::Spawner) -> Result<Infallible> {
    // Define REST_MS as a static clip of silence, 80 milliseconds long.
    static REST_MS: samples_ms! { AudioPlayer8, 80 } = AudioPlayer8::silence();
    // Define each note as a static clip of a sine wave at the appropriate frequency, 220 ms long.
    static NOTE_E4: samples_ms! { AudioPlayer8, 220 } = AudioPlayer8::tone(330);
    static NOTE_D4: samples_ms! { AudioPlayer8, 220 } = AudioPlayer8::tone(294);
    static NOTE_C4: samples_ms! { AudioPlayer8, 220 } = AudioPlayer8::tone(262);

    let p = embassy_rp::init(Default::default());
    // Create an `AudioPlayer8` instance with the specified pins and resources.
    let audio_player8 = AudioPlayer8::new(p.PIN_8, p.PIN_9, p.PIN_10, p.PIO0, p.DMA_CH0, spawner)?;

    audio_player8.play(
        [
            &NOTE_E4, &REST_MS,
            &NOTE_D4, &REST_MS,
            &NOTE_C4, &REST_MS,
            &NOTE_D4, &REST_MS,
            &NOTE_E4, &REST_MS,
            &NOTE_E4, &REST_MS,
            &NOTE_E4,
        ],
        AtEnd::Stop,
    );

    // Audio plays in the background while we can do other things here, like blink an LED or read a button.

    core::future::pending().await // run forever

}

§Example: Compiling in an External Audio Clip and Runtime Volume Changes

This example shows how to “compile in” an audio clip from an external file, adjust its loudness at compile time, and then play it in a loop while changing the volume while it plays. This also demonstrates how to stop playback and reset the volume.

use device_envoy::{
    Result,
    audio_player::{
        AtEnd, Gain, Volume, audio_clip, audio_player, samples_ms, VOICE_22050_HZ,
    },
    button::{Button, PressedTo},
};
use embassy_futures::select::{Either, select};
use embassy_time::{Duration, Timer};

audio_player! {
    AudioPlayer10 {
        data_pin: PIN_8,
        bit_clock_pin: PIN_9,
        word_select_pin: PIN_10,
        sample_rate_hz: VOICE_22050_HZ,
        pio: PIO0,                             // optional, defaults to PIO0
        dma: DMA_CH1,                          // optional, defaults to DMA_CH0
        max_clips: 8,                          // optional, defaults to 16
        max_volume: Volume::spinal_tap(11),    // optional, defaults to Volume::MAX
        initial_volume: Volume::spinal_tap(5), // optional, defaults to Volume::MAX
    }
}

// Define a `const` function that, if called, will return the audio from this file.
audio_clip! {
    Nasa {
        sample_rate_hz: VOICE_22050_HZ,  // To avoid a compiler error, this must match the player sample rate.
        file: concat!(env!("CARGO_MANIFEST_DIR"), "/examples/data/audio/nasa_22k.s16"),
    }
}

async fn example(spawner: embassy_executor::Spawner) -> Result<Infallible> {
    // After lower its loudness (at compile time), materialize the clip as a static value.
    static NASA: Nasa::AudioClip = Nasa::audio_clip().with_gain(Gain::percent(25));
    static GAP: samples_ms! { AudioPlayer10, 80 } = AudioPlayer10::silence();

    let p = embassy_rp::init(Default::default());
    let mut button = Button::new(p.PIN_13, PressedTo::Ground);
    let audio_player10 =
        AudioPlayer10::new(p.PIN_8, p.PIN_9, p.PIN_10, p.PIO0, p.DMA_CH1, spawner)?;

    const VOLUME_STEPS_PERCENT: [u8; 7] = [50, 25, 12, 6, 3, 1, 0];

    loop {
        // Wait for user input before starting.
        button.wait_for_press().await;

        // Start playing the NASA clip, over and over.
        audio_player10.play([&NASA, &GAP], AtEnd::Loop);

        // Lower runtime volume over time, unless the button is pressed.
        for volume_percent in VOLUME_STEPS_PERCENT {
            match select(
                button.wait_for_press(),
                Timer::after(Duration::from_secs(1)),
            )
            .await
            {
                Either::First(()) => {
                    // Button pressed: leave inner loop.
                    break;
                }
                Either::Second(()) => {
                    // Timer elapsed: lower volume and keep looping.
                    audio_player10.set_volume(Volume::percent(volume_percent));
                }
            }
        }
        audio_player10.stop();
        audio_player10.set_volume(AudioPlayer10::INITIAL_VOLUME);

    }

    core::future::pending().await // run forever
}

Modules§

audio_clip_generated
Module containing AudioClipGenerated, the sample module generated by the audio_clip! macro.
audio_player_generated
Module containing AudioPlayerGenerated, the sample struct type generated by the audio_player! macro.

Macros§

audio_clip
Macro to “compile in” an audio clip from an external file (includes syntax details). See AudioClipGenerated for a sample of generated items.
audio_player
Macro to generate an audio player struct type (includes syntax details). See AudioPlayerGenerated for a sample of a generated type.
samples_ms
Macro that expands to an AudioClipBuf type sized from a player type and milliseconds.

Structs§

AudioClip
Unsized view of static audio clip data. &AudioClip values of different lengths can be sequenced together.
Gain
Relative loudness adjustment for audio clips.
Volume
Absolute playback loudness setting for the whole player.

Enums§

AtEnd
End-of-sequence behavior for playback.
AudioFormat
Audio clip source formats for audio_clip!. Currently, only one format is supported.

Constants§

CD_44100_HZ
Compact-disc sample rate.
NARROWBAND_8000_HZ
Common audio sample-rate constants in hertz. Narrowband telephony sample rate.
PRO_48000_HZ
Pro-audio sample rate.
VOICE_16000_HZ
Wideband voice sample rate.
VOICE_22050_HZ
Common low-memory voice/music sample rate.

Type Aliases§

AudioClipBuf
Sized, const-friendly storage for static audio clip data.