本記事では、RMSの理論的背景を簡潔に整理し、その理解のため、openFrameworksを使って音のRMSをリアルタイム音声入力から計算・可視化する方法をまとめます。フィールドレコーディングや音の視覚化・オーディオリアクティブのプロジェクトにも応用可能です。

1. RMS(Root Mean Square)とは?

RMS(Root Mean Square、二乗平均平方根)とは、変動する値の「平均的な大きさ(エネルギー量)」を表す指標です。主に物理や音響、電気工学、信号処理などの分野で使われます。

デジタル音声などで使用される離散データの場合は、以下の式で定義されます。

ここで、xi は各サンプル値、Nはサンプル数です。絶対値の平均よりも滑らかで、ピーク値よりも実際の音量感に近い値を得られるため、音響解析では広く使用されています。

単純な平均(平均値)は「正負がある波」ではゼロに近づいてしまうため、振幅の「実効的な大きさ」を表すためにRMSが使われます。
RMSは、以下のステップで求めます。

  1. 値を全て二乗する。
  2. 二乗値の平均を取る。
  3. 最後に平方根を取る

2. RMSをプログラム(openFrameworks)にて計算し理解する。

openFrameworksにて、次の通りの方法でRMSを計算します。

  • リアルタイム音声入力(マイク)を使うofSoundStream, ofSoundBuffer, audioIn を利用

リアルタイム音声入力からRMSを計算

マイクや外部入力音声からRMSを計算する場合、ofSoundStream, ofSoundBuffer, audioInを利用しRMS を計算します。以下、それぞれの役割。

  • ofSoundStream
    音声の入出力を管理するクラス。サンプリングレートやバッファサイズ、入力チャンネルなどを設定します。
  • ofSoundBuffer
    バッファに溜まった音データを保持・操作するクラス。今回はRMSを計算するため、バッファに溜まったデータを使用します。
  • audioIn(ofSoundBuffer & input)
    マイクから入ってきた音データをリアルタイムで受け取る関数。audioInはofBaseAppに定義されいる仮想関数。引数にて得られたofSoundBufferを受け分析処理を行います。

▸ 処理の流れ

  1. ofSoundStream で入力の設定。(bufferSize や Channles数など)
  2. ofSoundBufferにてサンプルを貯める。
  3. audioIn() にて ofSoundBuffer を使ってRMSのを行う。

コード例1:audioIn()でのRMS計算


void ofApp::audioIn(ofSoundBuffer & input){
    float sum = 0.0;
    int numCounted = 0;
    for (size_t i = 0; i < input.getNumFrames(); i++){
        float sample = input[i];
        sum += sample * sample;
        numCounted++;
    }
    sum = sqrt(sum / (float)numCounted);
    smoothedRms *= 0.93;
    smoothedRms += 0.07 * sum;
}

▸ コード例1 説明

1. 初期化

  • float sum = 0.0;
    各サンプルの二乗値を合計するための変数をゼロで初期化します。
  • int numCounted = 0;
    処理したサンプル数を数えるための変数をゼロで初期化します。

2. 全サンプルの処理

  • for (size_t i = 0; i < input.getNumFrames(); i++){ ... }
    入力された音声データ (input) のすべてのサンプルに対して、以下の処理を繰り返します。input.getNumFrames() は、現在入力されている音声データのサンプル数を取得します。
    補足: ここで言う "Frames" は、実際には個々の音声サンプルの数を意味します。リアルタイム処理では、ofSoundStream で設定したバッファサイズと完全に一致するとは限りません。そのため、ofSoundBuffer から実際に得られたサンプル数 (getNumFrames()) を使うことが重要です。
  • float sample = input[i];
    現在のサンプルの値を変数 sample に格納します。
  • sum += sample * sample;
    現在のサンプルの値を二乗し、それを sum 変数に加算します。これは、RMS (Root Mean Square: 二乗平均平方根) を計算する準備段階です。

3. RMS (Root Mean Square) の計算

  • sum = sqrt(sum / (float)numCounted);
    すべてのサンプルの二乗値の合計 (sum) を、処理したサンプル数 (numCounted) で割り、その結果の平方根を計算します。これが、現在の音声データの RMS 値となります。

4. RMS 値の平滑化

  • smoothedRms *= 0.93;:過去の平滑化された RMS 値 (smoothedRms) に 0.93 を掛け、過去の値を少し減衰させます。
  • smoothedRms += 0.07 * sum;:現在の RMS 値 (sum) に 0.07 を掛け、その結果を現在の smoothedRms に加算します。

