Early days: oxframe is under very active development. The API is not stable yet and may change from version to version. Pin the exact version in your Cargo.toml and check the changelog before upgrading.

12. Sound and voice

Sounds start on the frame where the scene starts them, so they stay in sync when the timing changes.

Loading live preview…

Source of learn_12_sound — edit in the playground
//! Lesson 12 — Sound and voice.
//!
//! A sound starts at the frame where the scene starts it, so it stays in
//! sync when you change the timing. A soundtrack plays under the whole
//! project and ducks when a voice speaks.

use oxframe::prelude::*;

fn asset(name: &str) -> String {
    format!("{}/assets/{name}", env!("CARGO_MANIFEST_DIR"))
}

#[oxframe::scene]
pub async fn sound_lesson(view: View) {
    let dot = view.add(Circle::new().size(24.0).fill(Accent));

    // A click on the beat: start it, then animate.
    sound(asset("click.wav")).trim(0.0, 0.18).play();
    dot.size().to(140.0, 0.2).await;
    dot.size().to(24.0, 0.3).await;

    // A spoken line. Without a speech provider its length is estimated,
    // which is enough to time the picture to it.
    let line = voice("Sound follows the picture").start();
    line.at_word("follows").await;
    dot.size().to(200.0, 0.3).await;
    line.await;
}

// Try: move the second `dot.size()` before `line.at_word(..)`.

pub fn project() -> Project {
    Project::new("sound")
        .audio(
            Audio::track(asset("tone.wav"))
                .volume(0.4)
                .duck_under_voice(),
        )
        .scene(sound_lesson())
}

A sound on the beat

sound("assets/click.wav").play() starts the file at the current frame. .trim(0.0, 0.18) plays only part of it and .volume(..) sets its level. Put the call right before the animation it belongs to: if you add a pause earlier in the scene, the click moves with the picture.

A soundtrack under everything

Project::audio(Audio::track("assets/music.mp3")) plays under the whole project. .duck_under_voice() makes it quieter while someone speaks.

A spoken line

voice("Sound follows the picture").start() starts a line and returns a handle. line.at_word("follows").await waits for that word, and line.await waits for the end. Without a speech provider oxframe estimates how long the line takes, which is enough to time the picture; Rendering shows how to plug in a real voice.