2012-08-07 33 views
6

Tôi có tệp âm thanh (.3gp) và khoảng ~ 1 phút. Tôi muốn nhận được tần số của tập tin âm thanh này trong mỗi 1/4 giây. Ý tưởng của tôi là nhận mẫu trong mỗi 1/4 giây từ tệp âm thanh và sử dụng FFT tôi có thể nhận được các giá trị tần số. Có cách nào để làm điều này không?Nhận tần suất của một tệp âm thanh trong mỗi 1/4 giây trong android

Thực ra tôi sẽ chia tệp âm thanh thành các tệp âm thanh mẫu 1/4sec (alwyas ghi đè lên tập tin âm thanh), sau đó sử dụng thuật toán FFT và phát hiện tần suất mà magintude là bigggest. Nhưng có thể có các giải pháp dễ dàng hơn tuy nhiên tôi không có một đầu mối làm thế nào để làm điều này hoặc.

*** UPDATE 2 - mã mới

tôi sử dụng mã này cho đến nay:

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

    @Override 
    protected Void doInBackground(Void... arg0) { 

     try { 
      int bufferSize = AudioRecord.getMinBufferSize(frequency, 
      AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); 


      //int bufferSize = AudioRecord.getMinBufferSize(frequency, 
        // channelConfiguration, audioEncoding); 

      AudioRecord audioRecord = new AudioRecord( 
        MediaRecorder.AudioSource.MIC, frequency, 
        channelConfiguration, audioEncoding, bufferSize); 

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


      audioRecord.startRecording(); 


      // started = true; hopes this should true before calling 
      // following while loop 

      while (started) { 
       sampling++; 

       double[] re = new double[blockSize]; 
       double[] im = new double[blockSize]; 

       double[] newArray = new double[blockSize*2]; 
       double[] magns = new double[blockSize]; 

       double MaxMagn=0; 
       double pitch = 0; 

       int bufferReadResult = audioRecord.read(buffer, 0, 
         blockSize); 


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

       newArray = FFTbase.fft(re, im,true); 

       for (int i = 0; i < newArray.length; i+=2) { 

        re[i/2]=newArray[i]; 
        im[i/2]=newArray[i+1]; 
        magns[i/2] = Math.sqrt(re[i/2]*re[i/2]+im[i/2]*im[i/2]); 
       } 

       // I only need the first half  

       for (int i = 0; i < (magns.length)/2; i++) { 
        if (magns[i]>MaxMagn) 
        { 
         MaxMagn = magns[i]; 
         pitch=i; 
        } 
       }           
       if (sampling > 50) { 
        Log.i("pitch and magnitude", "" + MaxMagn + " " + pitch*15.625f); 
        sampling=0; 
        MaxMagn=0;pitch=0; 
        }     


      } 

      audioRecord.stop(); 

     } catch (Throwable t) { 
      t.printStackTrace(); 
      Log.e("AudioRecord", "Recording Failed"); 
     } 
     return null; 
    } 

tôi sử dụng này: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

chuỗi Guitar vẻ đúng, nhưng âm thanh của riêng tôi không phải là tốt vì điều này:

enter image description here

Độ lớn của hai đỉnh thay đổi phần lớn thời gian và tôi luôn tìm ra mức lớn nhất để có được tần số cơ bản.

+0

Xin chào, tôi có cùng một sự cố, tôi cần ghi lại thời gian thực thoại và tính tần suất trong mỗi 4ms, bạn đã đạt được điều này như thế nào? Bất kỳ mã mẫu nào với bạn? –

+0

Xin chào, tôi đã không thành công để vượt qua vấn đề tuy nhiên âm thanh guitar của tôi là thích hợp 9 trên 10, nhưng giọng nói của tôi có thể là 7 trong số 10 .. –

Trả lời

7

Pitch theo dõi với FFT được hỏi như vậy thường trên Stack Overflow tôi đã viết một blog entry with sample code. Mã này là trong C, nhưng với lời giải thích và liên kết bạn sẽ có thể làm những gì bạn muốn.

