Projet de lecture RFID + GUI

Projet de lecture RFID + GUI - C++ - Programmation

Marsh Posté le 10-07-2013 à 18:40:16    

Bonjour à tous,
 
Je travaille actuellement sur un projet qui permettrai de lancer la lecture d'un album de musique (pour commencer) à la suite de la lecture d'un tag RFID.
 
De façon à le rendre le plus souple possible, je me suis tourné vers le C++ et la bibliothèque Qt 5.1.0 pour l'interface utilisateur, ainsi que AppleScript pour controler iTunes qui sera le premier lecteur média (d'autres plus tard si possible). J'ai quelques notions de C++ mais je me considère débutant. Néanmoins, cela ne devrait pas poser trop de problèmes dans un premier temps.
 
On considèrera qu'il existe déjà une base de données mettant en relation des numéros de tag RFID avec des identifiants d'albums (ou de morceaux) dans iTunes.
 
La logique d'action est la suivante :
- Lecture du tag RFID
- Recherche de l'album correspondant à l'identifiant RFID
- Exécution de la commande AppleScript qui lance l'album correspondant sur iTunes
 
Que pensez-vous du choix des différents éléments pour ce projet (C++, Qt 5.1.0, AppleScript) ?
 
Je développe sous Mac OS X Snow Leopard (10.6.8) avec Xcode 4.2 (par défaut), est-ce également un bon choix ? Existe-t-il une solution plus optimale ?
Sachant que j'ai déjà quelques soucis pour y linker Qt (il ne trouve tout simplement pas les librairies lors de la compilation, apparemment une histoire de PATH). Je ne vois pas où configurer le chemin vers Qt (néanmoins cela fonctionne très bien dans Qt Creator).
 
Je compte y aller par petits bouts, j'ai déjà trifouillé l'AppleScript (récupérer la liste des albums, lancer un morceau, etc.), également l'exécution du script via C++, et je pense ajouter les fonctionnalités au fur et à mesure de mon apprentissage.
 
Vos avis et recommandations me seraient très précieux :)

Reply

Marsh Posté le 10-07-2013 à 18:40:16   

Reply

Marsh Posté le 10-07-2013 à 19:08:07    

Bonjour !
 
Étant assez fan de Qt (que je pratique depuis 10 ans), je ne peux qu'approuver votre choix !
 
En revanche, n'ayant jamais travaillé sur Mac', je ne saurais guère vous conseiller au niveau du compilateur et/ou de l'API AppleScript.
 
Pour la configuration et les bibliothèques dynamiques, je confirme, c'est bien un problème de path (ou de DYLD_LIBRARY_PATH, en l'occurrence). En revanche, sous Linux, l'option "rpath" fonctionne avec g++, xcode ne la gère pas ?
 
Et, pour finir, concernant votre approche, rien de particulier à redire, une vision incrémentale me paraît tout à fait adaptée.
 
Bon courage et tenez nous au courant de votre progression !

Reply

Marsh Posté le 14-07-2013 à 20:29:49    

Cela semble bien fonctionner jusqu'alors sur Qt Creator, je pense donc rester dessus pour le moment.
J'ai appris presque par hasard que Qt propose bien plus que du fenêtrage, c'est pas mal du tout !
 
Ma première question est basique.
 
Je compte récupérer la liste des albums iTunes via un AppleScript :

Code :
  1. tell application "iTunes"
  2. set uniqueNames to {}
  3. set {albumName, artistName} to {album, artist} of every track
  4. repeat with i from 1 to count albumName
  5.  set trackInfo to item i of albumName & ";" & item i of artistName
  6.  if trackInfo is not in uniqueNames then
  7.   copy trackInfo to beginning of uniqueNames
  8.  end if
  9. end repeat
  10. return reverse of uniqueNames
  11. end tell


 
Ça me sort donc une liste des albums et des artistes associés (du style {"Album 1;Artiste 1", "Album 2; Artiste 2", etc}).
 