この平滑化処理により、急激な音量の変化が緩和され、より滑らかな音量の変化として smoothedRms に反映されます。0.93 と 0.07 という係数は、平滑化の度合いを調整するための値です。

これは「指数移動平均(Exponential Moving Average, EMA)」によるスムージング処理になります。

  • smoothedRms は前回までの滑らかなRMS値
  • sum は今回のRMS計算結果

この2行は、最新値sumと、過去の値smoothedRmsを重み付けして「滑らかに追従する値」を作っています。

  • smoothedRms *= 0.93;
    → 過去の値を93%残す
  • smoothedRms += 0.07 * sum;
    → 今回の新しい値(sum)を7%だけ足す

    合計で100%になる(0.93 + 0.07 = 1.0)。

このようなスムージング処理は大きく変動する音量の見た目のガタ付きをスムーズにします。0.93/0.07のバランスを変えると「追従の速さ」が変わります。(0.07を大きくすると追従が速くなり、0.07を小さくするとより滑らか(反応が遅い)になります。)

コード例2 応用:audioIn()でのRMS計算(マルチチャンネル)


void ofApp::audioIn(ofSoundBuffer & input){
    float sum = 0.0;
    int numCounted = 0;
    int numChannels = input.getNumChannels();
    for (size_t i = 0; i < input.getNumFrames(); i++){
        for (int ch = 0; ch < numChannels; ch++) {
            float sample = input[i * numChannels + ch];
            sum += sample * sample;
            numCounted++;
        }
    }
    sum = sqrt(sum / (float)numCounted);
    smoothedRms *= 0.93;
    smoothedRms += 0.07 * sum;
}

▸ コード例2 説明

ステレオなど複数のチャンネルがある場合getNumChannels()にてチャンネル数をあてforで回します。

float sample = input[i * numChannels + ch];の配列は、ofSoundBufferの配列は[Left] [Right] [Left] [Right] ...といったインターリーブ形式(Interleaved)にて値が格納されているため配列にchとして0,1とそれぞれ加算します。これにより、0フレーム目がindex 0, 11フレーム目がindex 2, 32フレーム目がindex 4, 5...となります。

3. RMSの値の視覚化

この smoothedRmsdraw() 関数内で視覚化することで、リアルタイムな音の強さを直感的に表示できます。下記は円の大きさを音のRMSにて変化を加えます。


void ofApp::draw() {
    ofBackground(0);
    ofNoFill();
    ofSetColor(255);
    ofSetLineWidth(2);
    float radius = ofMap(smoothedRms, 0.0, 0.1, 0.0, 500.0, true) + 100;
    ofSetCircleResolution(100);
    ofDrawCircle(ofGetWidth()/2, ofGetHeight()/2, radius);
}

4. RMSの可視化方法

RMSはそのまま数値として出力するだけでなく、次のような視覚表現に応用できます

  • 音量バー
  • 時系列の折れ線グラフ
  • ヒートマップや波形へのオーバーレイ表示
  • インタラクティブな音の粒子表現など

RMS計算を応用し、以下のような拡張を進めます

  • 複数チャンネル(ステレオ/サラウンド)での比較
  • RMSの時間変化からエンベロープを描く
  • ピーク値やスペクトル解析との組み合わせ
  • 録音環境の自動評価やトリガー検出への応用

また、openFrameworksとMax/MSPやPure Dataなどのツールと連携することで、より複雑な音響インタラクションも構築できます。

5. RMS(Root Mean Square)

RMS(実効値)は、音の「強さ」を表現するための基本かつ重要な指標です。本記事では、RMSの理論的な背景から、openFrameworksによる実装、さらにその可視化までをまとめました。

その他の音響指標(ピーク値、ラウドネス、FFTなど)と組み合わせることで、より豊かな音の理解と視覚表現が可能になるます。

参考:openFrameworks公式サイト

BGD_SOUNDS on bandcamp

BGD_SOUNDSでは、アートワークで使用するために録音された様々な音を公開しています。ぜひフォローしてください。

Link / BGD_SOUNDS on bandcamp

安価で利用できる膨大な著作権フリーのサウンドライブラリーを目指し、定期的に音源ライブラリーを増やしています。音源のほとんどは、192kHzの32bitにて録音。音楽制作や映像制作など、それぞれの用途に合わせて利用できます。(メタデータも含まれています。)

BGD_CLUB(月額サブスクリプション)も始めました。低価格からすべてのライブラリーにアクセスし自由にダウンロードすることが可能です。