4

Android: 私は音声プロセスを初めて使用します。JTransform ライブラリを使用して sampleRate 8000Hz の AudioRecord オブジェクトを作成しました。周波数をフィルタリングしようとしています。次のコードには、次のような質問がわかりません。

Q.1 なぜ「toTransform[i] = (double) buffer[i] / 32768.0; // 符号付き 16 ビット」バッファを 16 ビット値に変換するのですか?

Q.2 Rite now audioRecord の読み取りデータ配列は、バイト配列を読み取ると短い配列になります。

Q.3 double 配列で音の周波数を Hz で表示したいのですが、どうすれば音の周波数を計算できますか?

Q.4 フィルタメソッド filterAudio() を書きましたが、周波数のフィルタリング範囲ではありませんか?

私を助けてください、私の心にはたくさんの質問があります

/* コードは次のとおりです */

private final int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 };
final AudioRecord audioRecord = findAudioRecord();
                if(audioRecord == null){
                    return null;
                }

                final short[] buffer = new short[blockSize];
                final double[] toTransform = new double[blockSize];

                audioRecord.startRecording();

                while (started) {
                    Thread.sleep(100);
                    final int bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                    for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                        toTransform[i] = (double) buffer[i] / 32768.0; // signed 16 bit
                    }

                    //Audio Filter passing frequency of mSampleRates[3]
                    filterAudio(bufferReadResult, toTransform, mSampleRates[3]);
                    transformer.realForward(toTransform);                   
                    publishProgress(toTransform);
                }
                audioRecord.stop();
                audioRecord.release();


public static void filterAudio(int bufferSize, double[] audioBuffer, float sampleRate ){

        //it is assumed that a float array audioBuffer exists with even length = to 
        //the capture size of your audio buffer

        //float frequency=0F;
        //The size of the FFT will be the size of your audioBuffer / 2
        int FFT_SIZE = bufferSize / 2;
        //RealDoubleFFT mFFT = new RealDoubleFFT(FFT_SIZE);
        DoubleFFT_1D mFFT = new DoubleFFT_1D(FFT_SIZE); //this is a jTransforms type

        //Take the FFT
        mFFT.realForward(audioBuffer);
        //mFFT.ft(audioBuffer);

        //The first 1/2 of audioBuffer now contains bins that represent the frequency
        //of your wave, in a way.  To get the actual frequency from the bin:
        //frequency_of_bin = bin_index * sample_rate / FFT_SIZE

        //assuming the length of audioBuffer is even, the real and imaginary parts will be
        //stored as follows
        //audioBuffer[2*k] = Re[k], 0<=k<n/2
        //audioBuffer[2*k+1] = Im[k], 0<k<n/2

        //Define the frequencies of interest
        float freqMin = 14400;
        float freqMax = 14500;

        //Loop through the fft bins and filter frequencies
        for(int fftBin = 0; fftBin < FFT_SIZE; fftBin++){        
            //Calculate the frequency of this bin assuming a sampling rate of 44,100 Hz
            float frequency = (float)fftBin * sampleRate / (float)FFT_SIZE;

            //Now filter the audio, I'm assuming you wanted to keep the
            //frequencies of interest rather than discard them.
            if(frequency  < freqMin || frequency > freqMax){
                //Calculate the index where the real and imaginary parts are stored
                int real = 2 * fftBin;
                int imaginary = 2 * fftBin + 1;

                //zero out this frequency
                audioBuffer[real] = 0;
                audioBuffer[imaginary] = 0;
            }
        }

        //Take the inverse FFT to convert signal from frequency to time domain
        mFFT.realInverse(audioBuffer, false);
    }

final AudioRecord findAudioRecord() {
        for (int rate : mSampleRates) {
            for (short audioFormat : new short[] { AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT }) {
                for (short channelConfig : new short[] { AudioFormat.CHANNEL_CONFIGURATION_MONO , AudioFormat.CHANNEL_CONFIGURATION_STEREO }) {
                    try {

                        bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);

                        if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {
                            // check if we can instantiate and have a success
                            AudioRecord recorder = new AudioRecord(AudioSource.DEFAULT, rate, channelConfig, audioFormat, bufferSize);

                            if (recorder.getState() == AudioRecord.STATE_INITIALIZED){
                                Log.d(TAG, "Attempting rate " + rate + "Hz, bits: " + audioFormat + ", channel: "
                                        + channelConfig);
                                return recorder;
                            }
                        }
                    } catch (Exception e) {
                        Log.e(TAG, rate + "Exception, keep trying.",e);
                    }
                }
            }
        }

        return null;
    }
4

1 に答える 1

4

Q.1 なぜ「toTransform[i] = (double) buffer[i] / 32768.0; // 符号付き 16 ビット」バッファを 16 ビット値に変換するのですか?

32768 が最大値です。コード行がデータを 0 から 1 の間に正規化していると思います。

Q.2 現在、audioRecord の読み取りデータ配列は、バイト配列を読み取ると短い配列になります。

なぜbyte配列に読み込むのですか?その場合、2 つを組み合わせbytesて 16 ビット値を取得する必要があります。代わりに、short配列を読み取ってデータを取得します。短い配列を処理する方法の例を次に示します。このコードはそれを読み取ります。

Q.3 double 配列で音の周波数を Hz で表示したいのですが、どうすれば音の周波数を計算できますか?

これは、周波数を推定するための正確ではない方法の 1 つです。他にも方法はありますが、より複雑です

于 2012-06-08T13:16:01.210 に答える