Pour la récupérer dans mon programme C++, puis-je utiliser une commande (QProcess::execute() par exemple) ou dois-je la stocker dans un fichier que je lis ensuite avec le programme ?
Dans le cas de QProcess::execute(), la fonction retourne -2, -1 ou 0, mais puis-je récupérer la sortie d'une commande système via cette fonction ?


Message édité par wizardman le 14-07-2013 à 20:30:25
Reply

Marsh Posté le 14-07-2013 à 20:46:41    

Ton programme n'aura jamais besoin de tourner sur une machine qui ne soit pas Apple ?
Parce que je soupçonne que l'AppleScript ne fonctionne pas top pour dialoguer avec un iTunes sous windows ... Peut-être que je me trompe, cela dit.
De même, je trouve la dépendance forte vers un lecteur de musique spécifique un peu contraignante, mais ca, c'est aussi notamment une question de goût.


---------------
last.fm
Reply

Marsh Posté le 14-07-2013 à 22:39:03    

theshockwave a écrit :

Ton programme n'aura jamais besoin de tourner sur une machine qui ne soit pas Apple ?
Parce que je soupçonne que l'AppleScript ne fonctionne pas top pour dialoguer avec un iTunes sous windows ... Peut-être que je me trompe, cela dit.
De même, je trouve la dépendance forte vers un lecteur de musique spécifique un peu contraignante, mais ca, c'est aussi notamment une question de goût.


 
En effet, si je souhaite le distribuer, il faudra que je l'adapte pour les autres systèmes et lecteurs, car pas d'AppleScript sous Windows par exemple.
Mais mon niveau en C++ est encore trop faible pour déjà me soucier de portabilité et d'API, si j'arrive à mener à bien ce projet pour qu'il fonctionne chez moi ce sera déjà un grand pas :ange:
Je peux par contre m'efforcer de développer le truc de sorte à ce qu'il soit modulable et donc pouvoir facilement ajouter un nouveau lecteur...

Reply

Marsh Posté le 23-07-2013 à 14:56:27    

J'ai un petit soucis avec mon parser XML.
 
J'utilise QtXML sur cet extrait de la librairie iTunes (qui n'utilise pas vraiment XML de façon standard comme vous le remarquerez), ce qui me permet de pouvoir trouver la liste des albums iTunes toutes plateformes confondues sans passer par AppleScript.
J'ai modifié le nom de certains tags pour pouvoir les repérer dans la sortie.
 
La logique est la suivante : j'analyse tous les tags et leurs enfants (et leurs enfants, etc) jusqu'à trouver un <key> qui contient Album, auquel cas j'affiche le contenu du tag suivant qui contient le nom de l'album en question.
 
Voici mon code :
 

Code :
  1. #include <iostream>
  2. #include <QtCore>
  3. #include <QFile>
  4. #include <QtXml>
  5. using namespace std;
  6. void parse(QDomNode n) {
  7. while(!n.isNull()) {
  8.  // If the node has children
  9.  if(n.hasChildNodes() && !n.isNull()) {
  10.   // We get the children
  11.   QDomNodeList nChildren = n.childNodes();
  12.   // We print the current tag name
  13.   std::cout << "[~] Current tag : <" << qPrintable(n.toElement().tagName()) << ">" << std::endl;
  14.   // And for each sub-tag of the current tag
  15.   for(int i = 0; i < nChildren.count(); i++) {
  16.    // We get the children node
  17.    QDomNode nChild = nChildren.at(i);
  18.    // And the tag value (we're looking for *Album* here)
  19.    QString tagValue = nChild.toElement().text();
  20.    // If the tag isn't null and contain *Album*
  21.    if(!nChild.isNull() && tagValue == "Album" ) {
  22.     // The album name is in the next tag
  23.     QDomElement albumNode = nChild.nextSiblingElement();
  24.     std::cout << "[-] Album found -> " << qPrintable(albumNode.text()) << std::endl;
  25.    }
  26.    // And we parse the children node
  27.    parse(nChild);
  28.   }
  29.  }
  30.  n = n.nextSibling();
  31. }
  32. }
  33. int main() {
  34. QDomDocument doc("Lib" );
  35. QFile file("/Users/wizardman/QtRFIDMusic/Lib.min.xml" );
  36. if(!file.open(QIODevice::ReadOnly))
  37.  return 1;
  38. if(!doc.setContent(&file)) {
  39.  file.close();
  40.  return 1;
  41. }
  42. file.close();
  43. // Root element
  44. QDomElement docElem = doc.documentElement();
  45. // <plist> -> <dict>
  46. QDomNode n = docElem.firstChild().firstChild();
  47. cout << endl << "Album list" << endl;
  48. cout << "------------------------------------" << endl;
  49. parse(n);
  50. return 0;
  51. }


 
