MP3-Player Lib, with example

Hmmm... maybe...

there's a (minor) bug in AudioStream.h, the codec use 32-Bit accesses.

Can you try to add two lines:
Code:
typedef struct audio_block_struct {
	unsigned char ref_count;
	unsigned char memory_pool_index;
	unsigned char reserve1; // Add this Line
	unsigned char reserve2; // Add this Line
	int16_t data[AUDIO_BLOCK_SAMPLES];
} audio_block_t;
This patch will be in Teensyduino 121, i think.

Is your serial flash on the Audioshield, or do you use an other connection ?
Does the same file play from SD ?

Edit : You should get warning when compiling ;-) Hm, maybe i should use a slower copy-variant till 121 is out...
 
Last edited:
cool. thanks, that was that. it's playing now! (at least starting from position 0x0)


i'll be curious to compare the latency vs SDcard (ie. that comes with opening the file)


edit:

pretty neat! it's down from ~500-1000us + (SD, stereo .wav) to 5us (SPI Flash, mp3)

edit2:

well, not quite. with mp3, the latency goes up somewhat; it's more consistent though.
 
Last edited:
Glad that it works now :)

It's a "bug by design"..or "in silicon"...or however you want to call it. There is a special adress in the middle of the RAM which does not allow unaligned access. Ok, it's not really a bug, but the result is the same...

The latency when opening will be a bit less. But it#s relatively large, because the first audioframe is decoded when opening the file. This takes time, more than opening the file.
 
Hmmm... maybe...
there's a (minor) bug in AudioStream.h, the codec use 32-Bit accesses.
Can you try to add two lines:

I added a #if TEENSYDUINO < 121 and a memcpy_frominterleaved() in c.
The assembler-optimzed function is now automatically used when teensyduino 121 is released.
So, the patching is not needed anymore.
 
Mxxx, let me ask, is the latency whith opening important for you ?
If so, i could add a switch (#define) that disables decoding the first frame when opening.

The latency with "Opus" is the best of all codecs, according to their webpage. Minimum 2.x ms.
 
hi frank,

it's not terribly important, but if disabling is possible without major hassle, why not. low latency will be of interest to anyone trying to build a drum machine or the like, where timing needs to be tight. drum samples are fairly small, so the spi flash is an attractive alternative to the SD card.

presently, i see the mp3 function returns in about ~ 5000 us consistently, which isn't too bad (that's by simply calling micros() before and after play( )). playSDwav and playSDraw return a bit faster, actually it's quite good. they fluctuate around ~500 - 2000 us (though i didn't test this with lots of files, just 20 or so; RAW vs parsing the file doesn't seem to make much of a difference; probably bypassing the open-by-filename approach would. that's compared to playing PCM from RAM, in which case the play function returns in just 1 us)*. i meant to try to adapt your SPI Flash stuff for PCM, to see what the difference is, if any, but have been sick in bed for a couple of days now and can't think straight ...

* i still have to test how all this actually translates into practice, ie compared to triggering some analog sound source from the same signal.
 
Last edited:
Hmm..okay, in this case, it does not help to disable the first-frame-decoding. I can do nothing, becaus the decoding needs time, and the frames are fixed size. It depends on the number of channels (ok, for your case mono i think?) and bitrate.
You can try to overclock to 144MHz, and edit the robots.txt (add -O2 to the compiler options)
The bitrate is important for reading from SD too: higher bitrate -> more to read.

In theory, RAW from serial flash is the best solution for you if there is enough space. The latency should be very low.

Edit: AAC is a little bit faster than MP3, especially with Mono. But be aware of Audacity and export of mono-AAC: It seems to me, that there is a Bug. In the AAC-Frame is a field which tells how many channels there are. In case of mono, Audacity writes "2" - which is wrong. This results in noise in the first frame. Later, the codec handles this automatically.
 
Last edited:
ok, not a problem. but true, mono would be sufficient and for drum samples 22.05kHz will be more than ok, too.

i'll look into RAW from serial flash, that's the relevant function, right? --

Code:
//__attribute__ ((optimize("O2")))
inline void readserflash(uint8_t* buffer, const size_t position, const size_t bytes)
{//flash_spi.h has no such function.
	digitalWriteFast(SERFLASH_CS, LOW);
	SPI.transfer(0x0b);//CMD_READ_HIGH_SPEED
	SPI.transfer((position >> 16) & 0xff);
	SPI.transfer((position >> 8) & 0xff);
	SPI.transfer(position & 0xff);
	SPI.transfer(0);
	for(unsigned i = 0;i < bytes;i++) {
		*buffer++ = SPI.transfer(0);
	}
	digitalWriteFast(SERFLASH_CS, HIGH);
}
 
Yes.
Adding RAW to the codecs is trivial, I had planned it anyway.
I'll do this in the next days.

