Go Down

Topic: Lecture mp3 aléatoire (Read 1 time) previous topic - next topic

viddal

Bonjour

Un ami à moi se fabrique une borne d'arcade sur les bases d'un raspberry pi et recalbox.

On va ajouter 2 boutons qui déclencheront des répliques de films ou des bruitages.

En gros c'est un lecteur mp3 qui à l'appui sur un des boutons déclenchera un des fichiers mp3 au hasard.


Nous allons donc utiliser un arduino, un module mp3 dfplayer, un ampli et une enceinte.

Je suis débutant et je m'y perds un peu.


Je suis parti sur ce tuto là : http://educ8s.tv/arduino-mp3-player/

Image du montage

Le 1er problème est que ça lance directement un mp3 alors même que je n'ai pas appuyé sur un bouton. Je voudrais qu'au lancement, aucun mp3 ne soit lancé.

Le 2ème est qu'il n'y a pas la fonction shuffle.
D'après ce que j'ai compris elle n'y est pas de base sur le dfplayer.

J'ai trouvé ça mais je n'arrive pas à la faire la synthèse des 2 : https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#2.29_AD_KEY_Mode


Voici le code de base sur lequel je commence :

Code: [Select]

///              MP3 PLAYER PROJECT
/// http://educ8s.tv/arduino-mp3-player/
//////////////////////////////////////////


#include "SoftwareSerial.h"
SoftwareSerial mySerial(10, 11);
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00 //Returns info with command 0x41 [0x01: info, 0x00: no info]

# define ACTIVATED LOW

int buttonNext = 2;
int buttonPause = 3;
int buttonPrevious = 4;
boolean isPlaying = false;



void setup () {

pinMode(buttonPause, INPUT);
digitalWrite(buttonPause,HIGH);
pinMode(buttonNext, INPUT);
digitalWrite(buttonNext,HIGH);
pinMode(buttonPrevious, INPUT);
digitalWrite(buttonPrevious,HIGH);

mySerial.begin (9600);
delay(1000);
playFirst();
isPlaying = true;


}



void loop () {

 if (digitalRead(buttonPause) == ACTIVATED)
  {
    if(isPlaying)
    {
      pause();
      isPlaying = false;
    }else
    {
      isPlaying = true;
      play();
    }
  }


 if (digitalRead(buttonNext) == ACTIVATED)
  {
    if(isPlaying)
    {
      playNext();
    }
  }

   if (digitalRead(buttonPrevious) == ACTIVATED)
  {
    if(isPlaying)
    {
      playPrevious();
    }
  }
}

void playFirst()
{
  execute_CMD(0x3F, 0, 0);
  delay(500);
  setVolume(20);
  delay(500);
  execute_CMD(0x11,0,1);
  delay(500);
}

void pause()
{
  execute_CMD(0x0E,0,0);
  delay(500);
}

void play()
{
  execute_CMD(0x0D,0,1);
  delay(500);
}

void playNext()
{
  execute_CMD(0x01,0,1);
  delay(500);
}

void playPrevious()
{
  execute_CMD(0x02,0,1);
  delay(500);
}

void setVolume(int volume)
{
  execute_CMD(0x06, 0, volume); // Set the volume (0x00~0x30)
  delay(2000);
}

void execute_CMD(byte CMD, byte Par1, byte Par2)
// Excecute the command and parameters
{
// Calculate the checksum (2 bytes)
word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);
// Build the command line
byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge,
Par1, Par2, highByte(checksum), lowByte(checksum), End_Byte};
//Send the command line to the module
for (byte k=0; k<10; k++)
{
mySerial.write( Command_line[k]);
}
}


Merci d'avance pour vos réponses

lesept

Declare ton bouton button pause en INPUT_PULLUP
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

hbachetti

Salut

Quote
Je voudrais qu'au lancement, aucun mp3 ne soit lancé.
Normal, dans le setup il y a :
Code: [Select]

playFirst();


D'autre part les lignes suivantes sont inutiles :
Code: [Select]

digitalWrite(buttonPause,HIGH);
digitalWrite(buttonNext,HIGH);
digitalWrite(buttonPrevious,HIGH);


Prendre en compte la remarque de lesept.

Quote
Le 2ème est qu'il n'y a pas la fonction shuffle.
Lecture aléatoire ?
Il suffit d'utiliser la fonction random(min, max).

J'ai déjà réalisé un proto de carillon avec un DFPLAYER, mais je n'ai pas le code sous la main.
S'il y a des questions, je pourrai y répondre ce soir.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

marco74

#3
Dec 06, 2018, 02:24 pm Last Edit: Dec 06, 2018, 03:16 pm by marco74
Bonjour à tou(te)s.
Merci à vous d'avoir apporté des réponses aux différentes questions de @viddal.

