Category Archives: Info

Horloge parlante à la demande

Bonjour à tous!

Dans la série des projets un peu fou, je voudrais vous parler de mon horloge parlante !?

D’abord, un peu de contexte. Depuis peu, je fréquente un serveur discord (The language sloth) dédié à l’apprentissage des langues.
Je participe à ma hauteur pour aider les débutants en français. Ce n’est pas mon métier mais l’ambiance est assez cool.

De coup, je me suis dit un peu renseigner sur les connaissances à avoir pour obtenir le niveau A1 (le minimum).
Il y a comprendre l’heure. Sur ce constat, j’ai démarré un petit projet pour proposer un système capable de sortir un fichier audio pour chaque heure de la journée.
Et de proposer l’ensemble des façons de dire l’heure.

Le code:
Pour mes petits scripts, j’aime bien utiliser du python. Ici, mon petit script python permet d’enregistrer facilement les samples nécessaires pour bâtir l’ensemble de données.
Ce travail construit les données d’une voix.
Il y a 28 mots à enregistrer:

unity=["un","une","deux","trois","quatre","cinq","six","sept","huit","neuf"]
tens=["dix","onze","douze","treize","quatorze","quinze","seize","vingt","trente","quarante","cinquante"]
words=["midi","minuit","et","quart","moins", "heure", "le"]
Les samples à enregistrer

 

Le site:
Le reste de l’application est constitué d’un site web qui permet de choisir une voix, et une heure.
Suite à cela, le site affiche un ou deux lecteurs audios pour permettre la lecture des sons.
J’ai recyclé l’architecture php de mes sites applicatifs. Je la trouve vraiment formidable. Même si, je trouve le PHP de plus en plus dégueulasse.

Pour la suite, j’aimerai bien «gamifier» la chose. Permettre d’entendre une heure et de choisir la bonne valeur parmi trois propositions. Jouer avec ce genre d’éléments.

Si vous testez le site, pensez à mettre le son pas trop fort.

 

Conclusion:
J’avais cette idée de partir des samples pour construire les messages audios qui traîner dans ma tête depuis un moment. J’avais envie de tester ce que cela donnerait d’enregistrer 28 samples environ pour générer 1560 fichiers audios. J’ai décidé de l’écrire et voilà le résultat. La curiosité s’attardait sur la qualité qu’on pourrait obtenir avec cette méthode. C’est audible, il y a quelques sont qui mériterait d’être retravailler mais dans l’ensemble, cela remplit son rôle.
Je serai ravi de recevoir de nouvelles voix. Vous pouvez m’envoyer vos 28 samples et je peux m’occuper du reste.

Les liens:
Le projets en ligne: http://heures.renaudguezennec.eu/
Le code source du projet: https://github.com/obiwankennedy/french_talking_clock_game

Rolisteam Evolution

The function evolution…

I would like to show the evolution of one function in rolisteam code.
This function is called when the user (Game Master) closes a map or image.

The function must close the map or image and send a network order to each player to close the image or plan.

At the beginning, the function looked like that.
Some code line and comments were written in French. No coding rules were respected.
Low-level code for networking. The function was very long.

