I put together a little music file browser to enable me to audition digital audio music on the device. Here it is for all to use!
Some time later I added support for animations (GIFs or image tables).
And finally support for static images.
usage
put your compatible files as follows:
MP3/WAV or .PDA compiled audio in Music/
GIFs or .PDT compiled imagetables in Animations/
still images or .PDI compiled images in Images/
build and run in Simulator
upload to Device
compiled files
files types such as (.PDA, .PDI, .PDT etc) can be put in the datastore directory, using the same folder names as above. That way you do not need to rebuild the app to see new files.
controls
Up/Down = prev/next
Left/Right = seek backward/forward
A = play
B = stop
menu options
seek speed (1,2,3,4,5) [music only]
auto next (Y/n)
loop play (Y/n)
notes
key repeat on up/down/left/right
currently playing song is marked with # and (MM:SS) time remaining, not in bold
playback position shown as a progress bar along the bottom of the screen
auto next independent of selected row
files sorted case-insensitive alphabetical
device auto lock disabled only when music is playing
I am using Audition on my new device, it works great! I am using it to test the performance of the speaker. I really wish there was a way to drag audio files into the data folder without compiling into pda. Is there any way to speed up the process?
Have you ever run into issues with fileplayer streaming randomly stopping for no reason? Audition was working great when I had less than 8 PDA files or so (compressed IMA ADPCM). But as soon as I added more, the tracks will randomly stop, and the music:setFinishCallback(nextSong) will be called. They stop at a different place each time, which makes me think it is related to performance or garbage collection. I can't really see anything in the code that would cause this, so it might be a bug with the SDK.
EDIT: It might be related to the buffer size. Do you know what the default buffer size is?
I set the fileplayer buffer size to 1 second, which solves the problem. I guess performance hitches and garbage collection can interfere with the fileplayer if the buffer is too short. Unfortunately increasing the buffer makes seeking less responsive, but at least the audio will actually play. Do you think this is a bug I should report?
Right, the problem is the fileplayer is starving for data because the decoder can't keep the buffer full. Using a bigger buffer gives the decoder more leeway to use CPU when it's available. The default size is 1/4 second, but I think I'll bump that up to 1/2 s because other people are running into this.
The other thing going on here is that I decided that fileplayers should stop playing when they run out of data because I hate it when the audio starts stuttering in a game. (Probably because I suffered this a lot as a kid, trying to play games that my ancient PC wasn't up to.) You can do fileplayer:setStopOnUnderrun(false) to have it stutter instead. Another weird thing/bad decision here is the flag is off by default in the simulator--that is, files will continue and stutter--but on on the device. I turned it off there because the simulator decodes on the main thread and macOS will happily block the main thread for long enough to drain fileplayer buffers, just from e.g. clicking on a menu. I should move that to a separate thread to match how it now works on the device.
When you say you started seeing the problem when you got up to around 8 files.. Are those all playing at the same time? Or just in the file list? I'm not surprised if it can't keep up playing a bunch of files at the same time, but if those extra files are just sitting there I don't know why they'd be slowing things down.
One last bit of history here, for the record: When we changed to a journaling filesystem driver on the device we unintentionally added a limit to the number of simultaneous open files. Some games were creating fileplayers at startup for every file they might play, and each was keeping an open filehandle for each. Eventually the system can't open any more files, and the game crashes. In 1.10 I changed it so the fileplayer doesn't open the file until it starts playing or you manually set the buffer size with fileplayer:setBufferSize(). But ideally you'd only have as many fileplayers as you need to play simultaneously, and use fileplayer:load() to change what they play.
There's only ever one file playing at a time here, but lots in the list.
List populated with listFiles
On my device I have ~50 files (2xMP3, 1xPDA, 3xPDI, the rest PDT) fileplayer.new is called on press of the A button.
Do I need to discard the fileplayer after use? I don't think I am doing that right now.
If you're letting it scope out it should get collected and the resources freed up. I'll double-check that the file is actually getting closed and not leaked, tho. I'm not sure what's going on with that buggy mp3 file. It spews a bunch of "bad loadlen" errors and then the hang is a deadlock on the audio device. Looks like the error is causing us to jump out of a function without releasing that lock.
Thanks for clearing that up. I didn't know about the fileplayer:setStopOnUnderrun(), but that would address the problem I was having. I think I would always prefer stuttering to the file completely stopping, as it gives me an idea of how the game is performing and where I can improve things. To answer your question about the files, as far as I understand there is only ever one file being played at a time. I'm guessing adding more files creates a bigger load due to the text being drawn in the update function, as well as more frequent garbage collection. I think it's mostly the garbage collection spikes that cause the issues with the short buffer size.
This is an awesome tool and great for prototyping! It also reminded me that it would be useful to be able to modify file playback speed in the SDK without affecting the tempo (which is what fileplayer:setRate() does). I'm not sure how those complex those algorithms are or if the hardware/OS would even support that, and maybe @dave would know. Having a tempo-only option would allow an app like this one to play back podcasts and such at 1.25x or 1.5x speed, or enable the creation of slow-mo/running-out-of-time game effects by dynamically speeding up (or slowing down) the background music without having to export multiple versions of the same song.