Je suis l'ami en question qui fabrique en ce moment la borne d'arcade et viddal s'occupe de la partie électronique décrite ci dessus.

On va donc essayer de mettre en pratique les différentes pistes que vous venez de nous donnez.
Ça sera en tout cas un bon début. Encore merci car c'est pour nous la première fois qu'on se lance dans le monde de l'électronique...

----

Juste pour résumer le projet final qu'on souhaiterai mettre en place je vous fait le récap, histoire que ça soit plus clair :

On voudrait faire qq chose de "simple"  ::)


Status :
- Joueur 1 et 2 sont sur la même borne d'arcade
- Le joueur 1 dispose de son propre bouton (a)
- Le joueur 2 dispose de son propre  bouton (b)

note : La durée des sons mp3 que l'on a, dure entre 1 et 5s en moyenne. Elles sont stockées sur carte Micro SD du DFPlayer Mini, qui elle même est reliée à un Arduino Nano.

Conditions :
[1] Quand le joueur 1 appui sur (a) ou quand le joueur 2 appui sur (b) un son aléatoire se déclenche.
[2] A l'instant où l'un des 2 boutons est déclenché, aucun autre son aléatoire ne peut être relancer pendant une durée de 12s si l'un des 2 joueurs ré-appuie une nouvelle fois sur (a) ou (b).
[3] Quand les 12s se sont écoulés, réinitialisation des paramètres et retour au point [1]

Après voilà, ya peut être beaucoup plus simple ^^

-
On voulait au départ faire un autre système de lecture un peu plus avancée, on va déjà tenter de faire celui ci déjà, on verra après ^^

Si vous avez d'autres remarque à nous faire sur ce que j'ai écrit au niveau des conditions de déclenchement, n'hésitez pas.

En vous remerciant.

:)
This is only a test, not a question without answer.

marco74

#4
Dec 16, 2018, 07:02 pm Last Edit: Dec 16, 2018, 07:03 pm by marco74
Hello !
De retour après plusieurs jours d'essai.

J'ai donc récupéré et simplifier le code au maximum en prenant compte des remarques précédentes :

Code: [Select]

///              MP3 PLAYER PROJECT
/// http://educ8s.tv/arduino-mp3-player/
//////////////////////////////////////////


#include "SoftwareSerial.h"

SoftwareSerial mySerial(10, 11);
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00 //Returns info with command 0x41 [0x01: info, 0x00: no info]

# define ACTIVATED LOW

int buttonNext = 3;
int buttonRandom = 4;
boolean isPlaying = false;

void setup () {

pinMode(buttonNext, INPUT_PULLUP);
pinMode(buttonRandom, INPUT_PULLUP);

mySerial.begin (9600);
delay(1000);
isPlaying = true;
setVolume(12);

}

// // // // // // // // //

void loop () {

 if (digitalRead(buttonNext) == ACTIVATED)
  {
    if(isPlaying)
    {
      playNext();
    }
  }
 
 if (digitalRead(buttonRandom) == ACTIVATED)
  {
    if(isPlaying)
    {
     playRandom();
    }
  }

}

// // // // // // // // //

void playNext()
{
  execute_CMD(0x01,0,1);
  delay(500);
}


 void playRandom()
{
  execute_CMD2(0x08,3);
  delay(500);
}


void setVolume(int volume)
{
  execute_CMD(0x06, 0, volume); // Set the volume (0x00~0x30)
  delay(2000);
}

void execute_CMD(byte CMD, byte Par1, byte Par2)
// Excecute the command and parameters
{
// Calculate the checksum (2 bytes)
word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);
// Build the command line
byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge,
Par1, Par2, highByte(checksum), lowByte(checksum), End_Byte};
//Send the command line to the module
for (byte k=0; k<10; k++)
{
mySerial.write( Command_line[k]);
}
}

void execute_CMD2(byte CMD, byte Par1) // en me basant sur execute_CMD juste précédemment
{
// Calculate the checksum (2 bytes)
word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1);
// Build the command line
byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge,
Par1, highByte(checksum), lowByte(checksum), End_Byte};
//Send the command line to the module
for (byte k=0; k<10; k++)
{
mySerial.write( Command_line[k]);
}
}


J'ai donc un bouton pour la lecture suivante, et un bouton pour la lecture aléatoire.

Pour le lancement des musiques avec "playNext" aucun problème.
J'ai donc ensuite créer un paramètre "playRandom" pour lancer de manière aléatoire une musique, en me basant sur le pdf, où il est écrit :

CMD: 0x08
Function Description: Specify playback mode (0/1/2/3)
Parameters (16bit): Repeat/folder repeat/single repeat/ random

