Go Down

Topic: PCM and Mega2560 (Read 764 times) previous topic - next topic

SashaD

Nov 03, 2018, 03:05 am Last Edit: Nov 04, 2018, 01:07 am by SashaD
I am using the Mega 2560 and am attempting to play a custom mp3 file converted into a bunch of numbers on a speaker attached to Arduino directly using PCM. I loaded up the playback example given with the PCM.h library. When I upload the script, however, I hear nothing. The speaker is attached to the DIGITAL- GND(black wire) and the DIGITAL 11~(red wire). The speaker works with simple tone() script songs. I hear nothing with the default numbers from the example, I have not implemented my own.




Here is the code from the example project, I had to remove over half of the numbers due to the 9000 letter limit per post. Please download the library PCM and open the example project to get the full thing. (when running, it should say a name for 3 seconds)
Code: [Select]

#include <PCM.h>

const unsigned char sample[] PROGMEM = {
  126, 127, 128, 128, 128, 128, 128, 127, 128, 128, 128, 129, 129, 128, 127, 128, 128, 127, 126, 127, 128, 129, 128, 127, 126, 127, 128, 128, 126, 126, 127, 127, 127, 127, 127, 127, 126, 127, 129, 130, 129, 128, 126, 126, 126, 126, 127, 129, 130, 129, 127, 127, 127, 127, 128, 128, 128, 128, 127, 127, 127, 127, 127, 127, 128, 130, 131, 129, 127, 126, 126, 126, 127, 127, 128, 128, 128, 128, 127, 128, 128, 127, 127, 128, 128, 130, 130, 129, 126, 125, 127, 129, 130, 129, 128, 126, 125, 126, 129, 131, 131, 127, 123, 125, 129, 131, 130, 128, 129, 130, 130, 129, 127, 127, 128, 130, 129, 128, 126, 125, 126, 129, 131, 130, 128, 128, 128, 126, 125, 126, 128, 129, 128, 125, 125, 127, 129, 129, 129, 129, 127, 124, 123, 125, 128, 128, 126, 125, 125, 127, 129, 127, 126, 127, 128, 129, 129, 127, 124, 121, 123, 127, 130, 130, 128, 124, 122, 123, 127, 130, 131, 129, 125, 122, 122, 126, 128, 128, 128, 125, 123, 121, 118, 114, 111, 112, 113, 112, 109, 106, 107, 112, 117, 115, 111, 108, 109, 111, 112, 115, 116, 115, 112, 109, 107, 110, 114, 116, 115, 116, 117, 118, 118, 118, 117, 116, 115, 113, 110, 109, 111, 111, 111, 111, 114, 116, 115, 112, 110, 111, 113, 113, 110, 108, 110, 115, 117, 116, 114, 114, 114, 114, 113, 112, 113, 116, 116, 116, 116, 118, 119, 120, 121, 123, 124, 123, 119, 114, 112, 115, 118, 120, 122, 123, 123, 119, 116, 118, 124, 131, 130, 122, 116, 117, 123, 128, 132, 133, 131, 126, 121, 117, 117, 120, 124, 125, 123, 120, 118, 120, 125, 129, 128, 124, 120, 116, 115, 118, 123, 126, 125, 121, 117,   
};

void setup()
{
  startPlayback(sample, sizeof(sample));
}

void loop()
{
}




