Music Notation Recorder调试和解析

时间:2013-12-03 19:06:49

标签: java android signal-processing fft

我目前正在尝试创建一个Android应用程序,用户按下按钮,应用程序会听取音乐,找到速度,通过以下方式从节奏中收集每个季度音符的音符信息:

  • 接收音频字节数组。
  • FFT(寻找频率)
  • 使用频率来确定该四分音符的音符。
  • 将该注释分配给稍后将显示为乐谱的数组。

这是我目前所做的代码:

package com.tentmaker.musicnotationrecorder;

import java.io.IOException;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioSource;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.badlogic.gdx.audio.analysis.FFT;

public class Record extends Activity implements OnClickListener {

Button btnRecord;
private MediaRecorder mRecorder = null;
private static String mFileName = null;
    float[] fftArray;

    private boolean recording;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_record);

    btnRecord = (Button)findViewById(R.id.recordButton);
    btnRecord.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    try{
        switch(v.getId()){
            case R.id.recordButton:
                buttonEvent();
                return;
            default:
                return; 
        }
    }
    catch (Exception e){
        Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_LONG).show();
    }
}

public void buttonEvent(){
    if(recording){
        startRecording();
        frequencyCollection();
        process(fft());
    }
    else if(!recording){
        stopRecording();
    }
}

public void startRecording(){
    mRecorder = new MediaRecorder();
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setOutputFile(mFileName);
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    Toast.makeText(getApplicationContext(), "recording...", Toast.LENGTH_LONG).show();
    try {
        mRecorder.prepare();
    } catch (IOException e) {
        Toast.makeText(getApplicationContext(), "prepare() failed", Toast.LENGTH_LONG).show();
    }
    mRecorder.start();
}

@SuppressWarnings("unused")
private void stopRecording() {
    mRecorder.stop();
    mRecorder.release();
    mRecorder = null;
    Toast.makeText(getApplicationContext(), "done recording", Toast.LENGTH_LONG).show();
}

@SuppressWarnings("unused")
private float[] fft() {
    int fs = 8374;
    int N = fftArray.length;
    float[] fft_cpx, tmpr, tmpi;
    float[] res = new float[N / 2];
    // float[] mod_spec =new float[array.length/2];
    float[] real_mod = new float[N];
    float[] imag_mod = new float[N];
    double[] real = new double[N];
    double[] imag = new double[N];
    double[] mag = new double[N];
    double[] phase = new double[N];
    float[] new_array = new float[N];
    // Zero Pad signal
    for (int i = 0; i < N; i++) {
        if (i < fftArray.length) {
            new_array[i] = fftArray[i];
        } 
        else {
            new_array[i] = 0;
        }
    }

    FFT fft = new FFT(N, 8373);

    fft.forward(new_array);
    fft_cpx = fft.getSpectrum();
    tmpi = fft.getImaginaryPart();
    tmpr = fft.getRealPart();
    for (int i = 0; i < new_array.length; i++) {
        real[i] = (double) tmpr[i];
        imag[i] = (double) tmpi[i];

        mag[i] = Math.sqrt((real[i] * real[i]) + (imag[i] * imag[i]));
        phase[i] = Math.atan2(imag[i], real[i]);

        /**** Reconstruction ****/
        real_mod[i] = (float) (mag[i] * Math.cos(phase[i]));
        imag_mod[i] = (float) (mag[i] * Math.sin(phase[i]));

        double freq = (double)i*(double)fs/(double)N;
        Toast.makeText(getApplicationContext(), 
                       "Frequency: "+ Double.toString(freq) + 
                       "Magnitude: "+ Double.toString(mag[i]), 
                       Toast.LENGTH_LONG).show();

    }
    fft.inverse(real_mod, imag_mod, res);
    return res;

}

private void process(float[] fft){

}

@SuppressWarnings("deprecation")
private void frequencyCollection(){
    int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    int format = AudioFormat.ENCODING_PCM_16BIT;
    int sampleSize = 8000;
    int bufferSize = AudioRecord.getMinBufferSize(sampleSize, channel_config, format);
    AudioRecord audioInput = new AudioRecord(AudioSource.MIC, sampleSize, channel_config, format, bufferSize);

    byte[] audioBuffer = new byte[bufferSize];
    audioInput.startRecording();
    audioInput.read(audioBuffer, 0, bufferSize);

    float[] fftTempArray = new float[bufferSize];
    for (int i=0; i<bufferSize; i++)
    {
        fftTempArray[i] = audioBuffer[i];
    }
    fftArray = fftTempArray;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.record, menu);
    return true;
}

}

我很确定大部分都行不通。现在我正在尝试理解并完成接收字节数组并通过FFT发送它的代码。在那之后,我想从FFT得到它,并找到特定部分的最大频率(四分音符),这样我就可以完成其余部分(其中我知道该怎么做)。我该如何完成这些步骤?

1 个答案:

答案 0 :(得分:0)

这些步骤不适用于大多数实际的现场音乐,因为大多数音乐音高都由非常复杂的FFT频率序列表示(每“四分音符”的最大频率多一个)。在mirex-IR查看很多研究生论文,了解如何在有限的案例中解决问题。