Hello,
I've been following this thread with great interest because we have
been facing this aac/m4a loop problem with some of our games.
As I'm not an experienced programmer, (I'm a sound designer with some
programming knowledge, as a matter of fact) I was wondering if you
could post some sample code to show me how you did to get the file
looping. (skipping the primer and remainder frames).
Thank you very much.
Cordially,
Jorge
_______________________________________
Jorge
Peirano
-
Sound
Designer / Composer
gameloft Montreal
Message: 3
Date: Tue, 17 Feb 2009 14:31:35 -0800
From: Marco Papa <email@hidden>
Subject: Re: Loop Audio on iPhone
To: William Stewart <email@hidden>
Cc: email@hidden
Message-ID:
email@hidden"><email@hidden>
Content-Type: text/plain; charset="iso-8859-1"
Bill,
I did some more research. You say in your post below:
"AudioQueue's buffer routines provide a trimming function for just this
purpose. AVAudioPlayer uses these."
I did the same exercise you mentioned below. I obtained a fairly long
"uncompressed" WAV file. I played it using the "loop" function
of AVAudioPlayer: the loop worked flawlessly.
Then I encoded it with AAC and stored in a CAF file using afconvert, as
suggested in your post below.
I verified using afiinfo that the "priming frames" (2112) at the beginning
and the "remainder frames" at the end are also stored in the CAF file.
Then I tried to loop the CAF file using AudioQueuebuffer routines (using
AudioFileGetProperty((audio_file, kAudioFilePropertyPacketTableInfo,... to
get the priming and remainder frames totals ). This seems to also loop fine.
Then I tried to loop the CAF file using AVAudioPlayer routines using the
same code that loops fine with the uncompressed WAV file. This one did NOT
loop fine and there is a very audible glitch.
I tried both of the above using the iPhone Simulator - 2.2.1 (latest
release). I haven't tried it an actual iPhone yet, but I would not expect
it to be any different.
Should I submit a bug report?
On Wed, Feb 11, 2009 at 7:11 PM, William Stewart <email@hidden> wrote:
ok - Iets pull this apart a bit
% afconvert -d aac -f caff /System/Library/Sounds/Submarine.aiff
/tmp/out.caf
% afinfo /tmp/out.caf
File: /tmp/out.caf
File type ID: caff
Data format: 2 ch, 44100 Hz, 'aac ' (0x00000000) 0 bits/channel, 0
bytes/packet, 1024 frames/packet, 0 bytes/frame
no channel layout.
estimated duration: 0.975 sec
audio bytes: 10541
audio packets: 45
audio 42998 valid frames + 2112 priming + 970 remainder = 46080
----
That is, to encode Submarine.aiff with AAC, you require 45 audio packets
(which is 46080 samples long). The first 2112 samples are silence - this is
encoder priming and for reasons best left unsaid, were published as
essentially empty AAC packets (as well as packets that contain information
used to correctly decode the first samples). The last packet has had 970
samples of silence added to it (in other words, of the 1024 samples
represented in the last packet, 1024 - 970 (54 samples) are actually valid.
So, 46080 - 970 - 2112 is 42998 valid samples - the original lenght of
submarine:
% afinfo /System/Library/Sounds/Submarine.aiff
Data format: 2 ch, 44100 Hz, 'lpcm' (0x0000000E) 16-bit big-endian
signed integer
no channel layout.
estimated duration: 0.975 sec
audio bytes: 171992
audio packets: 42998
So, because we know the encoder latencies and padding we can completely
understand (and represent in the file) these pads and thus derive the actual
number of samples in the bitstream. M4A files that iTunes generates has
similar information to the CAF file here
To decode this bit stream and get the same number of samples out, you feed
all of the packets you have in to a decoder, trim off 2112 samples from the
start, trim off 970 samples from the last output and you will have decoded
this completely accurately to the sample.
This is the only way that you can do gapless - by knowing all of this
information and taking this action.
AudioQueue's buffer routines provide a trimming function for just this
purpose. AVAudioPlayer uses these. ExtAudioFile (which is used by afconvert)
does this trimming for you (provided you have that information in the file),
so decoding /tmp/out.caf I get:
% afconvert /tmp/out.caf /tmp/lpcm.wav -d LEI16 -f WAVE
% afinfo /tmp/lpcm.wav
File: /tmp/lpcm.wav
File type ID: WAVE
Data format: 2 ch, 44100 Hz, 'lpcm' (0x0000000C) 16-bit little-endian
signed integer
no channel layout.
estimated duration: 0.975 sec
audio bytes: 171992
audio packets: 42998
----
So, if you want looping, then there should not be any reason why you can't
do that with compressed content provided you can accurately know this
information and loop with that in mind.
Bill
(just to shamelessly plug our file format, this is one reason I like CAF
files alot as they require that you provide this information for any VBR
encoded format - in all of the other formats this has been added as an
afterthought, if its there at all)
On Feb 11, 2009, at 12:21 PM, Marco Papa wrote:
James,
I have indeed seen several mentions in the iPhone Dev. Forum of the fact
that the audio file must be "an exact multiple of the packet size",
otherwise the player will fill the missing portion of the last packet with
"silence" when looping, but this is the first time I see mention of "enough
context before the beginning and after the end of the loop." What is that?
Thanks for any insight.
--
Marco Papa, Ph.D.
|