私が取り組んでいる音声合成アプリについて質問があります。オーディオ ファイルを読み込んで、グラニュラー合成技術を使用してランダム化された「グレイン」を作成し、それらを出力バッファーに配置してから、OpenAL を使用してユーザーに再生できるようにしようとしています。テスト目的で、出力バッファーをファイルに書き込んで、後でリッスンできるようにします。
私の結果から判断すると、私は正しい方向に進んでいますが、エイリアシングの問題がいくつか発生しており、再生音はまったく正しくないようです。通常、出力ファイルの途中でかなり大きなポップ音があり、音量レベルが非常に大きくなることがあります。
必要な結果を得るために行った手順は次のとおりですが、いくつかのこと、つまり AudioStreamBasicDescription に指定している形式について少し混乱しています。
.aiff 形式のモノラル ファイルである私の mainBundle からオーディオ ファイルを読み込みます。
ExtAudioFileRef extAudioFile; CheckError(ExtAudioFileOpenURL(loopFileURL, &extAudioFile), "couldn't open extaudiofile for reading"); memset(&player->dataFormat, 0, sizeof(player->dataFormat)); player->dataFormat.mFormatID = kAudioFormatLinearPCM; player->dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; player->dataFormat.mSampleRate = S_RATE; player->dataFormat.mChannelsPerFrame = 1; player->dataFormat.mFramesPerPacket = 1; player->dataFormat.mBitsPerChannel = 16; player->dataFormat.mBytesPerFrame = 2; player->dataFormat.mBytesPerPacket = 2; // tell extaudiofile about our format CheckError(ExtAudioFileSetProperty(extAudioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &player->dataFormat), "couldnt set client format on extaudiofile"); SInt64 fileLengthFrames; UInt32 propSize = sizeof(fileLengthFrames); ExtAudioFileGetProperty(extAudioFile, kExtAudioFileProperty_FileLengthFrames, &propSize, &fileLengthFrames); player->bufferSizeBytes = fileLengthFrames * player->dataFormat.mBytesPerFrame;
次に、AudioBufferList を宣言し、さらにいくつかのプロパティを設定します。
AudioBufferList *buffers; UInt32 ablSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * 1); buffers = (AudioBufferList *)malloc(ablSize); player->sampleBuffer = (SInt16 *)malloc(sizeof(SInt16) * player->bufferSizeBytes); buffers->mNumberBuffers = 1; buffers->mBuffers[0].mNumberChannels = 1; buffers->mBuffers[0].mDataByteSize = player->bufferSizeBytes; buffers->mBuffers[0].mData = player->sampleBuffer;
私の理解では、.mData は formatFlags で指定されたものになります (この場合は、SInt16 と入力します)。タイプ (void * ) であるため、これをオーディオ操作で明らかな float データに変換したいと考えています。バッファを反復処理して各サンプルを float* にキャストする for ループを設定する前に。これは不要に思えたので、作成した関数に .mData バッファーを渡し、オーディオを粒状化します。
float *theOutBuffer = [self granularizeWithData:(float *)buffers->mBuffers[0].mData with:framesRead];
この関数では、いくつかのバッファーを動的に割り当て、ランダムなサイズのグレインを作成し、ハミング ウィンドウを使用してウィンドウ処理した後に出力バッファーに配置し、そのバッファー (フロート データ) を返します。この時点まですべてがクールです。
次に、すべての出力ファイル ASBD などを設定します。
AudioStreamBasicDescription outputFileFormat; bzero(audioFormatPtr, sizeof(AudioStreamBasicDescription)); outputFileFormat->mFormatID = kAudioFormatLinearPCM; outputFileFormat->mSampleRate = 44100.0; outputFileFormat->mChannelsPerFrame = numChannels; outputFileFormat->mBytesPerPacket = 2 * numChannels; outputFileFormat->mFramesPerPacket = 1; outputFileFormat->mBytesPerFrame = 2 * numChannels; outputFileFormat->mBitsPerChannel = 16; outputFileFormat->mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; UInt32 flags = kAudioFileFlags_EraseFile; ExtAudioFileRef outputAudioFileRef = NULL; NSString *tmpDir = NSTemporaryDirectory(); NSString *outFilename = @"Decomp.caf"; NSString *outPath = [tmpDir stringByAppendingPathComponent:outFilename]; NSURL *outURL = [NSURL fileURLWithPath:outPath]; AudioBufferList *outBuff; UInt32 abSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * 1); outBuff = (AudioBufferList *)malloc(abSize); outBuff->mNumberBuffers = 1; outBuff->mBuffers[0].mNumberChannels = 1; outBuff->mBuffers[0].mDataByteSize = abSize; outBuff->mBuffers[0].mData = theOutBuffer; CheckError(ExtAudioFileCreateWithURL((__bridge CFURLRef)outURL, kAudioFileCAFType, &outputFileFormat, NULL, flags, &outputAudioFileRef), "ErrorCreatingURL_For_EXTAUDIOFILE"); CheckError(ExtAudioFileSetProperty(outputAudioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(outputFileFormat), &outputFileFormat), "ErrorSettingProperty_For_EXTAUDIOFILE"); CheckError(ExtAudioFileWrite(outputAudioFileRef, framesRead, outBuff), "ErrorWritingFile");
ファイルは CAF 形式で正しく書き込まれます。私の質問は次のとおりです。サンプルをフロート データにキャストし、さまざまなウィンドウ サイズを操作 (粒状化) してから、ExtAudioFileWrite (CAF 形式) を使用してファイルに書き込むという点で、.mData バッファーを正しく処理していますか? ASBD formatFlag を kAudioFlagIsFloat として宣言するなど、これを行うためのよりエレガントな方法はありますか? 私の出力 CAF ファイルにはいくつかのクリックがあり、Logic で開くと、多くのエイリアシングがあるように見えます。これは、float データを送信しようとしている場合には理にかなっていますが、私が気付いていない何らかの変換が行われています。
この件に関するアドバイスをお寄せいただきありがとうございます。私は、コア オーディオ ブック、さまざまなブログ、チュートリアルなど、ほぼすべてのソース マテリアルをオンラインで熱心に読んでいます。私のアプリの最終的な目標は、グラニュラライズされたオーディオをリアルタイムでユーザーにヘッドフォンで再生することです。ファイルへの書き込みは、現時点ではテストに使用されているだけです。ありがとう!