Để chia nó thành khoảng tăng 1/4 giây, bạn có thể chỉ cần lấy FFT của 1/4 phân đoạn thứ hai như bạn đã đề xuất, thay vì mặc định (mà tôi nghĩ là khoảng 1 giây). Nếu điều này không cung cấp cho bạn độ phân giải tần số bạn muốn, bạn có thể phải sử dụng phương pháp nhận dạng độ cao khác. Một điều bạn có thể làm là sử dụng các phân đoạn chồng chéo dài hơn 1/4 giây, nhưng bắt đầu tại các khoảng cách cách nhau 1/4 giây. Phương pháp này được ám chỉ đến mục nhập blog, nhưng nó có thể không đáp ứng thông số kỹ thuật thiết kế của bạn.

+0

Cảm ơn câu trả lời, cập nhật nhiệm vụ của tôi với mã của tôi. Tôi đã giải quyết được 1/4 giây khi bắt đầu một bộ đếm mẫu và khi nó đạt đến một giá trị đã cho, nó bắt đầu lại. Nhưng phát hiện sân không tốt ở tần số cao hơn.Nếu tôi tạo ra âm thanh lớn, âm điệu trên làm cho toàn bộ điều sai và tôi nhận được khoảng 13khz thay vì 3khz. Tuy nhiên ví dụ tôi nhận được 600hz insted của 1kz vì vậy tôi không biết whats vấn đề. –

+0

Vấn đề là nếu bạn có âm thanh có sóng hài (nghĩa là bất kỳ nhạc cụ nào, hoặc bất kỳ tiếng ồn nào không phải là sóng sin thuần túy) thì chỉ cần tìm điểm cao nhất của FFT sẽ không cho bạn biết độ cao. Tần số tương ứng với độ cao có thể là biên độ thấp hơn sóng hài. Bạn cần phải đọc trên [thuật toán Ước tính Pitch] (http://en.wikipedia.org/wiki/Pitch_detection_algorithm) –

+0

Đó là sự thật mà the_mandrill đã nói, nhưng rõ ràng bạn có các vấn đề khác vì tần suất bạn nhận được không phải là bội số và do đó không phải là hài. Nếu tôi có cơ hội sau này, tôi sẽ xem xét kỹ hơn mã của bạn, nhưng trên skim đầu tiên có vẻ như bạn đang mắc phải một vài sai lầm: 1. xem xét toàn bộ dữ liệu được chuyển đổi, thay vì nửa dưới, 2. không cửa sổ dữ liệu của bạn. Tất cả điều này và nhiều hơn nữa được đề cập trong hướng dẫn nhập blog của tôi. –

1

Hãy thử AsyncTask:

class GetFrequency extends AsyncTask<String, Void, Void> { 
    public Void doInBackground(String... params) { 
      while (true) { 

      // Apply Logic Here 

      try { 
       Thread.sleep(250); 
       } catch (Exception ie) { 
        // TODO Auto-generated catch block 
       e.printStackTrace(); 
       } 
     } 
    } 
} 

Gọi này trong MainActivity của bạn bằng cách,

frequencyButtonListener.setOnClickListener(new OnClickListener() { 

     @Override 
     public void onClick(View v) { 

     new GetFrequency.execute(params); 

     } 
    }); 
+0

Xin chào, Cảm ơn bạn đã trả lời. Tôi có một số lỗi tôi không thể sửa chữa. Cập nhật onPostExecute, onPreExecute và onProgress cho tôi lỗi sytax. –

+0

Nếu bạn không muốn chúng, sau đó chỉ cần loại bỏ chúng !! –

+0

Tôi đã xóa chúng. Thành thật mà nói, tôi không hiểu làm thế nào nó sẽ làm việc. Tôi có một tập tin .3gp trong /sdcard/music.3gp và muốn phân tích điều đó. Vì vậy, tôi đã thực hiện một nút với GetFrequency.execute (params) mới; nhưng nó mang lại cho tôi một lỗi GetFrequency.execute không thể được giải quyết thành một loại. –

Các vấn đề liên quan