// On recupere la fenetre active (qui est forcement de type CarteFenetre ou Image, sans quoi l'action
       // ne serait pas dispo dans le menu Fichier)
       QWidget *active = workspace->activeWindow();

       // Ne devrait jamais arriver
       if (!active)
       {
               qWarning("Close map action called when no widget is active in the workspace (fermerPlanOuImage - MainWindow.h)");
               return;
       }

       // On verifie pour le principe qu'il s'agit bien d'une CarteFenetre ou d'une Image
       if (active->objectName() != "CarteFenetre" && active->objectName() != "Image")
       {
               qWarning("not expected type of windows (fermerPlanOuImage - MainWindow.h)");
               return;
       }

       // Creation de la boite d'alerte
       QMessageBox msgBox(this);
       msgBox.addButton(QMessageBox::Yes);
       msgBox.addButton(QMessageBox::Cancel);
       msgBox.setIcon(QMessageBox::Information);
       msgBox.move(QPoint(width()/2, height()/2) + QPoint(-100, -50));
       // On supprime l'icone de la barre de titre
       Qt::WindowFlags flags = msgBox.windowFlags();
       msgBox.setWindowFlags(flags ^ Qt::WindowSystemMenuHint);
       // M.a.j du titre et du message
       if (active->objectName() == "CarteFenetre")
       {
               msgBox.setWindowTitle(tr("Close Map"));
               msgBox.setText(tr("Do you want to close this map?\nIt will be closed for everybody"));
       }
       else
       {
               msgBox.setWindowTitle(tr("Close Picture"));
               msgBox.setText(tr("Do you want to close this picture?\nIt will be closed for everybody"));
       }
       msgBox.exec();

       // Si l'utilisateur n'a pas clique sur "Fermer", on quitte
       if (msgBox.result() != QMessageBox::YesRole)
               return;

       // Emission de la demande de fermeture de la carte
       if (active->objectName() == "CarteFenetre")
       {
               // Recuperation de l'identifiant de la carte
               QString idCarte = ((CarteFenetre *)active)->carte()->identifiantCarte();

               // Taille des donnees
               quint32 tailleCorps =
                       // Taille de l'identifiant de la carte
                       sizeof(quint8) + idCarte.size()*sizeof(QChar);

               // Buffer d'emission
               char *donnees = new char[tailleCorps + sizeof(enteteMessage)];

               // Creation de l'entete du message
               enteteMessage *uneEntete;
               uneEntete = (enteteMessage *) donnees;
               uneEntete->categorie = plan;
               uneEntete->action = fermerPlan;
               uneEntete->tailleDonnees = tailleCorps;

               // Creation du corps du message
               int p = sizeof(enteteMessage);
               // Ajout de l'identifiant de la carte
               quint8 tailleIdCarte = idCarte.size();
               memcpy(&(donnees[p]), &tailleIdCarte, sizeof(quint8));
               p+=sizeof(quint8);
               memcpy(&(donnees[p]), idCarte.data(), tailleIdCarte*sizeof(QChar));
               p+=tailleIdCarte*sizeof(QChar);

               // Emission de la demande de fermeture de la carte au serveur ou a l'ensemble des clients
               emettre(donnees, tailleCorps + sizeof(enteteMessage));
               // Liberation du buffer d'emission
               delete[] donnees;

               // Suppression de la CarteFenetre et de l'action associee sur l'ordinateur local
               ((CarteFenetre *)active)->~CarteFenetre();
       }

       // Emission de la demande de fermeture de l'image
       else
       {
               // Recuperation de l'identifiant de la carte
               QString idImage = ((Image *)active)->identifiantImage();

               // Taille des donnees
               quint32 tailleCorps =
                       // Taille de l'identifiant de la carte
                       sizeof(quint8) + idImage.size()*sizeof(QChar);

               // Buffer d'emission
               char *donnees = new char[tailleCorps + sizeof(enteteMessage)];

               // Creation de l'entete du message
               enteteMessage *uneEntete;
               uneEntete = (enteteMessage *) donnees;
               uneEntete->categorie = image;
               uneEntete->action = fermerImage;
               uneEntete->tailleDonnees = tailleCorps;

               // Creation du corps du message
               int p = sizeof(enteteMessage);
               // Ajout de l'identifiant de la carte
               quint8 tailleIdImage = idImage.size();
               memcpy(&(donnees[p]), &tailleIdImage, sizeof(quint8));
               p+=sizeof(quint8);
               memcpy(&(donnees[p]), idImage.data(), tailleIdImage*sizeof(QChar));
               p+=tailleIdImage*sizeof(QChar);

               // Emission de la demande de fermeture de l'image au serveur ou a l'ensemble des clients
               emettre(donnees, tailleCorps + sizeof(enteteMessage));
               // Liberation du buffer d'emission
               delete[] donnees;

               // Suppression de l'Image et de l'action associee sur l'ordinateur local
               ((Image *)active)->~Image();
       }

A big step forward, the networking code has been reworked.
So the readability is improved. It is also possible to see the beginning of polymorphism. MediaContener is used but not everywhere.

