質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • Android

    6521questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

android jtransformsで調べたデシベルがおかしい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 326

ehu

score 24

 やりたいこと・問題

静寂状態から喧騒状態になるのを検知し、音声認識APIで文字起こしをするアルゴリズムを作っています。喧騒状態の検知にはある程度デシベルが大きかったら検知するようにするつもりです。デシベルを調べるにはFFTであるjtransformsを使用しました。まず、この記事を参考にしてdbを取得できるようにコード書いたところ問題が発生しました。以下のクラスRecordVoiceServiceを実行してもD/db: Hz0.0maxdb-120.0としか出力されません(MediaRecorder.AudioSource.VOICE_RECOGNITIONをMediaRecorder.AudioSource.MICにしても結果は同じでした)。これはAudioRecordクラス上で音を拾えてないと言うことでしょうか?(もし、音を拾えているか確認する手段があるなら教えてください。)なぜ、このようになるのでしょうか?

 参考にした記事

Androidで録音する 2 FFTして周波数とdBFSを調べる。
Androidで周波数を解析してみよう Android プログラミング 研究
AndroidでFFTはJTransformsが楽だった

 コード

RecordVoiceServiceクラス

import android.app.Service;
import android.content.Intent;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import org.jtransforms.fft.DoubleFFT_1D;

/**
 * Created by kaikoro on 2017/11/13.
 */

public class RecordVoiceService extends Service {
    //録音クラスの宣言
    AudioRecord audioRecord;
    //録音フラグ。録音を開始するなら、true。停止するなら、false。ボタンで切り替える
    boolean bIsRecording = false;
    int bufferSize = 0;
    final static int FFT_SIZE = 4096;
    double dB_baseline = Math.pow(2, 15) * FFT_SIZE * Math.sqrt(2);

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("LifeCycle", "onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startRecordVoice();
        Log.d("LifeCycle", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }


    //録音開始
    private void startRecordVoice() {
        initAudioRecord();
        startAudioRecorder();
    }


    public void getVoice() {

    }

    //録音停止
    private void stopRecordVoice() {
        //録音フラグを停止にする
        bIsRecording = false;
        Log.d("bIsRecording", String.valueOf(bIsRecording));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("LifeCycle", "onDestroy");
        stopRecordVoice();
    }

    //初期化
    public void initAudioRecord() {
        int audioSource = MediaRecorder.AudioSource.VOICE_RECOGNITION;
        int rate = 44100;
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
        if (FFT_SIZE > bufferSize) bufferSize = FFT_SIZE;

        audioRecord = new AudioRecord(audioSource, rate, channelConfig, audioFormat, bufferSize * 2);
    }

    //録音開始、停止が押されるまで録音する
    private void startAudioRecorder() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                bIsRecording = true;
                short buf[] = new short[bufferSize];
                //stopRecordVoice()が呼ばれるまでbufに書き込む
                while (bIsRecording) {
                    //bufに音声データを格納
                    audioRecord.read(buf, 0, buf.length);
                    Log.d("bIsRecording", String.valueOf(bIsRecording));

                    //FFTで解析
                    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;
                        }
                    }
                    Log.d("db", "Hz" + (44100 / (double) FFT_SIZE) * max_i + "maxdb" + max_db);
                }
                // 録音停止
                audioRecord.stop();
                audioRecord.release();
            }
        }).start();
    }
}

 Logcat

11-19 01:09:14.750 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.778 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.805 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.832 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.859 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.887 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.914 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.942 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.970 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:14.998 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
11-19 01:09:15.025 16266-16683/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-120.0
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

AudioRecord.startRecording()を書き忘れていただけでした。その他、初期化できているか確認するメソッドAudioRecord.getState()と、録音しているか確認できるメソッドAudioRecord.getgetRecordingState()もここに記しておきます。

RecordVoiceServiceクラスのstartAudioRecorder()

  private void startAudioRecorder() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                bIsRecording = true;
                short buf[] = new short[bufferSize];
                audioRecord.startRecording();
                //stopRecordVoice()が呼ばれるまでbufに書き込む
                while (bIsRecording) {
                    //bufに音声データを格納
                    audioRecord.read(buf, 0, buf.length);
                    Log.d("RecordingState", String.valueOf(audioRecord.getRecordingState()));
                    //省略


RecordVoiceServiceクラスのstartRecordVoice()

 private void startRecordVoice() {
        initAudioRecord();
        if (audioRecord.getState() == audioRecord.STATE_INITIALIZED) {
            Log.d("AudioRecord", "state" + audioRecord.getState());
            startAudioRecorder();
        } else {
            Log.w("AudioRecord", "state" + audioRecord.getState());
        }
    }

AudioRecord.getState()と、AudioRecord.getgetRecordingState()を使ってみたのですが、書き方がこれでいいのか不安ですね。美しい書き方を教えていただくと幸いです。

試しに録音開始の後「OK Google」と言って、録音停止してみました。

11-19 15:06:28.479 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz527.5634765625maxdb-35.0
11-19 15:06:28.570 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz506.0302734375maxdb-47.0
11-19 15:06:28.627 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz301.46484375maxdb-52.0
11-19 15:06:28.753 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz10.7666015625maxdb-44.0
11-19 15:06:28.806 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-47.0
11-19 15:06:28.916 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz366.064453125maxdb-45.0
11-19 15:06:28.997 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz236.865234375maxdb-48.0
11-19 15:06:29.125 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz118.4326171875maxdb-51.0
11-19 15:06:29.198 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz473.73046875maxdb-47.0
11-19 15:06:29.284 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-68.0
11-19 15:06:29.373 18270-19294/com.example.ehu.recodevoiceinbackgroud D/db: Hz0.0maxdb-70.0

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Android

    6521questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。