Keypad and playing wav with DUE

Hi guys.
I am trying to make a “phone” which would play a certain .wav track for a specific button. I have 4x4 keypad, DUE, amp and speaker. I have audio and keypad parts connected and working separately. Only problem is how to make a track play when I press the button.
I have this code:

#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char* wavas;

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 


Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
    // debug output at 9600 baud
  Audio.begin(44100, 100);
}

void loop() {
  int count = 0;
  //pressing the key -> assigning the filename
  char customKey = customKeypad.getKey();
  if (customKey == '1'){
  char* wavas[]={"jonas.wav"};
  Serial.println("playing jonas.wav");
    }
  if (customKey == '2'){
  char* wavas[]={"petras.wav"};
    Serial.println("playing petras.wav");

  }
    if (customKey == '3'){
   char* wavas[]={"antanas.wav"};
       Serial.println("playing antanas.wav");
  }
    // open wave file from sdcard
    File myFile = SD.open(wavas);
   const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);
  }
  myFile.close();
    while (true) ;
}

Seemed that it sometimes works if keep pressing the button as soon as I start serial monitor. Serial.println() works fine, it just the .wav is misbehaving. Btw, I don’t really even need serial monitor, I use it for debugging.
Any ideas?
Cheers!

char* wavas;

This pointer points to nothing.

  if (customKey == '1'){
  char* wavas[]={"jonas.wav"};
  Serial.println("playing jonas.wav");
    }

This pointer goes out of scope when this snippet ends.

    File myFile = SD.open(wavas);

This opens the file pointed to. But, wavas points to nothing.

Hi atlaikesbriedi,

Maybe give this a try, sorry I’m not familiar with the audio libraries or file IO stuff, I can look into it further if you are still having issues but if sound plays sometimes as you said hopefully what you had written works fine, I just wrapped it up differently.

Let me know what happens, and if you want any explanation to what I’ve written feel free to ask.

Edited code where I made a mistake with the initialization of the char wavas array to only 2 instead of 3

#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char wavas[3];

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 


Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
    // debug output at 9600 baud
  Audio.begin(44100, 100);
}

void loop() {
  //pressing the key -> assigning the filename
  char customKey = customKeypad.getKey();

  if (customKey){ //Check for valid input
    switch(customKey){
      case '1':
        wavas[0]={"petras.wav"};
        Serial.println("playing petras.wav");
        playSound(0);
        break;
      case '2':
        wavas[1]={"petras.wav"};
        Serial.println("playing petras.wav");
        playSound(1);
        break;
      case '3':
        wavas[2]={"antanas.wav"};
        Serial.println("playing antanas.wav");
        playSound(2);
        break;
      default:
        break;
    }
  }
}

void playSound(int iIter){
  File myFile = SD.open(wavas[iIter]);
  const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);
  }
  myFile.close();
}

Thanks for helping me guys!

char wavas[2]; changed to char* wavas[2]; since it gives me an invalid conversion.

Now it works! Kinda works at least.
It only works with first 2 chars: jonas.wav and petras.wav. When pressing 3 it crashes. Serial monitor says "playing antan" - cannot print a whole message.
In each play sound seems more and more distorted - that I haven't seen before.
Still trying to change a few things.

It only works with first 2 chars: jonas.wav and petras.wav

Please post a picture of your keyboard with the jonas.wav key circled.

There is NO reason to use an array of pointers when you only care about ONE pointer at a time.

There is NO excuse for writing beyond the end of an array. char *wavas[2] can hold TWO pointers, at positions 0 and 1. There is NO position 2.

Yes, now wavas holds 3 pointers, antanas.wav works!:

char* wavas[3];

But the distortions still persists. Not sure what causes it. Still trying to solve it.

Please post a picture of your keyboard with the jonas.wav key circled.

Sure, here it is:
https://ibb.co/iswRec

Sorry I altered that code pretty quickly and had no way of testing what I wrote.

Should it not still work as a char wavas[3] and not use pointers?

