使用環境
- macOS High Sierra
- Xcode 10.0.0
- ofxFft : https://github.com/kylemcdonald/ofxFft 【18.10.25 現在】
背景
最近触り始めた openFrameworks で、音を視覚化するアプリを作ってみようと思い立った。折角なので、周波数空間(フーリエ空間)を表現してみたい。でも、ぶっちゃけ FFT を自力で組むのが面倒...。
で、ググってみたら、案の定作っている先人がいらっしゃった(kylemcdonald/ofxFFT)。どうやら oF で簡単かつ基本的な周波数解析(FFT)が計算できるアドオンらしい。特に細かいカスタマイズする気もなかったから、今回はありがたく拝借することに。
だが、実際動かしてみたらおかしなことが。なぜか、特定の処理を draw()
で実行しないと正常な値が得られない様子。
最終的には”初歩的なミス”というオチだったが、原因の特定やら対処やらで手こずったので、備忘録を残しておく。
注意:
本稿は、アドオンの詳細についての説明を省略しております。あらかじめご了承ください。
使い方自体は GitHub に記載されておりますので、そちらをご参照ください。
症状
今回行った処理は下記の通り。マイク入力に対して FFT を行い、値を標準出力する。
なおfft.drawDebug()
は、計測した値を画面にビットマップ出力する。fft.drawBars()
は、計測した値をグラフで描画する。
# include "ofxProcessFFT.h"
class ofApp : public ofBaseApp{
public:
...
ProcessFFT fft;
};
# include "ofApp.h"
void ofApp::setup() {
...
// FFT setting
fft.setup();
fft.setNumFFTBins(16);
fft.setNormalize(true);
...
}
void ofApp::update() {
fft.update();
// Output values
float lowVal = fft.getLowValue();
float midVal = fft.getMidValue();
float highVal = fft.getHighValue();
std::cout << "ofApp : " << "Low value : " << lowVal << endl;
std::cout << "ofApp : " << "Middle value : " << midVal << endl;
std::cout << "ofApp : " << "High value : " << highVal << endl;
}
void ofApp::draw() {
fft.drawDebug();
fft.drawBars();
}
主な症状は下記の通り。
- 上記のプログラムでは、正常な計測値が得られる。
-
fft.drawDebug()
をコメントアウトすると、急に正常な値が得られなくなる。 -
fft.drawDebug()
の内部でも各行をコメントアウトしてみたが、特定の処理が影響している様子ではない(むしろ、"処理の数"が影響しているような...?) -
ProcessFFT
の内部パラメータを全て観察してみたところ、パラメータの1つであるavgMaxSoundOverTime
の値が増加し続けてしまうことに原因があるっぽい(正常時には増え続けていなかった)。 - さらに細かくみると、
avgMaxSoundOverTime
を求めるときに使う値accumMaxSounds
が増え続けていることが根本的な原因である様子。
原因
下記のように、ofxProcessFFT.cpp
でaccumMaxSounds
が初期化されていなかった。
...
void ofxProcessFFT::calculateFFT( ... ) {
...
float accumMaxSounds; /* It is not initialized! */
for (int i = 0; i < graphMaxSound.size(); i++) {
accumMaxSounds = accumMaxSounds+graphMaxSound[i]; // ...
}
avgMaxSoundOverTime = accumMaxSounds/graphMaxSound.size(); // ...
...
}
対処
accumMaxSounds
を初期化してやれば良い。
...
void ofxProcessFFT::calculateFFT( ... ) {
...
- float accumMaxSounds; /* It is not initialized! */
+ float accumMaxSounds = 0;
for (int i = 0; i < graphMaxSound.size(); i++) {
accumMaxSounds = accumMaxSounds+graphMaxSound[i]; // ...
}
avgMaxSoundOverTime = accumMaxSounds/graphMaxSound.size(); // ...
...
}
まとめ
うーん、しょーもない(失礼)。
ただ、結果的に見ると単純な話、初歩的なミスで良かった。おそらく「処理の数が影響してる様子」だったのも、変数のアドレスが関係していたと思われる(偶然ゼロになっていた、またはその逆)。
今回の件を GitHub で直接 issue に出そうかは検討中。
この手のエラーは意外と忘れがちかも...。
Reference
None