Go Down

Topic: Interface class for the Arduino Wave Shield (Read 9348 times) previous topic - next topic

avandalen

Jan 29, 2009, 05:23 pm Last Edit: Jan 30, 2009, 04:08 pm by avandalen Reason: 1
Using the Arduino Wave Shield (http://www.ladyada.net/make/waveshield) was not easy and requires writing too much code. Therefore I have made an interface for it, the MediaPlayer class. The class is very easy to use.

You only have to add the MediaPlayer class to your project and add these three lines:
#include "util.h"
#include "MediaPlayer.h"
MediaPlayer mediaPlayer;

Now we can play WAV files by using functions as:
play(), stop(), pause(), resume() etc.
The class is idiot proof, it is allowed to use any erroneous combination of these functions, such as stop() before using play(). Use the MediaPlayerTest project to learn about all the opportunities of the MediaPlayer class.

This is optional: the function blinkLed() requires on the wave shield card the onboard LED LED2, resistor R10 (470 ohm) and a wire between pin WP2 and digital I/O pin 6.

Procedure:
Create a folder with the name "MediaPlayerTest" and add the 4 files to it. Start Arduino and open MediaPlayerTest.pde.
Put some WAV files (songs) on the SD card. Change the 3 filenames in MediaPlayerTest to your song names. Upload to the Arduino and use the serial monitor to view (and listen) what happens.

It is preferable to use the Atmega 328p, which has more memory. Else the Wave Shield may be unstable. But the Atmega 168 can still be used here.

Do you have any questions, please put a reply!

File MediaPlayerTest.pde, THIS IS YOUR APPLICATION:
Code: [Select]
#include <avr/pgmspace.h>
#include "util.h"
#include "MediaPlayer.h"

int onboardLed = 13; // digital
MediaPlayer mediaPlayer; // create only one object, must be global

void loop()                    
{ blinkLed();
 putstring("\nThese files are on the SD card:\n"); mediaPlayer.exploreSDcard(true);

 putstring("\nSD card file count =  ");  Serial.print(mediaPlayer.exploreSDcard());
 
 if(!mediaPlayer.play("Notexist")) putstring("\nFile not exist"); // result is false

 char fileName[13];
 putstring("\nSD card filename of file no. 3 = ");
 mediaPlayer.fileName(3, fileName); // get the filename
 Serial.print(fileName);
 
 putstring("\nPlay ANOUK1.WAV"); mediaPlayer.play("ANOUK1.WAV");
 delay(2000);
 
 putstring("\nPlay ILSE1.WAV without using stop()"); mediaPlayer.play("ILSE1.WAV");  
 while (mediaPlayer.isPlaying()) { putstring("."); delay(50);}
 
 putstring("\nPlay  KREZIP1.WAV"); mediaPlayer.play("KREZIP1.WAV");
 delay(2000);
 putstring("\nPause"); mediaPlayer.pause();
 if(mediaPlayer.onPause()) putstring("\nMediaPlayer on pause");
 delay(500);
 putstring("\nResume"); mediaPlayer.resume();
 delay(2000);  
 putstring("\nStop"); mediaPlayer.stop();

 playComplete("ANOUK1.WAV");
       
 putstring("\nPlay all songs");
 for(int i=1; i<=mediaPlayer.exploreSDcard(); i++) playComplete(i);
}


File MediaPlayer.pde, don't change
Code: [Select]
// This class is an interface for the Arduino Wave Shield
// Pins 2, 3, 4, 5 are used by the Arduino Wave Shield

MediaPlayer::MediaPlayer():
pausePosition(0)
{ openMemoryCard();
 card.reset_dir();
 setupWaveShieldPins();
}

MediaPlayer::~MediaPlayer()
{ stop();
}

void MediaPlayer::setupWaveShieldPins()
{ pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
}

bool MediaPlayer::play(char *fileName)
{ stop();
 file = card.open_file(fileName);  
 if (!file)
 { putstring(" Couldn't open WAV file");
   return false;
 }  
 if (!waveFile.create(file))
 { putstring(" Not a valid WAV file");
   return false;
 }
 waveFile.play();
 return true;
}

void MediaPlayer::resume()
{ if (!isPlaying() & (bool)file) // If not stopped
 { waveFile.seek(pausePosition);
   waveFile.play();
 }
}

void MediaPlayer::stop()
{ if (isPlaying()) waveFile.stop();
 if (file) file = closeFile(file);
 card.reset_dir(); // if not done after card.get_next_name_in_dir() do it here
 pausePosition = 0;
}

void MediaPlayer::pause()
{ if (isPlaying())
 { pausePosition = waveFile.getSize() - waveFile.remainingBytesInChunk;
   waveFile.stop();
 }
}

File MediaPlayer::closeFile(const File file) // This should be done in AF_Wave.cpp
{ card.close_file(file);
 return 0;
}

void MediaPlayer::openMemoryCard()
{ if (!card.init_card())
 { putstring_nl("Card init failed");
   return;
 }
 if (!card.open_partition())
 { putstring_nl("No partition");
   return;
 }
 if (!card.open_filesys())
 { putstring_nl("Couldn't open filesys");
   return;
 }
if (!card.open_rootdir())
 { putstring_nl("Couldn't open dir");
   return;
 }
}

bool MediaPlayer::isPlaying()
{ return waveFile.isplaying;
}

bool MediaPlayer::onPause()
{ return !isPlaying() & (bool)pausePosition;
}

int MediaPlayer::exploreSDcard(const bool print)
{ int fileCount=0;
 char fileName[13];
 card.reset_dir();
 while(card.get_next_name_in_dir(fileName))
 { fileCount++;
   if(print)
   { Serial.print(fileCount);
     putstring(". ");
     Serial.println(fileName);
   }
 }
 card.reset_dir();
 return fileCount;
}

void MediaPlayer::fileName(const int fileNumber, char* _fileName)
{ int fileCount=1;
 char fileName[13];
 card.reset_dir();  
 while(card.get_next_name_in_dir(fileName))
 { if(fileCount++==fileNumber) break;
   else fileName[0]=0;
 }
 card.reset_dir();  
 strncpy(_fileName, fileName, 12); // fill the string argument
 _fileName[12] = 0;    
}



File MediaPlayer.h, don't change
Code: [Select]
#ifndef MEDIAPLAYER_H
#define MEDIAPLAYER_H

#include <AF_Wave.h>
#include "wave.h"

class MediaPlayer
{
public:
 MediaPlayer();
 ~MediaPlayer();
 bool play(char *fileName);
 void resume();
 void stop();
 void pause();
 bool isPlaying();
 bool onPause();
 int exploreSDcard(const bool print=0);
 void fileName(const int fileNumber, char* _fileName);
 
private:
 File closeFile(const File file);
 void openMemoryCard();
 void setupWaveShieldPins();

 AF_Wave card;
 File file; // struct fat16_file_struct*
 Wavefile waveFile;
 uint32_t pausePosition;    
};

#endif


File MediaPlayerTestFunctions.pde
Code: [Select]
void setup() // Run once, when the sketch starts
{ pinMode(onboardLed, OUTPUT); // Sets the digital pin as output
 Serial.begin(9600);
}

void blinkLed()
{ for(byte i=0; i<3; i++)
 { digitalWrite(onboardLed, HIGH);        
   delay(200);                
   digitalWrite(onboardLed, LOW);  
   delay(200);
 }
}  

void playComplete(char* fileName)
{ putstring("\nPlay complete: ");  
 Serial.print(fileName);
 mediaPlayer.play(fileName);
 while (mediaPlayer.isPlaying())
 { putstring(".");
   delay(100);
 }
}

void playComplete(const int fileNumber)
{ char fileName[13];
 mediaPlayer.fileName(fileNumber, fileName);
 playComplete(fileName);
}



Dave M

THANK YOU!!! This is extremely helpful.

avandalen

New version: 1.2.
This version is a little more efficient, it saves 222 bytes of code.
The function mediaPlayer.fileName() is improved.

File MediaPlayerTest.pde, THIS IS YOUR APPLICATION:
Code: [Select]
#include <avr/pgmspace.h>
#include "util.h"
#include "MediaPlayer.h"

int onboardLed = 13; // digital
int frontLed = 9; // digital
MediaPlayer mediaPlayer; // create only one object, must be global

void loop()                    
{ blinkLed();
 
 putstring("\nThese files are on the SD card:\n"); mediaPlayer.exploreSDcard(true);

 putstring("\nSD card file count =  ");  Serial.print(mediaPlayer.exploreSDcard());
 
 if(!mediaPlayer.play("Notexist")) putstring("\nFile not exist"); // result is false

 putstring("\nSD card filename of file no. 3 = "); Serial.print(mediaPlayer.fileName(3)); // now easier
 
 putstring("\nPlay ANOUK1.WAV"); mediaPlayer.play("ANOUK1.WAV");
 delay(2000);
 
 putstring("\nPlay ILSE1.WAV without using stop()"); mediaPlayer.play("ILSE1.WAV");  
 while (mediaPlayer.isPlaying()) { putstring("."); delay(50);}
 
 putstring("\nPlay  KREZIP1.WAV"); mediaPlayer.play("KREZIP1.WAV");
 delay(2000);
 putstring("\nPause"); mediaPlayer.pause();
 if(mediaPlayer.onPause()) putstring("\nMediaPlayer on pause");
 delay(500);
 putstring("\nResume"); mediaPlayer.resume();
 delay(2000);  
 putstring("\nStop"); mediaPlayer.stop();

 playComplete("ANOUK1.WAV");
       
 putstring("\nPlay all songs");
 for(int i=1; i<=mediaPlayer.exploreSDcard(); i++) playComplete(i);
 printAvailableRAM();
}


File MediaPlayer.pde, don't change
Code: [Select]
// This class is an interface for the Arduino Wave Shield
// Pins 2, 3, 4, 5 are used by the Arduino Wave Shield

MediaPlayer::MediaPlayer():
pausePosition(0)
{ openMemoryCard();
 card.reset_dir();
 setupWaveShieldPins();
}

MediaPlayer::~MediaPlayer()
{ stop();
}

void MediaPlayer::setupWaveShieldPins()
{ pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
}

bool MediaPlayer::play(char *fileName)
{ stop();
 file = card.open_file(fileName);  
 if (!file)
 { putstring(" Couldn't open WAV file");
   return false;
 }  
 if (!waveFile.create(file))
 { putstring(" Not a valid WAV file");
   return false;
 }
 waveFile.play();
 return true;
}

void MediaPlayer::resume()
{ if (!isPlaying() & (bool)file) // If not stopped
 { waveFile.seek(pausePosition);
   waveFile.play();
 }
}

void MediaPlayer::stop()
{ if (isPlaying()) waveFile.stop();
 if (file) file = closeFile(file);
 card.reset_dir(); // if not done after card.get_next_name_in_dir() do it here
 pausePosition = 0;
}

void MediaPlayer::pause()
{ if (isPlaying())
 { pausePosition = waveFile.getSize() - waveFile.remainingBytesInChunk;
   waveFile.stop();
 }
}

File MediaPlayer::closeFile(const File file) // This should be done in AF_Wave.cpp
{ card.close_file(file);
 return 0;
}

void MediaPlayer::openMemoryCard()
{ if (!card.init_card())
 { putstring_nl("Card init failed");
   return;
 }
 if (!card.open_partition())
 { putstring_nl("No partition");
   return;
 }
 if (!card.open_filesys())
 { putstring_nl("Couldn't open filesys");
   return;
 }
if (!card.open_rootdir())
 { putstring_nl("Couldn't open dir");
   return;
 }
}

bool MediaPlayer::isPlaying()
{ return waveFile.isplaying;
}

bool MediaPlayer::onPause()
{ return !isPlaying() & (bool)pausePosition;
}

int MediaPlayer::exploreSDcard(const bool print) // 104 bytes, was 156
{ int fileCount=0;
 card.reset_dir();
 while(card.get_next_name_in_dir(globalTempFileName))
 { fileCount++;
   if(print)
   { Serial.print(fileCount);
     putstring(". ");
     Serial.println(globalTempFileName);
   }
 }
 card.reset_dir();
 return fileCount;
}

char* MediaPlayer::fileName(const int fileNumber) // 82 bytes, was 158
{ int fileCount=1;
 card.reset_dir();  
 while(card.get_next_name_in_dir(globalTempFileName))
 { if(fileCount++==fileNumber) break;
   else globalTempFileName[0]=0;
 }
 card.reset_dir();  
 return globalTempFileName;
}


File MediaPlayer.h, don't change
Code: [Select]
#ifndef MEDIAPLAYER_H
#define MEDIAPLAYER_H

#include <AF_Wave.h>
#include "wave.h"

char globalTempFileName[13]; //  not nice but efficient

class MediaPlayer
{
public:
 MediaPlayer();
 ~MediaPlayer();
 bool play(char *fileName);
 void resume();
 void stop();
 void pause();
 bool isPlaying();
 bool onPause();
 int exploreSDcard(const bool print=0);
 char* fileName(const int fileNumber);
 
private:
 File closeFile(const File file);
 void openMemoryCard();
 void setupWaveShieldPins();

 AF_Wave card;
 File file; // struct fat16_file_struct*
 Wavefile waveFile;
 uint32_t pausePosition;    
};

#endif


File MediaPlayerTestFunctions.pde
Code: [Select]
void setup() // Run once, when the sketch starts
{ pinMode(onboardLed, OUTPUT); // Sets the digital pin as output
 pinMode(frontLed, OUTPUT); // Sets the digital pin as output
 Serial.begin(9600);
}

void blinkLed()
{ for(byte i=0; i<3; i++)
 { digitalWrite(onboardLed, HIGH);  digitalWrite(frontLed, HIGH);      
   delay(200);                
   digitalWrite(onboardLed, LOW); digitalWrite(frontLed, LOW);  
   delay(200);
 }
}  

void playComplete(char* fileName)
{ putstring("\nPlay complete: ");  
 Serial.print(fileName);
 mediaPlayer.play(fileName);
 while (mediaPlayer.isPlaying())
 { putstring(".");
   delay(100);
 }
}

void playComplete(const int fileNumber)
{ playComplete(mediaPlayer.fileName(fileNumber));
}

void printAvailableRAM() // 590 bytes
{ int size = 1024;
 byte *buf;
 while ((buf = (byte *) malloc(--size)) == NULL);
 free(buf);
 putstring("\nAvailable RAM: ");
 Serial.print(size);
}


guibot

#3
Feb 21, 2009, 08:22 pm Last Edit: Feb 21, 2009, 08:22 pm by guibot Reason: 1
Oh boy this class is absolutely amazing! Great work!!
Thank you for the effort and for sharing!

I just have a question though, when you say to use a jumper wire between WP2 and digital9, what do you mean by WP2.. where is it ?   ::)