Et voici ma sortie...
En commentant la ligne qui indique le tag analysé, je souhaiterai que le programme ne me sorte que les deux albums listés dans le XML.
 
Je n'arrive pas à comprendre pourquoi il tourne en boucle, j'ai l'impression de faire tous les tests nécessaires pour ne séléctionner que ce que je cherche.
Des idées ?

Message cité 1 fois
Message édité par wizardman le 23-07-2013 à 14:57:48
Reply

Marsh Posté le 24-07-2013 à 11:33:09    

wizardman a écrit :

J'ai un petit soucis avec mon parser XML.
 
J'utilise QtXML sur cet extrait de la librairie iTunes (qui n'utilise pas vraiment XML de façon standard comme vous le remarquerez), ce qui me permet de pouvoir trouver la liste des albums iTunes toutes plateformes confondues sans passer par AppleScript.
J'ai modifié le nom de certains tags pour pouvoir les repérer dans la sortie.
 
La logique est la suivante : j'analyse tous les tags et leurs enfants (et leurs enfants, etc) jusqu'à trouver un <key> qui contient Album, auquel cas j'affiche le contenu du tag suivant qui contient le nom de l'album en question.
 
...
Je n'arrive pas à comprendre pourquoi il tourne en boucle, j'ai l'impression de faire tous les tests nécessaires pour ne séléctionner que ce que je cherche.
Des idées ?


 
Bonjour !  
 
Plutôt que de continuer à chercher ce qui ne va pas dans votre code, je suis reparti d'un vieux code de parsing DOM que j'avais écrit il y a 10 ans (!)  et que j'ai adapté pour l'occasion :  
 

Code :
  1. void parse(const QDomElement& element)
  2. {
  3.     for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
  4.     {
  5.         QDomElement elementFils = n.toElement();
  6.         if (!elementFils.isNull())
  7.         {
  8.             QString tagValue = elementFils.tagName();
  9.             if (tagValue == "key" && elementFils.text() == "Album" )
  10.             {
  11.                 qDebug() << n.nextSiblingElement().text();
  12.             }
  13.             parse(elementFils);
  14.         }
  15.     }
  16. }


 
qui est appelée ainsi :  

Code :
  1. ...
  2.     QDomElement docElem = doc.documentElement();
  3.     // <plist> -> <dict>
  4.     qDebug() << "Album list" ;
  5.     qDebug() << "------------------------------------" ;
  6.     parse(docElem);
  7. ...


 
Le résultat est satisfaisant :  

Code :
  1. Album list
  2. ------------------------------------
  3. "J Dilla - Legacy Vol.1"
  4. "J Dilla - Legacy Vol.2"


 
