入力音声のデシベルを取得する方法【Android】
マイクから入力した音声を高速フーリエ変換して音声部分のデシベルを取得する方法を紹介します。
FFT変換にはJTransformsを使用しています。
https://github.com/wendykierp/JTransforms
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
import org.jtransforms.fft.DoubleFFT_1D;
public class MainActivity extends Activity {
final static int SAMPLING_RATE = 44100;
final static int FFT_SIZE = 4096;
AudioRecord audioRec = null;
boolean bIsRecording = false;
int bufSize;
TextView textInfo = null;
Handler mHandler;
String msg = "";
double dB_baseline = Math.pow(2, 15)*FFT_SIZE*Math.sqrt(2);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textInfo = findViewById(R.id.view);
mHandler = new Handler();
bufSize=AudioRecord.getMinBufferSize(
SAMPLING_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
if (FFT_SIZE > bufSize) bufSize = FFT_SIZE;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.main, menu);
return true;
}
int nosound_count = 0;
boolean record_mode = false;
@Override
protected void onResume() {
super.onResume();
//AudioRecordの作成
audioRec = new AudioRecord(
MediaRecorder.AudioSource.MIC,
SAMPLING_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufSize *2);
audioRec.startRecording();
bIsRecording = true;
new Thread(new Runnable() {
@Override
public void run() {
short buf[] = new short[bufSize];
while (bIsRecording) {
audioRec.read(buf, 0, buf.length);
// Log.d("audiorecord", String.valueOf(buf.length));
DoubleFFT_1D fft = new DoubleFFT_1D(FFT_SIZE) ;
double[] FFTdata = new double[FFT_SIZE];
for(int i=0;i<FFT_SIZE;i++){
FFTdata[i] = (double) buf[i];
}
fft.realForward(FFTdata);
//dBFS計算
double[] dbfs = new double[FFT_SIZE/2];
double max_db = -120d;
int max_i = 0;
for(int i=0;i<FFT_SIZE;i+=2){
dbfs[i/2]=(int)
(20*Math.log10( Math.sqrt(Math.pow(FFTdata[i], 2)
+Math.pow(FFTdata[i+1], 2))/dB_baseline));
if(max_db<dbfs[i/2]){
max_db = dbfs[i/2];
max_i = i/2;
}
}
msg = "";
boolean on_voice = false;
int hz = (int)((SAMPLING_RATE/ (double) FFT_SIZE) * max_i);
int db = (int)max_db;
if (hz > 100) {
if (db > -50) {
if (record_mode == false) {
record_mode = true;
nosound_count = 0;
}
on_voice = true;
Log.i("音声", hz + "[Hz]" + max_db + "[db]");
}
}
if (record_mode) {
if (on_voice == false) {
nosound_count++;
}
if (nosound_count > 10) {
record_mode = false;
nosound_count = 0;
}
}
if (record_mode) {
msg = "記録中..." ;
} else {
msg = "";
}
//メインスレッドのメッセージキューにメッセージを登録します。
mHandler.post(new Runnable() {
//run()の中の処理はメインスレッドで動作されます。
public void run() {
textInfo.setText(msg);
}
});
}
// 録音停止
audioRec.stop();
audioRec.release();
}
}).start();
}
@Override
protected void onPause() {
super.onPause();
if (bIsRecording) {
bIsRecording = false;
}
}
}dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}


