jangofett jangofett - 5 months ago 130
iOS Question

ios Core audio: how to get samples from AudioBuffer with interleaved audio

I have read an audio file into

AudioBufferList
with
ExtAudioFileRead
function.

This is and ASBD for the audio:

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];


So we got and interleaved audio with 2 channels with 16 bits signed int for each channel

AudioBufferList
init:

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;


And reading into buffer:

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


audioFileObject
is and instance of
ExtAudioFileRef
which is initiated earlier in code which I did not paste here to save space.


What I am trying to accomplish is to modify audio samples in my render callback.

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;

}


Is it possible to get Sint16 left and right channel samples from UInt32 array of audio data?

Answer

Let both audioData and frameBuffer be SInt16s:

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

Your buffer size calculations should be n * 2 * sizeof(SInt16) and you'll either need to changesoundStruct` or add type casts.

Then you can access the interleaved samples like so:

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
Comments