Pensant bien faire, j'ai donc créé dans le code la fonction "execute_CMD2" pour lui assigner le paramètre adéquate, et évidement, "playRandom" ne fonctionne pas du tout, aucun son ne sort (ça aurait été trop beau).

Il semblerai donc que je suis complétement à coté de la plaque, j'essaye de m'initier au C++ depuis quelque jours et j'ai encore bq bq bq de travail...

Auriez vous une piste pour m'indiquer ce qui n'irai pas du tout dans le code ?

En vous remerciant.
This is only a test, not a question without answer.

hbachetti

Tu connais ceci ?

DFPlayer-Mini-library

On dirait que pour jouer un MP3 en mode random, ils utilisent une commande 0x18.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

marco74

#6
Dec 16, 2018, 11:08 pm Last Edit: Dec 16, 2018, 11:24 pm by marco74
oui j'ai vu ce lien, mais je n'avais pas vu que c'était sur 0x18, car je me suis basé sur la doc référence.
Du coup j'ai changé une partie de mon code précédent par :

Code: [Select]

 void playRandom()
{
  execute_CMD(0x18,0,1);
  delay(500);
}



Et bien le random fonctionne ! je ne comprend pas pourquoi la commande n'est pas la même que la doc.

mais :

- Les sons (d'environ 5sec) ne s'arrête pas à chaque morceau, les sons s'enchainent, contrairement à playNext, qui stop à la fin de chaque son.
- quand j'appuie pour lancer le 1er random, cela démarre toujours sur le même son.

par contre je ne comprend pas encore les 2 autres paramètres "(0x18,0,1)" je pensais qu'en changeant les valeurs allait changer qq chose mais non.

Donc merci c'est un bon début de piste, il va donc falloir, dans un 1er temps, que je trouve un bout de code pour lui dire d'arrêter la boucle après que j'ai appuyé 1 fois sur "buttonRandom" pour lancer le random.
This is only a test, not a question without answer.

lesept

Il suffit d'arrêter la lecture au bout des cinq secondes
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

marco74

cela aurait peut être été "simple" si tous les sons faisait pile 5s.
certaines font 3s et d'autres 7-8s.

Je cherche surtout à stopper l'enchainement à la fin de la lecture une fois le random lancé. Comme "playNext" qui le fait très bien tout seul.

Je cherche donc à bidouiller du code pour espérer que cela marche. Pas simple quand on démarre de 0.
This is only a test, not a question without answer.

hbachetti

Il est possible de savoir quand un morceau est terminé.
Dans les exemples de la librairie DFPLAYER :
GetStarted.ino

Faire comme ceci :

Code: [Select]

  if (myDFPlayer.available()) {
    if (myDFPlayer.readType() == DFPlayerPlayFinished) {
      myDFPlayer.stop();
    }
  }


Avec une librairie cela simplifie les choses.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

marco74

#10
Feb 11, 2019, 08:56 pm Last Edit: Feb 11, 2019, 09:59 pm by marco74
Re bonjour !
J'ai pas mal été pris depuis noel, j'avais entre temps essayé la méthode de @hbachetti, malheuresement sans succès, et j'ai dû laisser de coté l'arduino une grosse partie du mois de janvier.

Depuis pas mal de chose ont changé, j'ai essayé de pas mal bosser sur le language arduino, et j'ai tout repris à 0 concernant le code de mon projet.
j'ai utilisé la librairie DFRobotDFPlayerMini pour avoir juste la commande de base de lecture.

Aujourdhui, après plusieurs jours d'essai je suis assez content du résultat.
J'ai donc tout réécrit, et tout fonctionne correctement.

je peux maintenant :

- lancer un son aléatoire, avec un timer avant de pouvoir lancer le son suivant, en fonction du bouton (btnP1 ou btnP2) qui sera actionné.
- le son suivant qui sera lu, sera toujours différent du son précédent.
- certains sons, plus rare, seront lus, mais plus aléatoirement que les autres sons.
- la possibilité d'ajuster la fréquence aléatoire de ces sons "rare".

Je vous donne le résultat ici, j'ai essayé de simplifier et de réduire mon code au maximum, mais je suis preneur de conseil si vous trouvez un truc plus opti ^^

j'ai épuré au maximum car j'avais bourré de log de partout pour voir tous les résultats possible dans la console (moniteur série).

Merci !

Code: [Select]

#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

# define ACTIVATED LOW

const int btnP1 = 3;
const int btnP2 = 2;

byte start;
byte randNumDefault;
byte randNumRare;
int doublon1 = 0;
int doublon2 = 0;

//
const int varRareMP3 = 5; // % de chance pour trouver les MP3 rare
const int varRareMP3 = ((100 / rareMP3)+1);
//

void setup () {
  pinMode(btnP1, INPUT_PULLUP);
  pinMode(btnP2, INPUT_PULLUP);

  mySoftwareSerial.begin(9600);
  Serial.begin(9600);

  !myDFPlayer.begin(mySoftwareSerial);
  myDFPlayer.setTimeOut(500); // Set serial communication time out
  myDFPlayer.volume(12);
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
  randomSeed(analogRead(0));
  delay(2000);
}

////////////////////////////////////////////////////////

void loop () {


  if ((digitalRead(btnP1) == ACTIVATED) || (digitalRead(btnP2) == ACTIVATED)) {

    start = random(1, varRareMP3 );

    if (start == 1) {                                    // RARE MP3 FOUND
      while (randNumRare == doublon2) {
        randNumRare = random(1, 16); 15 mp3 dans le dossier SD:/02/
      }
      doublon2 = randNumRare;
      myDFPlayer.playLargeFolder(2, randNumRare);
      delay(12000);
    } else {                                              // NORMAL MP3 FOUND
      while (randNumDefault == doublon1) {
        randNumDefault = random(1, 15); // 14 mp3 dans le dossier SD:/01/
      }
      doublon1 = randNumDefault;
      myDFPlayer.playLargeFolder(1, randNumDefault);
      delay(12000);
    }
   
  }

}


Ce que je vais essayé de faire maintenant, c'est de faire en sorte que je puisse lister de manière auto le nombre de mp3 situé sur la carte SD et de faire le random aléatoire en fonction de ce nombre, car pour le moment je suis obligé de rentrer manuellement, dans mon code, le nombre de mp3 présent, dans chaque dossier situé sur la carte SD.

Si vous avez des pistes je suis preneur ^^
This is only a test, not a question without answer.

hbachetti

Quote
J'ai pas mal été pris depuis noel, j'avais entre temps essayé la méthode de @hbachetti, malheuresement sans succès
Tu veux parler du post #9 ?

Quote
faire en sorte que je puisse lister de manière auto le nombre de mp3 situé sur la carte SD
readFileCountsInFolder

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

marco74

#12
Feb 12, 2019, 09:27 am Last Edit: Feb 12, 2019, 12:27 pm by marco74
Tu veux parler du post #9 ?
oui j'ai essayé de faire comme tu l'avais écrit, mais impossible de le faire marcher correctement, dès que je réappuyait sur un bouton ça ne fonctionnait plus. Et après plusieurs jours d'essai, j'ai laissé tombé.
Je pense que j'étais trop mauvais :( (même si c'est toujours le cas encore maintenant ^^)

