#175389 - Relfos - Thu Nov 11, 2010 10:56 pm
I'm trying to find out how to stream audio data, using a timer and a double buffer aproach.
My idea would be to decode audio into two buffers, play buffer one, start timer, when timer finishes, play buffer two, decode new data into buffer one, and restart timer, etc
Now, how can I setup a timer that finishes exactly on the right spot to switch the buffers?
And what function should be used to swap the buffers? I'm thinking of soundPlaySample, but maybe there's something better?
#175393 - sverx - Fri Nov 12, 2010 4:41 pm
The ARM9 (well, each processor to say the truth) has 4 timers that could trigger an IRQ at the end of the expected time. Using one of those and soundPlaySample() function would probably fit your needs :)
#175394 - Relfos - Fri Nov 12, 2010 4:50 pm
sverx wrote: |
The ARM9 (well, each processor to say the truth) has 4 timers that could trigger an IRQ at the end of the expected time. Using one of those and soundPlaySample() function would probably fit your needs :) |
Yes, that was my idea, but looking at the timer example on the devkitpro, I don't really understand how to get the timing right.
Code: |
//calls the timerCallBack function 5 times per second.
timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(5), timerCallBack);
|
Why five times per second?
Does this ClockDivider_1024 constant means that the timer will tick 1024 times per second?
So, if I'm playing a sample with frequency X, that is a multiple of 1024, I guess I know how to setup the timer, but what if the frequency is not a multiple of 1024, for example, say 11025hz
#175395 - Exophase - Fri Nov 12, 2010 8:24 pm
For audio playback, you want to have a buffer that's not too large such that there's a lot of latency, but not too small or else there will be too much extra overhead involved in going in and out of the routine that fills it. If the buffer is being filled 5 times per second that means the buffer needs to hold at least 200ms worth of data (if it's double buffered you'd have 400ms worth). That's a little on the large side in terms of latency, but if you're just using it for music then it's fine. The actual size of the buffer depends on the sample playback rate.
This sample playback rate has nothing to do with the buffering rate except that it dictates how large the buffer must be. The sound hardware visible to the ARM7 will automatically play back from the buffer at this rate. You can think of the sound channels as being separate timers that tick down at the appropriate rate. You have to setup the playback rate separately.
ClockDivider_1024 means that this timer will tick at the bus clock rate (33MHz) divided by 1024. So the timer will increment every 1024 bus cycles, or at a rate of around 32.7KHz. The timer IRQ will occur every time the 16-bit counter value wraps around from 0xFFFF to 0x0000, and will call the callback when this happens and reload the counter value. Therefore, the reload value determines how often the IRQ is called. The macro TIMER_FREQ_1024 converts a period from Hz to 32.7KHz units.
This is what the macro actually does:
TIMER_FREQ_1024(n) (-(0x2000000>>10)/(n))
The 0x2000000 value is the number of bus ticks in a second: 2^25 (33,554,432 cycles per second). Then it's shifted right by 10 to divide by 1024, giving you the number of 1024 cycle ticks in a second. This is then divided by the number of counts you want in a second. Finally, the value is negated because you're counting up towards 0.
#175396 - Relfos - Fri Nov 12, 2010 9:51 pm
I see, thanks!
But soundPlaySample hangs when called inside a timer, it this normal behavior?
#175397 - wintermute - Fri Nov 12, 2010 10:41 pm
#175398 - Relfos - Fri Nov 12, 2010 11:19 pm
Thank you, that seems perfect!