QMdiSubWindow* subactive = m_mdiArea->currentSubWindow();
QWidget* active = subactive;
MapFrame* bipMapWindow = NULL;

if (NULL!=active)
{

    QAction* action=NULL;

    Image*  imageFenetre = dynamic_cast(active);

    QString mapImageId;
    QString mapImageTitle;
    mapImageTitle = active->windowTitle();
    bool image=false;
    //it is image
    if(NULL!=imageFenetre)
    {
        m_pictureList.removeOne(imageFenetre);

        mapImageId = imageFenetre->getMediaId();
        image = true;
        action = imageFenetre->getAction();
    }
    else//it is a map
    {
        bipMapWindow= dynamic_cast(active);
        if(NULL!=bipMapWindow)
        {
            mapImageId = bipMapWindow->getMediaId();
            action = bipMapWindow->getAction();

        }
        else// it is undefined
        {
            return;
        }
    }

    QMessageBox msgBox(this);
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel );
    msgBox.setDefaultButton(QMessageBox::Cancel);
    msgBox.setIcon(QMessageBox::Information);
    msgBox.move(QPoint(width()/2, height()/2) + QPoint(-100, -50));
    Qt::WindowFlags flags = msgBox.windowFlags();
    msgBox.setWindowFlags(flags ^ Qt::WindowSystemMenuHint);

    if (!image)
    {
        msgBox.setWindowTitle(tr("Close Map"));
    }
    else
    {
        msgBox.setWindowTitle(tr("Close Picture"));
    }
    msgBox.setText(tr("Do you want to close %1 %2?\nIt will be closed for everybody").arg(mapImageTitle).arg(image?tr(""):tr("(Map)")));

    msgBox.exec();
    if (msgBox.result() != QMessageBox::Yes)
        return;

    if (!image)
    {
        NetworkMessageWriter msg(NetMsg::MapCategory,NetMsg::CloseMap);
        msg.string8(mapImageId);
        msg.sendAll();

        m_mapWindowMap.remove(mapImageId);
        m_playersListWidget->model()->changeMap(NULL);
        m_toolBar->changeMap(NULL);
    }
    else
    {
        NetworkMessageWriter msg(NetMsg::PictureCategory,NetMsg::DelPictureAction);
        msg.string8(mapImageId);
        msg.sendAll();
    }

    MediaContainer*  mediaContener = dynamic_cast(subactive);
    if(NULL!=mediaContener)
    {
        CleverURI* cluri = mediaContener->getCleverUri();
        cluri->setDisplayed(false);
        if(NULL!=m_sessionManager)
        {
            m_sessionManager->updateCleverUri(cluri);
        }
    }

    delete action;
    delete subactive;
}
Version Intermédiaire

Then, we implements a solution to describe map, vmap (v1.8) or image as mediacontener.
They share a large part of their code, so it becomes really easy to do it.

QMdiSubWindow* subactive = m_mdiArea->currentSubWindow();
    MediaContainer* container = dynamic_cast(subactive);
    if(NULL != container)
    {
        CleverURI::ContentType type = container->getContentType();
        if(CleverURI::VMAP == type)
        {
            removeVMapFromId(container->getMediaId());
        }
        else if(CleverURI::MAP == type)
        {
            removeMapFromId(container->getMediaId());
        }
        else if(CleverURI::PICTURE == type )
        {
            removePictureFromId(container->getMediaId());
        }
    }
Actuel

Cerfication Qt

j’ai obtenu ma certification Qt : (Qt Essentials).

Je décris vite fait l’examen:
-50 questions à choix multiples.
-1h pour le faire + 30 mins, si vous êtes dans un pays dont la langue officielle n’est pas l’anglais.
– Prix: 140 € si ma mémoire est bonne. (75 € si vous voulez le repasser après un échec)

Je suis sûr d’avoir réussi 40 questions, j’ai des doutes sur les 10 autres. C’était souvent des questions ou il y avait plusieurs réponses demandées, j’en avais souvent une de sûre mais de sérieux doutes pour les autres. Cela ne m’a pas empêché de réussir.

Je suis donc officiellement “Nokia Certified Qt Developer”.