人生を豊かにする上で欠かせないのが音楽ですが、現代の音楽制作に欠かせないのがシンセサイザーです。今回は、音楽データのデジタル表現の方法を確認した後、サウンドフォント形式に対応したシンセを作ってみましょう。

  • ピアノの演奏を行うWAVファイルを生成したところ

音楽データのデジタル表現

音楽データと聞いて思い浮かぶのは下記のような波形データではないでしょうか。ミュージシャンのレコーディング風景に必ず映っているのが、次のような波形データです。この波形データとは一体何なのでしょうか。

  • 音楽データと言えばこんな感じの波形

そもそも、音というのは空気の振動です。湖に石を落とすと、落とした場所を中心に波紋が広がりますが、それと同じように、音は空気を振動させて音源を中心に周囲へと波が伝えるのです。

それで、コンピューターで音を扱うためには、空気の振動(アナログ情報)をデジタル化(数値化)する必要があります。空気の信号をデジタル化するには、波を一定の時間間隔で区切り、その時間ごとの波の圧力(音圧)を測定します。それで、よく見る波形データは、横軸(X座標)が時間であり、縦軸(Y座標)が音圧となっています。

  • コンピューターで音を扱うには空気の振動をデジタル化する

音楽CDは1秒間に44,100回分の情報を記録しており、サンプリング周波数は44,100Hzとなります。これに対して、旧来の電話では1秒間に8,000回程度の情報を記録しており、サンプリング周波数は8,000Hzとなります。つまり、サンプリング周波数が大きいほど、それだけ滑らかで高音質となります。

Rustで簡単なサイン波のWAVファイルを作成しよう

それでは、音のデジタル表現について分かったところで、RustでWAVファイルを作成してみましょう。Rustのパッケージ(クレート)を集約したcrates.ioには、WAVファイルを手軽に扱うためのものが複数用意されています。今回は、手軽にWAVファイルを生成できるwav_ioを利用してみます。

ターミナルを起動して、以下のcargoコマンドを実行しましょう。cargoコマンドは、Rustのビルドシステムであり、パッケージマネージャーです。

# プロジェクトを作成
$ cargo init
# wav_ioをプロジェクトに追加
$ cargo add wav_io

すると、プロジェクトのひな形が作成されるので、src/main.rsというファイルが作成されます。そこで、このファイルを開いて次のように書き換えてみましょう。

以下のプログラムは、最もシンプルなサイン派と呼ばれる音(プーという感じの音)をプログラムで生成して「sine.wav」というWAVファイルに書き出すものです。

use wav_io;
use std::f32::consts::PI;

fn main() {
    // ここで作成する波形の設定 ---- (*1)
    let sample_rate = 44_100; // サンプリング周波数(CD音質)を指定
    let tone = 440.0; // 周波数(Hz) A(ラ)の音
    let volume = 0.6; // 音量(0-1)
    // WAVファイルのヘッダを生成 --- (*2)
    let mut wav_head = wav_io::new_mono_header();
    wav_head.sample_rate = sample_rate; // サンプリング周波数を設定
    // WAVデータを作成する --- (*3)
    let sample_len = (sample_rate * 2) as usize; // 2秒間のデータを作成
    let mut samples: Vec<f32> = vec![];
    for i in 0..sample_len {
        let c = i as f32 / sample_rate as f32;
        let v = (c * tone * 2.0 * PI).sin() * volume;
        samples.push(v);
    }
    // ファイルへ保存 --- (*4)
    let mut wav_out = std::fs::File::create("./sine.wav").unwrap();
    wav_io::write_to_file(&mut wav_out, &wav_head, &samples).unwrap();
}

最初にプログラムを実行してみましょう。ターミナル上で、以下のコマンドを実行します。すると「sine.wav」というWAVファイルが作成されます。

$ cargo run

Windowsならメディアプレーヤー、macOSならQuicktimeプレイヤーで再生するとプーっというサイン波が2秒再生されます。

なお、Audacityなどの波形編集ツールをインストールすると、具体的な波形を確認できます。作成したWAVファイル「sine.wav」を開いて波形を確認してみると、次の画像のように綺麗な波の波形となります。このように一定周期で繰り返すことで、安定した音階を奏でることができます。

  • 作成されたsine.wavを再生しているところ

プログラムを確認してみましょう。(*1)ではサンプリング周波数を指定します。ここでは、CD音質の44,100Hzを指定しました。また、サイン波の周波数を440.0Hzとしていますので、ラの音が書き込まれます。ここを、523.251などと変更すると、少し上のドの音になります。

(*2)ではWAVファイルのヘッダを生成します。そして、(*1)で指定したサンプリング周波数である44,100Hzを指定します。

(*3)では2秒分のサイン波を生成します。44,100Hzとはつまり1秒間に44100個のデータがあることで、2秒分なら44100*2=88200個のデータを指定することになります。なお、WAVファイルのデータには、実数(f32型)で-1.0から1.0までのデータを与えます。ここでは、f32型のsinメソッドを利用してサイン波を作成しています。

そして、(*4)でファイルへ保存します。wav_ioクレートの、write_to_file関数を使う事で、作成した波形をWAV形式でファイルに保存できます。

サウンドフォントをダウンロードしよう

ところで、プーとかポートかシンプルな音を鳴らすだけでは面白くありません。せっかくなので、ピアノやギターなどの音を鳴らしてみたいものです。今回は、伝統的なシンセサイザーの音源データであるサウンドフォント(SoundFont)を利用して、ピアノを演奏するシンセを作ってみましょう。

なお、サウンドフォントを使ってWAVファイルを作成する場合も、サイン波を計算して書き込んでいた部分、上記のプログラムで言えば(*3)の部分を、サウンドフォントを使った波形計算に変えるだけです。

インターネット上では、さまざまなサウンドフォントが配布されています。「SoundFont」あるいは「sf2/sf3」などで検索してみましょう。今回は、オープンソースのシンセデータであり、6MBという小サイズのサウンドフォント「TimGM6mb.sf2」をこちらからダウンロードして使ってみましょう。ちなみに、サウンドフォントについては、こちらに入手可能サイトの一覧がまとまっています。

RustySynthでサウンドフォントを操ろう

サウンドフォントの扱いは、それなりに大変ですが、今回は、RustySynthというクレートを利用してみましょう。ターミナルで以下のコマンドを実行して、プロジェクトを作成し、必要なクレートをインストールしましょう。

# プロジェクトを作成
$ cargo init
# クレートを追加
$ cargo add rustysynth
$ cargo add wav_io

次に「src/main.rs」を開いて、次のプログラムを記述しましょう。これは、ドミソの和音と、レファラの和音をピアノで演奏するWAVファイルを作成するプログラムです。こちらにプログラムをアップしてあります。

use std::fs::File;

この記事は
Members+会員の方のみ御覧いただけます

ログイン/無料会員登録

会員サービスの詳細はこちら