Audio, Day 3

Here are my notes from day 3 of working with audio:

First of all, buffering 8000 bytes into two different buffers and switching between them, loading one while the other played, did not work well. The audio played, but with with big pauses every 1/4 second or so. I assume the pauses happened every 8000 bytes, but it was hard to see visually (no scope at home). I think fread() is uninterruptable? My background Ticker() is what would read from the buffer and set AnalogOut. It was like that ticker wasn't ticking every once in a while. Why isn't fread(), or for that matter, stdio.h, documented anywhere??

So I simplified - No Ticker(). Here's the (pseudo)code:

while (!eof)

byte = fgetc(file)

AnalogOut(byte)

end

But what happens? It plays fine, but choppy! So I fooled around with the Timer() class and found out that every 512 bytes read with fgetc() takes about 10000 us, or about 10 ms. Every fgetc in-between takes about 2us. I think I've hit a limitation of the built-in flash memory, or at least the driver for it. :( For 8kHz audio, the longest delay I can have is 125us. Now if I use a buffer... :) I'll try that tomorrow.

Going back, I wrote a test program to test if fread is uninterruptable. It is. As soon as the fread starts, the Ticker() no longer fires. :( Again, it's either the hardware limiting, or it's the implementation. The code is at TickerFreadTest. So, can I just pump the data over the USB serial driver from the PC? How fast is that? 921600bps? That's 57600 16-bit values per second. Good enough for one stream of 44.1kHz mono audio, uncompressed. Hm. I was hoping for more than one stream. Now I have to go to either ethernet or the other USB interface. Or just reading from an external, fast SD card. Is that why Vlad used an SD card in the first place? I just thought maybe his hardware didn't have the LocalFileSystem.

Any comments?

Later,

-Owen Piette


3 comments

06 Oct 2010

I highly doubt you can get the usb serial to run at 921600bps. The highest stable speed I've worked with was 230400. The buffers fill up pretty fast at that speed and you end up losing data if you don't read fast enough. I think the simplest solution is to use an external codec chip or something to pump out the audio..

As for the documentation, see http://www.keil.com/support/man/docs/armccref/, there might be something useful..

07 Oct 2010

Thanks, Igor. I won't try to use the USB serial. As it was, I was getting some odd numbers, but I couldn't tell if the data was really corrupt - it's WAV data, which is pretty messy to begin with! I'll probably try ethernet, what with people saying it's pretty easy to implement.

And thanks for the link! I've already found some interesting things. For example, this link, where someone else has hit the 512Byte hidden buffer in fread and has a good example of how to work around it:

http://www.keil.com/forum/16781/

The library documentation wasn't very helpful. No mention of how it's actually implemented. But thanks anyways.

11 Jan 2011

Hi Owen,

I've updated the LocalFileSystem handbook page to make the following limitation more clear. The blocking (and speed) is actually a limitation of LocalFileSystem, not fread/fwrite.

When you are using the LocalFileSystem, the file accesses are actually debug "semihosting" requests from the target to the mbed interface over jtag, for the interface to do something on your behalf. These mean the core is effectively halted on a breakpoint, saying "do this for me on your file system". While in this state, no interrupts etc will be serviced.

If you move to an SD card for example, it is all running on the target, so not only will it be much faster, but also it wont block interrupts in the same way. The LocalFileSystem is great for getting something working quickly, and low bandwidth loging, but for Audio you really need to move to a proper storage/filesystem setup.

For more, see the bottom of LocalFileSystem

Great work btw. Hope this clears things up.

Simon

You need to log in to post a comment