No, I think it's better to add it to the audiolibrary.
I'll provide a wav2raw.exe too. Maybe Paul accepts a pullrequest for this addition to the audiolib ?
 
No, I think it's better to add it to the audiolibrary.
I'll provide a wav2raw.exe too. Maybe Paul accepts a pullrequest for this addition to the audiolib ?

probably. i was looking at play_memory as a template, assuming those u-law and reduced sample rate options will be useful for the flash, too.

(though triviality is a relative thing)
 
Hey frank, sorry I'm late to the party, but I've been terribly busy. Nice work on the library.
This gives me a chunk of what I needed to play streaming audio from the 'net.
I still need to do a little bit of code to make it easily connect to ethernet (which is in the works) however for now, SLIP will do just fine for initial testing... when I finally get time to play.
If you would like to play ahead of me with networking, just use my stack, which already works on little endian <insert microcontroller or CPU here>.
Source for the stack is here: http://https://github.com/xxxajk/ajkstack
Note that this is a real IP stack, and does not require a WIFI board or anything else in particular, since it can just do SLIP. You also get REAL sockets, not fake stuff like many Arduino/spinoff libraries have.
 
Hey frank, sorry I'm late to the party, but I've been terribly busy. Nice work on the library.
This gives me a chunk of what I needed to play streaming audio from the 'net.
I still need to do a little bit of code to make it easily connect to ethernet (which is in the works) however for now, SLIP will do just fine for initial testing... when I finally get time to play.
If you would like to play ahead of me with networking, just use my stack, which already works on little endian <insert microcontroller or CPU here>.
Source for the stack is here: http://https://github.com/xxxajk/ajkstack
Note that this is a real IP stack, and does not require a WIFI board or anything else in particular, since it can just do SLIP. You also get REAL sockets, not fake stuff like many Arduino/spinoff libraries have.

Yes streaming is a good thing.
I'd prefer to make it more generic. Currently i have streaming with ESP8266 working, this board uses it's own stack. For overseas radiostations the available RAM on the teensy is too small (half of it is needed for the decodingprocess). I learned that a *really* large buffer is needed (several hundred kilobyte, esp. for high-bitrate streams) , so streaming without too much hardware-requirements (= additional external RAM) make only sense for very reliable internetconnections, or local LAN/WLAN . For local streaming, having no external RAM may be ok.

(I created a board with six spi-rams. The perfect solution would be a single extension board with WLAN and RAM, and ideally, an interface for a good Display. The Teensy-SPI is currently used heavily, and a second SPI would be wonderful (and more on-board ram... i hope for the next-gen teensy...)

Unfortunately i'll have no time for the next couple of weeks, but i work on this.. i hope i can find a good way to use your stack.
I'll have to buy some lan/wlan-breakouts, too...

Generally, the interest to audio streaming seems not be particularly large. And i did not get any requests.
 
Last edited:
I think there will be no problem space wise on a teensy 3.1. 3.0 should be close, but possible with a small MTU. How large is an MP3 frame anyway?
 
I think there will be no problem space wise on a teensy 3.1. 3.0 should be close, but possible with a small MTU. How large is an MP3 frame anyway?

I never tried a teensy 3.0. Maybe it works ?
But there is no reason to try it :)
3.1 has enough memory to play it, important is, that the transfer-speed is sufficiant and "realtime" enough to have fresh data when it is needed.

