入力音声のデシベルを取得する方法【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'
}

 

システム開発

Posted by @erestage