You are saying the sounds distort more after each playback? or just distorted from the get go?

Looking at your code again, I think you should open and store the .wavs once if you have memory for it at the setup stage then access them as they are, that way you aren't constantly re-reading them in every button press.

Looking at your code again, I think you should open and store the .wavs once if you have memory for it at the setup stage then access them as they are, that way you aren't constantly re-reading them in every button press.

That's silly. The file to be opened should be pointed to. By a scalar pointer variable.

Still trying to solve it.

You've made some code changes, but did not post your current code. So, only you can fix the problem. Good luck.

MADMAN-_-zZ:
Sorry I altered that code pretty quickly and had no way of testing what I wrote.

Should it not still work as a char wavas[3] and not use pointers?

Sorry, I have very little experience with different data types.

You are saying the sounds distort more after each playback? or just distorted from the get go?

Looking at your code again, I think you should open and store the .wavs once if you have memory for it at the setup stage then access them as they are, that way you aren’t constantly re-reading them in every button press.

Yes, sounds distorts more and more after each play, also adding some jitter/pauses. 1st - no distortion, 2nd - quite some, 3rd - almost impossible to understand.

No matter how long/short the file is, the distortion acts the same way after each playback.

But Arduino DUE only has 512 KB of memory, has it not? Or how this buffer storage works? The smallest file size is 580 KB.

Full code:

#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char* wavas[4];

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 


Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
  Audio.begin(44100, 100);
}

void loop() {
  //pressing the key -> assigning the filename
  char customKey = customKeypad.getKey();

  if (customKey){ //Check for valid input
    switch(customKey){
      case '1':
        wavas[0]={"jonas.wav"};
        Serial.println("playing jonas.wav");
        playSound(0);
        break;
      case '2':
        wavas[1]={"petras.wav"};
        Serial.println("playing petras.wav");
        playSound(1);
        break;
      case '3':
        wavas[2]={"antanas.wav"};
        Serial.println("playing antanas.wav");
        playSound(2);
        break;
        case '4':
        wavas[3]={"test.wav"};
        Serial.println("playing test.wav");
        playSound(3);
        break;
      default:
        break;
    }
  }
}

void playSound(int iIter){
  File myFile = SD.open(wavas[iIter]);
  const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);
  }
  myFile.close();
}

Why does playSound() take an index into an array? Why does it not just take the name of the file to play?

There is a section of the forum specifically for the Due. You should ask a moderator to move your post there. Use the Report to moderator link.

PaulS:
Why does playSound() take an index into an array? Why does it not just take the name of the file to play?

There is a section of the forum specifically for the Due. You should ask a moderator to move your post there. Use the Report to moderator link.

But aren't we trying to use arrays so we don't need to retype the filename again?

Already asked to be moved for the DUE forum.

try this

#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 


Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
  Audio.begin(44100, 100);
}

void loop() {
  //pressing the key -> assigning the filename
  char customKey = customKeypad.getKey();

  if (customKey){ //Check for valid input
    switch(customKey){
      case '1':
        Serial.println("playing jonas.wav");
        playSound("jonas.wav");
        break;
      case '2':
        Serial.println("playing petras.wav");
        playSound("petras.wav");
        break;
      case '3':
        Serial.println("playing antanas.wav");
        playSound("antanas.wav");
        break;
        case '4':
        Serial.println("playing test.wav");
        playSound("test.wav");
        break;
      default:
        break;
    }
  }
}

void playSound(const char* cName){
  File myFile = SD.open(cName);
  const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);
  }
  myFile.close();
}

refactored a bit, hopefully it is not broken, as I said I can’t test it.

Paul S is correct, maybe should have done it this way to be a bit cleaner but I was not really making the neatest code, just trying to make it work first off.

MADMAN-_-zZ:
try this

#include <DAC.h>

#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;

