🎵
Rustで音響プログラミング - PCM音源の生成
はじめに
この記事ではRust言語を用いてWAVファイルを音響合成するプログラムを紹介するとともに、PCM音源の基本的な構造を解説します。
筆者はWindows上のRustを用いていますが、MacやLinuxでも同じように動くのではないかと思います。
この記事制作時の環境は以下です。
- Windows
- Rust 2018
PCM音源とは
PCM音源は音のアナログ信号をPulse Code Modulation(パルス符号変調)によりデジタルデータ化したもので、ファイル形式としてはWAVやAIFFといった形式が有名です。
簡単にPCMについて説明します。PCMでは以下のステップでアナログ信号をデジタル化します。
- 標本化
- 量子化
- 符号化
まず、標本化ではアナログ信号のある瞬間の値を取得します。これをサンプリングと言います。その後、量子化で先ほど取得した値を数値に置き換え、さらにそれを符号化で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