2013-12-03 25 views
0

我目前正在嘗試創建一個Android應用程序,其中用戶按下按鈕,應用程序收聽音樂,找到節奏,從節奏收集每個四分音符的音符信息:音樂記譜儀調試和解決(Java)

  • 接收音頻字節數組。
  • 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中得到它並找出該特定部分的最大頻率(四分音符),以便我可以完成剩下的工作(我知道該怎麼做)。我應該如何完成這些步驟?

回答

0

這些步驟不適用於大多數實際的現場音樂,因爲大多數音樂音調都是由非常複雜的FFT頻率序列表示的(每個「四分音符」的最大頻率多於一個)。請在mirex-IR中查找很多關於可能如何在有限的案例中解決您的問題的研究生論文。

+0

現在我想看看是否可以用單音符組成的簡單旋律來做這樣的事情。這是可能的使用這些步驟,或者甚至是這個簡單的要求研究生水平的項目? – JoshSchellenberger

+0

如果你的旋律是由一個由嚴格節奏計時器驅動的正弦波發生器產生的話,可能是合理的。 – hotpaw2

+0

那麼你會推薦我做什麼? – JoshSchellenberger