Androidでシンプルなディレイ・エフェクト
この文章は前回と同様、Victor Lazzariniのブログを翻訳したものです。前回、マイクからの音をスピーカーで鳴らしました。今回はその間にエフェクトを挟んで音を変えます。
>>>それでは本文
前回の私の記事で書いたコードだが、音声処理アプリケーションをどう書いたらいいかと感じている人もいるかも知れない。この点について、明らかにしていく。実際、再利用を念頭において、OpenSLモジュールを設計しておいた。だから、モジュールに触れることなく、君のプロジェクトにそのまま加えればいい。
前回のブログから、NDKプロジェクトの置き方について知ってるはずです。君はそれをコピーし、コードを修正し始める。opensl_example.cとopensl_example.hファイルを編集することだけすればいい。このファイルにいくつかの処理能力を追加していく。
くし形フィルタをベースにした、エコー効果を追加しよう。そのためにインフラを構築しよう。データ構造(データメンバ)とエコーを操作する関数(メソッド)を基礎にして、C言語の簡単なクラスを作る。以下のコードを、C言語のソースの一番上に加えます。
typedef struct delayline_t { float *delay; // delayline int size; // length in samples int rp; // read pointer float fdb; // feedback amount } DELAYLINE; DELAYLINE *delayline_create(float delay, float fdb) { // allocate memory and set feedback parameter DELAYLINE *p = (DELAYLINE *) calloc(sizeof(float), delay*SR); p->fdb = fdb > 0.f ? (fdb < 1.f ? fdb : 0.99999999f) : 0.f ; return p; } void delayline_process(DELAYLINE *p,float *buffer, int size) { // process the delay, replacing the buffer float out, *delay = p->delay, fdb = p->fdb; int i, dsize = p->size, *rp = &(p->rp); for(i = 0; i < size; i++){ out = delay[*rp]; p->delay[(*rp)++] = buffer[i] + out*fdb; if(*rp == dsize) *rp = 0; buffer[i] = out; } }
決まったところにこいつを置いて、やるべきことは、ディレイラインを使うためにメインプロセスを修正することだけ。メイン処理関数(start_processからmain_processにリネーム)に2つの引数を加えることで、Javaのコードからフィードバックとディレイタイムの量をセットできるようにする。
void main_process(float delay, float fdb) { OPENSL_STREAM *p; int samps, i; float buffer[VECSAMPS]; DELAYLINE *d; p = android_OpenAudioDevice(SR,1,1,BUFFERFRAMES); if(p == NULL) return; d = delayline_create(delay, fdb); if(d == NULL) { android_CloseAudioDevice(p); return; } on = 1; while(on) { samps = android_AudioIn(p,buffer,VECSAMPS); delayline_process(d,buffer,samps); android_AudioOut(p,buffer,samps); } android_CloseAudioDevice(p); }
もう、やり残しているのは2つだけで、opensl_example.hヘッダーファイルを編集し、start_process()をmain_process(float delay, float fdb)のプロトタイプで置き換える。
#ifdef __cplusplus extern "C" { #endif void main_process(float delay, float fdb); void stop_process(); #ifdef __cplusplus }; #endif
そして、この新しい関数を呼ぶためにJavaコードを修正する。
t = new Thread() { public void run() { setPriority(Thread.MAX_PRIORITY); opensl_example.main_process(0.5f, 0.7f); } };
これでいいだろう!。
>>>以上本文、以下修正など
(3/10修正メンバ)変数ー>データメンバ