XFitter

#4
Apr 05, 2009, 12:45 am Last Edit: Apr 05, 2009, 12:45 am by jmmoses Reason: 1
I was working with your 1.2 version.  I tried in both Arduino 15 and 13 and neither worked.  Here were the errors I was getting in MediaPlayer.pde:

Code: [Select]
error: 'MediaPlayer' has not been declared In function 'int MediaPlayer()':
At global scope:
In function 'bool play(char*)':
At global scope:
In function 'void resume()':
At global scope:
In function 'void stop()':
At global scope:
In function 'void pause()':
At global scope:
In function 'void openMemoryCard()':
At global scope:
In function 'bool isPlaying()':
At global scope:
In function 'bool onPause()':
At global scope:
In function 'int exploreSDcard(bool)':
At global scope:
In function 'char* fileName(int)':
At global scope:
In function 'void loop()':
In function 'void playComplete(char*)':
In function 'void playComplete(int)':


If I then add #include "MediaPlayer.h" to MediaPlayer.pde I get the following error:

Code: [Select]
n member function 'bool MediaPlayer::play(char*)':
error: 'putstring' was not declared in this scope In member function 'void MediaPlayer::openMemoryCard()':
In member function 'int MediaPlayer::exploreSDcard(bool)':


I'm very new to this and I'm stumped.  I really like the idea of easy to understand class because all I want to do is stop/pause/start based on a timer I input.

