勿論,MATLABやScilabで信号処理をして音を出すことは,当時も簡単にできました.しかし,音楽・音響制作の分野に身を置いていた私は,とにかく,リアルタイム入出力のアプリケーションこそが正義.これができなければ信号処理を勉強している意味がないと思っていました.
そんな中,知人が「最近使い始めた」と教えてくれたのがPortAudioでした.
http://www.portaudio.com/
PortAudioは,オープンソースのオーディオ入出力APIで,以下の点が特徴です.
・オーディオの基本的な機能を使うソースコードが簡単になる
・既存のオーディオAPIの抽象化として存在する
・クロス・プラットフォームである
クロス・プラットフォームというのはかなり魅力的で,現在のバージョンでは以下に対応しています.
・Windows DirectSound
・Windows WASAPI
・ASIO
・Mac CoreAudio
・UNIX OSS/ALSA
OS依存のAPIを同時に使ったりしない限り,これらの扱いが,全く同じソースコードでできてしまいます.
歴史はかなり古く,コンピュータ音楽の作曲家・技術者の間ではお馴染みのICMCで,2001年に発表されています.
http://www.portaudio.com/docs/portaudio_icmc2001.pdf
調べれば調べるほど,多くの音関係のオープンソースプロジェクトがPortAudioを使っていることが分かります.
私は,これまでずっとv18.1を使ってきました.理由は,上記の知人もそのバージョンを使っていたのと,まだプログラミングに完全に慣れきっていなかった私にもしっくりくる書き方ができたからです.しかし,v18.1のリリースは2003年.さすがに古すぎます.(ことさらに古さを演出するために,ここで「2003年といえば,〇〇があった年ですよ」とか書こうと思い,2003年の出来事を調べたが,あまり古いと感じる出来事がなかったので書くのをやめた)
そこで最新バージョンv19.06を使ってみることにしました.使ってみると,私の知っているPortAudioとは少し勝手が違っていたので,ビルド方法を紹介します.ゆとり世代なので,初めから統合開発環境Visual Studioを使います.先ほど紹介したPortAudioの特徴の恩恵に預かることが目的なので,PortAudioそのものの深い詮索等はせずに,一旦音の出るアプリケーションがビルドできればOKとします.
対象とするオーディオ環境はDirectSound.ビルドまでの手順が一番簡単だからです.
1, 上記webからPortAudioをダウンロード,解凍して "portaudio" フォルダを適当な場所にコピー.
2, ASIO SDKをダウンロード(今現在の最新バージョンは 2.3)
https://www.steinberg.net/en/company/developers.html
3, 解凍した "ASIOSDK2.3" フォルダを "portaudio/src/hostapi/asio/" にコピー.更に, "ASIOSDK2.3" -> "ASIOSDK" にリネーム.
4, "portaudio/build/msvc/portaudio.vcproj"をVisual Studioで開く(この時,比較的新しいVisual Studioを使うと,プロジェクトが最新化の環境に合わせて変換される)
5, ビルド設定を好みの設定にしてビルド.(今回はx86 Releaseにした)
6, 成功すると,"portaudio/build/msvc/Win32/Release"(Win32以下はビルド設定によって変わる) に "portaudio_x86.lib" "portaudio_x86.dll" が出来ている.
7, 新しいプロジェクト(空のプロジェクト)を作って,PortAudioを使ったコードをコーディング.
8, "portaudio/include/" をインクルードパスに設定して同ディレクトリの "portaudio.h" "pa_win_ds.h" をプロジェクトに追加する.
9, "portaudio/build/msvc/Win32/Release" をリンカのライブラリパスに設定して,同ディレクトリの "portaudio_x86.lib","winmm.lib"と"dsound.lib"をライブラリに追加する.
10, ビルド."portaudio_x86.dll" をアプリケーションと同じディレクトリにコピーすれば動作する.
という流れになります.v18.1と違うのは,"portaudio_〇〇.lib" "portaudio_〇〇.dll" をビルドしないといけない点です.v18.1では,各オーディオ環境に応じたインクルードファイルとソースファイルを追加してビルドする方式でしたが,現在のバージョンでは,Windowsベースのオーディオ環境(恐らくDirectSoundとWASAPIとASIO)はlibとdllにまとめられていて,それをリンクすれば全ての環境が使えるようになるみたいです.例えば,同じアプリケーションで複数のオーディオ環境をサポートするようなアプリケーションは,これで作りやすくなったと言えますが,個人的には,事前準備なくソースを追加するだけで音を出せるv18.1の方が楽なので好きです.
さて,ソースコードですが,例えば,正弦波を出すようなアプリケーションは以下のコードで出来ます.特にちゃんとやる必要性がある訳ではないので,エラー処理を完全に省略しましたが,それにしても本当に簡単です.
#include<stdio.h> #include<math.h> #include"portaudio.h" #define Fs 44100 //サンプリング周波数 #define FRAMES_PER_BUFFER 128 //バッファサイズ #define pi 3.14159265358979323 /*ユーザ定義データ*/ typedef struct{ float freq; //正弦波の周波数 float index; }padata; /* オーディオ処理コールバック関数*/ static int dsp(const void *inputBuffer, //入力 void *outputBuffer, //出力 unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData //ユーザ定義データ ){ padata *data = (padata *)userData; float *out = (float *)outputBuffer; long i; for( i=0; i<framesPerBuffer; i++){ *out++ = 0.7 * sin( 2 * pi * data->freq * data->index / Fs ); //チャンネル1(左) *out++ = 0.7 * sin( 2 * pi * data->freq * data->index / Fs ); //チャンネル2(右) data->index+=1.f; } return 0; } int main(void){ PaStreamParameters outParam; //出力の定義 PaStream *stream; PaError err; padata data; //ユーザ定義データ data.freq = 800.f; data.index = 0.f; //PortAudio初期化 Pa_Initialize(); //出力の設定 outParam.device = Pa_GetDefaultOutputDevice(); //デフォルトのオーディオデバイス outParam.channelCount = 2; outParam.sampleFormat = paFloat32; //32bit floatで処理 outParam.suggestedLatency = Pa_GetDeviceInfo( outParam.device )->defaultLowOutputLatency; outParam.hostApiSpecificStreamInfo = NULL; //PortAudioオープン Pa_OpenStream( &stream, NULL, &outParam, Fs, FRAMES_PER_BUFFER, paClipOff, dsp, &data); //PortAudioスタート Pa_StartStream(stream); //エンターキーが押されるまで待機 getchar(); //PortAudio終了 Pa_StopStream(stream); Pa_CloseStream(stream); Pa_Terminate(); return 0; }
入力を使いたいときは,同じように PaStreamParameters を入力用に定義して,PaOpenStreamの引数にすればよいです.
0 件のコメント:
コメントを投稿