iOS:如何将audio文件读入浮动缓冲区

我有一个非常短的audio文件,比如说.PCM格式

我想要使​​用RemoteIO重复循环文件以产生连续的音乐音调。 那么我怎么把这个读入一个浮点数组呢?

编辑:虽然我可能挖出的文件格式,提取到NSData的文件,并手动处理,我猜是有一个更合理的通用方法…(即应付不同的格式)

您可以使用ExtAudioFile以多种客户端格式从任何支持的数据格式中读取数据。 下面是一个以16位整数forms读取文件的例子:

CFURLRef url = /* ... */; ExtAudioFileRef eaf; OSStatus err = ExtAudioFileOpenURL((CFURLRef)url, &eaf); if(noErr != err) /* handle error */ AudioStreamBasicDescription format; format.mSampleRate = 44100; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFormatFlagIsPacked; format.mBitsPerChannel = 16; format.mChannelsPerFrame = 2; format.mBytesPerFrame = format.mChannelsPerFrame * 2; format.mFramesPerPacket = 1; format.mBytesPerPacket = format.mFramesPerPacket * format.mBytesPerFrame; err = ExtAudioFileSetProperty(eaf, kExtAudioFileProperty_ClientDataFormat, sizeof(format), &format); /* Read the file contents using ExtAudioFileRead */ 

如果你想Float32数据,你可以像这样设置format

 format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; format.mBitsPerChannel = 32; 

我对RemoteIO并不熟悉,但是我对WAV很熟悉,并且认为我会在其上发布一些格式信息。 如果你需要的话,你应该能够很容易的parsing出信息,比如持续时间,比特率等。

首先,这是一个很好的网站,详细介绍了WAVE PCM soundfile格式 。 这个网站也做了一个很好的工作,说明“fmt”子块内的不同字节地址是指什么。

WAVE文件格式

  • WAVE由“RIFF”块和随后的子块组成
  • 每个块至less有8个字节
  • 前4个字节是块ID
  • 接下来的4个字节是块大小(块大小给出块的剩余部分的大小,除了用于块ID和块大小的8个字节)
  • 每个WAVE都有以下块/子块
    • “RIFF”(第一块也是唯一的块,其余的在技术上都是小块的)。
    • “fmt”(通常是“RIFF”之后的第一个子块,但是可以在“RIFF”和“data”之间的任何地方),这个块有关于WAV的信息,比如通道数量,采样率和字节率)
    • “数据”(必须是最后的子块并包含所有的声音数据)

常见的WAVEaudio格式:

  • PCM
  • IEEE_Float
  • PCM_EXTENSIBLE(具有PCM或IEEE_FLOAT的子格式)

波的持续时间和大小

WAVE文件的持续时间可按如下计算:

 seconds = DataChunkSize / ByteRate 

哪里

 ByteRate = SampleRate * NumChannels * BitsPerSample/8 

并且DataChunkSize不包括为“数据”子块的ID和大小保留的8个字节。

知道这一点,如果知道WAV和ByteRate的持续时间,则可以计算DataChunkSize。

 DataChunkSize = seconds * ByteRate 

这对计算从mp3或wma等格式转换时的wav数据的大小是有用的。 请注意,一个典型的 wav头是44个字节,其次是DataChunkSize(如果使用Normalizer工具转换wav,总是这样 – 至less在撰写本文时)。

这是我用来将audio数据(audio文件)转换为浮点表示并保存到数组中的代码。

 -(void) PrintFloatDataFromAudioFile { NSString * name = @"Filename"; //YOUR FILE NAME NSString * source = [[NSBundle mainBundle] pathForResource:name ofType:@"m4a"]; // SPECIFY YOUR FILE FORMAT const char *cString = [source cStringUsingEncoding:NSASCIIStringEncoding]; CFStringRef str = CFStringCreateWithCString( NULL, cString, kCFStringEncodingMacRoman ); CFURLRef inputFileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, str, kCFURLPOSIXPathStyle, false ); ExtAudioFileRef fileRef; ExtAudioFileOpenURL(inputFileURL, &fileRef); AudioStreamBasicDescription audioFormat; audioFormat.mSampleRate = 44100; // GIVE YOUR SAMPLING RATE audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; audioFormat.mBitsPerChannel = sizeof(Float32) * 8; audioFormat.mChannelsPerFrame = 1; // Mono audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * sizeof(Float32); // == sizeof(Float32) audioFormat.mFramesPerPacket = 1; audioFormat.mBytesPerPacket = audioFormat.mFramesPerPacket * audioFormat.mBytesPerFrame; // = sizeof(Float32) // 3) Apply audio format to the Extended Audio File ExtAudioFileSetProperty( fileRef, kExtAudioFileProperty_ClientDataFormat, sizeof (AudioStreamBasicDescription), //= audioFormat &audioFormat); int numSamples = 1024; //How many samples to read in at a time UInt32 sizePerPacket = audioFormat.mBytesPerPacket; // = sizeof(Float32) = 32bytes UInt32 packetsPerBuffer = numSamples; UInt32 outputBufferSize = packetsPerBuffer * sizePerPacket; // So the lvalue of outputBuffer is the memory location where we have reserved space UInt8 *outputBuffer = (UInt8 *)malloc(sizeof(UInt8 *) * outputBufferSize); AudioBufferList convertedData ;//= malloc(sizeof(convertedData)); convertedData.mNumberBuffers = 1; // Set this to 1 for mono convertedData.mBuffers[0].mNumberChannels = audioFormat.mChannelsPerFrame; //also = 1 convertedData.mBuffers[0].mDataByteSize = outputBufferSize; convertedData.mBuffers[0].mData = outputBuffer; // UInt32 frameCount = numSamples; float *samplesAsCArray; int j =0; double floatDataArray[882000] ; // SPECIFY YOUR DATA LIMIT MINE WAS 882000 , SHOULD BE EQUAL TO OR MORE THAN DATA LIMIT while (frameCount > 0) { ExtAudioFileRead( fileRef, &frameCount, &convertedData ); if (frameCount > 0) { AudioBuffer audioBuffer = convertedData.mBuffers[0]; samplesAsCArray = (float *)audioBuffer.mData; // CAST YOUR mData INTO FLOAT for (int i =0; i<1024 /*numSamples */; i++) { //YOU CAN PUT numSamples INTEAD OF 1024 floatDataArray[j] = (double)samplesAsCArray[i] ; //PUT YOUR DATA INTO FLOAT ARRAY printf("\n%f",floatDataArray[j]); //PRINT YOUR ARRAY'S DATA IN FLOAT FORM RANGING -1 TO +1 j++; } } }}