Ogg vs Caf for audio
4 posters
Page 1 of 2 • 1, 2
Ogg vs Caf for audio
First off, in Tutorial09 you used .ogg files for all audio. Are .caf files supported as well?
What is the preferred audio file format? I may be mistaken, but I thought the iPhone can play .caf files natively and that it was the file format Apple was recommending for all audio. Don't .ogg files require a bit of processor time to make them playable? What are the pros/cons of using .ogg vs .caf?
Thanks for an awesome engine by the way. I am liking SIO2 more and more every day that i use it.
What is the preferred audio file format? I may be mistaken, but I thought the iPhone can play .caf files natively and that it was the file format Apple was recommending for all audio. Don't .ogg files require a bit of processor time to make them playable? What are the pros/cons of using .ogg vs .caf?
Thanks for an awesome engine by the way. I am liking SIO2 more and more every day that i use it.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
Yeah OGG require some processing to be playable (and a little bit way too much I think...), Im really not familiar with CAF but i'll check it out...
Tks for the tip!
Cheers,
Tks for the tip!
Cheers,
Re: Ogg vs Caf for audio
Here is a bit of info about .caf files:
The command I have been using to convert audio files for other iPhone projects is:
- For uncompressed audio, use 16-bit, little-endian, linear PCM audio packaged in a CAF file
- If you need to play multiple compressed sounds simultaneously, use the IMA/ADPCM audio (IMA4) format.
The command I have been using to convert audio files for other iPhone projects is:
- Code:
/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}
- Code:
afconvert -h
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
Yeah that's all great... but what Im expecting for its a loader to plug the binary data to OpenAL
Re: Ogg vs Caf for audio
I can give creating the loader a shot. Do you have any pointers on where to start such as the location of the ogg to openal code?
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
The Sound_Engine.cpp which comes with the CrashLander SDK example should be a good starting point. It uses CAF files and feeds them into OpenAL.
Best,
Matt
Best,
Matt
Re: Ogg vs Caf for audio
I had some problems with Sound_Engine.cpp that I never resolved in my initial testing of it. In particular is this puzzling line of code located in LoadFileData function.
It seems to limit sound files to only 8bits. Changing this to 16 didn't work, but maybe my file wasn't compatible (afconvert is a great tip! ). When I asked someone about this, they told me to use some code from WWDC which was better and they had no problems with 16 bit sounds.
- Code:
if (!TestAudioFormatNativeEndian(theFileFormat) && (theFileFormat.mBitsPerChannel > 8))
return kSoundEngineErrInvalidFileFormat;
It seems to limit sound files to only 8bits. Changing this to 16 didn't work, but maybe my file wasn't compatible (afconvert is a great tip! ). When I asked someone about this, they told me to use some code from WWDC which was better and they had no problems with 16 bit sounds.
zzajin- Posts : 81
Join date : 2008-10-14
Re: Ogg vs Caf for audio
zzajin wrote:
When I asked someone about this, they told me to use some code from WWDC which was better and they had no problems with 16 bit sounds.
What code from WWDC did they recommend? I went and have access to all of the code and SoundEngine is what I have been using without issue.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
They didn't say. I assume it was the TouchFighter (game?) code people seem to want access to.
zzajin- Posts : 81
Join date : 2008-10-14
Re: Ogg vs Caf for audio
Looks like TouchFighter uses the same SoundEngine class.
Has anyone dug into SIO2's audio playback code enough to let me know where I need to plugin the caf loader? SoundEngine is a bit heavy to plugin completely as it would completely replace the current SIO2 audio playback and openAL management code so knowing where to plugin caf loading and playback would be great. This would definitely be a worthwhile addition to SIO2.
Has anyone dug into SIO2's audio playback code enough to let me know where I need to plugin the caf loader? SoundEngine is a bit heavy to plugin completely as it would completely replace the current SIO2 audio playback and openAL management code so knowing where to plugin caf loading and playback would be great. This would definitely be a worthwhile addition to SIO2.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
My guess is that loading soundbufffers would be similar to the way images are done. Probably what is in sio2SoundBufferLoad would get moved to a sio2SoundBufferLoadOGG and a switch statement would select that or a sio2SoundBufferLoadCAF function based on the stream's filename. Checkout sio2ImageLoad in sio_image.
zzajin- Posts : 81
Join date : 2008-10-14
Re: Ogg vs Caf for audio
I have basic .caf file playback working but it is not without issues. There is an odd sound artifiact that plays for a split second when the sound loops. Also missing is automatic detection of frequency and format.
Modify sio2_soundbuffer.cc:
In order to get the exporter to let you export a CAF file from blender you need to modify the exporter python script. Replace the following two lines (238, 240):
with these 2 lines:
That should get you going. If anyone can give me a clue as to why the sound artifact is there I would be happy to look into it to the best of my abilities.
Modify sio2_soundbuffer.cc:
- Code:
// Replace the old sio2SoundBufferLoad function with this one
void sio2SoundBufferLoad( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
if( strstr( _SIO2stream->fname, ".ogg" ) ||
strstr( _SIO2stream->fname, ".OGG" ))
{
sio2SoundBufferLoadOGG( _SIO2soundbuffer, _SIO2stream );
}
else if( strstr( _SIO2stream->fname, ".caf" ) ||
strstr( _SIO2stream->fname, ".CAF" ))
{
sio2SoundBufferLoadCAF( _SIO2soundbuffer, _SIO2stream );
}
}
// This is a new function. Put it in the header also.
void sio2SoundBufferLoadOGG( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
OggVorbis_File ovfile;
vorbis_info *info;
ov_callbacks callbacks;
int count,
bitstream;
char *cursor;
callbacks.read_func = sio2SoundBufferRead;
callbacks.seek_func = sio2SoundBufferSeek;
callbacks.tell_func = sio2SoundBufferTell;
callbacks.close_func = sio2SoundBufferClose;
ov_open_callbacks( _SIO2stream, &ovfile, NULL, 0, callbacks );
info = ov_info( &ovfile, -1 );
if( info->channels == 1 )
{ _SIO2soundbuffer->format = AL_FORMAT_MONO16; }
else
{ _SIO2soundbuffer->format = AL_FORMAT_STEREO16; }
_SIO2soundbuffer->size = ( ov_pcm_total( &ovfile, -1 ) * info->channels << 1 );
_SIO2soundbuffer->data = ( char * ) malloc( _SIO2soundbuffer->size );
_SIO2soundbuffer->freq = info->rate;
cursor = _SIO2soundbuffer->data;
while( ( count = ov_read( &ovfile,
cursor,
SIO2_SOUND_BUFFER_SIZE,
0, 2, 1,
&bitstream ) ) > 0 )
{ cursor += count; }
ov_clear( &ovfile );
}
// This is a new function. Put it in the header also.
void sio2SoundBufferLoadCAF( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
_SIO2soundbuffer->format = AL_FORMAT_STEREO16;
_SIO2soundbuffer->size = ( _SIO2stream->size );
_SIO2soundbuffer->freq = 44100;
_SIO2soundbuffer->data = ( char * ) malloc( _SIO2soundbuffer->size );
sio2StreamRead( _SIO2stream, &_SIO2soundbuffer->data[ 0 ], _SIO2stream->size - 1 );
}
In order to get the exporter to let you export a CAF file from blender you need to modify the exporter python script. Replace the following two lines (238, 240):
- Code:
ogg_uc_pos = t_name.upper().rfind('.OGG' )
if( ogg_uc_pos > -1 ):
with these 2 lines:
- Code:
if( t_name.upper().endswith('.OGG') or t_name.upper().endswith('.CAF') ):
That should get you going. If anyone can give me a clue as to why the sound artifact is there I would be happy to look into it to the best of my abilities.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
It looks like caf files have at least 2 "chunks" an audio description and an audio data chunk.
http://developer.apple.com/documentation/MusicAudio/Reference/CAFSpec/CAF_overview/chapter_2_section_3.html#//apple_ref/doc/uid/TP40001862-CH209-TPXREF102
Perhaps there is some noise because the audio description is sent to the OpenAL buffer. Doesn't it need only the data chunk?
http://developer.apple.com/documentation/MusicAudio/Reference/CAFSpec/CAF_overview/chapter_2_section_3.html#//apple_ref/doc/uid/TP40001862-CH209-TPXREF102
Perhaps there is some noise because the audio description is sent to the OpenAL buffer. Doesn't it need only the data chunk?
zzajin- Posts : 81
Join date : 2008-10-14
Re: Ogg vs Caf for audio
good call zzajin. The clicking artifact is most definetely the header and description chunk. I'll try parsing them put and I might as well grab the correct file format data as well.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
Parsing out the header did the trick. Caf files are working flawlessly now. Here is the code for sio2_soundbuffer.cc:
You will need to make the change to the exporter as shown above. You will also need to include the AudioToolbox.framework in your project and add one line to sio2.h:
If anyone can write a CAF parser the AudioToolbox/AudioFileStream.h requirement can be removed though that probably isn't all that important. This solution should work with any CAF files that are supported by the iPhones openAL implementation.
- Code:
void sio2SoundBufferLoad( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
if( strstr( _SIO2stream->fname, ".ogg" ) ||
strstr( _SIO2stream->fname, ".OGG" ))
{
sio2SoundBufferLoadOGG( _SIO2soundbuffer, _SIO2stream );
}
else if( strstr( _SIO2stream->fname, ".caf" ) ||
strstr( _SIO2stream->fname, ".CAF" ))
{
sio2SoundBufferLoadCAF( _SIO2soundbuffer, _SIO2stream );
}
}
void sio2SoundBufferLoadOGG( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
OggVorbis_File ovfile;
vorbis_info *info;
ov_callbacks callbacks;
int count,
bitstream;
char *cursor;
callbacks.read_func = sio2SoundBufferRead;
callbacks.seek_func = sio2SoundBufferSeek;
callbacks.tell_func = sio2SoundBufferTell;
callbacks.close_func = sio2SoundBufferClose;
ov_open_callbacks( _SIO2stream, &ovfile, NULL, 0, callbacks );
info = ov_info( &ovfile, -1 );
if( info->channels == 1 )
{ _SIO2soundbuffer->format = AL_FORMAT_MONO16; }
else
{ _SIO2soundbuffer->format = AL_FORMAT_STEREO16; }
_SIO2soundbuffer->size = ( ov_pcm_total( &ovfile, -1 ) * info->channels << 1 );
_SIO2soundbuffer->data = ( char * ) malloc( _SIO2soundbuffer->size );
_SIO2soundbuffer->freq = info->rate;
cursor = _SIO2soundbuffer->data;
while( ( count = ov_read( &ovfile,
cursor,
SIO2_SOUND_BUFFER_SIZE,
0, 2, 1,
&bitstream ) ) > 0 )
{ cursor += count; }
ov_clear( &ovfile );
}
void sio2SoundBufferLoadCAF( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
// TODO: add error checking on the OSStatus return values
// Open the audio file stream and parse it
AudioFileStreamID afID;
OSStatus result = AudioFileStreamOpen(_SIO2soundbuffer, sio2CAFAudioPropertyListener, sio2CAFProcessAudioStreamPackets, kAudioFileCAFType, &afID);
result = AudioFileStreamParseBytes(afID, (UInt32)_SIO2stream->size, _SIO2stream->buf, NULL);
AudioFileStreamClose(afID);
}
void sio2CAFAudioPropertyListener( void *_source,
AudioFileStreamID inAudioFileStream,
AudioFileStreamPropertyID inPropertyID,
UInt32 *ioFlags )
{
// We only really care about the dataFormat
if(inPropertyID == kAudioFilePropertyDataFormat)
{
AudioStreamBasicDescription audioFormat;
UInt32 sizeOfPlaybackFormatASBDStruct = sizeof(audioFormat);
AudioFileStreamGetProperty(inAudioFileStream, kAudioFilePropertyDataFormat, &sizeOfPlaybackFormatASBDStruct, &audioFormat);
// Copy relevant data to the soundBuffer
SIO2soundbuffer *_SIO2soundbuffer = ( SIO2soundbuffer *)_source;
if( audioFormat.mChannelsPerFrame == 1 )
_SIO2soundbuffer->format = AL_FORMAT_MONO16;
else
_SIO2soundbuffer->format = AL_FORMAT_STEREO16;
_SIO2soundbuffer->freq = audioFormat.mSampleRate;
}
}
void sio2CAFProcessAudioStreamPackets( void *_source,
UInt32 inNumberBytes,
UInt32 inNumberPackets,
const void *inInputData,
AudioStreamPacketDescription *inPacketDescriptions )
{
SIO2soundbuffer *_SIO2soundbuffer = ( SIO2soundbuffer *)_source;
_SIO2soundbuffer->size = inNumberBytes;
_SIO2soundbuffer->data = ( char * ) malloc( inNumberBytes );
memcpy(_SIO2soundbuffer->data, inInputData, inNumberBytes);
}
You will need to make the change to the exporter as shown above. You will also need to include the AudioToolbox.framework in your project and add one line to sio2.h:
- Code:
#include #include <AudioToolbox/AudioFileStream.h>
If anyone can write a CAF parser the AudioToolbox/AudioFileStream.h requirement can be removed though that probably isn't all that important. This solution should work with any CAF files that are supported by the iPhones openAL implementation.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
I am working on adding support for IMA4 compressions as well and that should wrap up Caf file loading. Will report back with final code when it's done.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
UPDATE:
I've got caf's working for everything except one small little item that someone who is a bit more experienced in C should be able to help me out with pretty quickly. The issue is the call to sio2IMAdecompress: it takes in a buffer to write the decompressed audio to (int16_t* pDst). I need the decompressed audio to be written to _SIO2soundbuffer->data which is a char *. If someone could clue me in on how to get this working caf file support will be done and ready for use.
I've got caf's working for everything except one small little item that someone who is a bit more experienced in C should be able to help me out with pretty quickly. The issue is the call to sio2IMAdecompress: it takes in a buffer to write the decompressed audio to (int16_t* pDst). I need the decompressed audio to be written to _SIO2soundbuffer->data which is a char *. If someone could clue me in on how to get this working caf file support will be done and ready for use.
- Code:
void sio2CAFProcessAudioStreamPackets( void *_source,
UInt32 inNumberBytes,
UInt32 inNumberPackets,
const void *inInputData,
AudioStreamPacketDescription *inPacketDescriptions )
{
SIO2soundbuffer *_SIO2soundbuffer = ( SIO2soundbuffer *)_source;
// Decompress CAF if it is ima4
if( _SIO2soundbuffer->cafType == 'ima4')
{
_SIO2soundbuffer->data = ( char * ) malloc( _SIO2soundbuffer->size );
sio2IMAdecompress(inNumberPackets, _SIO2soundbuffer->format, (uint8_t*)inInputData, (int16_t*)_SIO2soundbuffer->data );
}
else
{
_SIO2soundbuffer->size = inNumberBytes;
_SIO2soundbuffer->data = ( char * ) malloc( inNumberBytes );
}
memcpy( _SIO2soundbuffer->data, inInputData, _SIO2soundbuffer->size );
}
static int32_t ima_index_table[16] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
static int32_t ima_step_table[89] =
{
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
void sio2IMAdecompress_packet( const uint8_t* pSrc, int16_t* pDst, int32_t stride )
{
// Read packet header
uint16_t value = *(uint16_t*)pSrc;
uint16_t header = ( value >> 8 ) | ( value << 8 );
int32_t predictor = header & 0xff80;
int32_t step_index = header & 0x007f;
int32_t step, nibble, diff;
// Sign extend predictor
if( predictor & 0x8000 )
predictor |= 0xffff0000;
// Skip header
pSrc += 2;
// Read 64 nibbles, 2 at a time
UInt32 byteCount = 32;
while( byteCount-- )
{
// Read 2 nibbles
uint8_t byte = *pSrc++;
// Process low nibble
nibble = byte & 0x0f;
if( step_index < 0 ) step_index = 0;
else if( step_index > 88 ) step_index = 88;
step = ima_step_table[ step_index ];
step_index += ima_index_table[ nibble ];
diff = step >> 3;
if (nibble & 4) diff += step;
if (nibble & 2) diff += (step >> 1);
if (nibble & 1) diff += (step >> 2);
if (nibble & 8) predictor -= diff;
else predictor += diff;
if( predictor < -32768 ) predictor = -32768;
else if( predictor > 32767 ) predictor = 32767;
*pDst = predictor;
pDst += stride;
// Process high nibble
nibble = byte >> 4;
if( step_index < 0 ) step_index = 0;
else if( step_index > 88 ) step_index = 88;
step = ima_step_table[ step_index ];
step_index += ima_index_table[ nibble ];
diff = step >> 3;
if (nibble & 4) diff += step;
if (nibble & 2) diff += (step >> 1);
if (nibble & 1) diff += (step >> 2);
if (nibble & 8) predictor -= diff;
else predictor += diff;
if( predictor < -32768 ) predictor = -32768;
else if( predictor > 32767 ) predictor = 32767;
*pDst = predictor;
pDst += stride;
}
}
void sio2IMAdecompress( uint32_t packetCount, const unsigned int format, const uint8_t* pSrc, int16_t* pDst )
{
// Stereo?
if( format == AL_FORMAT_STEREO16 )
{
// Decompress all stereo packets
while( packetCount > 0 )
{
// Decompress channel0 and channel1 interleaved
sio2IMAdecompress_packet( &pSrc[0], &pDst[0], 2 );
sio2IMAdecompress_packet( &pSrc[34], &pDst[1], 2 );
// Next 2 channel packets
pSrc += 34*2;
pDst += 64*2;
packetCount -= 2;
}
}
else
{
// Decompress all mono packets
while( packetCount-- )
{
// Decompress single channel
sio2IMAdecompress_packet( pSrc, pDst, 1 );
// Next channel packet
pSrc += 34;
pDst += 64;
}
}
}
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
UPDATE
I finally got uncompressed cafs and compressed cafs (IMA4) working. After a bit of code cleanup and testing, I will post code here.
I finally got uncompressed cafs and compressed cafs (IMA4) working. After a bit of code cleanup and testing, I will post code here.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
Instructions for getting Caf files working with SIO2:
sio2_soundbuffer.h - Add this line to the SIO2soundbuffer struct
sio2_soundbuffer.cc:
In order to get the exporter to let you export a CAF file from blender you need to modify the exporter python script. Replace the following two lines (possibly lines 238, 240 but I have the prv decompressor so it is different line numbers):
with this line to allow caf export:
You will also need to include the AudioToolbox.framework in your project (until I can figure out caf header parsing) and add one line to sio2.h:
That should do it. Just add caf files (either uncompressed or ima4 compressed) as usual, export and enjoy faster audio load times.
I will be out of the country for 2 weeks so if someone wants to write a caf header parser it would finalize caf audio playback with no dependencies .
sio2_soundbuffer.h - Add this line to the SIO2soundbuffer struct
- Code:
unsigned int cafType;
sio2_soundbuffer.cc:
- Code:
// Replace the old sio2SoundBufferLoad function with this one
void sio2SoundBufferLoad( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
if( strstr( _SIO2stream->fname, ".ogg" ) ||
strstr( _SIO2stream->fname, ".OGG" ))
{
sio2SoundBufferLoadOGG( _SIO2soundbuffer, _SIO2stream );
}
else if( strstr( _SIO2stream->fname, ".caf" ) ||
strstr( _SIO2stream->fname, ".CAF" ))
{
sio2SoundBufferLoadCAF( _SIO2soundbuffer, _SIO2stream );
}
}
// This is a new function. Put it in the header also.
void sio2SoundBufferLoadOGG( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
OggVorbis_File ovfile;
vorbis_info *info;
ov_callbacks callbacks;
int count,
bitstream;
char *cursor;
callbacks.read_func = sio2SoundBufferRead;
callbacks.seek_func = sio2SoundBufferSeek;
callbacks.tell_func = sio2SoundBufferTell;
callbacks.close_func = sio2SoundBufferClose;
ov_open_callbacks( _SIO2stream, &ovfile, NULL, 0, callbacks );
info = ov_info( &ovfile, -1 );
if( info->channels == 1 )
{ _SIO2soundbuffer->format = AL_FORMAT_MONO16; }
else
{ _SIO2soundbuffer->format = AL_FORMAT_STEREO16; }
_SIO2soundbuffer->size = ( ov_pcm_total( &ovfile, -1 ) * info->channels << 1 );
_SIO2soundbuffer->data = ( char * ) malloc( _SIO2soundbuffer->size );
_SIO2soundbuffer->freq = info->rate;
cursor = _SIO2soundbuffer->data;
while( ( count = ov_read( &ovfile,
cursor,
SIO2_SOUND_BUFFER_SIZE,
0, 2, 1,
&bitstream ) ) > 0 )
{ cursor += count; }
ov_clear( &ovfile );
}
// This is a new function. Put it in the header also.
void sio2SoundBufferLoadCAF( SIO2soundbuffer *_SIO2soundbuffer,
SIO2stream *_SIO2stream )
{
// TODO: add error checking on the OSStatus return values
// Open the audio file stream and parse it
AudioFileStreamID afID;
OSStatus result = AudioFileStreamOpen(_SIO2soundbuffer, sio2CAFAudioPropertyListener, sio2CAFProcessAudioStreamPackets, kAudioFileCAFType, &afID);
result = AudioFileStreamParseBytes(afID, (UInt32)_SIO2stream->size, _SIO2stream->buf, NULL);
AudioFileStreamClose(afID);
}
void sio2CAFAudioPropertyListener( void *_source,
AudioFileStreamID inAudioFileStream,
AudioFileStreamPropertyID inPropertyID,
UInt32 *ioFlags )
{
// When we have kAudioFilePropertyAudioDataByteCount all data is in so we can grab the relevant data and calculate our total decompressed buffer size for compressed ima4 files
if(inPropertyID == kAudioFilePropertyAudioDataByteCount)
{
// Copy relevant data to the soundBuffer
SIO2soundbuffer *_SIO2soundbuffer = ( SIO2soundbuffer *)_source;
AudioStreamBasicDescription audioFormat;
UInt32 sizeOfPlaybackFormatASBDStruct = sizeof(audioFormat);
AudioFileStreamGetProperty(inAudioFileStream, kAudioFilePropertyDataFormat, &sizeOfPlaybackFormatASBDStruct, &audioFormat);
// IMA4 files require decompression before sending them off to openAL. We save out the type so we can deal with it later
_SIO2soundbuffer->cafType = audioFormat.mFormatID;
if( audioFormat.mChannelsPerFrame == 1 )
_SIO2soundbuffer->format = AL_FORMAT_MONO16;
else
_SIO2soundbuffer->format = AL_FORMAT_STEREO16;
_SIO2soundbuffer->freq = audioFormat.mSampleRate;
}
}
void sio2CAFProcessAudioStreamPackets( void *_source,
UInt32 inNumberBytes,
UInt32 inNumberPackets,
const void *inInputData,
AudioStreamPacketDescription *inPacketDescriptions )
{
SIO2soundbuffer *_SIO2soundbuffer = ( SIO2soundbuffer *)_source;
// Decompress CAF if it is ima4
if( _SIO2soundbuffer->cafType == 'ima4')
{
_SIO2soundbuffer->size = inNumberPackets * 128;
_SIO2soundbuffer->data = ( char * ) malloc( _SIO2soundbuffer->size );
sio2IMAdecompress( inNumberPackets, _SIO2soundbuffer->format, (uint8_t*)inInputData, (int16_t*)_SIO2soundbuffer->data );
}
else
{
_SIO2soundbuffer->size = inNumberBytes;
_SIO2soundbuffer->data = ( char * ) malloc( inNumberBytes );
memcpy( _SIO2soundbuffer->data, inInputData, _SIO2soundbuffer->size );
}
}
static int32_t ima_index_table[16] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
static int32_t ima_step_table[89] =
{
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
void sio2IMAdecompress_packet( const uint8_t* pSrc, int16_t* pDst, int32_t stride )
{
// Read packet header
uint16_t value = *(uint16_t*)pSrc;
uint16_t header = ( value >> 8 ) | ( value << 8 );
int32_t predictor = header & 0xff80;
int32_t step_index = header & 0x007f;
int32_t step, nibble, diff;
// Sign extend predictor
if( predictor & 0x8000 )
predictor |= 0xffff0000;
// Skip header
pSrc += 2;
// Read 64 nibbles, 2 at a time
UInt32 byteCount = 32;
while( byteCount-- )
{
// Read 2 nibbles
uint8_t byte = *pSrc++;
// Process low nibble
nibble = byte & 0x0f;
if( step_index < 0 ) step_index = 0;
else if( step_index > 88 ) step_index = 88;
step = ima_step_table[ step_index ];
step_index += ima_index_table[ nibble ];
diff = step >> 3;
if (nibble & 4) diff += step;
if (nibble & 2) diff += (step >> 1);
if (nibble & 1) diff += (step >> 2);
if (nibble & 8) predictor -= diff;
else predictor += diff;
if( predictor < -32768 ) predictor = -32768;
else if( predictor > 32767 ) predictor = 32767;
*pDst = predictor;
pDst += stride;
// Process high nibble
nibble = byte >> 4;
if( step_index < 0 ) step_index = 0;
else if( step_index > 88 ) step_index = 88;
step = ima_step_table[ step_index ];
step_index += ima_index_table[ nibble ];
diff = step >> 3;
if (nibble & 4) diff += step;
if (nibble & 2) diff += (step >> 1);
if (nibble & 1) diff += (step >> 2);
if (nibble & 8) predictor -= diff;
else predictor += diff;
if( predictor < -32768 ) predictor = -32768;
else if( predictor > 32767 ) predictor = 32767;
*pDst = predictor;
pDst += stride;
}
}
void sio2IMAdecompress( int32_t packetCount, const unsigned int format, const uint8_t* pSrc, int16_t* pDst )
{
// Stereo?
if( format == AL_FORMAT_STEREO16 )
{
// Decompress all stereo packets
while( packetCount > 0 )
{
// Decompress channel0 and channel1 interleaved
sio2IMAdecompress_packet( &pSrc[0], &pDst[0], 2 );
sio2IMAdecompress_packet( &pSrc[34], &pDst[1], 2 );
// Next 2 channel packets
pSrc += 34*2;
pDst += 64*2;
packetCount -= 2;
}
}
else
{
// Decompress all mono packets
while( packetCount-- )
{
// Decompress single channel
sio2IMAdecompress_packet( pSrc, pDst, 1 );
// Next channel packet
pSrc += 34;
pDst += 64;
}
}
}
In order to get the exporter to let you export a CAF file from blender you need to modify the exporter python script. Replace the following two lines (possibly lines 238, 240 but I have the prv decompressor so it is different line numbers):
- Code:
ogg_uc_pos = t_name.upper().rfind('.OGG' )
if( ogg_uc_pos > -1 ):
with this line to allow caf export:
- Code:
if( t_name.upper().endswith('.OGG') or t_name.upper().endswith('.CAF') ):
You will also need to include the AudioToolbox.framework in your project (until I can figure out caf header parsing) and add one line to sio2.h:
- Code:
#include <AudioToolbox/AudioFileStream.h>
That should do it. Just add caf files (either uncompressed or ima4 compressed) as usual, export and enjoy faster audio load times.
I will be out of the country for 2 weeks so if someone wants to write a caf header parser it would finalize caf audio playback with no dependencies .
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
Cool! Thanks for sharing. I wish I wasn't preoccupied with other things for the next 2 1/2 weeks and could try this out
zzajin- Posts : 81
Join date : 2008-10-14
Re: Ogg vs Caf for audio
Hehe, same here
Can you post also some benchmark concerning the loading time on the device... you something like file size, loading time in MS etc...
Cheers,
Can you post also some benchmark concerning the loading time on the device... you something like file size, loading time in MS etc...
Cheers,
Re: Ogg vs Caf for audio
I will be out of the country for 2 weeks but when I get back I can certainly get a little benchmark together. If you don't see it on here shortly after that stick a post in this thread and it will send me a reminder email.
uprise78- Posts : 228
Join date : 2008-10-31
Re: Ogg vs Caf for audio
I ran an informal benchmark of an IMA4 compressed audio file and an OGG file. Obviously, the regular CAF files (uncompressed) load nearly instantly so I didn't bother adding them to the test due to the file size of an uncompressed CAF. Load times were checked before and after sio2SoundBufferLoad( _SIO2soundbuffer, _SIO2stream ).
The test file was converted using Audacity for OGG and afconvert for IMA4. The file sizes are:
OGG (rate 44100) - 4.7 meg
OGG (rate 22050) - 2.7 meg
CAF - 3.9 meg
OGG (rate 44100)
(1228838433) Start load (sound/testOGG44.ogg)
(1228838638) Done load (sound/testOGG44.ogg)
OGG (rate 22050)
(1228839027) Start load (sound/testOGG22.ogg)
(1228839126) Done load (sound/testOGG22.ogg)
CAF
(1228838426) Start load (sound/TestIMA4.caf)
(1228838428) Done load (sound/TestIMA4.caf)
It's pretty much no contest between ogg and caf on the device.
The test file was converted using Audacity for OGG and afconvert for IMA4. The file sizes are:
OGG (rate 44100) - 4.7 meg
OGG (rate 22050) - 2.7 meg
CAF - 3.9 meg
OGG (rate 44100)
(1228838433) Start load (sound/testOGG44.ogg)
(1228838638) Done load (sound/testOGG44.ogg)
OGG (rate 22050)
(1228839027) Start load (sound/testOGG22.ogg)
(1228839126) Done load (sound/testOGG22.ogg)
CAF
(1228838426) Start load (sound/TestIMA4.caf)
(1228838428) Done load (sound/TestIMA4.caf)
It's pretty much no contest between ogg and caf on the device.
uprise78- Posts : 228
Join date : 2008-10-31
Page 1 of 2 • 1, 2
Similar topics
» Video with Audio...
» Another Audio Engine can be used in SIO2 :)
» Audio Stops when screen goes black (not just locked)
» Another Audio Engine can be used in SIO2 :)
» Audio Stops when screen goes black (not just locked)
Permissions in this forum:
You cannot reply to topics in this forum