Thanks

zachtos

I get the same error on the 0015 /dueminalove.

I have not been able to get this to compile, but can get the default library demos to work.  
IR Combat laser tag developer/inventor

MaleBuffy

I get an error when I try to compile the my sketch. I just added the following into a working sketch:

#include "util.h"
#include "MediaPlayer.h"
MediaPlayer mediaPlayer;

I try to compile it and I get this error:

hardware\libraries\AF_Wave/util.h:1: error: 'uint8_t' has not been declared


Another questions, are the pins used by the waveshield the default pins Ladyada uses or have you chamged them?

MaleBuffy


RobertC

Hi I'm really new physical computing and for that fact programming. I was wondering where I could get these files to make the sketch work properly:
util.h
pgmspace.h
AF_Wave.h
wave.h
They are called in the other sketches but I can't find them in the Arduino hardware library folder and there aren't sketches for them here.

Thanks,

RobertC

mem

the library for the wave shield is here: http://www.ladyada.net/media/wavshield/AFWave_18-02-09.zip

Vick Jr

Has anyone made an interface like this for the WaveHC library?

Hi there,

I am facing a little problem with the code and would just like to ask if anyone might be able to help me on this?

I loaded the Arduino Uno with the cose for the MediaPlayer and also made the necessary preparation/steps to load my SD card with 3 audio .wav files.

