2016-06-26 72 views
2

我已经读取音​​频文件AudioBufferListExtAudioFileRead函数。
这是和ASBD的音频:ios核心音频:如何从音频缓冲区获得采样与交错音频

AudioStreamBasicDescription importFormat; 

importFormat.mFormatID   = kAudioFormatLinearPCM; 
importFormat.mFormatFlags  = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
importFormat.mBytesPerPacket = 4; 
importFormat.mFramesPerPacket = 1; 
importFormat.mBytesPerFrame  = 4; 
importFormat.mChannelsPerFrame = 2; 
importFormat.mBitsPerChannel = 16; 
importFormat.mSampleRate = [[AVAudioSession sharedInstance] sampleRate]; 

因此,我们得到和交错的音频,2个通道,16位有符号整数为每个通道
AudioBufferList初始化:

UInt32 *audioData = (UInt32 *) calloc (totalFramesInFile, sizeof (UInt32)); 

AudioBufferList *bufferList; 
bufferList = (AudioBufferList *) malloc (sizeof (AudioBufferList)); 

// buffers amount is 1 because audio is interleaved 
bufferList->mNumberBuffers = 1; 

bufferList->mBuffers[0].mNumberChannels = 2; 
bufferList->mBuffers[0].mDataByteSize = totalFramesInFile * sizeof(UInt32); 
bufferList->mBuffers[0].mData   = audioData; 

并读入缓冲区:

CheckError(ExtAudioFileRead (
          audioFileObject, 
          &numberOfPacketsToRead, 
          bufferList), "error ExtAudioFileRead"); 

audioFileObject是和的实例这是在代码中启动的,我没有在这里粘贴以节省空间。
我试图完成的是修改我的渲染回调中的音频样本。

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


    ViewController *view = (__bridge ViewController *) inRefCon; 

    soundStruct *soundStruct = (soundStruct *) &view->mys; 

    SInt64   frameTotalForSound  = soundStruct->frameCount; 

    soundStruct->isPlaying = true; 

    UInt32 *audioData = soundStruct->audioData; 

    UInt32 sampleNumber = soundStruct->sampleNumber; 

    for(int i = 0; i < ioData->mNumberBuffers; i++){ 

     AudioBuffer buffer = ioData->mBuffers[i]; 
     UInt32 *frameBuffer = buffer.mData; 

     for(UInt32 frame = 0; frame < inNumberFrames; frame++) { 

      // here I fill the buffer with my audio data. 
      // i need to get left and right channel samples 
      // from audioData[sampleNumber], modify them 
      // and write into frameBuffer 

      frameBuffer[frame] = audioData[sampleNumber]; 

      sampleNumber++; 

      if(sampleNumber > frameTotalForSound) { 
       soundStruct->isPlaying = false; 
       AudioOutputUnitStop(soundStruct->outputUnit); 
      } 
     } 
    } 

    soundStruct->sampleNumber = sampleNumber; 

    return noErr; 

} 

是否有可能从UInt32阵列音频数据获取Sint16左右声道采样?

+0

我不知道如果我理解你的问题:您的程序是以交错的“UInt32”格式生成音频数据,并希望将其转换为非交错的“SInt16”,以进行实时播放? – user3078414

+0

@ user3078414,不完全。我根本不想转换。我有一个音频文件,每个通道都有交错的音频和“SInt16”值。目标是将其写入'AudioBufferList'并保存在内存中。当RemoteIO AudioUnit请求新的声音部分时,会触发此呈现回调,并且我希望实时修改每个通道的采样。由于有2个通道 - 我将样品存储在'UInt32'阵列中。我不确定这是否是一个正确的电话,因为我不知道如何在稍后的回调中抽取样本。 – jangofett

+1

这是我的[答案](http://stackoverflow.com/questions/37670071/using-extaudiofilewriteasync-in-callback-function-cant-get-to-run/37684811#37684811)到一个类似的,但稍有不同的问题:输出 - 写入文件需要一个交错缓冲区,而AU产生非交错缓冲区。我还看到了你的问题的答案 - 对最内层实时循环中的索引乘法要小心......''[2 *(n-1)+1]'对演示的清晰度很好 - 我宁愿使用[n + n-1]'代替。 ( - : – user3078414

回答

1

让双方audioDataframeBufferSInt16 S:

SInt16 *audioData; 
// ... 
SInt16 *frameBuffer; 

你缓冲区大小的计算应该是n * 2 * sizeof(SInt16) and you'll either need to change soundStruct`或添加类型转换。

然后你就可以访问交错样本像这样:

frameBuffer[0] = modify(audioData[0]); // left sample 1 
frameBuffer[1] = modify(audioData[1]); // right sample 1 
frameBuffer[2] = modify(audioData[2]); // left sample 2 
frameBuffer[3] = modify(audioData[3]); // right sample 2 
// ... 
frameBuffer[2*(n-1)] = modify(audioData[2*(n-1)]); // left sample n 
frameBuffer[2*(n-1)+1] = modify(audioData[2*(n-1)+1]); // right sample n 
1

@Rhythmic Fistman,非常感谢 - 它帮助。
我无法设置frameBuffer以这种方式工作。输出声音失真。
我想这是因为AudioUnit期望一个帧中的两个通道数据。或者,也许还有一些解释。
下面是我修改了代码,希望这将帮助别人:

audioData初始化:

SInt16 *audioData = (SInt16 *) malloc (sizeof(SInt16) * totalFramesInFile * 2); 

修改呈现回调:

OSStatus MyCallback (void *inRefCon, 
      AudioUnitRenderActionFlags *ioActionFlags, 
      const AudioTimeStamp *inTimeStamp, 
      UInt32 inBusNumber, 
      UInt32 inNumberFrames, 
      AudioBufferList *ioData) 
{ 
    ViewController *view = (__bridge ViewController *) inRefCon; 

    soundStruct *soundStruct = (soundStruct *) &view->mys; 

    SInt64 frameTotalForSound = soundStruct->frameCount; 

    soundStruct->isPlaying = true; 

    SInt16 *audioData = soundStruct->audioData; 

    UInt32 sampleNumber = soundStruct->sampleNumber; 

    for(int i = 0; i < ioData->mNumberBuffers; i++){ 
     AudioBuffer buffer = ioData->mBuffers[i]; 
     SInt16 *frameBuffer = (SInt16*) ioData->mBuffers[0].mData; 

     for(UInt32 frame = 0; frame < inNumberFrames * 2; frame+=2) { 

      /* .. some samples modification code .. */ 

      // left channel 
      frameBuffer[frame] = audioData[sampleNumber]; 
      // right channel 
      frameBuffer[frame + 1] = audioData[sampleNumber + 1]; 

      sampleNumber +=2; 

      if(sampleNumber > frameTotalForSound * 2) { 
       soundStruct->isPlaying = false; 
       AudioOutputUnitStop(soundStruct->outputUnit); 
      } 
     } 
    } 

    soundStruct->sampleNumber = sampleNumber; 
    return noErr; 
} 
+1

为什么不把'frameBuffer'改为'SInt16'?那么你就不需要修改这个对。 –

+0

完成:)我修改了源代码。现在没有失真,并且一切似乎都很好。感谢您的帮助 – jangofett

+0

不客气! –