Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use the native fixed point type (8.24) for iOS audio processing

so i want to properly scale floats in the range of -1 to +1 into the format expected by an AUGraph with a stream format that is set up like this:

size_t bytesPerSample = sizeof (AudioUnitSampleType); // is 4 bytes

stereoStreamFormat.mFormatID          = kAudioFormatLinearPCM;
stereoStreamFormat.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
stereoStreamFormat.mBytesPerPacket    = bytesPerSample;
stereoStreamFormat.mFramesPerPacket   = 1;
stereoStreamFormat.mBytesPerFrame     = bytesPerSample;
stereoStreamFormat.mChannelsPerFrame  = 2;                    
stereoStreamFormat.mBitsPerChannel    = 8 * bytesPerSample;
stereoStreamFormat.mSampleRate        = graphSampleRate; // 44.1k

this question helped me setup the graph, but when i cast a float like this:

sampleValueLeft = (Fixed) (floatVal * 32767.0f); 
// there doesn't seem to be any difference whether i cast into 
// SInt16 or SInt32 (which the Fixed type is defined to be)..

it works, the signal sounds good, but is very quiet. So i'm doing the scaling wrong? Scaling by a bigger number messes up the signal. Doesn't sound like clipping, and the output volume does not get higher. I do not intend to deeply study fixed point math, all i need is a one-liner which casts into the proper format.

thank you!

edit: i had been using a different stream format before which i could not figure out how to use properly with a stereo signal. With this different setup, i have had no trouble with the output volume though, so i figure the gain problem must have to do with the scaling...

like image 591
Jakob Avatar asked Feb 25 '23 02:02

Jakob


2 Answers

Read this post, it is a really good explanation on the iOS 8.24 format.

Here is its conclusion:
Basically it tells you that the first (left) 8 bits are dedicated only for the (+/-) sign, the rest 24 bits are the sound.
So if you want to convert it to a Sint16 shift the bits 9 places to the right and cast. This way the (+/-) sign is preserved in the as the first bit and the sound data is reduced to a lower precision.
If you want it as a float in the range of (+/-)1 to 0, divide it by the maximum posible value which is 32768.

Here is the code:

    SInt16 sampleInt16 = (SInt16)(samples[i] >> 9);
    float sampleFloat = sampleInt16 / 32768.0;
like image 176
Eyal.K Avatar answered May 03 '23 21:05

Eyal.K


I hate 8.24, because I don't think there are convenience functions to do math with it.

Counter-proposal: put a converter unit (AUConverter) at the front of your graph, and set the input ASBD to be something more convenient for you, like 16-bit ints or whatever (I always use ints on iOS... floats may work going into a converter, but I wouldn't count on it). Don't set the converter's output ASBD; it'll just default to audio unit canonical (8.24). In fact, see if you can set a convenient ASBD on your first unit without using an AUConverter.

like image 39
invalidname Avatar answered May 03 '23 20:05

invalidname