However, I am receiving this feedback whenever I try to compile the code in Arduino:

MediaPlayerTest.cpp:2:18: error: util.h: No such file or directory
MediaPlayerTest.cpp:3:25: error: MediaPlayer.h: No such file or directory
MediaPlayerTest:6: error: 'MediaPlayer' does not name a type
MediaPlayerTest.cpp: In function 'void loop()':
MediaPlayerTest:9: error: 'blinkLed' was not declared in this scope
MediaPlayerTest:11: error: 'putstring' was not declared in this scope
MediaPlayerTest:11: error: 'mediaPlayer' was not declared in this scope
MediaPlayerTest:34: error: 'playComplete' was not declared in this scope
MediaPlayerTest:38: error: 'printAvailableRAM' was not declared in this scope


Any idea how to rectify this problem?

Your advice would really help.


Thanks,
CNEC

I did create the MediaPlayer.h file though but it still does not seem to work. As for Util.h, is there a specific code for that too?


Thanks.

Hey Everyone!

I am fairly new to physical computing and kind of stumped so hopefully someone can help me out.

I found this post and the code in it seems to be what I have been looking for in order to get my wave shield to function the way I want, the only problem is I cannot get this code working.

I followed the steps outlined, but when I try to upload the code to my arduino I get the following errors:

'MediaPlayer' does not name a type

MediaPlayerTest.cpp:3:25: error: MediaPlayer.h: No such file or directory
MediaPlayerTest:6: error: 'MediaPlayer' does not name a type
MediaPlayerTest.cpp: In function 'void setup()':
MediaPlayerTest:15: error: a function-definition is not allowed here before '{' token
MediaPlayer_h:31: error: expected `}' at end of input


Can anyone tell me why this might be happening? Any help will be greatly appreciated.

Thanks!

PaulS

Quote
MediaPlayerTest.cpp:3:25: error: [glow]MediaPlayer.h: No such file[/glow] or directory

I think the highlighted portion really says it all.

The compiler can't find the header file, which means that you put it in the wrong place.

Go Up