1
votes

I'm trying to record audio and get the frequencies. I can successfully do so with a sampling rate of 44100 and a block size of 2048. The bin size is around 20, I believe. However, if I try to increase the block size to 4096, then rather than get accurate frequencies, I just get the same inaccurate frequency back, with no magnitude/decibels.

My recording task is as follows:

 private class RecordAudio extends AsyncTask<Void, double[], Boolean> {

    @Override
    protected Boolean doInBackground(Void... params) {

        int bufferSize = AudioRecord.getMinBufferSize(frequency,
                channelConfiguration, audioEncoding);
        audioRecord = new AudioRecord(
                MediaRecorder.AudioSource.DEFAULT, frequency,
                channelConfiguration, audioEncoding, bufferSize);
        int bufferReadResult;
        short[] buffer = new short[blockSize];
        double[] toTransform = new double[blockSize];
        try {
            audioRecord.startRecording();
        } catch (IllegalStateException e) {
            Log.e("Recording failed", e.toString());

        }
        while (started) {
            if (isCancelled() || (CANCELLED_FLAG == true)) {

                started = false;
                //publishProgress(cancelledResult);
                Log.d("doInBackground", "Cancelling the RecordTask");
                break;
            } else {
                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
                }

                transformer.ft(toTransform);

                publishProgress(toTransform);

            }

        }
        return true;
    }
    @Override
    protected void onProgressUpdate(double[]...progress) {

        int mPeakPos = 0;
        double mMaxFFTSample = 150.0;
        for (int i = 100; i < progress[0].length; i++) {
            int x = i;
            int downy = (int) (150 - (progress[0][i] * 10));
            int upy = 150;
            //Log.i("SETTT", "X: " + i + " downy: " + downy + " upy: " + upy);

            if(downy < mMaxFFTSample)
            {
                mMaxFFTSample = downy;
                mMag = mMaxFFTSample;
                mPeakPos = i;
            }
        }

        mFreq = (((1.0 * frequency) / (1.0 * blockSize)) * mPeakPos)/2;
        //Log.i("SSS", "F: " + mFreq + " / " + "M: " + mMag);

        Log.i("SETTT", "FREQ: " + mFreq + " MAG: " + mMaxFFTSample);

    }
    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        try{
            audioRecord.stop();
        }
        catch(IllegalStateException e){
            Log.e("Stop failed", e.toString());

        }
    }
}

Hoping there is a quick fix I'm missing. Thanks.

1
How is transformer initialized and what is its type so we can at least refer to its documentation? Also, what do you mean by "with no magnitude?" Is everything zero?jaket
I am using RealDoubleFFT which can be found here: github.com/charlesmunger/RoomDetector/blob/master/src/ca/uol/…Jameson

1 Answers

1
votes

You'll need to look closer at the documentation of the RealDoubleFft.ft function. The values going into the function are real but the values coming out are complex FFT coefficients such that toTransform[0] is the real part of the first coefficient, toTransform[1] is the imaginary part of the first coefficient and so on. The final array size is the same but since complex numbers each take up 2 doubles then there are a total of N/2 coefficients where the last one is the coefficient for sampleRate/2.

Next since you are interested in the magnitude you need to compute the magnitude of the complex numbers. For a complex number x = a + bj, the magnitude |x| = sqrt(a*a + b*b)

    double maxMag = 0;
    int peakIndex = 0;
    for (int i = 0; i < progress[0].length/2; i++)
    {
        double re = progress[i*2];
        double im = progress[i*2+1];
        double mag = Math.sqrt(re*re + im*im);
        if (mag > maxMag)
        {
            peakIndex = i;
            maxMag = mag;
        }
    }

    double peakFreq = sampleRate/fftLen * i/2; // might need a bit of tweaking.
    double magInDb  = 20*Math.log10(mag);