char hexaKeys[ROWS][COLS] = {
 {‘1’, ‘2’, ‘3’, ‘A’},
 {‘4’, ‘5’, ‘6’, ‘B’},
 {‘7’, ‘8’, ‘9’, ‘C’},
 {’*’, ‘0’, ‘#’, ‘D’}
};

byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup() {
 // debug output at 9600 baud
 Serial.begin(9600);
 // setup SD-card
 SD.begin(10);
 Audio.begin(44100, 100);
}

void loop() {
 //pressing the key → assigning the filename
 char customKey = customKeypad.getKey();

if (customKey){ //Check for valid input
   switch(customKey){
     case ‘1’:
       Serial.println(“playing jonas.wav”);
       playSound(“jonas.wav”);
       break;
     case ‘2’:
       Serial.println(“playing petras.wav”);
       playSound(“petras.wav”);
       break;
     case ‘3’:
       Serial.println(“playing antanas.wav”);
       playSound(“antanas.wav”);
       break;
       case ‘4’:
       Serial.println(“playing test.wav”);
       playSound(“test.wav”);
       break;
     default:
       break;
   }
 }
}

void playSound(char cName){
 File myFile = SD.open(*cName);
 const int S = 1024; // Number of samples to read in block
 short buffer[S];
   // until the file is not finished
 while (myFile.available()) {
   myFile.read(buffer, sizeof(buffer));
       // Prepare samples
   int volume = 1024;
   Audio.prepare(buffer, S, volume);
   Audio.write(buffer, S);
 }
 myFile.close();
}




refactored a bit, hopefully it is not broken, as I said I can't test it.

Paul S is correct, maybe should have done it this way to be a bit cleaner but I was not really making the neatest code, just trying to make it work first off.

Thanks! I just tried it myself.
Of course, I though made a mistake. But I am getting the same message with your code:

Arduino: 1.6.12 (Mac OS X), Board: "Arduino Due (Programming Port)"

/var/folders/qc/x3db2l1j4j3d94t9y9w3lwqm0000gn/T/arduino_modified_sketch_127106/audio-player_buttonsABC.ino: In function 'void loop()':
audio-player_buttonsABC:41: error: cannot convert 'const char*' to 'char**' for argument '1' to 'void playSound(char**)'
         playSound("jonas.wav");
                              ^
audio-player_buttonsABC:45: error: cannot convert 'const char*' to 'char**' for argument '1' to 'void playSound(char**)'
         playSound("petras.wav");
                               ^
audio-player_buttonsABC:49: error: cannot convert 'const char*' to 'char**' for argument '1' to 'void playSound(char**)'
         playSound("antanas.wav");
                                ^
audio-player_buttonsABC:53: error: cannot convert 'const char*' to 'char**' for argument '1' to 'void playSound(char**)'
         playSound("test.wav");
                             ^
exit status 1
cannot convert 'const char*' to 'char**' for argument '1' to 'void playSound(char**)'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Now looking for documentation how playSound() can be used. No luck.
I’ve found this http://forum.arduino.cc/index.php?topic=370853.0
But it’s UNO…

atlaikesbriedi:
Thanks! I just tried it myself.
Of course, I though made a mistake. But I am getting the same message with your code:

Apologies, my syntax was a bit off, been a long time since using pointers and char arrays instead of strings, I usually program C#.

I edited my code above in Reply #11, try that again.

MADMAN-_-zZ:
Apologies, my syntax was a bit off, been a long time since using pointers and char arrays instead of strings, I usually program C#.

I edited my code above in Reply #11, try that again.

Thanks! What was the issue first time? Only missing void playSound(const char* cName)?

It works, but the same way - with sound distortions. Such a weird problem.

It seems that I am missing Audio.end();

Ok, it works now perfectly! (almost, still some tweaks needed).
Thanks all for help!
I’ve found the topic with similar problem and it seems I need to use Audio.begin() on each .wav file.

[edit] Seems that after case ‘3’ (antanas.wav) the playback stops for good. Can’t see anything different about it. Weird.

#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 


Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
}

