views:

92

answers:

2

Total noob to anything lower-level than Java, diving into iPhone audio, and realing from all of the casting/pointers/raw memory access.

I'm working with some example code wich reads a WAV file from disc and returns stereo samples as single UInt32 values. If I understand correctly, this is just a convenient way to return the 32 bits of memory required to create two 16 bit samples. Eventually this data gets written to a buffer, and an audio unit picks it up down the road. Even though the data is written in UInt32-sized chunks, it eventually is interpreted as pairs of 16-bit samples.

What I need help with is splitting these UInt32 frames into left and right samples. I'm assuming I'll want to convert each UInt32 into an SInt16, since an audio sample is a signed value. It seems to me that for efficiency's sake, I ought to be able to simply point to the same blocks in memory, and avoid any copying.

So, in pseudo-code, it would be something like this:

UInt32 myStereoFrame = getFramefromFilePlayer;

SInt16* leftChannel = getFirst16Bits(myStereoFrame);
SInt16* rightChannel = getSecond16Bits(myStereoFrame);

Can anyone help me turn my pseudo into real code?

Edit:

Much thanks to zneak for this answer, which works great:

SInt16* left = (SInt16*)&myUInt32Chunk;
SInt16* right = left + 1;

Now, to reassemble my SInt16s into a UInt32 (assuming I don't want to just use my original variable, myStereoFrame), I'll need to do more or less the same in reverse: line up my two SInt16s in contiguous memory slots and then cast that memory to a UInt32.

So I make an array:

SInt16 newFrameInMemory[2] = {*left, *right}

And then copy the entire length of that array into a UInt32

UInt32 newFrame32 = newFrameInMemory

That doesn't work though, but if I do this bit of ugliness -- cast the array to a pointer, then dereference the pointer, it does work.

UInt32 newFrame32 = *((UInt32*)&newFrameInMemory)

Is there a prettier way to do this?

+1  A: 

It's quite easy:

SInt16* left = (SInt16*)&myUInt32Chunk;
SInt16* right = left + 1;

Unless the iPhone is little-endian, in which case you'll have to invert right and left.

Since an int can be seen as two contiguous shorts, you just have to get the address to it, and then do exactly as if it was, indeed, two shorts.

zneak
Perfect! Thank you!
morgancodes
A: 

iPhone is little endian :-)

Corey