Since internetstations sometimes have hundreds of users per stream there are some limitations...
For example, most servers try to send some seconds (i've seen a german station that tried to send more than one minute) audiodata at the beginning of the streaming to fill the buffers of the client.
You could try to ignore most of these packets at startup, but the server thinks you have enough data buffered and will send new data at irregular intervals, which may be too long. The servers know the amount of data that they sent to you and they *think* that they know when the buffer of the client is nearly empty. But this only works if you buffered all data.
There is no handshake on a higher level. It's simple http, like transferring a download or picture. So, MTU and Framesize(1152+header for MP3, for AAC something in this range too..i forgot it :) ) are not important. The Buffer ist important, nothing else.
To make it even worse, the metadata are embedded in the mp3 stream and you only have a byte-counter which indicates the position of the data. If you're out of sync because you lost a packet (or ignored it), you don't know the position ... and hear blips, chirps and noise from the decoder - the decoders are not able to handle metadata. You must restart the stream. Syncing to the frameheader does not help because the only point where the bytecounter is set to zero is at the beginning...(well, and with every metadata-packet, but when you don't know its position...->crap)

For a local setup with your own streamingservice in your lan, there are ways to fine-tune this, or to use better protocols - this should'nt be a problem (i did not try it).



Edit: It may work to send no "ack" or something like this when you run out of free buffers, and indeed i remember that this helped a bit when i did my first streamingradio some years ago (it had LAN with a STM Cortex-M3 + FRAM + mp3-decoder-chip) (I do the same with the ESP8266 with RTS/CTS)
But i remember too that some servers (or proxy?)stopped the streaming after a minute or so. It was not reliable.
Maybe too much workload for the server, or too much handling for your particular client is detected and classified as "not acceptable". Don't know.

All good clients have large buffers..

If there is a way, i don't know it :)

Edit:
This is all no show-stopper for any ethernet stack - but i see no way to do really reliable streaming without enough memory in the range of minimum 128..256 KB, better much more, esp. with bitrates > 128kbits/sec
 
Last edited:
No.. not enough ram

What is the min RAM.
Could I trade off lower quality or another processor in the same line with more ram (if it is available)?
Basically I love the setup and the ability to decode some compression but I'd like to lower the cup cost for a future project.

Note: I have a few devices on the way to start the initial.

Thank you for the information and your work on this as it will be a great help to my initial prototype!

Brett
 
No, currently, the only board is teensy 3.2 (or the former 3.1). As far as i know, no other Arduino can decode MP3 or work with the Teensy-Audiolibrary.
 
No, currently, the only board is teensy 3.2 (or the former 3.1). As far as i know, no other Arduino can decode MP3 or work with the Teensy-Audiolibrary.

Great to know and I'm super happy I came across the libraries. It is a huge help.

Thank you for your time in doing the work and answering my questions.

Brett
 
Teensy Audio MP3 codec / trouble with alternative I2C

Hi Frank,
at first - many thanks for your great work with the mp3 decoder.

I try it first time and it Works really fine.

I try to use it for an audio player for my little child.

My child player has 2 hmi .
1. movement detection and interaction with teensy player by serial control commands by Pico-platinchen with a bno055 from fablab.eu (Stuttgart) and rgb strip.

2. Teensy player with Teensy Audio board and with 12 capacitive Inputs realized with MPR121 capactive sensing chip connected to second I2c modul.
The teensy player should be controlled by serial commands from the pico-platinchen and the 12 capacitive inputs.


To use the second I2C the new I2c t3 library is used. (https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3 )

i comment out the Wire libray and use the i2c_t3 library instead but everytime i get errors.
I replaced later also the includes of wire.h in other files ( audio lib .... but i get everytimes errors because the orginal arduino wire lib and the i2c_t3 conflicts.

I need the help really because it is for the 1. birthday of my child which was yesterday.

So if someone can help it would be really nice.

Best regards,
Frank
 
Hi Frank,
at first - many thanks for your great work with the mp3 decoder.

I try it first time and it Works really fine.

I try to use it for an audio player for my little child.

My child player has 2 hmi .
1. movement detection and interaction with teensy player by serial control commands by Pico-platinchen with a bno055 from fablab.eu (Stuttgart) and rgb strip.

2. Teensy player with Teensy Audio board and with 12 capacitive Inputs realized with MPR121 capactive sensing chip connected to second I2c modul.
The teensy player should be controlled by serial commands from the pico-platinchen and the 12 capacitive inputs.


To use the second I2C the new I2c t3 library is used. (https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3 )

i comment out the Wire libray and use the i2c_t3 library instead but everytime i get errors.
I replaced later also the includes of wire.h in other files ( audio lib .... but i get everytimes errors because the orginal arduino wire lib and the i2c_t3 conflicts.

I need the help really because it is for the 1. birthday of my child which was yesterday.

So if someone can help it would be really nice.

Best regards,
Frank

Hi Frank,

hm, this is not related to the mp3 library, it does not use i2c. Could you open a new thread please ?

And it would be good to know which errors do you get. Is it possible to post a minimal-example which does not work ?
Btw, the SGTL5000 control uses i2c, too. Maybe that is a reason for your problems.
And maybe it's more easy to use the first I2C ? It's connected to the Audioboard, but that is no problem, I2C is a bus.
 
Hi Frank,
thanks for your fast answer.
As you reccommend i will open a new thread.

Which errors i get?
the errors is because of double initialisation of i2c0_isr (more or less this name - sorry my little child is crying for me, the most time for things like this is the night....)
the solution would be to replace all #include Wire.h with #include I2c_t3
I was surprised at which modules all the Wire.h is used ( i think in 34 places in my project)
But as i replaced all also the original wire.h is comüpiled which brings an error.
Last night i roll all what i had done back because i get lost more and more.
At the end i had done some lib modification.... which brings me to totally trouble.

I will try next modification tomorow after work - open a new thread and hope that a solution can be found.

One question to you is also posible to use your player with more than 255 files?
wat is necessary to increase the arrays from 255 to let me say 800 and what should also modified?

I increase this Arrays :
int trackext[800]; // 0= nothing, 1= mp3, 2= aac, 3= wav.
String tracklist[800];

but in this case the player crased....

eventually easy and stupid question and for me at this point not so important (lower priority) because my complete project is not running at this time.
But if i solved this point this would be the next.

Best regards,
Frank
 
Back
Top