5

マイク データで FFT を実行するアプリケーションを作成しようとしています。たとえば、入力で最も大きな周波数を調べることができます。

オーディオ入力を取得する方法はたくさんあります (RemoteIO AudioUnit、AudioQueue サービス、および AVFoundation) が、AVFoundation が最も単純なようです。私はこのセットアップを持っています:

// 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];

(さらにエラーチェック、読みやすくするためにここでは省略)。

次に、次のAVCaptureAudioDataOutputSampleBufferDelegateメソッドを実装します。

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

次のステップがどうあるべきかわかりません。フォーマットは正確に何CMSampleBufferを記述していますか (また、もしあれば、それについてどのような仮定を立てることができますか)? vDSP_fft_zrip追加の前処理を最小限に抑えて生のオーディオ データを取得するにはどうすればよいですか? (また、私が見た生データが正しいことを確認するために何をすることをお勧めしますか?)

4

2 に答える 2

6

CMSampleBufferRef、0 個以上のメディア サンプルを含む不透明なタイプです。ドキュメントには少し宣伝文句があります:

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

この場合、オーディオ バッファ、サンプル形式の説明、タイミング情報などが含まれます。本当に興味がある場合は、デリゲート コールバックにブレークポイントを設定して見てください。

最初のステップは、返されたデータ バッファーへのポインターを取得することです。

// 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);

iPhone マイクのデフォルトのサンプル形式は、16 ビット サンプルのリニア PCM です。これは、外部マイクがあるかどうかに応じて、モノラルまたはステレオになります。FFT を計算するには、float ベクトルが必要です。幸いなことに、変換を行うための加速関数があります。

// 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
}

これで、 で使用できるサンプル バッファの float ベクトルが得られましたvDSP_fft_zrip。を使用してマイクからフロート サンプルに入力形式を変更することはできないようですAVFoundation。私は実際にはバッファーを回避し、より大きなバッファーが到着したときに必要に応じてそれらを再割り当てして、すべてのデリゲート コールバックでバッファーを割り当てたり解放したりしないようにします。

最後の質問については、これを行う最も簡単な方法は、既知の入力を挿入し、正しい応答が得られることを確認することだと思います。マイクに正弦波を再生し、FFT が正しい周波数ビンにピークを持っていることを確認できます。

于 2012-12-31T12:20:03.620 に答える
1

次の 3 つの理由から、AVFoundation の使用はお勧めしません。

  1. 私はそれをいくつかのアプリ(morsedec、irtty)に使用しました。シミュレーターと一部のハードウェアではうまく機能しますが、他のアプリでは完全に失敗しました!
  2. フォーマットのサンプルレートを適切に制御できません。
  3. レイテンシが高くなる可能性があります。

Apple のサンプル コード aurioTouch から始めることをお勧めします。FFT を作成するには、循環バッファーを使用して vDSP フレームワークに移行できます (I LOVE https://github.com/michaeltyson/TPCircularBuffer )。

この助けを願っています

于 2013-02-08T11:08:16.670 に答える