2012-01-21 15 views
5

AUGraphで一連のオーディオユニットを順番に持つシンプルなアプリケーションを作成しようとしていますが、その出力をファイルに書き込みます。 AUGraphAddRenderNotifyを使ってコールバックを追加しました。ここに私のコールバック関数です:AUGraphの出力をファイルに書き込む方法は?

OSStatus MyAURenderCallback(void *inRefCon, 
         AudioUnitRenderActionFlags *actionFlags, 
         const AudioTimeStamp *inTimeStamp, 
         UInt32 inBusNumber, 
         UInt32 inNumberFrames, 
         AudioBufferList *ioData) { 
    if (*actionFlags & kAudioUnitRenderAction_PostRender) { 
     ExtAudioFileRef outputFile = (ExtAudioFileRef)inRefCon; 
     ExtAudioFileWriteAsync(outputFile, inNumberFrames, ioData); 
    } 
} 

この種の作品です。ファイルは再生可能で、録音したものを聞くことができますが、静かに聞こえるほどの量の聴力があります。

誰にも分かりませんが、これは間違っていますか?あるいは、誰かがAUGraphの出力をファイルに記録する良い方法を知っていますか?

ありがとうございます。

+0

AUGraphとExtAudioFile(クライアントデータ形式)の形式は一致していますか?また、リアルタイムで記録する必要がありますか? – sbooth

+0

私はそれらがマッチすると思います。私は同じAudioStreamBasicDescriptionを使ってすべてのオーディオユニットを設定し、ファイルを作成しました。私は実際にどのようにチェックするのか分からない。あなたはそれをする方法を知っていますか?私はそれを調べるだろうと思う。 私はリアルタイムで記録する必要はないと思いますが、それを行うには他の方法がありますか?私がデータをリアルタイムで保存しないと、失われます。 – HowsItStack

+0

私は 'AUGraphStart'を呼び出す代わりに、グラフの先頭に' AudioUnitRender'を繰り返し呼び出すと思います。私はリアルタイムでそれを行うことの問題は、 'ExtAudioFile'の内部リングバッファがいっぱいになり、データを失うことだと思います。 – sbooth

答えて

6

私は私を助けてくれただけで、今のオーディオユニットに関してとひらめきました私自身の問題を解決する。私は、オーディオユニットの接続とコールバックのレンダリングについて誤解を感じました。私はそれらが完全に別のものだと思っていましたが、接続はレンダリングコールバックのための短い手です。オーディオユニットBの入力にオーディオユニットAの出力からkAudioUnitProperty_MakeConnectionを行う

は、ユニットBの入力上のkAudioUnitProperty_SetRenderCallbackを行って、オーディオユニットA

の出力にコールバック関数呼び出しAudioUnitRenderを有する同じです

私はレンダリングコールバックを設定した後にmake接続を行い、レンダリングコールバックが呼び出されなくなったことをテストしました。

OSStatus MyAURenderCallback(void *inRefCon, 
         AudioUnitRenderActionFlags *actionFlags, 
         const AudioTimeStamp *inTimeStamp, 
         UInt32 inBusNumber, 
         UInt32 inNumberFrames, 
         AudioBufferList *ioData) { 

    AudioUnit mixerUnit = (AudioUnit)inRefCon; 

    AudioUnitRender(mixerUnit, 
        actionFlags, 
        inTimeStamp, 
        0, 
        inNumberFrames, 
        ioData); 

    ExtAudioFileWriteAsync(outputFile, 
          inNumberFrames, 
          ioData); 

    return noErr; 
} 

は、このおそらく私には明らかとなっている必要があります。

したがって、私は以下のようにして、私の問題を解決することができました:

をそして、彼らは私のコールバック関数は、このような何かをしました私は同じ方法で混乱している他の人がいると確信していますので、これは彼らにとっても役立ちます。

私はAUGraphAddRenderNotifyコールバックに問題があった理由はまだ分かりません。私はこれを後で深く掘り下げますが、今のところ私はうまくいくと思われる解決策を見つけました。

+0

上記のコードは実際に動作しますか? refConを 'self'に設定してコールバックでAUMixerとしてキャストすると、エラーが発生すると思います。 –

+0

あなたは正しいです。私はプロジェクトのコードを少し簡略化しました。私は自分自身を渡し、プロパティを介してmixerUnitにアクセスしました。投稿を更新して出力ユニットの前のユニットであるmixerUnitを出力ユニットに渡す前にファイルに書きたいと思っていました。 – HowsItStack

+0

よかったですね。レンダリングコールバックをremoteIOインスタンスに置き、レンダリングしたデータを 'post_Render'ステージで取得することで、グラフ出力をファイルに保存する私のソリューションに興味があるかもしれません。それが「良い」方法であるかどうかは分かりませんが、それは機能します。また、ACCの圧縮形式の作業をライブで保存しました(よろしく!):http://stackoverflow.com/questions/10113977/recording-to-aac-from-remoteio-data-is-getting-written-but-file-unplayable –

0

多分これを試してください。オーディオユニットのコールバックから長いバッファにデータをコピーします。それをテストするためにバッファを再生し、次にバッファ全体がOKであることを確認した後でバッファ全体をファイルに書き込みます。ここで

1

は役立つかもしれない(プロジェクトが再生手順であるが、それはMIDI特有の問題ではありません)、アップルからいくつかのサンプルコードです:

{ 
    CAStreamBasicDescription clientFormat = CAStreamBasicDescription(); 
    ca_require_noerr (result = AudioUnitGetProperty(outputUnit, 
                kAudioUnitProperty_StreamFormat, 
                kAudioUnitScope_Output, 0, 
                &clientFormat, &size), fail); 
    size = sizeof(clientFormat); 
    ca_require_noerr (result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), fail); 

    { 
     MusicTimeStamp currentTime; 
     AUOutputBL outputBuffer (clientFormat, numFrames); 
     AudioTimeStamp tStamp; 
     memset (&tStamp, 0, sizeof(AudioTimeStamp)); 
     tStamp.mFlags = kAudioTimeStampSampleTimeValid; 
     int i = 0; 
     int numTimesFor10Secs = (int)(10./(numFrames/srate)); 
     do { 
      outputBuffer.Prepare(); 
      AudioUnitRenderActionFlags actionFlags = 0; 
      ca_require_noerr (result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL()), fail); 

      tStamp.mSampleTime += numFrames; 

      ca_require_noerr (result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL()), fail);  

      ca_require_noerr (result = MusicPlayerGetTime (player, &currentTime), fail); 
      if (shouldPrint && (++i % numTimesFor10Secs == 0)) 
       printf ("current time: %6.2f beats\n", currentTime); 
     } while (currentTime < sequenceLength); 
    } 
} 
関連する問題