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

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

ただいまの
回答率

90.48%

  • Java

    14153questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6637questions

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

  • Eclipse

    1716questions

    Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Androidアプリ開発~周波数解析~

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 3,672

YuujiUnno

score 17

バイノーラルマイクから取得した音の周波数を特定するAndroidアプリを作りたいのですが、周波数がうまく特定されません。
どこがおかしいのでしょうか?解決策やその確認方法などを教えてください。
FFTにはjtransformsを利用しています。

現在の状況
音を入力したら、順々にFFTされていき、出力は表示されます。
しかしその最も強い値(周波数帯域)が適した値ではなく、それ以外の値とそんなに差がない状態となってしまします。
窓関数をかけたらさらに真ん中部分のみが常に最大値として出力されます。

下に音声解析に関するソースコードを載せておきます。↓
/**
 * 
 */
package isa.android;

/**
 * @author Unno
 *
 */

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;

import java.lang.Math;

public class SoundRecord implements Runnable {
    // ボリューム感知リスナー
    
    /* (非 Javadoc)
     * @see java.lang.Runnable#run()
     */
    int pmax=0;
    public static double heltz;
    
    private OnReachedVolumeListener mListener;
    // 録音中フラグ
    private boolean isRecoding = true;
    // サンプリングレート
    private static final int SAMPLE_RATE = 44100;
    // FFTする要素数
    private final static int FFT_SIZE = 2048;
    // ボーダー音量
    private short mBorderVolume = 3000;
    // ボーダー音量をセット
    public void setBorderVolume(short volume) {
    mBorderVolume = volume;
    }
    // ボーダー音量を取得
    public short getBorderVolume() {
    return mBorderVolume;
    }
    // 録音を停止
    public void stop() {
    isRecoding = false;
    }
    // OnReachedVolumeListenerをセット
    public void setOnVolumeReachedListener(
    OnReachedVolumeListener listener) {
    mListener = listener;
    }
    // ボーダー音量を検知した時のためのリスナー
    public interface OnReachedVolumeListener {
    // ボーダー音量を超える音量を検知した時に
    // 呼び出されるメソッドです。
    void onReachedVolume(short volume);
    }
    
    public static int bufferSize = AudioRecord.getMinBufferSize(
            SAMPLE_RATE,
            AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT);
            AudioRecord audioRecord = new AudioRecord(
            MediaRecorder.AudioSource.MIC,
            SAMPLE_RATE,
            AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            bufferSize);
    public static double[] fbuffer = new double[FFT_SIZE];
    public static double[] power = new double[FFT_SIZE/2];
    
    public void hamming(double[] x) /*ハミング窓*/
    {
    int i;

    for(i=0;i<FFT_SIZE;i++){
    x[i] = 0.54 - 0.46*Math.cos((2 * Math.PI * i)/(FFT_SIZE - 1));
    }
    }
    
    @Override
    // スレッド開始(録音を開始)
    public void run() {
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
                
                short[] buffer = new short[FFT_SIZE];
                audioRecord.startRecording();
                while(isRecoding) {
                audioRecord.read(buffer, 0, FFT_SIZE);
                short max = 0;
                for (int i=0; i<FFT_SIZE; i++) {
                // 最大音量を計算
                max = (short)Math.max(max, buffer[i]);
                // 最大音量がボーダーを超えていたら
                if (max > mBorderVolume) {
                if (mListener != null) {
                // リスナーを実行
                mListener.onReachedVolume(max);
                FastFourieTransform fft = new FastFourieTransform();

                double[] x = new double[FFT_SIZE];
                hamming(x);
                for(int j=0; j < buffer.length; j++){
                    fbuffer[j] = buffer[j]/**x[j]*/;
                    }
                fft.fft(fbuffer , FFT_SIZE);
                
                //スペクトルを求める
                for(int k=0; k < power.length; k++){
                    power[k] = Math.sqrt(Math.pow(fbuffer[2*k], 2) + Math.pow(fbuffer[2*k + 1],2));
                    }
                //求めたスペクトルの最も大きな値を持つ添え字を求める
                for(int k=0; k < power.length; k++){
                    if(power[k] > power[pmax])
                        pmax = k;
                    Log.d("SoundRecord", "power[" + k + "] =" + power[k]);
                }
                
                //周波数を求める
                heltz = pmax * (SAMPLE_RATE/2) / (FFT_SIZE/2);
                //Log.d("SoundRecord", "heltz=" + heltz);
                Log.d("SoundRecord", "pmax=" + pmax);
                
                break;
        }
                }
                }
                }
                audioRecord.stop();
                audioRecord.release();
    }

}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

以下、いくつか気になった点をあげます。

時間分解能と周波数分解能はトレードオフな関係なので、欲しい情報にあわせFFT_SIZEを適切に設定する必要がある。

x[i] = 0.54 - 0.46*Math.cos((2 * Math.PI * i)/(FFT_SIZE - 1));
これではxにハミング窓を設定しているだけなので、次のように設定する。
x[i] = x[i] * (0.54 - 0.46*Math.cos((2 * Math.PI * i)/(FFT_SIZE - 1)));

入力値に対して最大音量の設定は適当か確認が必要。


投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2014/11/17 13:03

    回答ありがとうございます。

    ・FFT_SIZE
    FFT_SIZEについては周波数分解能:約21 Hz,時間分解能約40 ms程に設定しております。

    ・ハミング窓
    すみません。まずは窓関数なしである程度正しい値を得られるか見るためにソース内ではカットしてしまいましたが、実際にFFTしている行の1行前でbufferにx[i]をかけてfbufferとしております。

    ・最大音量
    最大音量に関しては実機テストをする際に、値を変えて外部音をうまく入力できるようにしております。

    キャンセル

関連した質問

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

  • Java

    14153questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6637questions

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

  • Eclipse

    1716questions

    Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。