5

Tôi đang cố gắng tạo một ứng dụng chạy FFT trên dữ liệu micrô, vì vậy tôi có thể kiểm tra ví dụ: tần số to nhất trong đầu vào.Truyền dữ liệu AVCaptureAudioDataOutput vào vDSP/Accelerate.framework

Tôi thấy rằng có rất nhiều phương pháp nhận đầu vào âm thanh (Remote AudioUnit, AudioQueue dịch vụ và AVFoundation) nhưng có vẻ như AVFoundation là đơn giản nhất. Tôi có thiết lập này:

// Configure the audio session 
AVAudioSession *session = [AVAudioSession sharedInstance]; 
[session setCategory:AVAudioSessionCategoryRecord error:NULL]; 
[session setMode:AVAudioSessionModeMeasurement error:NULL]; 
[session setActive:YES error:NULL]; 

// Optional - default gives 1024 samples at 44.1kHz 
//[session setPreferredIOBufferDuration:samplesPerSlice/session.sampleRate error:NULL]; 

// Configure the capture session (strongly-referenced instance variable, otherwise the capture stops after one slice) 
_captureSession = [[AVCaptureSession alloc] init]; 

// Configure audio device input 
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; 
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL]; 
[_captureSession addInput:input]; 

// Configure audio data output 
AVCaptureAudioDataOutput *output = [[AVCaptureAudioDataOutput alloc] init]; 
dispatch_queue_t queue = dispatch_queue_create("My callback", DISPATCH_QUEUE_SERIAL); 
[output setSampleBufferDelegate:self queue:queue]; 
[_captureSession addOutput:output]; 

// Start the capture session. 
[_captureSession startRunning]; 

(cộng với kiểm tra lỗi, bỏ qua ở đây để dễ đọc).

Sau đó, tôi thực hiện AVCaptureAudioDataOutputSampleBufferDelegate phương pháp sau đây:

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection 
{ 
    NSLog(@"Num samples: %ld", CMSampleBufferGetNumSamples(sampleBuffer)); 
    // Usually gives 1024 (except the first slice) 
} 

tôi không chắc chắn những gì bước tiếp theo nên được. Định dạng CMSampleBuffer mô tả chính xác (và những giả định nào có thể được thực hiện về nó, nếu có)? Làm cách nào để nhận dữ liệu âm thanh thô thành vDSP_fft_zrip với số tiền xử lý bổ sung ít nhất có thể? (Ngoài ra, bạn sẽ khuyên bạn nên làm gì để xác minh rằng dữ liệu thô tôi thấy là chính xác?)

Trả lời

6

CMSampleBufferRef là loại mờ có chứa từ 0 mẫu trở lên. Có một chút lời giới thiệu trong tài liệu:

http://developer.apple.com/library/ios/#documentation/CoreMedia/Reference/CMSampleBuffer/Reference/reference.html

Trong trường hợp này nó sẽ chứa một bộ đệm âm thanh, cũng như mô tả của các định dạng mẫu và thông tin thời gian và vân vân. Nếu bạn thực sự quan tâm chỉ cần đặt một breakpoint trong gọi lại đại biểu và hãy xem.

Bước đầu tiên là để có được một con trỏ đến bộ đệm dữ liệu đã được trả về:

// get a pointer to the audio bytes 
CMItemCount numSamples = CMSampleBufferGetNumSamples(sampleBuffer); 
CMBlockBufferRef audioBuffer = CMSampleBufferGetDataBuffer(sampleBuffer); 
size_t lengthAtOffset; 
size_t totalLength; 
char *samples; 
CMBlockBufferGetDataPointer(audioBuffer, 0, &lengthAtOffset, &totalLength, &samples); 

Định dạng mẫu mặc định cho mic iPhone là PCM tuyến tính, với mẫu 16 bit. Điều này có thể là đơn âm hoặc âm thanh nổi tùy thuộc vào micrô bên ngoài hay không. Để tính toán FFT, chúng ta cần có một vector float. May mắn thay có một thúc đẩy chức năng để làm việc chuyển đổi đối với chúng tôi:

// check what sample format we have 
// this should always be linear PCM 
// but may have 1 or 2 channels 
CMAudioFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer); 
const AudioStreamBasicDescription *desc = CMAudioFormatDescriptionGetStreamBasicDescription(format); 
assert(desc->mFormatID == kAudioFormatLinearPCM); 
if (desc->mChannelsPerFrame == 1 && desc->mBitsPerChannel == 16) { 
    float *convertedSamples = malloc(numSamples * sizeof(float)); 
    vDSP_vflt16((short *)samples, 1, convertedSamples, 1, numSamples); 
} else { 
    // handle other cases as required 
} 

Bây giờ bạn có một vector phao của bộ đệm mẫu mà bạn có thể sử dụng với vDSP_fft_zrip. Có vẻ như không thể thay đổi định dạng đầu vào từ micrô thành mẫu nổi với AVFoundation, vì vậy bạn đang mắc kẹt với bước chuyển đổi cuối cùng này. Tôi sẽ giữ xung quanh các bộ đệm trong thực tế, reallocing chúng nếu cần thiết khi một bộ đệm lớn hơn đến, do đó bạn không mallocing và giải phóng bộ đệm với mỗi gọi lại đại biểu.

Đối với câu hỏi cuối cùng của bạn, tôi đoán cách dễ nhất để làm điều này là tiêm đầu vào đã biết và kiểm tra xem nó có cung cấp cho bạn phản hồi chính xác không. Bạn có thể chơi một sóng sin vào micrô và kiểm tra xem FFT của bạn có cao điểm trong thùng tần số chính xác hay không, giống như vậy.

+0

"Định dạng âm thanh mặc định cho micrô iPhone là một kênh gồm 16 bit nguyên" - thông tin này đến từ đâu? Tôi lo ngại rằng việc đưa ra các giả định như thế này sẽ không an toàn nói chung trên phần cứng thiết bị khác nhau. – jtbandes

+0

Bạn nói đúng, và giả định là trên thực tế sai, tôi đã cập nhật để kiểm tra định dạng âm thanh. Một số nhận xét ở đây về các mặc định AVCapture: http://developer.apple.com/library/ios/#samplecode/AVCaptureToAudioUnit/Listings/CaptureSessionController_mm.html – Tark

1

Tôi không đề nghị sử dụng AVFoundation cho 3 lý do:

  1. tôi đã sử dụng nó cho một số ứng dụng mỏ (morsedec, irtty), nó hoạt động tốt trên giả lập và trong một số phần cứng, nhưng trong những người khác hoàn toàn thất bại !
  2. bạn không có quyền kiểm soát tốt tỷ lệ mẫu ở định dạng.
  3. độ trễ có thể cao.

Tôi đề nghị bắt đầu bằng mã mẫu aurioTouch của apple. Để thực hiện FFT, bạn có thể chuyển sang khung công tác vDSP bằng bộ đệm tròn (I LOVE https://github.com/michaeltyson/TPCircularBuffer).

Hy vọng trợ giúp này

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