Journal Tuner, un accordeur de guitare en python / GTK

Posté par .
18
13
mar.
2012

Il y a quelques mois, j'ai décidé d'apprendre le python. Je me suis aussi lancé dans pyGTK. J'avais déjà essayé GTK en C, mais j'avais eu des difficultés. J'y retournerais peut-être un jour, mais plutôt en C++.

En guise d'exercice, j'ai choisi de développer un petit accordeur. Faute d'inspiration, je l'ai appelé Tuner. C'est une application très simple : une fenêtre avec des boutons qui déclenchent un son à la fréquence choisie.

Au fil du développement, ça s'est étoffé et c'est un peu devenu une usine à gaz :

Titre de l'image

Tuner est distribué sous licence beer-ware sur la page web du projet.

Fonctionnalités

  • Le clavier (le jeu de touches) est complètement configurable, donc dans la pratique, on doit pouvoir s'en servir avec tous les instruments (avec une précision au demi-ton seulement). On peut ajouter/retirer des touches. On peut choisir de décaler d'un demi-ton ou d'une octave une note, ou bien l'ensemble des notes (on obtient donc un Drop C en 4 clics). La durée des notes est paramétrable. Il n'y a pas (encore) de possibilité de sauvegarde de la configuration. On peut jouer les notes une par une ou toutes à la suite.

  • Les notations française (Do Ré Mi) et anglaise (A B C) sont gérées. (Ceci ne rentre pas dans le cadre de l'internationalisation / localisation, comme la langue ou les séparateurs de décimales, par exemple.)

  • Le son est émis via le buzzer interne ou la carte son. Dans le deuxième cas, on peut choisir entre une sinusoïde et un son de guitare assez sympa. Pour cela, j'ai utilisé beep et sox. Ce serait mieux d'utiliser un outil doté de bindings python, de façon à pouvoir stopper le son sans devoir tuer le process enfant à coup de SIGINT. Ça sera peut-être fait un jour, mais j'aime bien l'idée de pouvoir sortir par le buzzer quand on a pas d'enceintes grâce à beep. J'hésite entre plusieurs backends avec chacun leurs avantages/inconvénients en matière de portabilité, complétude, obsolescence, intégration. Dans le désordre : ossaudiodev, pygame, PortAudio, Gstreamer.

  • Ça fonctionne en boucle ouverte : ça ne dit pas à l'utilisateur si son instrument est bien accordé, ça émet le son, c'est tout. Pour un vrai accordeur, il faut aller voir du côté de gxTuner ou Lingot.

  • Seules les langues anglais et français sont disponibles. (L'archive contient le fichier .pot avec les chaînes de caractères à traduire…)

PyGObject

Sur la page de pyGTK, il est suggéré d'utiliser PyGObject pour les nouvelles applications. Dans la pratique, cela signifie GTK+ 3. C'est donc ce que j'ai fait. Ça n'a pas été simple : la documentation reste lacunaire. Ça devrait s'arranger, l'introspection aidant, mais les tutoriels ne se feront pas tout seuls…

Du fait de l'utilisation de GTK+ 3, Tuner dépend de python-gi (c'est le nom du paquet debian) qui n'est pas disponible avant Wheezy. Je ne sais pas ce qu'il en est des autres distributions.

À la réflexion, le passage à PyGObject / GTK+ 3 était peut-être prématuré…

  • # Beau travail

    Posté par . Évalué à 5.

    Merci pour le travail.

    La liste des outils pour musicien sur linuxmao.org

    Il faudrait ajouter le tiens. Peut-être que la possibilité d'utiliser le buzzer plutôt que la carte audio n'est pas disponible dans ces autres accordeurs.

    • [^] # Re: Beau travail

      Posté par . Évalué à 2.

      Merci. Tuner me semble un peu léger en comparaison des autres logiciels de la liste, donc ça me gène un peu de l'ajouter… Bon, ceci dit, tu peux le faire si tu penses que c'est susceptible de servir à quelqu'un.

    • [^] # Re: Beau travail

      Posté par . Évalué à 4.

      Merci !
      J'avais la flemme de décrocher le téléphone.

  • # Merci

    Posté par (page perso) . Évalué à 4.

    (on obtient donc un Drop C en 4 clics)

    Ça c'est plutôt intéressant !

    Dans le désordre : ossaudiodev, pygame, PortAudio, Gstreamer.

    Jack ?

    Ça fonctionne en boucle ouverte : ça ne dit pas à l'utilisateur si son instrument est bien accordé, ça émet le son, c'est tout.

    Dommage, ça aurait été sympa - surtout avec la possibilité d'avoir rapidement un accordage non-standard (Drop C ou en ce qui me concerne plutôt Drop C# :D). Un jour peut-être ? L'existence d'alternatives, si bonnes soient-elles, n'empêche rien à mon sens. ;)

    Ça devrait s'arranger, l'introspection aidant, mais les tutoriels ne se feront pas tout seuls…

    Donc, tu en as profité pour en fait un ? :D

    À la réflexion, le passage à PyGObject / GTK+ 3 était peut-être prématuré…

    Je ne crois pas. GTK3 est considéré comme stable, donc autant l'utiliser. A toujours reculer on fini par ne jamais sauter le pas. Alors certes c'est plus dur pour les 1ers qui essuient les plâtres, mais c'est aussi bénéfique à tout le monde.

    En tout cas, c'est très sympa à toi de nous faire partager ton projet, qui en ce qui me concerne risque de me servir, que ce soit au niveau de ses fonctionnalités intrinsèques (je suis guitariste en herbe) ou au niveau de son code (je code en python/gtk2, et j'aimerais bien me mettre à gtk3). Merci ;)

    PS: La Chimay, ça te va ? :)

    There is no spoon...

    • [^] # Re: Merci

      Posté par . Évalué à 1.

      Jack ?

      Oui, ça m'avait traversé l'esprit. Pas de façon exclusive, mais en plus d'ALSA, pourquoi pas, ça serait un bon exercice.

      Dommage, ça aurait été sympa

      Je pense que c'est loin d'être le même boulot. C'est peut-être plus simple de modifier les logiciels existants pour pouvoir changer les fréquences. (Je n'en ai pas essayé, mais je suis même surpris que ce ne soit pas possible.)

      Donc, tu en as profité pour en fait un ? :D

      Hé hé… Non. Peut-être un jour, mais je me considère bien trop néophyte pour ça. J'ai peut-être tort… Peut-être que je pourrais écrire qqchose de sorte que qqn de plus expérimenté n'ait plus qu'à corriger/compléter.``

      En tout cas, c'est très sympa à toi de nous faire partager ton projet, qui en ce qui me concerne risque de me servir, que ce soit au niveau de ses fonctionnalités intrinsèques (je suis guitariste en herbe) ou au niveau de son code (je code en python/gtk2, et j'aimerais bien me mettre à gtk3). Merci ;)

      Je suis pas sûr d'être un exemple, mais pour GTK+ 3 il se pourrait que ça t'aide : des fois, pour faire des choses simples, j'ai du chercher partout sur internet, jusqu'à trouver un bout de code dont m'inspirer sur un coin de blog.

      PS: La Chimay, ça te va ? :)

      Rien ne me ferait plus plaisir qu'une Saint-Luc, mais une Chimay, ça sera très bien ! Merci !

      • [^] # Re: Merci

        Posté par (page perso) . Évalué à 1.

        Oui, ça m'avait traversé l'esprit. Pas de façon exclusive, mais en plus d'ALSA, pourquoi pas, ça serait un bon exercice.

        Pour avoir pratiquer un peu en C, j'ai trouvé l'api plutôt bien pensée (en C, toujours) et grâce au serveur qui s'occupe de toute la partie matos, ça reste assez haut-niveau (pas technique, mais abstraction). Faut juste faire gaffe pour l'échantillonnage.
        Par contre, en python j'ai pas encore essayé.

        Je pense que c'est loin d'être le même boulot.

        Oui, c'est bien possible en effet. Mais ça peut être un exercice intéressant (ça me titille).

        Je suis pas sûr d'être un exemple

        Bah, étant donné que tu as produit quelque chose de fonctionnel, ça fait déjà une base. Après il y a peut-être moyen d'affiner ou d'optimiser certaines choses, mais au moins comme tu dis, le terrain est un peu débroussaillé pour ceux qui veulent s'y mettre.

        Rien ne me ferait plus plaisir qu'une Saint-Luc, mais une Chimay, ça sera très bien ! Merci !

        Ben va voir ça alors ;)

        There is no spoon...

    • [^] # Re: Merci

      Posté par (page perso) . Évalué à 2.

      Dans le désordre : ossaudiodev, pygame, PortAudio, Gstreamer.

      Jack ?

      +1, et ensuite le MIDI…

      * Ils vendront Usenet^W les boites noires quand on aura fini de les remplir.

    • [^] # Re: Merci

      Posté par . Évalué à 2.

      GTK3 est considéré comme stable, donc autant l'utiliser

      Sauf que Gtk3 n'est pas disponible sous windows (et le sera sans doute jamais), ça limite donc sérieusement les possibilités d'exécution de l'appli. C'est à cause de ça que je suis toujours en gtk2, avec pyGtk donc.

      • [^] # Re: Merci

        Posté par . Évalué à 1.

        L'une des raisons pour lesquelles j'ai publié ce journal était justement de recueillir des avis ou des retours d'expérience sur GTK+ 3.

        Jusqu'à présent, développer avec GTK permet le portage sous Windows. Si ce n'est plus le cas, ce n'est pas une petite différence. Qu'est-ce qui permet de dire que GTK+ 3 ne sera jamais disponible sous Windows ?

        On peut aussi penser aux distributions sur lesquelles il ne sera jamais disponible (debian squeeze et inférieures, mais surtout les distributions de long terme).

        C'était peut-être le même chantier au passage de Gtk 1 à 2, mais j'étais jeune, je ne me souviens que des applications qui avaient un rendu un peu moche. Au passage, il m'a fallu chercher un peu pour trouver un thème de bureau qui fonctionne bien et donne un rendu cohérent pour GTK+ 3 et 2, sans quoi certaines applis avaient aussi un rendu moche (evince,…).

        Autre élément au dossier : à partir de debian wheezy, Glade est en version 3.10 et ne gère plus que GTK+ 3. Il est possible, selon le développeur de Glade, d'installer 3.8 et 3.10, ceci justifierait selon lui la rupture de compatibilité, ou du moins ça aiderait à faire passer la pilule. Mais apparemment, côté debian, il n'est pas question de continuer à proposer les deux. Voir ce rapport de bug où les gens s'engueulent à ce sujet. J'avais envie d'argumenter en faveur de la distribution des deux en parallèle, mais je ne fais pas spécialement d'argument qui n'ait déjà été énoncé, et je ne veux pas polluer le bugtracker, donc je me suis tu.

        • [^] # Re: Merci

          Posté par . Évalué à 2. Dernière modification le 14/03/12 à 22:56.

          Il y a pas vraiment de volonté de porter vers windows hormis un ou deux cas à part qui n'avancent pas ou plus. La plateforme est délaissée et c'est bien dommage.

  • # Beep en python

    Posté par (page perso) . Évalué à 5.

    Projet sympa.

    Pour beep, tu peux utiliser subprocess.Popen()….kill() au lieu d'un signal à la main (.kill() fera la même chose, mais tu auras moins l'impression de le faire à la main)

    Sinon, regarde le code de beep, c'est 300 lignes de C, 150 pour parser la ligne de commande, 50 pour les includes, 100 de boiler plate, 25 d'accolades, 12 de commentaires et deux ou trois d'utiles dans lesquelles tu ouvres un fichier et tu écris dedans. Tu peux faire cela en python trivialement et ainsi t'affranchir de dépendance tout en ayant plus de contrôle.

    • [^] # Re: Beep en python

      Posté par . Évalué à 2.

      Pour beep, tu peux utiliser subprocess.Popen()….kill() au lieu d'un signal à la main (.kill() fera la même chose, mais tu auras moins l'impression de le faire à la main)

      C'est ce que j'avais fait au début mais ça ne marche pas : quand tu killes beep (SIGTERM), le buzzer reste à buzzer indéfiniment pour toute la vie jusqu'à ce que tu rebeepes. J'ai envoyé début janvier un patch à l'auteur et au packageur debian pour que SIGTERM ferme correctement, mais je n'ai pas eu de réponse. J'ai relancé ce matin. Je n'osais pas trop insister, faute d'être spécialiste des signaux…

      Sinon, regarde le code de beep, c'est 300 lignes de C, 150 pour parser la ligne de commande, 50 pour les includes, 100 de boiler plate, 25 d'accolades, 12 de commentaires et deux ou trois d'utiles dans lesquelles tu ouvres un fichier et tu écris dedans. Tu peux faire cela en python trivialement et ainsi t'affranchir de dépendance tout en ayant plus de contrôle.

      Je n'y avais pas regardé, mais peut-être que ça s'envisage, oui. Ceci dit, pour pas faire les choses à Poitiers, il faudrait créer un vrai module beep pour python avec les fonctionnalités et les paramètres utiles. Ça peut prendre un peu de temps. Et peut-être que ça existe déjà en partie. En regardant vite fait, je viens de trouver winsound mais c'est seulement pour windows.

      • [^] # Re: Beep en python

        Posté par (page perso) . Évalué à 1. Dernière modification le 13/03/12 à 23:02.

        Tient, sinon une autre solution marrante, avec ctypes.

        a) tu compiles un .so à partir de beep :

        gcc -shared beep.c -o beep.so
        
        

        b) tu fais un programme python qui fait le boulot en chargeant le module .so

        import ctypes
        
        class beep_parms_t(ctypes.Structure):
            _fields_ = [
                    ('freq', ctypes.c_float),
                    ('length', ctypes.c_int),
                    ('reps', ctypes.c_int),
                    ('delay', ctypes.c_int),
                    ('end_delay', ctypes.c_int),
                    ('stdin_beep', ctypes.c_int),
                    ('verbose', ctypes.c_int),
                    ('next', ctypes.c_void_p),
                ]
        
        # load the beep library
        lib = ctypes.CDLL('./beep.so')
        lib.play_beep.argtypes = (beep_parms_t, )
        
        def beep(frequency=440.0,
                 length=200,
                 reps=1,
                 delay=100,
                 end_delay=False,
                 stdin_beep=False,
                 verbose=False):
            '''
            Play a beep.
            '''
        
            param = beep_parms_t()
            param.freq = frequency
            param.length = length
            param.reps = reps
            param.delay = delay
            param.end_delay = end_delay
            param.stdin_beep = stdin_beep
            param.verbose = verbose
            param.next = None
        
            lib.play_beep(param)
        
        # usage simple
        beep()
        beep(frequency=500, reps=2)
        
        

        c) A toi de gérer le cas ou les choses tournent mal avec ton programme (ie, signal handler/atexit/…)

        (edit) Et en fait il semblerait que cela se passe bien, parce que lorsque le processus ferme le descripteur de fichier du beep, le système arrête le beep (mais dans ce cas là, à quoi sert le handler de signal dans beep.c ?)

        • [^] # Re: Beep en python

          Posté par (page perso) . Évalué à 2.

          En plus de ctypes, tu peux utiliser Cython (C extensions for Python)
          http://cython.org/

          If you choose open source because you don't have to pay, but depend on it anyway, you're part of the problem.evloper) February 17, 2014

      • [^] # kill beep

        Posté par . Évalué à 2.

        C'est ce que j'avais fait au début mais ça ne marche pas : quand tu killes beep (SIGTERM), le buzzer reste à buzzer indéfiniment pour toute la vie jusqu'à ce que tu rebeepes. J'ai envoyé début janvier un patch à l'auteur et au packageur debian pour que SIGTERM ferme correctement, mais je n'ai pas eu de réponse. J'ai relancé ce matin. Je n'osais pas trop insister, faute d'être spécialiste des signaux…

        J'ai bien fait d'insister : j'ai reçu hier un message de Gerfried Fuchs, le packageur debian me disant qu'il allait intégrer le patch et demander l'intégration upstream.

        À terme, on pourra donc utiliser kill() proprement sur beep.

  • # beerware

    Posté par (page perso) . Évalué à 5. Dernière modification le 13/03/12 à 23:00.

    bon je n'ai pas retrouvé pourquoi certains considéraient la beerware licence non libre (j'ai dû le voir passer sur debian-legal mais je n'ai plus le lien), j'ai cependant retrouvé http://romanrm.ru/en/beerware qui oublie d'indiquer :

    • faut-il que je me déplace pour te payer une bière ?
    • si je te rencontre, dois-je te payer une bière ?

    alors qu'il serait plus simple que je te l'offre pour avoir choisi une licence libre :-) (sans l'obligation, liée au "can" qui aurait pu être remplacé par un "may" iirc, oui, les juristes s'arrêtent à ce genre de chose : obligation ou possibilité/capacité o_O)

    en bref, autant prendre la WTFPL qui, elle, est reconnue et revient au même dans ce cas.

    • [^] # Re: beerware

      Posté par . Évalué à 2.

      Merci pour le retour.

      L'idée était que ce truc étant pas beaucoup plus qu'un exercice de tutoriel, je ne me voyais pas mettre une GPL dessus. Une peu comme si on plaçait sous GPL un algo de 20 lignes qu'on met sur un forum. Plus l'histoire de la bière que je trouve sympa (à la lecture, j'imagine un utilisateur qui croise le développeur au comptoir, tout ça).

      Si je veux quelque chose qui tient la route, je peux aussi mettre l'ensemble dans le domaine public ou sous une licence permissive comme BSD ou MIT, j'y connais rien.

      Bref, à l'échelle du projet, ça n'a pas d'importance, mais j'aime bien les discussions qui pinaillent sur ces questions.

  • # Plus simple, et plus portable ?

    Posté par (page perso) . Évalué à 2.

    J'hésite entre plusieurs backends avec chacun leurs avantages/inconvénients en matière de portabilité, complétude, obsolescence, intégration. Dans le désordre : ossaudiodev, pygame, PortAudio, Gstreamer.

    Pourquoi pas simplement générer à la volée un RIFF ou un WAV, et laisser l'utilisateur utiliser la commande qu'il veut pour jouer le son ?
    Laisser le choix entre une redirection (eg, vers /dev/dsp) ou un pipe (eg, vers mplayer), ça me paraît plutôt portable, non ?

  • # Accords ?

    Posté par . Évalué à 1.

    Autre possibilité d'évolution : proposer une liste d'accords, et offrir la possibilité de jouer toutes les notes à la fois.

    Un accord n'est qu'une combinaison de notes, donc ça se recoupe avec une fonction de sauvegarde de configuration (qui n'existe pas à l'heure actuelle et qui n'est pas une priorité, surtout si on ajoute à la liste des accords une liste d'accordages usuels).

    Reste à voir comment présenter ces accords pour que ça soit pratique.

    Dans cette hypothèse, je garderais bien sox pour le son de guitare. Sauf si je trouvais mieux : une banque de sons de différents instruments. J'ai pas encore cherché.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.