Ideas for a MP3 Player for a Person with reduced Eyesight?
Hi,
these days I am pondering, if it would be a good idea to try to build an MP3 player for a Person with reduced Eyesight using P2. The person is not used to use computers or mobil phones.
The goals are:
- A machine, that is very easy to use
- Hear Stories. Audio books. So it must be possible to pause and restart at the same point. If the audio is split into multiple files, these must be played in the right order.
- MP3 from SD Card.
- Perhaps have spoken feedback as user interface.
- Have a color display? I have got some ST7735?
- Possibility to use batteries?
(* Perhaps add a radio receiver ? DAB???)
What is clear, is that the DAC capability of P2 would be sufficient and would be an argument to use P2. I would like to do this in Forth, C or Basic. I want to use hardware and software building blocks. Perhaps spend the time to build some nice wooden enclosure.
What I have found so far:
A similar project with raspi:
https://github.com/NicolasBrondin/book-pie It seems to use java script, which I am not familiar with.
Mini DFPlayer https://picaxe.com/docs/spe033.pdf - has some limitations. Cannot work with directories. P2 should be able to do much itself.
MP3 offline decoding with P1:
https://forums.parallax.com/discussion/148036/mp3-decoder-works
The library is not included and this was done with P1 then.
Perhaps some ideas? Thank you very much!
Comments
I tried to recompile C-based mp3 decoders for a P2 using Flexprop. The result was way too slow to run in the real time.
I still think a P2 can decode mp3 in the real time, it only needs a proper decoder written for it, in asm.
Thank you for sharing this experience! Perhaps an offline decoder would still be useful to generate WAV files on the same SD card. Perhaps this would make the handling of data more easy.
MP3 was created when storage was small and expensive -- that's no longer the case. WAV decoding is easy; I just need a reliable uSD driver for Spin2 and I will be building a P2 audio player the way I did with the P1 (called the EFX-TEK AP-16+ and smaller version AP-8+).
I did some experimenting with WAV decoding in the P2 and got an assist from Chip to ensure it works. ATM, this code must be passed the hub address of an embedded WAV file. I'll adapt this to the double buffering code I wrote for the P1. It's nice having real DACs in the P2 (the P1 had race condition problems that would inject noise into the audio).
MP3 playback is something I have been looking at. I would love to create a Falcon Player (FFP) workalike with the P2. Sending the E1.31 sequence data would be easy. The audio, not so much.
RAM may be the bottleneck. It might require something like the P2-EC32MB to be able to pull it off. Read all of the data into the PSRAM and act on it from there.
I think you picked the wrong decoder . Attached is a zip file of the Adafruit_MP3 decoder, which on a P2 running at 250 MHz decodes at ~1824 kbps, which is enough for 48 kHz stereo (16 bits/sample). Mind you that is using a whole cog, and I don't have actual audio output hooked up yet (it's left as an exercise for the reader). You can optionally define WRITE_FILE in examples/standalone/main.c to get the output to the host in a file called "output.bin"; that slows the decode process down to below real-time, but allows verification of the output.
To compile this you'll need FlexC 5.9.26. The example is in examples/standalone; there's a README_P2.txt at the top level describing how to build and run.
Yes, they are wrong, as they are full blown Linux things (= noone thought about speed optimizing, but rather a lot of things that can be skipped)
I will try this adafruit thing. As I have a multiformat player already, this may add mp3 playing capability to it. Adafruit is focused on microcontrollers, so their code has to be efficient. The whole cog is not a problem there: SID and MOD both use (more than 1) cogs which I start and stop on demand.
@JonnyMac that code is actually busted. The valid DAC values only range from $0000 to §FF00, so at full volume, this will actually clip the top of the waveform off. Could also be significantly condensed, but it's not like this is performance-relevant.
Speaking of easy decoding, perhaps y'all want to take a look at this codec I wrote: https://github.com/Wuerfel21/Heptafon
Quarters the size of a WAV file (as the name implies, 7 bits per stereo sample, not counting sector overhead), can decode at 160 kHz on a P1 with PASM decoder and is better quality than many common ADPCM-based codecs. Haven't written a P2 ASM decoder, if someone needs one, just ask. I spent quite a lot of time trying different ideas and tuning everything, it is really quite good.
Says you. I pulled it from a working program, and only as an example snippet of the simplicity of WAV decoding.
Maybe, but I tend to go for simple, obvious, working code so that new people can join in.
When we have a proper uSD driver for Spin2, I will recreate the commercial WAV player I wrote for the P1 that is sold by EFX-TEK.
Obviously it works and the clipping is fairly minor at worst, but that doesn't make it less wrong, especially if you intend people to look at it to learn from. The DAC range issue is non-obvious and ignoring it in example code just makes it more so.
The (presumed) fix would be to simply change
mul level, #$7FFF/100
tomul level, #$7F7F/100
, thebitnot ls, #15
under.set_volume
toadd ls,##$7F80
andwypin ##$8000, #L_OUT
to towypin ##$7F80, #L_OUT
.You may correctly worry that this looses you some bit precision, but so does the code as-is due to bugs with the volume adjustment (which I just noticed looking at it again). First, there's rounding error in the volume calculation (
$(7FFF / 100) * 100
is only $7FBC), second,($8000 * $7FBC) >> 16
results in a max. amplitude of only $3FDE. The shift should be 15 bits to allow full swing. I guess this backflips into the clipping issue never being present because the full DAC range isn't used, anyways.Do not question my supernatural ability to decimate questionable code on sight. ;P
@ersmith Thanks for posting this! Going to have to check this out! I spent hours last week googling for something exactly like this. Closest I found was MP3PlayLib from mp3-tech.org
Thanks for the inputs!
Thanks Eric! That is certainly something to try out!
I used libmad on an ARM920t a long time ago. 90MHz was enough for playback. But know that libmad has ARM assembly for the inverse DCT.
Might also be worth looking at Rockbox. While most of the targeted platforms have hardware decoding, not all of them do, and many are slow enough to need a pretty efficient codec.
You have a working (and now efficient) driver in Flexprop, so simply compile the player with that. My player plays wav files without any problems using this. (there was a problem earlier with the driver being too slow, but now it is history)
I don't use FlexProp.
I also think wav is much better than mp3. Compression alters the waveforms. Maybe not in a way I can tell, but still…
uSD cards are huge now.
I think if Apple still made iPods, it would be uncompressed or at least lossless compressed
MP3 would be good though if don’t want to rely on uSD and put media on boot flash instead..
FLAC might be a suitable compromise between MP3 and uncompressed PCM.
It’s FOSS, supported by the major OSs, the system is biased toward fast decoding (at the expense of slower encoding), and there’s a reference implementation available in C.
The iPods that Apple make these days come with a phone built in ;-), and support use of ALAC (Apple Lossless Audio Codec) which is also FOSS but can be more power hungry and result in bigger files.
I simply have a lot of files in mp3 format, so the simplest solution is to put them on SD as they are. Now, my player plays .wav, so I have to decompress them first. I have no free time now to play with that, but while I find some time, I will add the decoder to my player. All what I need from the mp3 decoder to do this is a "decode frame" function. All the rest of the stuff is actually implemented it he player.
It is interesting, that people here keep saying that a WAV player would be sufficient. I was kind of locked into thinking, that MP3 is mandatory. There is a WAV player just sitting there on my table built into Taqoz.
On the other hand files from the internet or CD must somehow come onto this SD-card and it should be possible for a third person to do this relatively easily. I am somewhat scared that Digital Right Management might be the show stopper. Never heard of DAISY format, which is used here: https://katalog.blista.de/hoerbuecher/
Just downloaded an audio book (a free one from some other source) of 1.5h = 90MB MP3 and converted it on my PC with Audacity to signed 16bit WAV, which took about 2* 30sec and gave 900MB. So I can try, if my Taqoz circular knitting machine can tell me stories, if I hook up an amplifier. :-)
Just searched for a ST7735 driver and found this: https://forums.parallax.com/discussion/174147/parallax-font-on-st7735-tft
So once again something to be thankful for which has been given from Phil!!!
This thing is a classic C style code, a lot of small files, a main file can be written in C, but how to make a library out of this that can be used as a class for Basic code and compile without using a long command line, from inside standard Flexprop environment? I am now trying to put all of these c and h into one working file and now it even compiles, but how I can access in Basic something that is a pointer to enum? I think the workaround is to write an additional function in C that will work as an interface to Basic code, keeping, for example, that enum inside C and returning "normal" integer.
Edit:
(1) simply assign the enum to int
(2) I misunderstood the code, this is not a pointer to enum, this is simply void* and I hope it is compatible with Basic's pointer to any.
There is a hope...
I only need init and decode frame function to see from Basic, so I will try what I can do with my very limited C skills.
Edit: ## it works!
Yes, you can treat the enum just as an integer. void* should indeed be the same as "pointer to any".
In theory it should be possible to put all the .c files into a .fpide project file. But mixing BASIC and C isn't something I've tried, so it probably won't work as-is .
I wantedd to try the original decoder from > @ersmith said:
Maybe the decoder I tried was not as wrong as it looked. These fixed point decoders have asm part for several operation defined for standard CPUs but not for a P2. Your example has included asm code for a P2 while in what I tried to compile, I set the CPU to other and these function were defined in C instead of asm
The Adafruit MP3 decoder in my experiments works now, but what it outputs is not a good quality audio. I don't know now if it is decoder itself (too low precision?) or maybe I broke something during the implementation.