GPDSP ライブラリ概要

GPDSP とは

GPDSP ライブラリは, 音響演算やセンサデータの信号処理などのデジタル信号処理を手軽に行うための C++ 言語で記述されたライブラリです. 増幅遅延加算などを表す任意のノードをソースコード上で接続することにより, デジタル信号処理のアルゴリズムを迅速に構築して実行することができます.

開発者はデジタル信号処理の計算順序やアルゴリズムの詳細を記述する必要はなく, GPDSP ライブラリがデータフローを適切に最適化します. 最適化はデジタル信号処理の実行中にも動的に行われるため, ノードの構成をダイナミックに変更しても最速となる計算順序を自動的に探索します.

また, gpdsp 形式の外部ファイルから XML で記述された任意のノード構成を読み込み, 1つのノードとして利用することができます. この機能を利用することにより, あらかじめ用意されたノードの動作以外にも, 任意の特性を持つノードを作成して実行することができるようになります.

推奨環境と開発環境

GPDSP ライブラリは POSIX 準拠の C++ 言語で記述され, ソースコードとして提供されます. RTTI (Run-Time Type Information) を有効にした C++ 言語を利用できる環境であれば, ワンチップマイコンなどの少資源な環境でも動作させることができます.

一方で, 複雑な多数のノード構成の演算にはマシンパワーが必要であるため, リアルタイムにデジタル信号処理を行う場合は十分なマシンパワーを持った環境が推奨されます.

推奨環境

  • C++ 11 (RTTI 有効)
  • ヒープ割り当て利用可能

開発環境

  • macOS High Sierra (10.13.3)
  • Xcode 9.2 (9C40b)
  • Apple LLVM version 9.0.0 (clang-900.0.39.2)
  • MacBook Pro (Retina, 13-inch, Late 2013)
  • 2.8 GHz Intel Core i7
  • 16 GB 1600 MHz DDR3
  • Intel Iris 1536 MB

ダウンロードとインストール

GPDSP ライブラリの最新版は, 以下のサイトからダウンロードすることができます.

http://github.com/toolbits/GPDSP

クローン, もしくは .zip ファイルでダウンロードしたファイルを任意の場所に解凍して配置します. 実際の開発で利用するライブラリは lib/GPDSP ディレクトリに含まれており, ソースコードレベルでリンクして利用します.

ディレクトリの構成

  • docs – doxygen により生成されたドキュメント
  • libGPDSP ライブラリ本体
  • mcss-doxygen – m.css フレームワーク用のドキュメントテンプレート
  • openFrameworks – openFrameworks を利用したサンプルコード
  • release – コンパイル済みのサンプルコード

利用方法

ダウンロードしたディレクトリに含まれる lib/GPDSP ディレクトリ以下のすべてのヘッダファイルとソースファイルを GPDSP ライブラリを利用したいプロジェクトに追加し, ソースコードから次のように読み込みます.

ヘッダファイルの読み込み

#include "GPDSP.hpp"

GPDSP ライブラリでは, 基本的には GPDSPNodeRenderer クラスを利用して, 各種ノードを生成したりノードを接続してデータフローを設計します.

各種ノードに固有の属性を設定するときは, GPDSPNodeRenderer クラスのインスタンスから各種ノードのインスタンスを取得して, ノードに固有の関数を呼び出します.

次に 100 バイトのデータに対して増幅率 2.0 のデジタル信号処理を行うプログラム例を示します.

GPDSP ライブラリを利用したプログラム例

#include "GPDSP.hpp"

using namespace ir;

GPDSPNodeRenderer dsp;
float* in;
float const* out;
int i;

// サンプリングレートを 44100Hz に設定
dsp.setRate(44100);

// 100 バイトの入力バッファを確保して, バッファ入力ノードを作成
dsp.newNodeBufferInput("data_in", NULL, 100, 1);

// 100 バイトの出力バッファを確保して, バッファ出力ノードを作成
dsp.newNodeBufferOutput("data_out", NULL, 100, 1);

// 増幅率 2.0 の増幅ノードを作成
dsp.newNodeAmplify("amp", 2.0f);

// 増幅ノードの入力とバッファ入力ノードの出力を接続
dsp.setLinkPositiveI("amp", 0, "data_in", 0);

// バッファ出力ノードの入力と増幅ノードの出力を接続
dsp.setLinkPositiveI("data_out", 0, "amp", 0);

// バッファ入力ノードが確保した 100 バイトのバッファを取得
in = dsp.getNodeBufferInput("data_in")->getBufferWritable(NULL, NULL);

// バッファに処理前のデータを書き込み
for (i = 0; i < 100; ++i) {
    in[i] = i / 100.0f;
}

// 100 バイト分のデジタル信号処理を実行
dsp.render(100);

// バッファ出力ノードが確保した 100 バイトのバッファを取得
out = dsp.getNodeBufferOutput("data_out")->getBufferReadonly(NULL, NULL);

// 処理後のデータをバッファから読み出し
for (i = 0; i < 100; ++i) {
    std::cout << out[i] << std::endl;
}

ノードの種類

GPDSP ライブラリには, 以下の表に示すような具象ノードがあらかじめ用意されています.

開発者は GPDSPGenerativeNode クラスを利用するか, 抽象ノードを継承した新しいノードを実装することにより, 独自の機能を持ったカスタムノードを追加することもできます.

クラス名解説
GPDSPBufferInputNodeバッファ入力ノード
GPDSPBufferOutputNodeバッファ出力ノード
GPDSPConstantNode定数ノード
GPDSPSignNode符号ノード
GPDSPGateNode制限ノード
GPDSPPeakNode極値ノード
GPDSPAmplifyNode増幅ノード
GPDSPDelayNode単位遅延ノード
GPDSPBufferNode任意遅延ノード
GPDSPSumNode総和ノード
GPDSPMultiplyNode総積ノード
GPDSPSquareRootNode平方根ノード
GPDSPSinWaveNodeサイン波ノード
GPDSPTriangleWaveNode三角波ノード
GPDSPSawtoothWaveNode鋸波ノード
GPDSPSquareWaveNode矩形波ノード
GPDSPGenerativeNode生成的ノード

ライブラリの特徴

GPDSP ライブラリを利用することで, デジタル信号処理の計算順序やアルゴリズムの詳細を開発者が記述する必要がなくなります. これは GPDSPNodeRenderer::render() 関数が内部でデータフローを追跡し, ノード構成に最適な計算順序を自動的に探索することができるからです. 一度探索された最適な計算順序は記憶され, 次の演算では負荷のかかる探索を行わずに高速な演算を行います.

一方で GPDSP ライブラリは, 一度接続されたノード構成をデジタル信号処理の途中で動的に再接続することを可能にします. GPDSPNodeRenderer::render() 関数は, ノード構成に変更があるかどうかをなるべく負荷のかからない方法で演算のたびに検証します. ノード構成に変更がある場合は, 必要最低限の部分について計算順序を再探索して, 新しい順序を記憶し直します.

また, ディレイ・フリー・ループなどの離散的に演算ができないノード構成や, 入力を待ち続け演算を完了できない条件なども自動的に判別し, 安全にエラーを返却します.

これらの動作は, GPDSPGenerativeNode クラスによりノード構成が再帰的な入れ子構造を持つ場合にも有効であり, ダイナミックに特性の変わる非常に柔軟なデジタル信号処理の実現を可能にします.

その他の詳細

上記では記述されていない詳細な情報については, こちらを参照してください.