前提・実現したいこと
音の録音・フーリエ変換をするAndroidアプリを作成しています。
最初の画面で検出したい周波数と閾値を入力してスイッチを押すと処理が開始します。
音を録音すると同時にリアルタイムでフーリエ変換(FFT)をして、検出したい周波数が入力した閾値以上を超えればバイブレーションによって通知するシステムです。
発生している問題・エラーメッセージ
エラーメッセージは特にありませんが、明らかに閾値以上であるはずなのに安定してバイブレーション通知が行われません。
例えば、20kHzの音が大音量で出ているときに、20kHzが明らかに届く距離にいるのに、バイブレーションが遅れたり、バイブレーションが作動しなかったりします。
該当のソースコード
lang
1package com.example.xxxx.receiver; 2 3import java.nio.ByteBuffer; 4import java.nio.ByteOrder; 5import android.app.Activity; 6import android.media.AudioFormat; 7import android.media.AudioRecord; 8import android.media.MediaRecorder; 9import android.os.Bundle; 10import android.os.Vibrator; 11import android.util.Log; 12import android.widget.CompoundButton; 13import android.widget.CompoundButton.OnCheckedChangeListener; 14import android.widget.Switch; 15import android.widget.EditText; 16import android.widget.TextView; 17 18public class MainActivity extends Activity implements OnCheckedChangeListener { 19 20 int RECVFREQ; 21 double DECIBEL; 22 int FFTPOINT; 23 24 //サンプリングレート 25 int RecvSR = 44100; 26 //FFTのポイント数 27 int fftSize = 4096; 28 //デシベルベースラインの設定 29 double dB_baseline = Math.pow(2, 15) * fftSize * Math.sqrt(2); 30 //分解能の計算 31 double resol = RecvSR / (double) fftSize; 32 Vibrator vib; 33 AudioRecord audioRec = null; 34 boolean bIsRecording = false; 35 int RecvBufSize; 36 Thread fft; 37 38 @Override 39 public void onCreate(Bundle savedInstanceState) { 40 super.onCreate(savedInstanceState); 41 setContentView(R.layout.activity_main); 42 43 TextView RecvfreqText = findViewById(R.id.RecvfreqText); 44 RecvfreqText.setText(R.string.RecvfreqText); 45 TextView decibelText = findViewById(R.id.decibelText); 46 decibelText.setText(R.string.decibelText); 47 Switch switch1 = findViewById(R.id.Switch); 48 switch1.setOnCheckedChangeListener(this); 49 } 50 51 @Override 52 public void onResume() { 53 super.onResume(); 54 } 55 56 @Override 57 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 58 59 if(isChecked) { 60 61 EditText RecvfreqEdit = findViewById(R.id.RecvfreqEdit); 62 EditText decibelEdit = findViewById(R.id.decibelEdit); 63 64 RECVFREQ = Integer.parseInt(RecvfreqEdit.getText().toString()); 65 DECIBEL = Integer.parseInt(decibelEdit.getText().toString()); 66 67 if(RECVFREQ == 18000) FFTPOINT = 3344; 68 else if(RECVFREQ == 18500) FFTPOINT = 3436; 69 else if(RECVFREQ == 19000) FFTPOINT = 3530; 70 else if(RECVFREQ == 19500) FFTPOINT = 3622; 71 else if(RECVFREQ == 20000) FFTPOINT = 3716; 72 else if(RECVFREQ == 20500) FFTPOINT = 3808; 73 else if(RECVFREQ == 21000) FFTPOINT = 3900; 74 else if(RECVFREQ == 21500) FFTPOINT = 3994; 75 else if(RECVFREQ == 22000) FFTPOINT = 4086; 76 77 RecvBufSize = AudioRecord.getMinBufferSize( 78 RecvSR, 79 AudioFormat.CHANNEL_IN_MONO, 80 AudioFormat.ENCODING_PCM_16BIT) + 4608; 81 82 audioRec = new AudioRecord( 83 MediaRecorder.AudioSource.MIC, 84 RecvSR, 85 AudioFormat.CHANNEL_IN_MONO, 86 AudioFormat.ENCODING_PCM_16BIT, 87 RecvBufSize); 88 89 //Vibratorクラスのインスタンス取得 90 vib = (Vibrator)getSystemService(VIBRATOR_SERVICE); 91 92 audioRec.startRecording(); 93 bIsRecording = true; 94 95 //フーリエ解析スレッドを生成 96 fft = new Thread(new Runnable() { 97 @Override 98 public void run() { 99 100 byte buf[] = new byte[RecvBufSize]; 101 while (bIsRecording) { 102 audioRec.read(buf, 0, buf.length); 103 104 //エンディアン変換 105 //配列bufをもとにByteBufferオブジェクトbfを作成 106 ByteBuffer bf = ByteBuffer.wrap(buf); 107 //バッファをクリア(データは削除されない) 108 bf.clear(); 109 //バイト順序をビッグエンディアンに変更 110 bf.order(ByteOrder.BIG_ENDIAN); 111 short[] s = new short[RecvBufSize / 2]; 112 //位置から容量まで 113 for (int i = bf.position(); i < bf.capacity() / 2; i++) { 114 //short値を読むための相対getメソッド 115 //現在位置の2バイトを読み出す 116 s[i] = bf.getShort(); 117 } 118 119 //FFTクラスの作成と値の引き渡し 120 FFT4g fft = new FFT4g(fftSize); 121 double[] FFTdata = new double[fftSize]; 122 for (int i = 2048; i < fftSize; i++) { 123 FFTdata[i] = (double) s[i]; 124 } 125 fft.rdft(1, FFTdata); 126 127 // デシベルの計算 128 double[] dbfs = new double[fftSize / 2]; 129 for (int i = 2048; i < fftSize; i += 2) { 130 dbfs[i / 2] = (int) (20 * Math.log10(Math.sqrt(Math 131 .pow(FFTdata[i], 2) 132 + Math.pow(FFTdata[i + 1], 2)) / dB_baseline)); 133 134 if(i == FFTPOINT && dbfs[i / 2] > DECIBEL){ 135 vib.vibrate(100); 136 } 137 } 138 Log.d("audioRec","audioRec"); 139 } 140 audioRec.stop(); 141 audioRec.release(); 142 } 143 144 }); 145 //スレッドのスタート 146 fft.start(); 147 148 } else { 149 150 Log.d("value","RECVFREQ1:" + String.valueOf(RECVFREQ)); 151 Log.d("value","DECIBEL:" + String.valueOf(DECIBEL)); 152 153 if(audioRec.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { 154 audioRec.stop(); 155 //audioRec.release(); 156 bIsRecording = false; 157 } 158 } 159 } 160 161 @Override 162 public void onPause() { 163 super.onPause(); 164 165 if(audioRec.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { 166 audioRec.stop(); 167 bIsRecording = false; 168 } 169 170 } 171 172 @Override 173 public void onDestroy() { 174 super.onDestroy(); 175 176 if(audioRec.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { 177 audioRec.stop(); 178 audioRec.release(); 179 bIsRecording = false; 180 } 181 182 } 183 184}
試したこと
スレッド処理の中でバイブレーションを作動させるという処理が正常に動いてないのかもしれません。
しかし、どこをどう改善すればよいかわかりません。
そもそも違った原因があるのかもしれません。
補足情報(FW/ツールのバージョンなど)
FFT4gは大浦版FFTを使用しています。
パーミッションの付与はうまくいっています。
あなたの回答
tips
プレビュー