I have a project involving using an AVR microcontroller (ATMega328PB), connected to a keyboard and small speaker, where each key should play a specific tone, like a piano. I have used the keyboard to call inputs to activate LEDs, but I don't know how to best play tones through the speaker. Can I play mp3 files of the tones? Or is it better/easier to have the buzzer play sine waves generated in a program? I am programming the board in C. Thank you!
I've worked with the board already, tried inputting the mp3 files in the same directory and using , but I can't figure out how to get them to be played through the programming.
I think you have to clarify what exactly type of sound you want.
If simple single-tone square wave is enough, then you can use a timer in CTC mode, toggle output on compare match. You can get sound output into the amplifier from corresponding OC pin. If you want sound frequency to match closer, I recommend to use TIMER1, since it has 16 bit resolution and allows to select frequency more accurate.
If you want to generate some more complex wave, make fading sound (ding), polyphony etc, then you have to use some kind of DAC and feed the waveform to it. ATMega328 has no DAC on the board, so, either you need some external DAC, or you may put one of the timers to work on the high frequency (more than 20kHz) in PWM mode, and connect its output to some kind of a filter (e.g. RC-filter), and then feed the output of the filter to the amplifier.
I recommend to use one of 8 bit timers for that. You need update OCR value at each cycle, so it is better to do it in the timer overflow interrupt.
Note, this approach is computational extensive. You have less than 256 CPU cycles to prepare next sample value (that's besides all other code you want to run in parallel). Floating point arithmetic should be avoided. If you want to generate some complex waveforms, or feed the sound from some external source (e.g. reading wav from a SD-card), then I recommend to use a circular buffer, which will be filled in main code, and interrupt will only read next value from the buffer into OCR register.
ATmega328 has no CPU power, neither RAM enough to decode MP3 or any other highly compressed format (also no enough internal flash, where those MP3s to be stored). If you want to use MP3 playback, then you need some external decoder.