(je ne m'explique pas les sauts de ligne ... et la flemme de chercher ou de tester en dehors de QtCreator :) )
 
Ensuite, j'ai tenté une approche plus ambitieuse, qui récupère pour chaque album toutes les infos dans une map (clé, valeur) :  
 

Code :
  1. void parseAlbum(const QDomElement& element, QMap<QString, QString>& album)
  2. {
  3.     QString cle;
  4.     for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
  5.     {
  6.         QDomElement elementFils = n.toElement();
  7.         if (!elementFils.isNull())
  8.         {
  9.             QString tagValue = elementFils.tagName();
  10.             if (elementFils.tagName().startsWith("key" ))
  11.             {
  12.                 cle = elementFils.text();
  13.             }
  14.             else
  15.             {
  16.                 album[cle] = elementFils.text();
  17.             }
  18.         }
  19.     }
  20. }
  21. void parseAlbums(const QDomElement& element, QList<QMap<QString, QString> >& albums)
  22. {
  23.     for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
  24.     {
  25.         QDomElement elementFils = n.toElement();
  26.         if (!elementFils.isNull())
  27.         {
  28.             if (elementFils.tagName().startsWith("dict_FOCUS" ))
  29.             {
  30.                 QMap<QString, QString> album;
  31.                 parseAlbum(elementFils, album);
  32.                 if (album.size() > 0)
  33.                 {
  34.                     albums << album;
  35.                 }
  36.             }
  37.             else
  38.             {
  39.                 parseAlbums(elementFils, albums);
  40.             }
  41.         }
  42.     }
  43. }


 
l'appel et l'affichage se faisant ainsi :  

Code :
  1. ...
  2.     QDomElement docElem = doc.documentElement();
  3.     QList<QMap<QString, QString> > albums;
  4.     parseAlbums(docElem, albums);
  5.     QMap<QString, QString> album;
  6.     foreach (album, albums)
  7.     {
  8.         qDebug() << "Album :";
  9.         foreach (QString cle, album.keys())
  10.         {
  11.             qDebug() << "\t" << cle << ":" << album[cle];
  12.         }
  13.     }
  14.     ...


 
On obtient alors :  

Code :
  1. Album :
  2.  "Album" : "J Dilla - Legacy Vol.1"
  3.  "Artist" : "1st Down"
  4.  "Bit Rate" : "192"
  5.  "Comments" : "FEFE2003"
  6.  "Date Added" : "2010-11-03T21:01:56Z"
  7.  "Date Modified" : "2010-06-25T16:49:08Z"
  8.  "File Folder Count" : "5"
  9.  "Genre" : "Hip-Hop"
  10.  "Kind" : "Fichier audio MPEG"
  11.  "Library Folder Count" : "1"
  12.  "Location" : "file://localhost/Users/wizardman/Music/iTunes/iTunes%20Media/Music/1st%20Down/J%20Dilla%20-%20Legacy%20Vol.1/40%20No%20Place%20To%20Go.mp3"
  13.  "Name" : "No Place To Go"
  14.  "Persistent ID" : "BE4ED29CCB7ED086"
  15.  "Sample Rate" : "44100"
  16.  "Size" : "4409344"
  17.  "Skip Count" : "1"
  18.  "Skip Date" : "2012-12-14T14:31:18Z"
  19.  "Total Time" : "183666"
  20.  "Track ID" : "3456"
  21.  "Track Number" : "40"
  22.  "Track Type" : "File"
  23.  "Year" : "2006"
  24. Album :
  25.  "Album" : "J Dilla - Legacy Vol.2"
  26.  "Artist" : "1st Down"
  27.  "Bit Rate" : "192"
  28.  "Comments" : "FEFE2003"
  29.  "Date Added" : "2010-11-03T21:01:56Z"
  30.  "Date Modified" : "2010-06-25T16:49:08Z"
  31.  "File Folder Count" : "5"
  32.  "Genre" : "Hip-Hop"
  33.  "Kind" : "Fichier audio MPEG"
  34.  "Library Folder Count" : "1"
  35.  "Location" : "file://localhost/Users/wizardman/Music/iTunes/iTunes%20Media/Music/1st%20Down/J%20Dilla%20-%20Legacy%20Vol.1/40%20No%20Place%20To%20Go.mp3"
  36.  "Name" : "No Place To Go"
  37.  "Persistent ID" : "BE4ED29CCB7ED086"
  38.  "Sample Rate" : "44100"
  39.  "Size" : "4409344"
  40.  "Skip Count" : "1"
  41.  "Skip Date" : "2012-12-14T14:31:18Z"
  42.  "Total Time" : "183666"
  43.  "Track ID" : "3456"
  44.  "Track Number" : "40"
  45.  "Track Type" : "File"
  46.  "Year" : "2006"


 
Et vous pouvez ensuite accéder directement aux champs qui vous intéressent, par exemple l'affichage de l'artiste du nom de tous les albums :  
 

Code :
  1. ...
  2.     QDomElement docElem = doc.documentElement();
  3.     QList<QMap<QString, QString> > albums;
  4.     parseAlbums(docElem, albums);
  5.     QMap<QString, QString> album;
  6.     foreach (album, albums)
  7.     {
  8.         qDebug() << "Album : " << album["Album"] << "par : " << album["Artist"];
  9.     }
  10.     ...


 
Bonne continuation !

Reply

Marsh Posté le 24-07-2013 à 17:11:04    

Juste une proposition pour le pb de portabilité, je me disais que Java aurait été un choix peut-être plus judicieux; restait le pb du "pilotage" d'itunes. Après une rapide recherche sur Google "java iTunes", il semblerait qu'il existe une API pour java permettant de piloter iTunes :
http://code.google.com/p/java-itunes-api/wiki/Welcome  ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-07-2013 à 18:08:43    

rufo a écrit :

Juste une proposition pour le pb de portabilité, je me disais que Java aurait été un choix peut-être plus judicieux; restait le pb du "pilotage" d'itunes. Après une rapide recherche sur Google "java iTunes", il semblerait qu'il existe une API pour java permettant de piloter iTunes :
http://code.google.com/p/java-itunes-api/wiki/Welcome  ;)


 
mais apparamment, cette API est seulement pour OSX [:petrus75]


---------------
last.fm
Reply

Marsh Posté le 24-07-2013 à 18:51:01    

Merci Farian pour tes recherches. Elles m'ont permis, avec une aide sur Stackoverflow, d'en venir au code suivant en abandonnant la récursivité et en allant directement cherche le tag qui m'intéresse :
 

Code :
  1. #include <iostream>
  2. #include <QtCore>
  3. #include <QFile>
  4. #include <QtXml>
  5. #include <QtDebug>
  6. #include <QVector>
  7. using namespace std;
  8. int main() {
  9. QDomDocument doc("Lib" );
  10. QFile file("/Users/wizardman/QtRFIDMusic/Lib.xml" );
  11. if(!file.open(QIODevice::ReadOnly))
  12.  return 1;
  13. if(!doc.setContent(&file)) {
  14.  file.close();
  15.  return 1;
  16. }
  17. file.close();
  18. // Root element
  19. QDomElement docElem = doc.documentElement();
  20. // <plist> -> <dict>
  21. QDomNode n = docElem.firstChild().firstChildElement("dict" );
  22. cout << endl << "Album list" << endl;
  23. cout << "------------------------------------" << endl;
  24. QVector<QString> albums;
  25. QDomNodeList list = n.childNodes();
  26. int count = list.count();
  27. for(int i = 0; i < count; ++i) {
  28.  QDomElement node = list.at(i).toElement();
  29.  if(node.tagName().startsWith("dict" )) {
  30.   node = node.firstChildElement();
  31.   while(!node.isNull()) {
  32.    QString t = node.text();
  33.    if(node.text() == "Album" && node.tagName() == "key" ) {
  34.     node = node.nextSiblingElement();
  35.     if(!node.isNull() && node.tagName() == "string" ) {
  36.      QString album = node.text();
  37.      if(albums.indexOf(album) == -1)
  38.       albums.append(album);
  39.     }
  40.    }
  41.    node = node.nextSiblingElement();
  42.   }
  43.  }
  44. }
  45. qDebug() << albums;
  46. return 0;
  47. }


 
Rufo: peut-être oui, mais je ne suis vraiment pas familier de Java, et je préfère voir large avec le C++ qui est vraiment toutes plateformes pour le coup !

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed