Différences entre versions de « AdaFruit Wave Shield WaveHC dap »

De MCHobby - Wiki
Sauter à la navigation Sauter à la recherche
 
(9 versions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
== Get more RAM & Flash! ==
+
{{WaveShield-Nav}}
  
Before you try to play audio, you'll want to free up some Arduino RAM, so that you don't end up with a nasty stack-overflow. Running out of RAM is hard to debug and frustrating, and likely if you're using a '168
+
== Avoir plus de RAM et de Flash! ==
 +
Note MCHobby:
 +
Les plateformes Arduino sont maintenant distribuée avec un ATmega328.
  
[http://www.ladyada.net/library/arduino/hacks.html Follow these instructions] on how to get more RAM by reducing the input Serial library buffer. You dont need to do this if you're using an [http://www.ladyada.net/library/arduino/upgrade.html ATmega328]
+
Cette section n'est vraiment pertinente que si vous ne possédez pas d'ATmega328.
  
Note that the library is pretty big (about 10K) so if you want to do a lot more, I suggest [http://www.ladyada.net/library/arduino/upgrade.html upgrading to an ATmega328]. The shield was designed with the expectation that this upgrade would be available.
+
Avant d'essayer de jouer de l'audio, vous aurez besoin de faire un peu de place
  
== A tour of dap_hc.pde ==
+
la mémoire RAM d'Arduino, cela évitera que cela se termine en vilain
  
This is a tutorial of the [http://code.google.com/p/wavehc/ waveHC library] by going through dap_hc.pde
+
dépassement de pile (stack-overflow). Manquer de mémoire RAM est difficile à déboguer et frustrant, d'autant plus si vous disposez d'un ATMega168
  
Its detailed and a little daunting. But stick with it since much of the code is going to be duplicated from this sketch to others!
+
[http://www.ladyada.net/library/arduino/hacks.html Suivez ces instructions] (''anglais'') pour savoir comment avoir plus
  
Make sure you install the library by downloading it from the link above and sticking '''WaveHC''' folder in the libraries folder. The zip also contains '''dap_hc.pde'''
+
de RAM en réduisant la taille de la mémoire tampon de la librairie série (Serial library).
  
In case you need the sketch we're referring to here, its at the bottom of the page
+
Vous n'aurez pas besoin de faire cela si vous avez un [http://www.ladyada.net/library/arduino/upgrade.html ATmega328].
  
== Initialize the card ==
+
Notez que la librairie est vraiment grosse (approximativement 10K). Si vous voulez faire beaucoup plus avec Arduino, il est vivement conseillé de faire un Upgrade vers un [http://www.ladyada.net/library/arduino/upgrade.html ATmega328]. Ce shield a été développé en prévoyant la disponibilité d'un ATmega328.
  
The hard work of playing music is all done right on the Arduino. This lets us skip having an MP3 decoder or other dedicated chip. That means more control and flexibility, but more firmware! Lets take a tour through the canonical sketch "dapHC.pde" this is a Digital Audio Player (dap) sketch using the Wave HC librarry. We used to use the Adafruit AF_Wave library but Mr. Fat16 did a fantastic job rewriting our code and making it faster, smaller and better. So we're going to use his library in this tutorial :)
+
== Une introduction pour dap_hc.pde ==
  
Download the dapHC.pde sketch and read along! The first thing we need are some objects. The tough part is talking to the card. All cards are manufactured and formatted a little different. And the formatting has many layers - the card format - the partition format and the filesystem formatting. At the beginning of the sketch we have the #include to get the library header files in and an object for storing information about the card '''card''', partition volume '''vol''' and filesystem '''root'''. We also have a directory buffer, for information on any folder/directories and an object for storing information about a single wave file wave
+
Ceci est un tutoriel de la [http://code.google.com/p/wavehc/ librairie waveHC] basé sur le projet dap_hc.pde
  
These are all pretty much manditory unless perhaps you dont want directory traversal in which case you can probably skip '''dirBuf'''
+
C'est détaillé et un peu intimidant. Mais attardez vous puisque la plupart du code peut être dupliqué d'un sketch à l'autre.
 +
 
 +
Assurez vosu que vous avez installé la librairie en la téléchargeant depuis le lien ci dessus et placé dans un sous-répertoire '''WaveHC''' de votre répertoire "libraries". Le fichier zip contient également le projet '''dap_hc.pde'''
 +
 
 +
Nous avons placé ce sketch en bas de cet article au cas où vous en auriez besoin.
 +
 
 +
== Initialiser la carte ==
 +
 
 +
Les tâches complexes nécessaires au rendu musical est assuré par Arduino. Cela nous épargne d'avoir recours à un décodeur MP3ou autre circuit dédicacé. Cela signifie plus de contrôle et de flexibilité mais aussi pas de firmware!
 +
 
 +
Faisons donc un tour d'horizon du sketch "dapHC.pde". C'est un sketch de type "Digital Audio Player" (dap) utilisant la librairie Wave HC. Nous avions écrit ce projet pour l'utilisé avec notre librairie Adafruit AF_Wave mais Mr. Fat16 à réalisé un fantastique travail en réécrivant notre code en le rendant plus rapide, plus petit et meilleur. Donc nous allons utiliser sa librairie pour ce tutoriel :)
 +
 
 +
Téléchargez le sketch dapHC.pde et prenez le temps de le lire. La première chose dont nous avons besoin sont quelques objets. La partie la plus difficile est de dialoguer avec la carte. Toutes les cartes sont fabriquée et formattées différemment (juste un peu). Et le formatage repose sur différentes couches - le format de la carte - Le format de la partition et le formatage du système de fichier.
 +
 
 +
Au début du sketch nous avons l' #include qui incorpore le fichier d'entête de la librairie (fichier header) files ainsi qu'un objet '''card''' qui stocke les information concernant la carte, un autre '''vol''' relatif à la partition (partition volume) et le système de fichier '''root'''.
 +
 
 +
Nous avons aussi un tampon pour les répertoires, contenant des informations sur tous les répertoires (folders) et un objet stockant des information à propos d'un seul fichier wave.
 +
 
 +
Ils sont tous obligatoires à moins que vous ne désiriez pas lire la liste des fichiers. Dans ce cas, vous pouvez probablement vous passer de '''dirBuf'''
 
  <nowiki>#include "WaveUtil.h"
 
  <nowiki>#include "WaveUtil.h"
 
#include "WaveHC.h"
 
#include "WaveHC.h"
  
  
SdReader card;    // This object holds the information for the card
+
SdReader card;    // Cet objet maintien des informations sur la carte
FatVolume vol;    // This holds the information for the partition on the card
+
FatVolume vol;    // Maintien des information due la partition de la carte
FatReader root;  // This holds the information for the filesystem on the card
+
FatReader root;  // Maintien des information sur le système de fichier de la carte
  
uint8_t dirLevel; // indent level for file/dir names    (for prettyprinting)
+
uint8_t dirLevel; // Niveau d indentation pour fichiers et répertoire (pour un affichage plus sympa)
dir_t dirBuf;    // buffer for directory reads
+
dir_t dirBuf;    // tampon pour les lectures des répertoires
  
WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time
+
WaveHC wave;      // Le seul objet wave (audio), puisque nous jouons une seul fichier à la fois
 
</nowiki>
 
</nowiki>
First thing that must be done is initializing the SD card for reading. This is a multistep process. In the setup loop you can see the multiple checks we do as we proceed through the initialization process
 
  
Here are the steps:
+
La première chose à faire est d'initialiser la carte SD pour faire des lectures. C'est un processus qui se réalise en plusieurs étapes. Dans la fonction setup vous pouvez voir les différentes vérification qui sont faites par le processus d'initialisation.
# '''Wake up and print''' out the to Serial Monitor that we're running '''(OPTIONAL)'''
+
 
# '''Check how much free RAM we have''' after we have used the buffer for storing Wave audio data, make sure its more than 100 bytes and keep an eye on it as you modify your code. This test can be removed, its for your use '''(OPTIONAL)'''
+
Voici les étapes:
# '''Set the pin modes for the DAC''' control lines. These should not be changed unless you've modified them in the library as well. Its probably best to keep them as-is
+
# '''Initialisation et affichage''' sur la connexion série pour indiquer que nous démarrons '''(OPTIONNEL)'''
# '''Initialize the SD card''' and see if it responds. We try to talk to it at 8MHz. If you have a waveshield 1.0 you may need to use 4MHz mode so comment out one line and uncommment the other to swap which method is used. If the card fails to initialize, print out an error and halt.
+
# '''Vérifier la quantité de mémoire disponible''' après avoir utilisé la mémoire tampon pour stocker les données audio du Wave, faite en sorte qu'il reste plus de 100 octets (bytes) et gardez un oeil dessus si vous modifiez votre code. Ce test peut être enlevé, il n'est destiné qu'a votre information '''(OPTIONNEL)'''
# '''Allow partial block reads'''. Some SD cards don't like this so if you're having problems, comment this out first! (OPTIONAL)
+
# '''Initialise les pin modes pour le DAC''' (lignes de contrôles du DAC). Cela ne devrait pas être modifié à moins que vous ayez aussi modifié la librairie. Il est certainement préférable de les garder tels quels.
# '''Try to find a FAT partition''' in the first 5 slots. You did format the card to FAT format, right? If it cant find a FAT partition it will print out that it failed, so make sure you format it again if its giving you trouble
+
# '''Initialiser la carte SD''' et vérifier qu'elle réponde. Nous essayons de l'adresser à 8MHz. Si vous disposez d'un Shield Wave 1.0 vous pourriez avoir besoin d'utiliser le mode 4MHz (dé-commentez/re-commentez la ligne appropriée en fonction de la méthode utilisée). Si la carte ne s'initialise pas, alors afficher une erreur et arrêter.
# '''Print out what kind of FAT''' partition was found '''(OPTIONAL)'''
+
# '''Autoriser la lecture de bloc partiel'''. Certaines cartes SD n'apprécient pas vraiment. Commenter en priorité cette ligne si vous avez des problèmes! (OPTIONNEL)
# '''Try to open up the root directory'''. If this doesnt work, something is messed up with the formatting. Try to format it again!
+
# '''Essayer de trouver la partition FAT''' dans les 5 premiers slots. Vous avez bien formatez votre carte en FAT n'est-ce pas? S'il ne peut pas trouver la partition FAT il affichera un message d'erreur. En cas de problème, assurez vous que vous avez bien formaté la carte en FAT (quitte à re-formater la carte).
# Finally, print out the files found, one after the other in the directories on the card. This is great for debugging and will show you what you've got on there. Since we dont have long filename access and use the 'base' 8.3 format to define files, you'll need to see what the files are named on the partition and this helps a lot '''(OPTIONAL)'''
+
# '''Affiche le type de partition FAT''' qui a été trouvée '''(OPTIONNEL)'''
 +
# '''Essaye d'ouvrir le répertoire racine'''. Si cela ne fonctionne pas, c'est que quelque-chose s'est mal déroulé au cours du formatage. Essayer de formater la carte une fois de plus!
 +
# Finalement, afficher l'un après l'autre les fichiers trouvés dans les répertoires de la carte. C'est vraiment génial pour déboguer et vous montrera ce qui est disponible sur la carte. Puisque nous n'utilisons pas de nom de fichier long mais le format de base 8.3 pour définir les fichiers, vous aurez besoin de voir comment les fichiers sont nommés sur la partition (et cela peut vraiment aider beaucoup) '''(OPTIONNEL)'''
  
 
   <nowiki>void setup() {
 
   <nowiki>void setup() {
   Serial.begin(9600);          // set up Serial library at 9600 bps for debugging
+
   Serial.begin(9600);          // initialise la libraire serie a 9600 bauds pour deboguer
 
    
 
    
   putstring_nl("\nWave test!");  // say we woke up!
+
   putstring_nl("\nWave test!");  // Indiquer le "demarrage"!
 
    
 
    
   putstring("Free RAM: ");      // This can help with debugging, running out of RAM is bad
+
   putstring("Free RAM: ");      // cela peut aider pour deboguer, ne plus avoir assez de RAM est mauvais signe
 
   Serial.println(freeRam());   
 
   Serial.println(freeRam());   
 
   
 
   
   // Set the output pins for the DAC control. This pins are defined in the library
+
   // Initialiser les pins pour le controle du DAC. Ces pins sont définies dans la librairie
 
   pinMode(2, OUTPUT);
 
   pinMode(2, OUTPUT);
 
   pinMode(3, OUTPUT);
 
   pinMode(3, OUTPUT);
Ligne 64 : Ligne 85 :
 
   pinMode(5, OUTPUT);
 
   pinMode(5, OUTPUT);
 
    
 
    
   //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
+
   //  if (!card.init(true)) { //spi cadence a 4 MHz si 8MHz ne fonctionne pas
   if (!card.init()) {        //play with 8 MHz spi (default faster!)   
+
   if (!card.init()) {        //spi cadencé a 8 MHz (par defaut, le plus rapide!)   
     putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
+
     putstring_nl("Init Carte. Echec!");  // Quelque chose ne marche pas, affichons pourquoi
 
     sdErrorCheck();
 
     sdErrorCheck();
     while(1);                            // then 'halt' - do nothing!
+
     while(1);                            // Et arrêtons (ne plus rien faire)!
 
   }
 
   }
 
    
 
    
   // enable optimize read - some cards may timeout. Disable if you're having problems
+
   // Activer la lecture optimisee - Certaines cartes pourrait bloquer (timeout). Desactiver en cas de probleme
 
   card.partialBlockRead(true);
 
   card.partialBlockRead(true);
 
    
 
    
   // Now we will look for a FAT partition!
+
   // Recherche de la partition FAT!
 
   uint8_t part;
 
   uint8_t part;
   for (part = 0; part < 5; part++) {    // we have up to 5 slots to look in
+
   for (part = 0; part < 5; part++) {    // Vérifier dans les 5 slots disponibles
 
     if (vol.init(card, part))  
 
     if (vol.init(card, part))  
       break;                            // we found one, lets bail
+
       break;                            // Nous en avons trouvé un, sortons de la boucle
 
   }
 
   }
   if (part == 5) {                      // if we ended up not finding one :(
+
   if (part == 5) {                      // Terminé la boucle sans trouvé de partitions :(
     putstring_nl("No valid FAT partition!");
+
     putstring_nl("Pas de partition FAT valide!");
     sdErrorCheck();      // Something went wrong, lets print out why
+
     sdErrorCheck();      // Qlque chose ne va pas, affichons pourquoi
     while(1);                            // then 'halt' - do nothing!
+
     while(1);                            // et arreter le programme (ne plus rien faire)!
 
   }
 
   }
 
    
 
    
   // Lets tell the user about what we found
+
   // Indiquons à l'utilisateur ce que nous avons trouvé
   putstring("Using partition ");
+
   putstring("Utilise la partition ");
 
   Serial.print(part, DEC);
 
   Serial.print(part, DEC);
   putstring(", type is FAT");
+
   putstring(", type est FAT");
   Serial.println(vol.fatType(),DEC);    // FAT16 or FAT32?
+
   Serial.println(vol.fatType(),DEC);    // FAT16 ou FAT32?
 
    
 
    
   // Try to open the root directory
+
   // Essayer d ouvrir le répertoire racine
 
   if (!root.openRoot(vol)) {
 
   if (!root.openRoot(vol)) {
     putstring_nl("Can't open root dir!"); // Something went wrong,
+
     putstring_nl("Echec ouverture répertoire racine!"); // Quelque chose ne va pas,
     while(1);                            // then 'halt' - do nothing!
+
     while(1);                            // et arreter le programme (ne plus rien faire)!
 
   }
 
   }
 
    
 
    
   // Whew! We got past the tough parts.
+
   // Whaow! nous avons passé toutes les étapes difficiles.
   putstring_nl("Files found:");
+
   putstring_nl("Fichiers trouvés:");
 
   dirLevel = 0;
 
   dirLevel = 0;
   // Print out all of the files in all the directories.
+
   // Afficher tous les fichiers dans tous les répertoires.
 
   lsR(root);
 
   lsR(root);
 
}
 
}
 
</nowiki>
 
</nowiki>
  
== Looking for files in a directory ==
+
== Chercher les fichiers dans un répertoire ==
  
OK now that you've initialized the card, we perform a recursive list of all files found. This is useful for debugging and ALSO shows how you can navigate the file system
+
OK maintenant que la carte est initialisée, nous affichons une liste de tous les fichiers que nous trouvons. C'est utile pour deboguer et vous montre aussi comment naviguer dans le système de fichier.
  
To start, pass a directory object (like '''root''') to '''lsR()''' which will do the following:
+
Pour commencer, passer un objet répertoire (''directory'' en anglais) tel que '''root''' a la fonction '''lsR()'''.
# Read a file from the directory. The files are read in the order they are copied into the directory, '''not alphabetical order'''!
+
 
# If the directories are the special links "." (current directory) or ".." (upper directory) it ignores them and goes to step 1 again.
+
lsR effectue les opérations suivantes:
# It prints out spaces to create a nicely formatted output. Each level of directory gets 2 spaces
+
# Lire un fichier du répertoire. Les fichiers sont lus dans l'ordre dans lequel ils sont copiés dans le répertoire, '''pas par ordre alphabétique'''!
# It prints out the name of the file in 8.3 format
+
# Si le répertoire à un nom/liens spécial "." (répertoire courant) or ".." (répertoire parent) ignorez les et répéter encore l'opération 1.
# If it is a subdirectory, it makes a new object and opens up the subdirectory. Then it prints out all of the files in that new directory
+
# Il affiche des espaces pour formater correctement les sortie de message. Chaque niveau de répertoire prends deux espaces de plus.
# It continues to step 1 until there are no more files to be read
+
# Affiche le nom du fichier au format 8.3
 +
# S'il s'agit d'un sous répertoire, il crée un nouvel objet et ouvre le sous répertoire. Ensuite, il affiche tous les fichiers de ce nouveau répertoire.
 +
# Il continue à l'étape 1 jusqu'a ce qu'il ne reste plus de fichier à lire
  
 
  <nowiki>/*
 
  <nowiki>/*
  * list recursively - possible stack overflow if subdirectories too nested
+
  * Affichage récursif - Possiblilité de dépassement de pile (stack overflow)
 +
* s'il y a trop de répertoire imbriqués
 
  */
 
  */
 
void lsR(FatReader &d)
 
void lsR(FatReader &d)
 
{
 
{
   int8_t r;                    // indicates the level of recursion
+
   int8_t r;                    // indique le niveau de récursion
 
    
 
    
   while ((r = d.readDir(dirBuf)) > 0) {    // read the next file in the directory
+
   while ((r = d.readDir(dirBuf)) > 0) {    // Lire le prochain fichier dans le répertoire
     // skip subdirs . and ..
+
     // Ignore les sous répertoires . et ..
 
     if (dirBuf.name[0] == '.')  
 
     if (dirBuf.name[0] == '.')  
 
       continue;
 
       continue;
 
      
 
      
 
     for (uint8_t i = 0; i < dirLevel; i++)  
 
     for (uint8_t i = 0; i < dirLevel; i++)  
       Serial.print(' ');        // this is for prettyprinting, put spaces in front
+
       Serial.print(' ');        // Meilleur affichage, place des espaces devant
     printName(dirBuf);          // print the name of the file we just found
+
     printName(dirBuf);          // Afficher le nom de fichier trouvé
     Serial.println();          // and a new line
+
     Serial.println();          // et un retour à la ligne
 
      
 
      
     if (DIR_IS_SUBDIR(dirBuf)) {  // we will recurse on any direcory
+
     if (DIR_IS_SUBDIR(dirBuf)) {  // Nous allons répéter (récursion) pour chaque sous-répertoire
       FatReader s;                // make a new directory object to hold information
+
       FatReader s;                // Créer un nouvel objet répertoire pour maintenir les informations
       dirLevel += 2;              // indent 2 spaces for future prints
+
       dirLevel += 2;              // indenter de 2 espaces (pour les affichages futurs)
 
       if (s.open(vol, dirBuf))  
 
       if (s.open(vol, dirBuf))  
         lsR(s);                    // list all the files in this directory now!
+
         lsR(s);                    // Afficher tous les fichiers du répertoire. Maintenant!
       dirLevel -=2;                // remove the extra indentation
+
       dirLevel -=2;                // retirer l'indentation ajoutée (quand fini de lister le sous-répertoire)
 
     }
 
     }
 
   }
 
   }
   sdErrorCheck();                  // are we doign OK?
+
   sdErrorCheck();                  // Est-ce que tout est OK?
 
}
 
}
 
</nowiki>
 
</nowiki>
  
There is also a helper called '''printName''' which prints out the file in a nice format. Files are named in '''8.3''' format, an older and simpler way of addressing files. Its a little less pretty than "Long Name Format" so watch out to see what your files are renamed as. For example "Bird song.wav" may be renamed to "BIRDSONG.WAV" or "BIRDSO~1.WAV" !  
+
Il y a aussi une fonction d'aide nommée '''printName''' qui affiche le nom du fichier (dans un format lisible). les fichiers sont nommés au format  '''8.3''', une vieille façon d'adresser les fichier (mais aussi plus simple). C'est un petit peu moins beau qu'afficher les noms au format long, donc regardez quand même comment vos fichiers sont re-nommés en format court. Par exemple, le fichier "Bird song.wav" pourrait être renommé en "BIRDSONG.WAV" ou "BIRDSO~1.WAV" !  
  
 
  <nowiki>/*
 
  <nowiki>/*
  * print dir_t name field. The output is 8.3 format, so like SOUND.WAV or FILENAME.DAT
+
  * Affiche le champs name de dir_t. Format de sortie est 8.3, ressemble donc à SOUND.WAV ou FILENAME.DAT
 
  */
 
  */
 
void printName(dir_t &dir)
 
void printName(dir_t &dir)
 
{
 
{
   for (uint8_t i = 0; i < 11; i++) {    // 8.3 format has 8+3 = 11 letters in it
+
   for (uint8_t i = 0; i < 11; i++) {    // format 8.3 a 8+3 = 11 lettres
 
     if (dir.name[i] == ' ')
 
     if (dir.name[i] == ' ')
         continue;        // dont print any spaces in the name
+
         continue;        // N'affiche pas les espaces dans le nom
 
     if (i == 8)  
 
     if (i == 8)  
         Serial.print('.');          // after the 8th letter, place a dot
+
         Serial.print('.');          // placer un point après la 8ieme lettre
     Serial.print(dir.name[i]);      // print the n'th digit
+
     Serial.print(dir.name[i]);      // afficher la lettre à la position n
 
   }
 
   }
 
   if (DIR_IS_SUBDIR(dir))  
 
   if (DIR_IS_SUBDIR(dir))  
     Serial.print('/');      // directories get a / at the end
+
     Serial.print('/');      // Afficher un "/" à la fin quand c'est un répertoire
 
}
 
}
 
</nowiki>
 
</nowiki>
One thing that appears in '''loop()''' is '''dir.rewind()'''. The reason we rewind a directory is that our Arduino code is very simple. It can go through the files in a directory but only 'forward', not backward (FAT format is kinda like that). So if you skipped a file and want to go back, or you've gone through the directory, you will need to call '''rewind()''' to set it back to the beginning!
+
Une des chose qui apparait dans '''loop()''' c'est '''dir.rewind()''' (action de remonter) . La raison pour laquelle nous remontons les répertoires c'est que le code de notre Arduino est très simple. Il peut traverser les fichiers d'un répertoire mais seulement 'vers l'avant' (forward), pas vers l'arrière (le format FAT est un peu comme ca).
  
== Playing all the files ==
+
Donc, si vous avez raté un fichier ou si vous voulez aller en arrière, ou si vous avez traversé le répertoire, vous devrez appeler '''rewind()''' pour revenir au début du répertoire!
  
The digital audio player plays all files in the card. To do that it recursively looks in every directory, just like lsR() above so the code looks somewhat similar. The big difference is we call the play() routine to play a file!
+
== Jouer tous les fichiers ==
  
To start, pass a directory object (like root) to '''lsR()''' which will do the following:
+
Le "digital audio player" joue tous les fichier de la carte. Pour ce faire, il cherche les fichiers dans tous les répertoires de façon récursive (comme le fait lsR() ci-avant). Cela produit un code assez similaire eu point précédent.
# Read a file from the directory. The files are read in the order they are copied into the directory, '''not alphabetical order'''!
+
 
# If the directories are the special links "." (current directory) or ".." (upper directory) it ignores them and goes to step 1 again.
+
La grande différence c'est que nous appelons la fonction play() qui recherche les fichiers à jouer!
# It prints out spaces to create a nicely formatted output. Each level of directory gets 2 spaces
+
 
# It prints out the name of the file in 8.3 format
+
Le fichier est joué à l'aide de wave.play()
# If it is a subdirectory, it makes a new object and opens up the subdirectory. Then it plays all of the wave files in that new directory
+
 
# If it isn't a subdirectory, it will try to play the file by opening it as a Wave object. That requires looking through the file and trying to find a Wave header, etc. If it doesnt succeed it will print out that its not valid and skip to the next file
+
Pour commencer, passez un objet répertoire (tel que root) a '''play()''' effectue les étapes suivantes:
# If the wave file is valid, it will finally start the file by calling '''play()''' on the Wave object
+
# Lit un fichier depuis le répertoire. Les fichier sont lus dans l'ordre dans lequel ils ont étés copiés dans le répertoire, '''pas l'ordre alphabétique'''!
# While the wave sound file is playing, it prints out a dot every 100 ms or so.
+
# Si le répertoire à un nom/lien spécial comme "." (répertoire courant) or ".." (répertoire parent) sont ignorés et on recommence à l'étape 1.
# It continues to step 1 until there are no more files to be read
+
# Il affiche des espace pour créer un format d'affichage plus sympathique. Chaque niveau de répertoire ajoute deux espaces.
 +
# Il affiche le nom du fichier au format 8.3 .
 +
# Si c'est un sous répertoire, il crée un nouvel objet et ouvre le sous répertoire. Ensuite, il joue tous les fichioers wave qu'il y a dans ce nouveau répertoire.
 +
# Si ce n'est pas un sous répertoire, il va essayer de jouer le fichier en ouvrant celui-ci comme un objet Wave. Cela nécessite d'ouvrir le fiochier et d'essayer de trouver l'entête Wave (Wave header), etc. S'il n'y arrive pas, il affiche un message comme quoi le fichier n'est pas valide puis il passe au fichier suivant.
 +
# Si le fichier wave est valide, il commence à le jouer en appelant la fonction '''play()''' de l'objet Wave
 +
# Tant que le fichier wave est jouer, le programme affiche un point toutes les 100 ms.
 +
# Le programme continue à l'étape 1 jusqu'à ce qu'il n'y ait plus de fichier à lire.
  
 
  <nowiki>/*
 
  <nowiki>/*
  * play recursively - possible stack overflow if subdirectories too nested
+
  * Joue récursivement - Possibilité de dépassement de pile (stack overflow)
 +
* s'il y a trop de répertoire imbriqués
 
  */
 
  */
 
void play(FatReader &dir)
 
void play(FatReader &dir)
 
{
 
{
 
   FatReader file;
 
   FatReader file;
   while (dir.readDir(dirBuf) > 0) {    // Read every file in the directory one at a time
+
   while (dir.readDir(dirBuf) > 0) {    // lit un à un chaque fichier du répertoire
 
     // skip . and .. directories
 
     // skip . and .. directories
 
     if (dirBuf.name[0] == '.')  
 
     if (dirBuf.name[0] == '.')  
 
       continue;
 
       continue;
 
      
 
      
     Serial.println();            // clear out a new line
+
     Serial.println();            // Affiche une nouvelle ligne
 
      
 
      
 
     for (uint8_t i = 0; i < dirLevel; i++)  
 
     for (uint8_t i = 0; i < dirLevel; i++)  
       Serial.print(' ');      // this is for prettyprinting, put spaces in front
+
       Serial.print(' ');      // amélioration de l'affichage, place des espace à l'avant
  
     if (!file.open(vol, dirBuf)) {      // open the file in the directory
+
     if (!file.open(vol, dirBuf)) {      // Ouvre le fichier dans le répertoire
       Serial.println("file.open failed");  // something went wrong :(
+
       Serial.println("file.open failed");  // Qlque chose s'est mal passé :(
       while(1);                            // halt
+
       while(1);                            // Arrêter
 
     }
 
     }
 
      
 
      
     if (file.isDir()) {                    // check if we opened a new directory
+
     if (file.isDir()) {                    // Vérifie si c'est un nouveau sous-répertoire
 
       putstring("Subdir: ");
 
       putstring("Subdir: ");
 
       printName(dirBuf);
 
       printName(dirBuf);
       dirLevel += 2;                      // add more spaces
+
       dirLevel += 2;                      // Ajouter plus d'espace
 
       // play files in subdirectory
 
       // play files in subdirectory
       play(file);                        // recursive!
+
       play(file);                        // Récursivité!
 
       dirLevel -= 2;     
 
       dirLevel -= 2;     
 
     }
 
     }
 
     else {
 
     else {
       // Aha! we found a file that isnt a directory
+
       // HaHa! nous avons trouvé un fichier qui n'est pas un répertoire
       putstring("Playing "); printName(dirBuf);       // print it out
+
       putstring("Joue... "); printName(dirBuf); // Afficher le nom du fichier
       if (!wave.create(file)) {           // Figure out, is it a WAV proper?
+
       if (!wave.create(file)) {                 // Est-ce un fichier WAV ?
         putstring(" Not a valid WAV");    // ok skip it
+
         putstring(" fichier WAV invalide");    // non, alors on passe au suivant
 
       } else {
 
       } else {
         Serial.println();                  // Hooray it IS a WAV proper!
+
         Serial.println();                  // Hourra c'est un fichier WAV!
         wave.play();                      // make some noise!
+
         wave.play();                      // Faisons donc un peu de bruit!
 
        
 
        
         while (wave.isplaying) {          // playing occurs in interrupts, so we print dots in realtime
+
         while (wave.isplaying) {          // La reproduction audio utilise les interruption,  
           putstring(".");
+
           putstring(".");                 //    nous affichons donc les points en temps réel
 
           delay(100);
 
           delay(100);
 
         }
 
         }
         sdErrorCheck();                    // everything OK?
+
         sdErrorCheck();                    // Tout est OK?
//        if (wave.errors)Serial.println(wave.errors);    // wave decoding errors
+
//        if (wave.errors)Serial.println(wave.errors);    // Erreur de decodage wave
 
       }
 
       }
 
     }
 
     }
Ligne 233 : Ligne 264 :
  
 
== dap_hc.pde ==
 
== dap_hc.pde ==
Here is the full sketch  
+
Voici le sketch dans son intégralité.
 +
 
 +
Note MCHobby: Les commentaires ont étés traduit dans les notes explicatives ci-dessus. Il ne le sont plus dans ce sketch.
  
 
  <nowiki>#include <FatReader.h>
 
  <nowiki>#include <FatReader.h>
Ligne 435 : Ligne 468 :
 
}
 
}
 
</nowiki>
 
</nowiki>
 +
 +
{{WaveShield-TRAILER}}

Version actuelle datée du 30 août 2013 à 20:24

Avoir plus de RAM et de Flash!

Note MCHobby: Les plateformes Arduino sont maintenant distribuée avec un ATmega328.

Cette section n'est vraiment pertinente que si vous ne possédez pas d'ATmega328.

Avant d'essayer de jouer de l'audio, vous aurez besoin de faire un peu de place

la mémoire RAM d'Arduino, cela évitera que cela se termine en vilain

dépassement de pile (stack-overflow). Manquer de mémoire RAM est difficile à déboguer et frustrant, d'autant plus si vous disposez d'un ATMega168

Suivez ces instructions (anglais) pour savoir comment avoir plus

de RAM en réduisant la taille de la mémoire tampon de la librairie série (Serial library).

Vous n'aurez pas besoin de faire cela si vous avez un ATmega328.

Notez que la librairie est vraiment grosse (approximativement 10K). Si vous voulez faire beaucoup plus avec Arduino, il est vivement conseillé de faire un Upgrade vers un ATmega328. Ce shield a été développé en prévoyant la disponibilité d'un ATmega328.

Une introduction pour dap_hc.pde

Ceci est un tutoriel de la librairie waveHC basé sur le projet dap_hc.pde

C'est détaillé et un peu intimidant. Mais attardez vous puisque la plupart du code peut être dupliqué d'un sketch à l'autre.

Assurez vosu que vous avez installé la librairie en la téléchargeant depuis le lien ci dessus et placé dans un sous-répertoire WaveHC de votre répertoire "libraries". Le fichier zip contient également le projet dap_hc.pde

Nous avons placé ce sketch en bas de cet article au cas où vous en auriez besoin.

Initialiser la carte

Les tâches complexes nécessaires au rendu musical est assuré par Arduino. Cela nous épargne d'avoir recours à un décodeur MP3ou autre circuit dédicacé. Cela signifie plus de contrôle et de flexibilité mais aussi pas de firmware!

Faisons donc un tour d'horizon du sketch "dapHC.pde". C'est un sketch de type "Digital Audio Player" (dap) utilisant la librairie Wave HC. Nous avions écrit ce projet pour l'utilisé avec notre librairie Adafruit AF_Wave mais Mr. Fat16 à réalisé un fantastique travail en réécrivant notre code en le rendant plus rapide, plus petit et meilleur. Donc nous allons utiliser sa librairie pour ce tutoriel :)

Téléchargez le sketch dapHC.pde et prenez le temps de le lire. La première chose dont nous avons besoin sont quelques objets. La partie la plus difficile est de dialoguer avec la carte. Toutes les cartes sont fabriquée et formattées différemment (juste un peu). Et le formatage repose sur différentes couches - le format de la carte - Le format de la partition et le formatage du système de fichier.

Au début du sketch nous avons l' #include qui incorpore le fichier d'entête de la librairie (fichier header) files ainsi qu'un objet card qui stocke les information concernant la carte, un autre vol relatif à la partition (partition volume) et le système de fichier root.

Nous avons aussi un tampon pour les répertoires, contenant des informations sur tous les répertoires (folders) et un objet stockant des information à propos d'un seul fichier wave.

Ils sont tous obligatoires à moins que vous ne désiriez pas lire la liste des fichiers. Dans ce cas, vous pouvez probablement vous passer de dirBuf

#include "WaveUtil.h"
#include "WaveHC.h"


SdReader card;    // Cet objet maintien des informations sur la carte
FatVolume vol;    // Maintien des information due la partition de la carte
FatReader root;   // Maintien des information sur le système de fichier de la carte

uint8_t dirLevel; // Niveau d indentation pour fichiers et répertoire (pour un affichage plus sympa)
dir_t dirBuf;     // tampon pour les lectures des répertoires

WaveHC wave;      // Le seul objet wave (audio), puisque nous jouons une seul fichier à la fois

La première chose à faire est d'initialiser la carte SD pour faire des lectures. C'est un processus qui se réalise en plusieurs étapes. Dans la fonction setup vous pouvez voir les différentes vérification qui sont faites par le processus d'initialisation.

Voici les étapes:

  1. Initialisation et affichage sur la connexion série pour indiquer que nous démarrons (OPTIONNEL)
  2. Vérifier la quantité de mémoire disponible après avoir utilisé la mémoire tampon pour stocker les données audio du Wave, faite en sorte qu'il reste plus de 100 octets (bytes) et gardez un oeil dessus si vous modifiez votre code. Ce test peut être enlevé, il n'est destiné qu'a votre information (OPTIONNEL)
  3. Initialise les pin modes pour le DAC (lignes de contrôles du DAC). Cela ne devrait pas être modifié à moins que vous ayez aussi modifié la librairie. Il est certainement préférable de les garder tels quels.
  4. Initialiser la carte SD et vérifier qu'elle réponde. Nous essayons de l'adresser à 8MHz. Si vous disposez d'un Shield Wave 1.0 vous pourriez avoir besoin d'utiliser le mode 4MHz (dé-commentez/re-commentez la ligne appropriée en fonction de la méthode utilisée). Si la carte ne s'initialise pas, alors afficher une erreur et arrêter.
  5. Autoriser la lecture de bloc partiel. Certaines cartes SD n'apprécient pas vraiment. Commenter en priorité cette ligne si vous avez des problèmes! (OPTIONNEL)
  6. Essayer de trouver la partition FAT dans les 5 premiers slots. Vous avez bien formatez votre carte en FAT n'est-ce pas? S'il ne peut pas trouver la partition FAT il affichera un message d'erreur. En cas de problème, assurez vous que vous avez bien formaté la carte en FAT (quitte à re-formater la carte).
  7. Affiche le type de partition FAT qui a été trouvée (OPTIONNEL)
  8. Essaye d'ouvrir le répertoire racine. Si cela ne fonctionne pas, c'est que quelque-chose s'est mal déroulé au cours du formatage. Essayer de formater la carte une fois de plus!
  9. Finalement, afficher l'un après l'autre les fichiers trouvés dans les répertoires de la carte. C'est vraiment génial pour déboguer et vous montrera ce qui est disponible sur la carte. Puisque nous n'utilisons pas de nom de fichier long mais le format de base 8.3 pour définir les fichiers, vous aurez besoin de voir comment les fichiers sont nommés sur la partition (et cela peut vraiment aider beaucoup) (OPTIONNEL)
 void setup() {
  Serial.begin(9600);           // initialise la libraire serie a 9600 bauds pour deboguer
  
  putstring_nl("\nWave test!");  // Indiquer le "demarrage"!
  
  putstring("Free RAM: ");       // cela peut aider pour deboguer, ne plus avoir assez de RAM est mauvais signe
  Serial.println(freeRam());  
 
  // Initialiser les pins pour le controle du DAC. Ces pins sont définies dans la librairie
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  
  //  if (!card.init(true)) { //spi cadence a 4 MHz si 8MHz ne fonctionne pas
  if (!card.init()) {         //spi cadencé a 8 MHz (par defaut, le plus rapide!)  
    putstring_nl("Init Carte. Echec!");  // Quelque chose ne marche pas, affichons pourquoi
    sdErrorCheck();
    while(1);                            // Et arrêtons (ne plus rien faire)!
  }
  
  // Activer la lecture optimisee - Certaines cartes pourrait bloquer (timeout). Desactiver en cas de probleme
  card.partialBlockRead(true);
  
  // Recherche de la partition FAT!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // Vérifier dans les 5 slots disponibles
    if (vol.init(card, part)) 
      break;                             // Nous en avons trouvé un, sortons de la boucle
  }
  if (part == 5) {                       // Terminé la boucle sans trouvé de partitions  :(
    putstring_nl("Pas de partition FAT valide!");
    sdErrorCheck();      // Qlque chose ne va pas, affichons pourquoi
    while(1);                            // et arreter le programme (ne plus rien faire)!
  }
  
  // Indiquons à l'utilisateur ce que nous avons trouvé
  putstring("Utilise la partition ");
  Serial.print(part, DEC);
  putstring(", type est FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 ou FAT32?
  
  // Essayer d ouvrir le répertoire racine
  if (!root.openRoot(vol)) {
    putstring_nl("Echec ouverture répertoire racine!"); // Quelque chose ne va pas,
    while(1);                             // et arreter le programme (ne plus rien faire)!
  }
  
  // Whaow! nous avons passé toutes les étapes difficiles.
  putstring_nl("Fichiers trouvés:");
  dirLevel = 0;
  // Afficher tous les fichiers dans tous les répertoires.
  lsR(root);
}

Chercher les fichiers dans un répertoire

OK maintenant que la carte est initialisée, nous affichons une liste de tous les fichiers que nous trouvons. C'est utile pour deboguer et vous montre aussi comment naviguer dans le système de fichier.

Pour commencer, passer un objet répertoire (directory en anglais) tel que root a la fonction lsR().

lsR effectue les opérations suivantes:

  1. Lire un fichier du répertoire. Les fichiers sont lus dans l'ordre dans lequel ils sont copiés dans le répertoire, pas par ordre alphabétique!
  2. Si le répertoire à un nom/liens spécial "." (répertoire courant) or ".." (répertoire parent) ignorez les et répéter encore l'opération 1.
  3. Il affiche des espaces pour formater correctement les sortie de message. Chaque niveau de répertoire prends deux espaces de plus.
  4. Affiche le nom du fichier au format 8.3
  5. S'il s'agit d'un sous répertoire, il crée un nouvel objet et ouvre le sous répertoire. Ensuite, il affiche tous les fichiers de ce nouveau répertoire.
  6. Il continue à l'étape 1 jusqu'a ce qu'il ne reste plus de fichier à lire
/*
 * Affichage récursif - Possiblilité de dépassement de pile (stack overflow) 
 * s'il y a trop de répertoire imbriqués
 */
void lsR(FatReader &d)
{
  int8_t r;                     // indique le niveau de récursion
  
  while ((r = d.readDir(dirBuf)) > 0) {     // Lire le prochain fichier dans le répertoire 
    // Ignore les sous répertoires . et ..
    if (dirBuf.name[0] == '.') 
      continue;
    
    for (uint8_t i = 0; i < dirLevel; i++) 
      Serial.print(' ');        // Meilleur affichage, place des espaces devant
    printName(dirBuf);          // Afficher le nom de fichier trouvé
    Serial.println();           // et un retour à la ligne
    
    if (DIR_IS_SUBDIR(dirBuf)) {   // Nous allons répéter (récursion) pour chaque sous-répertoire
      FatReader s;                 // Créer un nouvel objet répertoire pour maintenir les informations
      dirLevel += 2;               // indenter de 2 espaces (pour les affichages futurs)
      if (s.open(vol, dirBuf)) 
        lsR(s);                    // Afficher tous les fichiers du répertoire. Maintenant!
      dirLevel -=2;                // retirer l'indentation ajoutée (quand fini de lister le sous-répertoire)
    }
  }
  sdErrorCheck();                  // Est-ce que tout est OK?
}

Il y a aussi une fonction d'aide nommée printName qui affiche le nom du fichier (dans un format lisible). les fichiers sont nommés au format 8.3, une vieille façon d'adresser les fichier (mais aussi plus simple). C'est un petit peu moins beau qu'afficher les noms au format long, donc regardez quand même comment vos fichiers sont re-nommés en format court. Par exemple, le fichier "Bird song.wav" pourrait être renommé en "BIRDSONG.WAV" ou "BIRDSO~1.WAV" !

/*
 * Affiche le champs name de dir_t. Format de sortie est 8.3, ressemble donc à SOUND.WAV ou FILENAME.DAT
 */
void printName(dir_t &dir)
{
  for (uint8_t i = 0; i < 11; i++) {     // format 8.3 a 8+3 = 11 lettres
    if (dir.name[i] == ' ')
        continue;         // N'affiche pas les espaces dans le nom
    if (i == 8) 
        Serial.print('.');           // placer un point après la 8ieme lettre
    Serial.print(dir.name[i]);      // afficher la lettre à la position n
  }
  if (DIR_IS_SUBDIR(dir)) 
    Serial.print('/');       // Afficher un "/" à la fin quand c'est un répertoire
}

Une des chose qui apparait dans loop() c'est dir.rewind() (action de remonter) . La raison pour laquelle nous remontons les répertoires c'est que le code de notre Arduino est très simple. Il peut traverser les fichiers d'un répertoire mais seulement 'vers l'avant' (forward), pas vers l'arrière (le format FAT est un peu comme ca).

Donc, si vous avez raté un fichier ou si vous voulez aller en arrière, ou si vous avez traversé le répertoire, vous devrez appeler rewind() pour revenir au début du répertoire!

Jouer tous les fichiers

Le "digital audio player" joue tous les fichier de la carte. Pour ce faire, il cherche les fichiers dans tous les répertoires de façon récursive (comme le fait lsR() ci-avant). Cela produit un code assez similaire eu point précédent.

La grande différence c'est que nous appelons la fonction play() qui recherche les fichiers à jouer!

Le fichier est joué à l'aide de wave.play()

Pour commencer, passez un objet répertoire (tel que root) a play() effectue les étapes suivantes:

  1. Lit un fichier depuis le répertoire. Les fichier sont lus dans l'ordre dans lequel ils ont étés copiés dans le répertoire, pas l'ordre alphabétique!
  2. Si le répertoire à un nom/lien spécial comme "." (répertoire courant) or ".." (répertoire parent) sont ignorés et on recommence à l'étape 1.
  3. Il affiche des espace pour créer un format d'affichage plus sympathique. Chaque niveau de répertoire ajoute deux espaces.
  4. Il affiche le nom du fichier au format 8.3 .
  5. Si c'est un sous répertoire, il crée un nouvel objet et ouvre le sous répertoire. Ensuite, il joue tous les fichioers wave qu'il y a dans ce nouveau répertoire.
  6. Si ce n'est pas un sous répertoire, il va essayer de jouer le fichier en ouvrant celui-ci comme un objet Wave. Cela nécessite d'ouvrir le fiochier et d'essayer de trouver l'entête Wave (Wave header), etc. S'il n'y arrive pas, il affiche un message comme quoi le fichier n'est pas valide puis il passe au fichier suivant.
  7. Si le fichier wave est valide, il commence à le jouer en appelant la fonction play() de l'objet Wave
  8. Tant que le fichier wave est jouer, le programme affiche un point toutes les 100 ms.
  9. Le programme continue à l'étape 1 jusqu'à ce qu'il n'y ait plus de fichier à lire.
/*
 * Joue récursivement - Possibilité de dépassement de pile (stack overflow)
 * s'il y a trop de répertoire imbriqués
 */
void play(FatReader &dir)
{
  FatReader file;
  while (dir.readDir(dirBuf) > 0) {    // lit un à un chaque fichier du répertoire
    // skip . and .. directories
    if (dirBuf.name[0] == '.') 
      continue;
    
    Serial.println();            // Affiche une nouvelle ligne
    
    for (uint8_t i = 0; i < dirLevel; i++) 
       Serial.print(' ');       // amélioration de l'affichage, place des espace à l'avant

    if (!file.open(vol, dirBuf)) {       // Ouvre le fichier dans le répertoire
      Serial.println("file.open failed");  // Qlque chose s'est mal passé :(
      while(1);                            // Arrêter
    }
    
    if (file.isDir()) {                    // Vérifie si c'est un nouveau sous-répertoire
      putstring("Subdir: ");
      printName(dirBuf);
      dirLevel += 2;                       // Ajouter plus d'espace
      // play files in subdirectory
      play(file);                         // Récursivité!
      dirLevel -= 2;    
    }
    else {
      // HaHa! nous avons trouvé un fichier qui n'est pas un répertoire
      putstring("Joue... "); printName(dirBuf); // Afficher le nom du fichier
      if (!wave.create(file)) {                 // Est-ce un fichier WAV ?
        putstring(" fichier WAV invalide");     // non, alors on passe au suivant
      } else {
        Serial.println();                  // Hourra c'est un fichier WAV!
        wave.play();                       // Faisons donc un peu de bruit!
       
        while (wave.isplaying) {           // La reproduction audio utilise les interruption, 
          putstring(".");                  //     nous affichons donc les points en temps réel
          delay(100);
        }
        sdErrorCheck();                    // Tout est OK?
//        if (wave.errors)Serial.println(wave.errors);     // Erreur de decodage wave
      }
    }
  }
}

dap_hc.pde

Voici le sketch dans son intégralité.

Note MCHobby: Les commentaires ont étés traduit dans les notes explicatives ci-dessus. Il ne le sont plus dans ce sketch.

#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"

SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card

uint8_t dirLevel; // indent level for file/dir names    (for prettyprinting)
dir_t dirBuf;     // buffer for directory reads

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

// Function definitions (we define them here, but the code is below)
void lsR(FatReader &d);
void play(FatReader &dir);

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps for debugging
  
  putstring_nl("\nWave test!");  // say we woke up!
  
  putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(freeRam());  
 
  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  
  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
  if (!card.init()) {         //play with 8 MHz spi (default faster!)  
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    sdErrorCheck();
    while(1);                            // then 'halt' - do nothing!
  }
  
  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);
  
  // Now we will look for a FAT partition!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // we have up to 5 slots to look in
    if (vol.init(card, part)) 
      break;                             // we found one, lets bail
  }
  if (part == 5) {                       // if we ended up not finding one  :(
    putstring_nl("No valid FAT partition!");
    sdErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  }
  
  // Lets tell the user about what we found
  putstring("Using partition ");
  Serial.print(part, DEC);
  putstring(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?
  
  // Try to open the root directory
  if (!root.openRoot(vol)) {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  }
  
  // Whew! We got past the tough parts.
  putstring_nl("Files found:");
  dirLevel = 0;
  // Print out all of the files in all the directories.
  lsR(root);
}

//////////////////////////////////// LOOP
void loop() { 
  root.rewind();
  play(root);
}

/////////////////////////////////// HELPERS

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  }
  return free_memory; 
} 

/*
 * print error message and halt if SD I/O error, great for debugging!
 */
void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  putstring("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  putstring(", ");
  Serial.println(card.errorData(), HEX);
  while(1);
}
/*
 * print dir_t name field. The output is 8.3 format, so like SOUND.WAV or FILENAME.DAT
 */
void printName(dir_t &dir)
{
  for (uint8_t i = 0; i < 11; i++) {     // 8.3 format has 8+3 = 11 letters in it
    if (dir.name[i] == ' ')
        continue;         // dont print any spaces in the name
    if (i == 8) 
        Serial.print('.');           // after the 8th letter, place a dot
    Serial.print(dir.name[i]);      // print the n'th digit
  }
  if (DIR_IS_SUBDIR(dir)) 
    Serial.print('/');       // directories get a / at the end
}
/*
 * list recursively - possible stack overflow if subdirectories too nested
 */
void lsR(FatReader &d)
{
  int8_t r;                     // indicates the level of recursion
  
  while ((r = d.readDir(dirBuf)) > 0) {     // read the next file in the directory 
    // skip subdirs . and ..
    if (dirBuf.name[0] == '.') 
      continue;
    
    for (uint8_t i = 0; i < dirLevel; i++) 
      Serial.print(' ');        // this is for prettyprinting, put spaces in front
    printName(dirBuf);          // print the name of the file we just found
    Serial.println();           // and a new line
    
    if (DIR_IS_SUBDIR(dirBuf)) {   // we will recurse on any direcory
      FatReader s;                 // make a new directory object to hold information
      dirLevel += 2;               // indent 2 spaces for future prints
      if (s.open(vol, dirBuf)) 
        lsR(s);                    // list all the files in this directory now!
      dirLevel -=2;                // remove the extra indentation
    }
  }
  sdErrorCheck();                  // are we doign OK?
}
/*
 * play recursively - possible stack overflow if subdirectories too nested
 */
void play(FatReader &dir)
{
  FatReader file;
  while (dir.readDir(dirBuf) > 0) {    // Read every file in the directory one at a time
    // skip . and .. directories
    if (dirBuf.name[0] == '.') 
      continue;
    
    Serial.println();            // clear out a new line
    
    for (uint8_t i = 0; i < dirLevel; i++) 
       Serial.print(' ');       // this is for prettyprinting, put spaces in front

    if (!file.open(vol, dirBuf)) {       // open the file in the directory
      Serial.println("file.open failed");  // something went wrong :(
      while(1);                            // halt
    }
    
    if (file.isDir()) {                    // check if we opened a new directory
      putstring("Subdir: ");
      printName(dirBuf);
      dirLevel += 2;                       // add more spaces
      // play files in subdirectory
      play(file);                         // recursive!
      dirLevel -= 2;    
    }
    else {
      // Aha! we found a file that isnt a directory
      putstring("Playing "); printName(dirBuf);       // print it out
      if (!wave.create(file)) {            // Figure out, is it a WAV proper?
        putstring(" Not a valid WAV");     // ok skip it
      } else {
        Serial.println();                  // Hooray it IS a WAV proper!
        wave.play();                       // make some noise!
       
        while (wave.isplaying) {           // playing occurs in interrupts, so we print dots in realtime
          putstring(".");
          delay(100);
        }
        sdErrorCheck();                    // everything OK?
//        if (wave.errors)Serial.println(wave.errors);     // wave decoding errors
      }
    }
  }
}


Source: Wave Shield créé par LadyAda pour AdaFruit. Crédit: AdaFruit.com.

Traduit par Meurisse D. pour MCHobby.be.

Traduit avec l'autorisation d'AdaFruit Industries - Translated with the permission from Adafruit Industries - www.adafruit.com

Toute référence, mention ou extrait de cette traduction doit être explicitement accompagné du texte suivant : «  Traduction par MCHobby (www.MCHobby.be) - Vente de kit et composants » avec un lien vers la source (donc cette page) et ce quelque soit le média utilisé.

L'utilisation commercial de la traduction (texte) et/ou réalisation, même partielle, pourrait être soumis à redevance. Dans tous les cas de figures, vous devez également obtenir l'accord du(des) détenteur initial des droits. Celui de MC Hobby s'arrêtant au travail de traduction proprement dit.