En fait j'ai ensuite trouver ce que je cherchais depuis le début dans le fichier FullFunction.ino où les commandes de base sont beaucoup plus clair (pour moi) que le fichier GetStarted.ino.

readFileCountsInFolder
Ah yes merci, je viens de le voir dans le fichier FullFunction.ino ! j'espère avoir plus de chance pour savoir m'en servir correctement :)
This is only a test, not a question without answer.

marco74

#13
Feb 12, 2019, 08:20 pm Last Edit: Feb 12, 2019, 08:21 pm by marco74
RE !
alors je rencontre un problème que je ne comprend pas du tout.

Dans le void (setup) et (loop), à la fin de chaque, j'essaye d'afficher les résultats avec println pour m'assurer que tout fonctionne.

Aucun souci quand le void (setup) se lance, je vois la liste écrite dans la console


Code: [Select]

#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;


void setup () {
  mySoftwareSerial.begin(9600);
  Serial.begin(9600);
  !myDFPlayer.begin(mySoftwareSerial);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

  const int folder01 = myDFPlayer.readFileCountsInFolder(1);
  const int folder02 = myDFPlayer.readFileCountsInFolder(2);
  delay(2000);

  Serial.println(folder01); // m'affiche correctement le nombre de mp3 dans le dossier 01
  Serial.println(folder02); // m'affiche correctement le nombre de mp3 dans le dossier 02

}

void loop () {



}




=> mais si jamais je déplace les println dans le void (loop), j'ai une erreur qui s'affiche lors de la compilation :

'folder01' was not declared in this scope


Code: [Select]

#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;


void setup () {
  mySoftwareSerial.begin(9600);
  Serial.begin(9600);
  !myDFPlayer.begin(mySoftwareSerial);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

  const int folder01  = myDFPlayer.readFileCountsInFolder(1);
  const int folder02  = myDFPlayer.readFileCountsInFolder(2);
  delay(2000);
}

void loop () {

  Serial.println(folder01); // m'affiche : 'folder01' was not declared in this scope
  Serial.println(folder02);

}


Avez vous une idée de l'erreur que j'ai du faire ?

En vous remerciant.
This is only a test, not a question without answer.

kamill

Bonjour,

folder01 et folder02 sont définis dans le setup et ne sont donc accessibles que dans le setup
Il faut que tu les définisse en global (avant le setup)

Go Up