【问题标题】:Using FFT transformation with AudioRecord将 FFT 转换与 AudioRecord 结合使用
【发布时间】:2018-03-05 10:24:06
【问题描述】:

我正在按照这个示例转换为 FFT http://som-itsolutions.blogspot.com.ee/2012/01/fft-based-simple-spectrum-analyzer.html。我已经让它运行了,但我得到的结果非常奇怪。如果我使用 transofrmer(来自 FFT 类),我得到的都是 0。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    text = (TextView) findViewById(R.id.kaka);

    int bufferSize = AudioRecord.getMinBufferSize(frequency,
            channelConfiguration, audioEncoding);
    audioRecord = new AudioRecord(
            MediaRecorder.AudioSource.DEFAULT, frequency,
            channelConfiguration, audioEncoding, bufferSize);

    buffer = new short[blockSize];
    toTransform = new double[blockSize];
    try {
        audioRecord.startRecording();
    } catch (IllegalStateException e) {
        Log.e("Recording failed", e.toString());

    }
    transformer = new RealDoubleFFT(blockSize);

    final Runnable r = new Runnable() {

        public void run() {

            Log.d("Amplify","HERE");
            Toast.makeText(getBaseContext(), "Working!", Toast.LENGTH_LONG).show();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    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);
                    text.setText("result:" + toTransform[10]);
                    handler.postDelayed(this, 150); // amount of delay between every cycle of volume level detection
                }
            });

        }
    };
    handler.postDelayed(r, 80);

我还看到一段代码,上面说你必须从我第一次提供的链接中实现代码并添加这个方法来计算它:

public static int calculate(int sampleRate, short [] audioData){
    int numSamples = audioData.length;
    int numCrossing = 0;
    for (int p = 0; p < numSamples-1; p++)
    {
        if ((audioData[p] > 0 && audioData[p + 1] <= 0) ||
                (audioData[p] < 0 && audioData[p + 1] >= 0))
        {
            numCrossing++;
        }
    }

    float numSecondsRecorded = (float)numSamples/(float)sampleRate;
    float numCycles = numCrossing/2;
    float frequency = numCycles/numSecondsRecorded;

    return (int)frequency;
}

方法calculate有2个参数,第一个是samplerate,另一个是short[] audiodata。我尝试将“缓冲区”作为变量,但我得到的结果与预期的结果相去甚远。

有没有人熟悉这个例子,或者有人可以向我解释如何从:audiorecord.read(...) 获取数据。我了解您设置音频记录以记录输入的部分,但是当您 .read 数据时究竟发生了什么是我不明白的。

涉及所有 FFT 转换类确实很难,但这里是本示例中使用的 .ft:

  public void ft(double x[]){
     if(x.length != ndim)
          throw new IllegalArgumentException("The length of data can not match that of the wavetable");
     rfftf(ndim, x, wavetable);
  }

我知道这一定令人困惑,所以我会尝试总结一下,我的问题是:

audiorecord.read(..) 提供什么输出以及如何使用它?

如果我要使用计算方法,那么预期的输入是什么?

FFT 变换给我一个长度为 2048 的数组,里面的所有整数都是 0.00,我该怎么办?

也许我的做法完全错误,我不需要使用 FFT 从用户输入中获取频率。但结果我不需要绘制图表,我只需要根据频率变化(更高/更低)移动图像。

【问题讨论】:

    标签: android audio fft audiorecord


    【解决方案1】:

    想到了一些事情......

    清单文件中是否允许录音?

    Audiorecord.read 似乎只运行一次?这应该包含在 while() 语句中。如果它一次捕获 256 个字节,它可能需要一遍又一遍地运行

    将整个代码块放入异步任务并将进度发布回 UI 会更容易。看看我下面的例子。唯一的区别是我使用的是字节而不是短裤

     @Override
        protected Boolean doInBackground(File... files) {
    
            try {
            waveOut = new FileOutputStream(files[0]);
    
    
            int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_MASK, ENCODING);
            audioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_MASK, ENCODING, minBufferSize);
    
    
                writeWavHeader(waveOut,CHANNEL_MASK,SAMPLE_RATE,ENCODING);
    
            int bufferReadData;
            byte[] buffer1 = new byte[blockSize * 2];
            long total = 0;
    
            try{
                startTime = SystemClock.elapsedRealtime();
                audioRecord.startRecording();
    
            }catch (IllegalStateException e){
    
                Log.e(TAG, " Records doInBackground: " + e.toString() );
            }
    
    
    
            while(running)
            {
    
    
                bufferReadData = audioRecord.read(buffer1,0,blockSize);  //we are requesting 256 byte obj and android is sending us 16bit so each byte hold half of a 16 bit!!
    
    
               createFFT(bufferReadData,buffer1);
    
    
    
                createWavFile(total,bufferReadData,buffer1);
    
    
            }
    
            } catch (IOException e) {
                Log.e(TAG, "Records doInBackground: " + e.toString(), e);
                stoprecording();
            } finally {
    
                Log.i(TAG, "Records doInBackground: calld from 2nd");
    
                    endTime = SystemClock.elapsedRealtime();
    
            }
    
            try {
            updateWavHeader(files[0]);}catch (IOException e) {
                Log.e(TAG, "doInBackground: ", e);
            }
    
            return false;
        }
    
    
    
    
    
      protected void createFFT(int bufferReadData, byte[] buffer1)
        {
            double[] toTransform = new double[blockSize/2];
    
            //ByteBuffer.wrap(buffer1).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer);   //this hopefully creates the buffer1 array
    
            // xx is correct bits. Here we load byte from buffer lilendian to big to feed into the newBuff
            //  xx xx xx xx 00 00 00 00
            //  00 00 00 00 xx xx xx xx
            //  xx xx xx xx xx xx xx xx
            // 0xFF added to fix a left padding problem??
    
            short newBuff, buffLil, buffBig, count = 0;
    
            for (int i = 0; i < blockSize/2 && i < bufferReadData/2; i++) //after 128 runs with a double increment it is pulling what data?
            {
    
                buffLil = buffer1[count];
                buffBig = buffer1[count + 1];
                newBuff = (short) ( buffBig <<8 | buffLil & 0xFF);
                count ++;
                count++;
                toTransform[i] = (double) newBuff / 32768.0;             //This takes the short and divides by total short value to give a decimal double value between -1.0 to 1.0 for input into fft
            }
    
            transformer.ft(toTransform);
    
            String w = String.valueOf(toTransform.length);
            //String w = String.valueOf(toTransform[0]);
            Log.i(TAG, "createFFT: " + w);
    
            publishProgress(toTransform);
    
    
    
    
    
        }
    
    
    
       @Override
        protected void onProgressUpdate(double[]...toTransform){
    
    
    
            uiChartBuffer = toTransform;
    
    
    
    
         }
    

    【讨论】:

      猜你喜欢
      • 2011-11-17
      • 2011-08-09
      • 1970-01-01
      • 2015-11-08
      • 2018-10-09
      • 1970-01-01
      • 2018-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多