index

Rust 播放 WAV 檔與即時音量控制

· 3min

Conclusion

// 播放 WAV 檔與即時音量控制
use rodio::{Decoder, Player};
use std::fs::File;

fn main() {
    let handle =
        rodio::DeviceSinkBuilder::open_default_sink().expect("Error to open default audio stream");
    let file = File::open("test.wav").unwrap();
    let player = Player::connect_new(handle.mixer());
    let source = Decoder::try_from(file).unwrap();

    // handle.mixer().add(source);
    player.append(source);

    std::thread::sleep(std::time::Duration::from_secs(2));

    player.set_volume(0.5);
    std::thread::sleep(std::time::Duration::from_secs(2));

    player.set_volume(1.5);
    std::thread::sleep(std::time::Duration::from_secs(2));
}

Practice

載入外部套件

cargo add rodio
warning


注意不同版本在用法上有些差異,以最新版為主

Audio Sink

quote

an audio sink is essentially an audio output device or destination. It is a conceptual endpoint (like your physical speakers, headphones, or a Bluetooth headset) where your sound server sends digital audio to be converted into physical sound.

簡單來說,音訊出口為 sink,反之入口為 source。

rodio

要達成音訊播放在 rodio 上有幾個步驟:

  1. 找到系統實體播放裝置的 sink handle(OS-sink)(DeviceSinkBuilder::open_default_sink()
  2. 建立一個串流音訊的物件,例如 sine wave、buffer 或 Decoder
  3. 將 source 添加到 OS-sink handle( MixerDeviceSink::mixer()

Player

除了直接對接 handle 播放之外,如果想要有更多控制選項,可以透過 Player 來播放,像是更改音量大小:

    let handle =
        rodio::DeviceSinkBuilder::open_default_sink().expect("Error to open default audio stream");
    let file = File::open("test.wav").unwrap();
    let player = Player::connect_new(&handle.mixer());
    let source = Decoder::try_from(file).unwrap();

    // handle.mixer().add(source);
    player.append(source);

MixerDeviceSink

在作業系統的底層音訊架構(如 macOS CoreAudio 或 Linux PipeWire/ALSA)中,實體音效卡(physical device)通常同一個時間只能接收「一條」連續的音訊資料流。

如果你的程式同時要發出兩個獨立的聲音(例如一首歌 + 一個 SFX),硬體是沒辦法自動幫你把兩個檔案疊在一起的。這時候就需要 Mixer 介入。

接收多個音訊源(Sources),在記憶體中將同一個時間點的樣本數值以數學方式相加、處理潛在的取樣率轉換(Resampling),最後打包成「一條」主音軌送給硬體播放。

Associated Functions(關聯函數)

不隸屬於某個特定的實例,而是直接隸屬於型別(type)本身,不使用 self,常用來建構實例,以 :: 表示。

其他一般 function 加上 self 表示它本身需要一個具體物件才能動。

也就是說,:: 表示它與從設計圖開始建造物件有關,而 . 則用在已經建立的物件上

tip


另外在引入其他 crates 也有看到, :: 有表示路徑的意思


References