Playing audio embended into code on MEGA

Hi!

I'm working on a project for person who is incapable to speak or move his hands - he communicates by pointing letters by nose on a sheet of paper.

Friend of mine told me, that he is a cool guy, so i wanted to help.

My idea is to build 'keyboard' for him, which plays letters on-button.

I've been wondering if it is possible to embend sounds into code, and found this:
https://123d.circuits.io/circuits/1093799-musica-do-mario - which is not in fact 'playing waves', so i need to look further
found this too:
http://playground.arduino.cc/Code/PCMAudio
but after uploading it to my mega*, it shouts nothing (and nothing was modified) - where the problem is?

*I'm quite sure, mega is too big, and quite pointless, but it is only one i have at home :wink:

Best regards

EDIT.
yup. found solution JUST asfter posting... :Tutorial: play simple Arduino audio samples – Dangerous Prototypes
change pin 11 to 10. end.

Ok, no, i’m confused…

I modified a bit this code, and got this:

/*
 * speaker_pcm
 *
 * Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
 * For Arduino with Atmega168 at 16 MHz.
 *
 * Uses two timers. The first changes the sample value 8000 times a second.
 * The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
 * depending on sample value. The second timer repeats 62500 times per second
 * (16000000 / 256), much faster than the playback rate (8000 Hz), so
 * it almost sounds halfway decent, just really quiet on a PC speaker.
 *
 * Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
 * (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
 * for the pulse width modulation, breaking PWM for pins 11 & 3.
 *
 * References:
 *     http://www.uchobby.com/index.php/2007/11/11/arduino-sound-part-1/
 *     http://www.atmel.com/dyn/resources/prod_documents/doc2542.pdf
 *     http://www.evilmadscientist.com/article.php/avrdac
 *     http://gonium.net/md/2006/12/27/i-will-think-before-i-code/
 *     http://fly.cc.fer.hr/GDM/articles/sndmus/speaker2.html
 *     http://www.gamedev.net/reference/articles/article442.asp
 *
 * Michael Smith <michael@hurts.ca>
 */

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 8000

/*
 * The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
 * to fit in flash. 10000-13000 samples is about the limit.
 *
 * sounddata.h should look like this:
 *     const int sounddata_length=10000;
 *     const unsigned char sounddata_data[] PROGMEM = { ..... };
 *
 * You can use wav2c from GBA CSS:
 *     http://thieumsweb.free.fr/english/gbacss.html
 * Then add "PROGMEM" in the right place. I hacked it up to dump the samples
 * as unsigned rather than signed, but it shouldn't matter.
 *
 * http://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
 * mplayer -ao pcm macstartup.mp3
 * sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
 * sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
 * wav2c macstartup-cut.wav sounddata.h sounddata
 *
 * (starfox) nb. under sox 12.18 (distributed in CentOS 5), i needed to run
 * the following command to convert my wav file to the appropriate format:
 * sox audiodump.wav -c 1 -r 8000 -u -b macstartup-8000.wav
 */

#include "sounddata.h"

int ledPin = 13;
int speakerPin = 10; // Can be either 3 or 11, two PWM outputs connected to Timer 2
volatile uint16_t sample;
byte lastSample;
int lastSampleNo;
int firstSampleNo;


void stopPlayback()
{
  // Disable playback per-sample interrupt.
  TIMSK1 &= ~_BV(OCIE1A);

  // Disable the per-sample timer completely.
  TCCR1B &= ~_BV(CS10);

  // Disable the PWM timer.
  TCCR2B &= ~_BV(CS10);

  digitalWrite(speakerPin, LOW);
}

// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
  if (sample >= lastSampleNo) {
      stopPlayback();
  }
  else {
       OCR2A = pgm_read_byte(&sounddata_data[sample]);
  }

  ++sample;
}

void startPlayback(int letterNo)
{
  pinMode(speakerPin, OUTPUT);

  // Set up Timer 2 to do pulse width modulation on the speaker
  // pin.

  // Use internal clock (datasheet p.160)
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));

  // Set fast PWM mode  (p.157)
  TCCR2A |= _BV(WGM21) | _BV(WGM20);
  TCCR2B &= ~_BV(WGM22);

  if(speakerPin==10){
    // Do non-inverting PWM on pin OC2A (p.155)
    // On the Arduino this is pin 11.
    TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
    TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
    // No prescaler (p.158)
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set initial pulse width to the first sample.
    //OCR2A = pgm_read_byte(&sounddata_data[0]);
    OCR2A = 127;
  } 
  else {
    // Do non-inverting PWM on pin OC2B (p.155)
    // On the Arduino this is pin 3.
    TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);
    TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
    // No prescaler (p.158)
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set initial pulse width to the first sample.
    //OCR2B = pgm_read_byte(&sounddata_data[0]);
    OCR2B = 128;
  }





  // Set up Timer 1 to send a sample every interrupt.

  cli();

  // Set CTC mode (Clear Timer on Compare Match) (p.133)
  // Have to set OCR1A *after*, otherwise it gets reset to 0!
  TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
  TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

  // No prescaler (p.134)
  TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

  // Set the compare register (OCR1A).
  // OCR1A is a 16-bit register, so we have to do this with
  // interrupts disabled to be safe.
  OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

  // Enable interrupt when TCNT1 == OCR1A (p.136)
  TIMSK1 |= _BV(OCIE1A);

  lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
  
  //Serial.print("Sampel no. ");
  //Serial.print(letterNo);
  
  
  //delay(500);
  
//  firstSampleNo = borders[letterNo][0];
//  lastSampleNo =  borders[letterNo][1];

  firstSampleNo = 1110;
  lastSampleNo =  2999;
 firstSampleNo = borders[0][0];
 lastSampleNo =  borders[0][1];
  
  //Serial.println(". Poczatek: ");
  //Serial.print(firstSampleNo);
  //Serial.print(". Koniec: ");
  //Serial.println(lastSampleNo);
  sample = firstSampleNo;
  
  //delay(500);
  sei();
}


void setup()
{  
  //Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  startPlayback(0);
  startPlayback(1);
  
}

void loop()
{
  //startPlayback(0);
  //startPlayback(1);
  //startPlayback(1);
}

It seems to work quite well but only for first ‘play’. I can not find why…

Part of sounddata:

// const int aa_sampleRate = 8000;
const int sounddata_length = 5417;

const int borders[][2] = {
  {0, 2496},      //a 
  {2496, 5417},      //b
};

const signed char sounddata_data[] PROGMEM ={
  
//a  
  126, 
125, 126, 126, 125, 126, 126, 125, 126, 125, 126, 126, 125, 126, 124, 125, 124, 126, 125, 126, 124, 
126, 126, 126, 125, 127, 125, 126, 125, 126, 125, 125, 123, 120, 119, 113, 121, 122, 131, 131, 131, 
124, 120, 120, 122, 127, 129, 131, 128, 130, 127, ...};

edit.
Forget it :wink: