我有一个关于我在做一个声音合成应用程序的问题。 我试图在音频文件读取,创建随机的“杂粮”使用颗粒合成技术 ,将它们放置到输出缓冲区,然后能够播放回使用OpenAL的用户。 出于测试目的,我只是写输出缓冲区中的文件,我可以再听听回。
看我的成绩,我在正确的轨道上,但我得到一些混淆的问题和播放声音,只是似乎不太对劲。 通常有输出文件和音量水平中间的相当响亮的流行是在时间非常响亮。
下面是我已得到我需要的结果的步骤,但我有点困惑的几件事情,即格式化,我指定我AudioStreamBasicDescription。
阅读从我mainBundle,这是.AIFF格式的单文件的音频文件:
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 *的),我想将它转换为浮动这是音频处理明显的数据。 之前,我成立了一个for循环刚刚通过缓冲迭代和每个样本转换为浮动*。 这似乎没有必要那么现在我通过我的.mData缓冲区我创建了一个函数,然后granularizes音频:
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格式。 我的问题是这样的:我在正确处理.mData缓冲区中,我铸造样品浮点数据,操纵(制粒)不同的窗口大小,然后将它写入到使用ExtAudioFileWrite一个文件(CAF格式)? 有没有更优雅的方式来做到这一点,如宣布我ASBD formatFlag为kAudioFlagIsFloat? 我的输出CAF文件中有一些点击,当我在逻辑打开它,它看起来像有很多混淆的。 这是有道理的,如果我试图把它漂浮数据,但有某种转换发生的这我不知道的。
在此先感谢对此事的任何建议! 我一直在几乎所有的源材料的热心读者在网上,包括Core声读物,各种博客,教程等我的应用程序的最终目的是用耳机,因此发挥实时颗粒化音频的用户写入文件的事只是被用于目前的测试。 谢谢!