Extra Notes: I am following the guide (https://github.com/charliegerard/dev-notes/blob/master/arduino/wavFilesWithoutSdCard.md)

Conclusion reached: The sound would be extremely low quality and no longer than a couple seconds due to multiple factors(see post 7,8)
                 

Grumpy_Mike

#1
Nov 03, 2018, 06:52 am Last Edit: Nov 03, 2018, 06:54 am by Grumpy_Mike
Quote
am attempting to play a custom mp3 file on a speaker attached to Arduino directly using PCM
You can not play MP3 files directly from an Arduino. They are compressed files and there is not enough processing power or memory to uncompressed them.

SashaD

#2
Nov 03, 2018, 07:36 am Last Edit: Nov 03, 2018, 07:40 am by SashaD
i followed this guide : https://github.com/charliegerard/dev-notes/blob/master/arduino/wavFilesWithoutSdCard.md

 i converted the mp3 file into a bunch of numbers

i updated the post, thank you for pointing out the error

Grumpy_Mike

Quote
i converted the mp3 file into a bunch of numbers
So what does this mean? How did you convert this? An MP3 file is a bunch of numbers.

You need to convert the MP3 into a wav file, then cut down the sample rate to about 8 KHz and then scale the samples down to 8 bit samples. Then cut off the wav header to get your bunch of numbers.
Then you can get approximately 3 seconds of sound on an Arduino Uno.

SashaD

#4
Nov 03, 2018, 05:28 pm Last Edit: Nov 03, 2018, 07:56 pm by SashaD
 I am using the Arduino called Mega 2560.
The Mega 2560 has more ram than other ordinary boards.
This is what it says when I load up the Pirate of the Carribean song I found someone made(30 seconds long)(I heard it just fine on port 10 and GND)

"Sketch uses 4360 bytes (1%) of program storage space. Maximum is 253952 bytes.
Global variables use 855 bytes (10%) of dynamic memory, leaving 7337 bytes for local variables. Maximum is 8192 bytes."

I am sure the Maximum for both is enough for a song around 3-4 minutes. (edit: when converted following the guide)
 I did what you said to get those numbers, as the guide said as well to do( https://github.com/charliegerard/dev-notes/blob/master/arduino/wavFilesWithoutSdCard.md )

The main problem is that I hear nothing at all, not even for 3 seconds.

Grumpy_Mike

#5
Nov 03, 2018, 07:09 pm Last Edit: Nov 03, 2018, 07:17 pm by Grumpy_Mike
Quote
The Mega 2560 has more ram than other ordinary boards.
Yes it has 8K as opposed to the normal 2K, so it can hold just under one second of sound.

Quote
I am sure the Maximum for both is enough for a song around 3-4 minutes.
No, I don't think you understand what those numbers mean.


Quote
This is what it says when I load up the Pirate of the Carribean song I found someone made(30 seconds long)(I heard it just fine on port 10 and GND)
So what ever that was it was not derived from a wav or MP3 file. The only way you could get that would be to have each note encoded and played through something like the tone() function.

The code you posted will not even compile.

SashaD

#6
Nov 03, 2018, 07:48 pm Last Edit: Nov 03, 2018, 07:59 pm by SashaD
Thank you, I shortened the code because there were a lot of numbers, and I've only put the first few followed by some text, which is probably why it did not compile. Also, I used the PCM library. I've changed the code to the exact example so it should compile, but it will probably be silent for there are only enough numbers for milliseconds of sound. Please download the PCM library and open up the example project for the library given. (all should be able to be done through the Arduino App)

Yes, the pirate song was through tone(). But converting the song into the numbers should make it be able to play without an SD card for extra space. Or at least that's what the guide title says(https://github.com/charliegerard/dev-notes/blob/master/arduino/wavFilesWithoutSdCard.md).

Lucario448

Yes, the pirate song was through tone(). But converting the song into the numbers should make it be able to play without an SD card for extra space. Or at least that's what the guide title says(https://github.com/charliegerard/dev-notes/blob/master/arduino/wavFilesWithoutSdCard.md).
tone() adjusts the output frequency (at a fixed 50% duty cycle), and not the "amplitude" (aka duty cycle).

At a quick glance of what's going on, I've realized that the PCM library uses actual 8-bit LPCM uncompressed (mono) samples, outputting them at a fixed frequency of 8 KHz. So it is not some sort of RTTL, but basically what you find in a WAV file (apart from the header). Uses timer1 for the sampling frequency, and timer2 for the output (presumably in fast PWM mode and lowest prescaler since it has to emulate a DAC); affected pins depend on the microncontroller itself, they aren't the same in the Arduino Uno and the Mega.



Since the library retrieves the samples from the program (flash) memory, it's coded to work well in AVR microcontrollers with no more than 64 KB of that memory. However, with micros such as the ATmega2560 (which has 256 KB), things become tricky.

The library uses pgm_read_byte() to retrieve data, and it works fine for the ATmega328 since it has 32 KB (of flash memory). But on a ATmega2560, we have the problem of only being able to address 1/8 of the total available.
Why? Because pgm_read_byte() receives a 16-bit pointer; and for 256 KB you need at least 18 bits.

So the correct function for an ATmega2560 is actually pgm_read_byte_far(), which receives a 32-bit pointer (later truncated to 24 to address all the available space). If for some reason the compiler decides to place your array beyond the 64 KB memory map, pgm_read_byte() (aka pgm_read_byte_near()) won't work.




From here I'll clarify what's the deal with the so called "pointers".
Every time you declare an array of any type, you declare an special type of variable: a memory pointer. The data type you explicitly specify, is just an indication of how the program should interpret whatever is on where the pointer points.
For the AVR compiler, a memory pointer is just an int; whose value is used for an special purpose: store a memory position.

Of course, when you declare an array, the associated pointer will automatically store the first (RAM) memory position of the first element of that array. It's also valid to use the [] (index) operator in a pointer, whether it cames from an array or not.

Now, declaring a constant array with the keyword PROGMEM, changes a little how the associated pointer works. In essence, it's the same; with the exception of its value: it stores an address for the flash and not for the RAM.
What makes the difference is who uses such value; while the special pgm functions assume a flash memory address, anything else will assume a RAM address (even if the pointer comes from a PROGMEM array).

The compiler always creates 16-bit pointers by default; so in order to use pgm_read_byte_far() properly, you'll have to first obtain the real pointer with pgm_get_far_address() (receives the PROGMEM array's name), then store the result in an unsigned long. In the end, pgm_read_byte_far() should make use of the intermediate variable I've mentioned before, instead of the array's name directly.
pgm_get_far_address() is the workaround of this compiler's default.



In summary: to make the library work properly on an Arduino Mega, you'll have to do some modifications; either by replacing parts of the code or using more definitions (#ifdef) and adding the new parts.




PD: since you're at it, lemme tell you that there's a somewhat annoying limitation with the AVR's compiler: you can't create arrays larger than 32767 bytes (PROGMEM or not), that amount represents 4.1 seconds of uncompressed 8-bit 8 KHz mono audio.

Lucario448

And by the way:
Code: [Select]
const unsigned char sample[] PROGMEM = {
  126, 127, 128, 128, 128, 128, 128, 127, 128, 128, 128, 129, 129, 128, 127, 128, 128, 127, 126, 127, 128, 129, 128, 127, 126, 127, 128, 128, 126, 126, 127, 127, 127, 127, 127, 127, 126, 127, 129, 130, 129, 128, 126, 126, 126, 126, 127, 129, 130, 129, 127, 127, 127, 127, 128, 128, 128, 128, 127, 127, 127, 127, 127, 127, 128, 130, 131, 129, 127, 126, 126, 126, 127, 127, 128, 128, 128, 128, 127, 128, 128, 127, 127, 128, 128, 130, 130, 129, 126, 125, 127, 129, 130, 129, 128, 126, 125, 126, 129, 131, 131, 127, 123, 125, 129, 131, 130, 128, 129, 130, 130, 129, 127, 127, 128, 130, 129, 128, 126, 125, 126, 129, 131, 130, 128, 128, 128, 126, 125, 126, 128, 129, 128, 125, 125, 127, 129, 129, 129, 129, 127, 124, 123, 125, 128, 128, 126, 125, 125, 127, 129, 127, 126, 127, 128, 129, 129, 127, 124, 121, 123, 127, 130, 130, 128, 124, 122, 123, 127, 130, 131, 129, 125, 122, 122, 126, 128, 128, 128, 125, 123, 121, 118, 114, 111, 112, 113, 112, 109, 106, 107, 112, 117, 115, 111, 108, 109, 111, 112, 115, 116, 115, 112, 109, 107, 110, 114, 116, 115, 116, 117, 118, 118, 118, 117, 116, 115, 113, 110, 109, 111, 111, 111, 111, 114, 116, 115, 112, 110, 111, 113, 113, 110, 108, 110, 115, 117, 116, 114, 114, 114, 114, 113, 112, 113, 116, 116, 116, 116, 118, 119, 120, 121, 123, 124, 123, 119, 114, 112, 115, 118, 120, 122, 123, 123, 119, 116, 118, 124, 131, 130, 122, 116, 117, 123, 128, 132, 133, 131, 126, 121, 117, 117, 120, 124, 125, 123, 120, 118, 120, 125, 129, 128, 124, 120, 116, 115, 118, 123, 126, 125, 121, 117,   
};

With the output set up correctly, this will sound more like a quiet hiss mixed with a quiet whatever it was supposed to be. The oscillation seems so weak that is maybe barely audible.
8-bit samples have a low "dynamic range"; making quiet sounds harder to listen, and the hiss ("white" noise) more apparent.

SashaD

Thank you so much! I heard some tiny hissing that I thought was static when I put the speaker into port 13. I simply thought it might've been due to the wrong port, but maybe not? I guess it is not possible to play a full song on Arduino without an SD card(?). I guess I'll just have to buy one :P. Thank you all for your time!

Lucario448

I guess it is not possible to play a full song on Arduino without an SD card(?).
256 KB aren't enough even for a lossy compression like MP3, well... unless you pick the lowest bit rate that makes the music sound either "metallic", distorted or muffled (in other words: horrible).


I guess I'll just have to buy one :P.
Not a big deal, you can get an SD card + a module for as little as $10

Go Up