void loop() {
  //pressing the key -> assigning the filename
  char customKey = customKeypad.getKey();

  if (customKey){ //Check for valid input
    switch(customKey){
      case '1':
        Audio.begin(44100, 100);
        Serial.println("playing jonas.wav");
        playSound("jonas.wav");
        break;
      case '2':
              Audio.begin(44100, 100);
        Serial.println("playing petras.wav");
        playSound("petras.wav");
        break;
      case '3':
              Audio.begin(44100, 100);
        Serial.println("playing antanas.wav");
        playSound("antanas.wav");
        break;
        case '4':
                Audio.begin(44100, 100);
        Serial.println("playing test.wav");
        playSound("test.wav");
        break;
      default:
        break;
    }
  }
}

void playSound(const char* cName){
  File myFile = SD.open(cName);
  const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);
  }
  myFile.close();
  Audio.end(); 
}

Another code cleanup here, let me know if it still works as per before, not sure about your issue playing antanas.wav, so after playing that file you can no longer play anymore sounds? only after playing that one?

#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 


Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
}

void loop() {
  //pressing the key -> assigning the filename
  keypadInput();
}

void keypadInput(){
char customKey = customKeypad.getKey();

  if (customKey){ //Check for valid input
    switch(customKey){
      case '1':
        playSound("jonas.wav");
        break;
      case '2':
        playSound("petras.wav");
        break;
      case '3':
        playSound("antanas.wav");
        break;
        case '4':
        playSound("test.wav");
        break;
      default:
        break;
    }
  }
}

void playSound(const char* cName){
  File myFile = SD.open(cName);
  const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  Serial.println("playing ");
  Serial.print(cName);
  Audio.begin(44100, 100);
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);    
  }
  Audio.end(); 
  myFile.close();  
}

MADMAN-_-zZ:
Another code cleanup here, let me know if it still works as per before, not sure about your issue playing antanas.wav, so after playing that file you can no longer play anymore sounds? only after playing that one?

#include <DAC.h>

#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;

char hexaKeys[ROWS][COLS] = {
  {‘1’, ‘2’, ‘3’, ‘A’},
  {‘4’, ‘5’, ‘6’, ‘B’},
  {‘7’, ‘8’, ‘9’, ‘C’},
  {’*’, ‘0’, ‘#’, ‘D’}
};

byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup() {
  // debug output at 9600 baud
  Serial.begin(9600);
  // setup SD-card
  SD.begin(10);
}

void loop() {
  //pressing the key → assigning the filename
  keypadInput();
}

void keypadInput(){
char customKey = customKeypad.getKey();

if (customKey){ //Check for valid input
    switch(customKey){
      case ‘1’:
        playSound(“jonas.wav”);
        break;
      case ‘2’:
        playSound(“petras.wav”);
        break;
      case ‘3’:
        playSound(“antanas.wav”);
        break;
        case ‘4’:
        playSound(“test.wav”);
        break;
      default:
        break;
    }
  }
}

void playSound(const char* cName){
  File myFile = SD.open(cName);
  const int S = 1024; // Number of samples to read in block
  short buffer[S];
    // until the file is not finished
  Serial.println("playing ");
  Serial.print(cName);
  Audio.begin(44100, 100);
  while (myFile.available()) {
    myFile.read(buffer, sizeof(buffer));
        // Prepare samples
    int volume = 1024;
    Audio.prepare(buffer, S, volume);
    Audio.write(buffer, S);   
  }
  Audio.end();
  myFile.close(); 
}

Thanks a bunch! This version works the same, but now I don’t have Audio.begin() in 4 places, very nice, thanks. Apparently antanas.wav file was damaged… :confused: When duplicating jonas.wav and renaming it as antanas.wav works just fine. [edit] Also, I just re-exported antanas.wav - works fine!

Have some karma for the help!

Now I will try instead of just pressing one button assign a short “phone number” to each soundtracks. Should be easy I guess.

Good luck with it, glad I could help