2

I used this converter wav2c to convert a .wav file to a C that I can put in a header file. I was able to put converted audio into the h file but the program where I reference it does not seem to be working correctly. The code compiles and uploads to the Arduino but no sound plays. I used the code here to implement the converted audio. I'm using an 8-ohm 0.25w speaker. I'm no programmer nor an expert at electronics so it's likely something dumb that I did wrong. Any help is much appreciated!

Note: The speaker does work with a simple tone sketch.

The code in the header file (minus the hundreds of lines of values for the audio)

#ifndef _HEADERFILE_H    // Put these two lines at the top of your file.
#define _HEADERFILE_H    // (Use a suitable name, usually based on the file name.)


const int sounddata_length=10000;
//const int sounddata_sampleRate=8000;

const unsigned char sounddata_data[] PROGMEM = {
  15,1,49,0,150,0,138,0,219,255,133,0,176,0,15,1,210,254,16,1,197,255,65,0,9,0,227,0,127,254,87,0,175,1,61,254,132,1,135,255,21,1,72,0,104,1,172,0,122,0,213,1,65,255,188,1,100,1,215,0,210,255,59,2,17,0,193,0,200,2,207,255,203,0,65,1,17,1,169,255,121,2,112,0,193,255,65,255,252,255,232,0,101,255,88,2,4,0,26,255,

//Several hundred lines more of these numbers for the audio

105,108,101,45,49,46,48,46,50,52,41,0,105,100,51,32,42,0,0,0,73,68,51,3,
  0,0,0,0,0,31,84,88,88,88,0,0,0,21,0,0,0,83,111,102,116,119,97,114,101,0,76,97,118,102,53,50,46,57,51,46,48,0,};

#endif // _HEADERFILE_H    // Put this line at the end of your file.

Here is the code that I used from the Arduino Playground page to play the audio from the header file.

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

#define SAMPLE_RATE 8000
#include "Test.h"

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


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 >= sounddata_length) {
        if (sample == sounddata_length + lastSample) {
            stopPlayback();
        }
        else {
            if(speakerPin==11){
                // Ramp down to zero to reduce the click at the end of playback.
                OCR2A = sounddata_length + lastSample - sample;
            } else {
                OCR2B = sounddata_length + lastSample - sample;                
            }
        }
    }
    else {
        if(speakerPin==11){
            OCR2A = pgm_read_byte(&sounddata_data[sample]);
        } else {
            OCR2B = pgm_read_byte(&sounddata_data[sample]);            
        }
    }

    ++sample;
}

void startPlayback()
{
    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==11){
        // 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]);
    } 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]);
    }





    // 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]);
    sample = 0;
    sei();
}


void setup()
{
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, HIGH);
    startPlayback();
}

void loop()
{
    while (true);
}
2
  • 1
    are you using the correct pin for output?
    – jsotola
    Commented Jul 1, 2019 at 1:55
  • Put a minumum 125 ohm resistor in series with the pin and the speaker to limit the current out of the pin to 40mA max. 10,000 samples read back at 8,000 Hz = 1.25 second burst of sound. Is that what you are expecting?
    – CrossRoads
    Commented Jul 1, 2019 at 18:18

1 Answer 1

1

This program uses the Timer 2 PWM facility to generate audio output on pins OC2A or OC2B. On the Arduino Uno, these pins are labeled “11” and “3” respectively, and the program carries this mapping as an implicit assumption. You are trying to run the program on an Arduino Mega, which has a different pinout. For instance, on the Mega:

  • OC2A = digital 10
  • OC2B = digital 9

You can easily port the program to the Mega by replacing every reference to pins 11 and 3 by 10 and 9 respectively. E.g., every occurrence of

if(speakerPin==11){

becomes

if(speakerPin==10){

Make sure to fix the comments so that they remain consistent with the code.

And you should, of course, choose an appropriate pin for your speaker.

Side note: you are stressing the output pin if you connect it directly to an 8 Ω speaker. It's fine for a test as long as you don't care too much about the life span of your Arduino.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.