🎵

Rustで音響プログラミング - PCM音源の生成

2023/03/24に公開

はじめに

この記事ではRust言語を用いてWAVファイルを音響合成するプログラムを紹介するとともに、PCM音源の基本的な構造を解説します。
筆者はWindows上のRustを用いていますが、MacやLinuxでも同じように動くのではないかと思います。
この記事制作時の環境は以下です。

  • Windows
  • Rust 2018

PCM音源とは

PCM音源は音のアナログ信号をPulse Code Modulation(パルス符号変調)によりデジタルデータ化したもので、ファイル形式としてはWAVやAIFFといった形式が有名です。

簡単にPCMについて説明します。PCMでは以下のステップでアナログ信号をデジタル化します。

  1. 標本化
  2. 量子化
  3. 符号化

まず、標本化ではアナログ信号のある瞬間の値を取得します。これをサンプリングと言います。その後、量子化で先ほど取得した値を数値に置き換え、さらにそれを符号化で0と1のデジタルデータで表現します。
最終的に0と1のバイナリデータとしてアナログ信号を表現することができます。

RustでWAVを作る

RustでWAVを作る方法は簡単で、既にクレートがあるので今回はそれを使いましょう。

use wav::BitDepth;
use wav::Header;
use wav::WavWriter;

fn main() {
    // サンプリング周波数、ビット深度、チャンネル数を設定
    let sample_rate = 44100; // Hz
    let bit_depth = BitDepth::Sixteen;
    let channels = 1; // モノラル

    // 1秒間のsin波を生成
    let duration = 1.0; // 秒
    let frequency = 440.0; // Hz
    let amplitude = i16::MAX as f32;
    let num_samples = (duration * sample_rate as f32) as usize;
    let mut samples = Vec::with_capacity(num_samples);
    for i in 0..num_samples {
        let t = i as f32 / sample_rate as f32;
        let sample = (amplitude * (2.0 * std::f32::consts::PI * frequency * t).sin()) as i16;
        samples.push(sample);
    }

    // WAVファイルに書き込み
    let header = Header::new(channels as u16, sample_rate as u32, bit_depth);
    let mut writer = WavWriter::create("output.wav", header).unwrap();
    writer.write_samples(&samples).unwrap();
}

このコードではoutput.wavとして、Sin関数を計算してsin波をwavにかきこんでいます。再生してみると、温かみのある純音が聞こえると思います。

Discussion