Partage
  • Partager sur Facebook
  • Partager sur Twitter

Pas de son lors de l'éxécution en console

    14 septembre 2014 à 18:49:31

    bonjour, j'ai crée un script python qui emet un son en boucle, le problème c'est que celà fonctionne si je le lance via l'IDE de python, mais pas si je lance via python en console.

    Infos :

    version python : 2.7

    console utilisé : console de base ubuntu 14, aplay arrive à lire le son depuis la console

    mon code : 

    import pygame
    import os
    import sys
    import platform
    
    sound_folder = "sound"
    if(len(sys.argv)<2):
        sound = "alert.wav"
    else:
        sound = sys.argv[1]
    
    path = os.getcwd()+os.sep
    filename = path+sound_folder+os.sep+sound
    if(os.path.isfile(filename) != True):
        print "le fichier n'existe pas"
        quit()
    if(platform.system() == "Windows"):
        print "Don't work on windows, only on linux"
        quit()
    else:
        print filename
        pygame.mixer.init()
        pygame.mixer.Sound(filename).play(-1)
        print os.getpid()
    

    -
    Edité par thib3113 14 septembre 2014 à 18:50:08

    • Partager sur Facebook
    • Partager sur Twitter
    L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
      14 septembre 2014 à 19:07:20

      Que se passe-t-il lors de l'exécution en console ? erreur, arrêt du programme, pas de son ?

      Une petite question : pourquoi windows n'est-il pas accepté ? pygame est multiplateforme pourtant.

       

      Pour terminer, une remarque:

      if(os.path.isfile(filename) != True):

      peut être remplacé par :

      if not os.path.isfile(filename):

      qui est plus simple et plus compréhensible. Les parenthèses autour des conditions ne sont pas nécessaires mais tu peux les mettre quand même (même si je trouve ça moche :))

      • Partager sur Facebook
      • Partager sur Twitter
        14 septembre 2014 à 19:11:05

        car c'est un script pour raspberry pi :), windows sur raspberry me semble un poil maso :).

        lors de l'éxécution en console, le programme se passe, et s'arrete ( les print se font )... 

        ah oui c'est vrai qu'il y à not en python .... 

        • Partager sur Facebook
        • Partager sur Twitter
        L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
          14 septembre 2014 à 19:20:42

            Ce n'est pas une raison pourinterdirel'utilisation de windows. Mais bon, passons.

          Pour le son qui ne se joue pas je pense que le programme se quitte avant. Rajoute donc ça :

          while pygame.mixer.get_busy()
              # On attend la fin du son (en ne faisant rien)
              pass
          Pour utiliser moins de processeur, tu peux remplacer pass par pygame.time.wait(50) (Edit: correction de l'argument)

          N'oublie pas de rajouter à la fin de ton script:

          pygame.quit()

          -
          Edité par tatrats 14 septembre 2014 à 20:26:29

          • Partager sur Facebook
          • Partager sur Twitter
            14 septembre 2014 à 20:00:26

            c'est vrai, mais c'est controlé d'une manière spécifique, et si c'est windows, certaines commandes système ne fonctionneront pas, il faut donc attendre que je developpe tout ça, en attendant, windows est bloqué :)

            pour ce qui est du script, j'ai fait une boucle infini qui attend une seconde au final, car ta technique s'arrete après avoir joué le son une fois.

            j'ai donc ce code au final, et le script fonctionne: 

            import pygame
            import os
            import sys
            import platform
            import time
            
            sound_folder = "sound"
            if(len(sys.argv)<2):
                sound = "alert.wav"
            else:
                sound = sys.argv[1]
            
            path = os.getcwd()+os.sep
            filename = path+sound_folder+os.sep+sound
            if not os.path.isfile(filename):
                print "le fichier n'existe pas"
                quit()
            if(platform.system() == "Windows"):
                print "Don't work on windows, only on linux"
                quit()
            else:
                print filename
                pygame.mixer.init()
                pygame.mixer.Sound(filename).play(-1)
                print os.getpid()
                while pygame.mixer.get_busy():
                    time.sleep(1)
                # On attend la fin du son (en ne faisant rien)
                    #pygame.time.wait(0.05)
            pygame.quit()



            • Partager sur Facebook
            • Partager sur Twitter
            L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
              14 septembre 2014 à 20:26:03

              Ah, d'accord, je n'avais pas eu l'idée que tu puisses utiliser des commandes système...

              Au passage, je m'aperçois que j'ai dit une bêtise, pour attendre 0.05 seconde avec pygame, c'est

              pygame.time.wait(50)  # En millisecondes
              Et je n'avait pas remarqué que tu avais une fonction quit(), du coup pygame.quit() devrait être appelé dans cette fonction, mais cette fonction doit obligatoirement être appelé à la fin du programme, qu'il y ait une erreur ou pas (sinon vu que pygame n'utilise pas l'espace mémoire python, il y a un risque de memory leak, fuite de mémoire).
              • Partager sur Facebook
              • Partager sur Twitter
                15 septembre 2014 à 20:06:59

                thib3113 a écrit:

                path = os.getcwd()+os.sep
                filename = path+sound_folder+os.sep+sound
                if not os.path.isfile(filename):
                    print "le fichier n'existe pas"
                Et ça : https://docs.python.org/2/library/os.path.html#os.path.join ? (et ça reste portable)

                -
                Edité par Maclou 15 septembre 2014 à 20:07:25

                • Partager sur Facebook
                • Partager sur Twitter
                  15 septembre 2014 à 21:44:09

                  @tatrats : même si pygame n'est pas encore initialisé quand j'utilise quit() ?

                  • Partager sur Facebook
                  • Partager sur Twitter
                  L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                    16 septembre 2014 à 8:26:17

                    Je m'interroge sur le choix de pygame.

                    Le but c'est de pouvoir lancer de la musique sur un Raspberry ? Sans interface ? En gros, de faire lecteur audio ?

                    Dans ce cas, le choix de Pygame est discutable. Sur ton RPi, tu peux installer un serveur mpd et utiliser un module comme python-mpd2 pour piloter la musique en cours de lecture.

                    Ça a le mérite d'être plus léger (pas besoin de te farcir une dépendance à la SDL juste pour ça, sur un RPi ça compte), plus "linuxien", donc probablement plus formateur aussi (MPD a une architecture intéressante, un modèle client-service très courant sur les unixoides).

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Zeste de Savoir, le site qui en a dans le citron !
                      16 septembre 2014 à 15:58:30

                      Le fait de quitter pygame s'il n'est pas initialisé n'a aucune importance, ça ne fera tout simplement rien. Si tu veux vraiment ne quitter pygame que s'il est initialisé, tu peux rajouter :

                      if pygame.mixer.get_init():
                          pygame.mixer.quit()

                      Mais ce n'est pas très utile (sauf en termes de logique, et encore, la fonction pygame, elle aussi, fait la vérification).

                      Par contre, Nohar a sans doute raison (il a toujours raison ;)) que pygame n'est certainement pas ce qu'il y a de mieux si son utilisation se limite à jouer un son. Je n'utilise Linux que très peu, donc je peux me tromper, mais il me semble que tu pourrais utiliser directement une commande Linux (tu as parlé de aplay). Au niveau "pythonesque", je pense que ça ne pose pas de problème de faire un appel système, si ton programme est spécifiquement dédié aux Raspberry. Prière de me détromper le cas échéant.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        17 septembre 2014 à 0:10:51

                        je vais me renseigner pour la solution de nohar, mais j'avais choisir pygame car il permet de répéter un son sans avoir à attendre ( j'avais regarder vite fait les utilitaires linux et je n'avais pas trouvé ce que je cherchais )
                        • Partager sur Facebook
                        • Partager sur Twitter
                        L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                        Anonyme
                          17 septembre 2014 à 1:08:35

                          Tu veux jouer du son dans quel but ? Parce que si c'est juste pour manipuler et jouer des petits fichiers wave en boucle, alors MPD est probablement lui aussi overkill. Dans ce cas en particulier, PyAudio est à mon avis un meilleur choix.

                          Mais s'il est vraiment question de jouer de la musique, avec playlist et autres contrôles avancés, alors effectivement MPD est peut-être un bon choix.

                          Ça dépend vraiment de ce que tu cherches à faire.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            17 septembre 2014 à 13:45:41

                            je cherche à faire un reveil, donc il me faut faire un son en boucle jusqu'à ce que l'on le stoppe :p
                            • Partager sur Facebook
                            • Partager sur Twitter
                            L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                            Anonyme
                              17 septembre 2014 à 18:52:52

                              Alors je pense que PyAudio est plus adapté, même s'il est plus complexe à l'utilisation (c'est un simple binding bas niveau de portaudio).

                              [édit] Un petit exemple d'utilisation simpliste (et prêt à l'emploi) :

                              #!/usr/bin/env python3
                              
                              from io import BytesIO
                              from pyaudio import PyAudio
                              from wave import Wave_read
                              from urllib.request import urlopen
                              
                              
                              # Télécharger le reveil du coyote...
                              with urlopen("http://wav.bruitages.net/bipbip.wav") as file:
                                  wave_file = Wave_read(BytesIO(file.read()))
                              frames = wave_file.readframes(wave_file.getnframes())
                              
                              # Initialiser une instance de portaudio :
                              proc_audio = PyAudio()
                              
                              # Initialiser le flux audio à partir du fichier WAVE téléchargé :
                              stream = proc_audio.open(
                                  format=proc_audio.get_format_from_width(wave_file.getsampwidth()),
                                  channels=wave_file.getnchannels(),
                                  rate=wave_file.getframerate(),
                                  output=True
                              )
                              
                              
                              # Lecture du flux audio en boucle :
                              try:
                                  while True:
                                      stream.write(frames)
                              except KeyboardInterrupt:
                                  # Ne jette pas ton PC contre un mur, ce serait dommage... 
                              
                              pass # Un simple Ctrl+C suffit à arréter la lecture audio.
                              

                              stream.stop_stream() stream.close()

                              proc_audio.terminate() wave_file.close()

                              </pre>

                              Par contre, parmis les effets indésirables d'un tel réveil, il important de noter la grande probabilité de voir du sang couler de ses oreilles. Nan mais je préviens hein, c'est tout... :-°

                              -
                              Edité par Anonyme 17 septembre 2014 à 19:14:11

                              • Partager sur Facebook
                              • Partager sur Twitter
                                17 septembre 2014 à 23:58:44

                                ah, merci, ça va m'aider ça  . Par contre, vous ne connaitriez pas un moyen d'arrété le programme via un autre programme ? autre qu'un kill méchant en bash :) ?
                                • Partager sur Facebook
                                • Partager sur Twitter
                                L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                                  18 septembre 2014 à 10:37:40

                                  from multiprocessing import Process
                                  
                                  # si on suppose que la lecture du son est encapsulée dans la fonction play_sound
                                  p = Process(target=play_sound)
                                  p.start()
                                  input("Appuyez sur Entrée pour arrêter le son")
                                  p.terminate()
                                  p.join()
                                  
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Zeste de Savoir, le site qui en a dans le citron !
                                    18 septembre 2014 à 11:53:43

                                    nohar a écrit:

                                    # si on suppose que la lecture du son est encapsulée dans la fonction play_sound
                                    

                                    c'est à dire ?
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                                    Anonyme
                                      18 septembre 2014 à 19:34:35

                                      thib3113 a écrit:

                                      nohar a écrit:

                                      # si on suppose que la lecture du son est encapsulée dans la fonction play_sound
                                      


                                      c'est à dire ?

                                      Ça veut dire qu'il faut définir une fonction qui lit un son en boucle et l'exécuter via Process(target=function, args=arguments), genre :

                                      def readloop(wavefile, audiostream):
                                          while True:
                                              frames = wavefile.readframes(1024)
                                              if not frames:
                                                  wavefile.rewind()
                                                  continue
                                              audiostream.write(frames)
                                      
                                      # ...
                                      
                                      # initialiser wavefile et audiostream...
                                      
                                      p = Process(target=readloop, args=(wavefile, audiostream))
                                      p.start()
                                      input("Appuyez sur Entrée pour arrêter le son")
                                      p.terminate()
                                      p.join()
                                      
                                      # fermer wavefile et audiostream...
                                      
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        18 septembre 2014 à 20:07:10

                                        d'accord, mais y as t'il un autre moyen de le fermer ? par exemple, si je lance le script depuis php via une commande bash, comment l'arrété ensuite depuis php ?
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                                        Anonyme
                                          18 septembre 2014 à 20:50:42

                                          Bah du coup pas la peine d'utiliser Process. Il suffit de gérer l'exception KeyboardInterrupt dans ton script Python pour qu'il se ferme proprement avec un kill -SIGINT {pid}.

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            19 septembre 2014 à 10:26:16

                                            Le truc tricky, c'est qu'il faut récupérer le PID du processus qui lit le son pour pouvoir lui envoyer un signal (un TERM, par exemple). La permière idée qui me vient en tête, ce serait de faire un truc à base de commandes système ps ou pgrep, mais y'a sûrement mieux. C'est pour ça que j'ai préféré montrer un code qui forke le processus en cours.

                                            Après ça dépend vraiment de l'architecutre du soft. Sans plus de détail on ne peut pas vraiment répondre.

                                            PS : Un service web en PHP pour un simple réveil ? Ça commence à devenir douteux...

                                            -
                                            Edité par nohar 19 septembre 2014 à 10:28:28

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Zeste de Savoir, le site qui en a dans le citron !
                                              19 septembre 2014 à 12:52:47

                                              pour avoir le PID on peux mettre dans le code un 
                                               print os.getpid()

                                              qui écris donc le PID.

                                              bon en fait c'est un soft pour jouer sur un raspberry pi, il y as donc un coeur sur le raspberry, avec une api JSON et une interface web. Et j'aimerais pouvoir le programmer pour me reveiller le matin ou autre :)

                                              -
                                              Edité par thib3113 19 septembre 2014 à 12:53:17

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                                              Anonyme
                                                19 septembre 2014 à 13:36:41

                                                J'avoue que l'arrivé de l'éléphant dans cette histoire m'a quelque peu surpris. o_O

                                                Mais du coup je ne sais même pas si Python est utile... en fait j'ai pas compris l'idée du réveil gérer en PHP ? Enfin bref, autant le faire en pur bash avec aplay, ça sera encore plus lègé que d'installer portaudio...

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  21 septembre 2014 à 14:48:58

                                                  pour avoir le PID on peux mettre dans le code un [...]

                                                  Je parlais de récupérer le PID d'un autre processus que le processus courant (sinon os.getpid() suffit), qui n'est pas non plus un processus fils du processus courant (parce que dans ce cas, on possède nécessairement le PID du fils au moment où le processus père a fait le fork(), et c'est même géré de façon transparente par le module multiprocessing).

                                                  Là, le fait de ramener PHP dans la boucle, ça te force à devoir récupérer le PID du processus qui fait tourner le son pour le killer (en considérant qu'on parte sur l'envoi d'un signal). Puisque tu lances un script Python alors que tu veux faire un service web en PHP pour l'arrêter (d'ailleurs je comprends pas pourquoi ramener php là dedans, Python sait très bien gérer un service web ainsi que des messages en json), et que de toute façon c'est un cron qui va lancer le son, il faut nécessairement que tu trouves un moyen de te connecter au processus pour lui demander de s'arrêter. En passant par un signal, ça demande de récupérer le PID du processus qui joue le son (et je ne vois, vraiment, aucun autre moyen qu'un gros pgrep moche).

                                                  Sinon, une autre façon de faire, plus élégante, serait que le soft qui joue le son crée une socket Unix, à laquelle n'importe quel programme peut se connecter pour lui envoyer l'ordre d'arrêter le son. C'est encore ce qui me semble le plus propre, conceptuellement parlant, mais pas le plus débutant-friendly.

                                                  -
                                                  Edité par nohar 21 septembre 2014 à 14:52:50

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Zeste de Savoir, le site qui en a dans le citron !
                                                    22 septembre 2014 à 0:51:04

                                                    Pourquoi php et pas python ?

                                                    Car je n'ai pas le niveau en python pour ce que je veux faire.

                                                    Pour ce qui est du PID, je compte lancer le programme via une commande envoyé depuis php ( une tache cron s'occupant d'appeller php toutes les secondes ), donc il me suffit de le stocker, ensuite, je peux envoyer un kill, mais celà fermera le script de manière brutale non ?

                                                    -
                                                    Edité par thib3113 22 septembre 2014 à 0:51:23

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                                                      22 septembre 2014 à 11:00:04

                                                      Define "brutal".

                                                      Sous les unixoïdes, envoyer un SIGTERM, c'est simplement envoyer un signal. C'est un mécanisme comme les autres de communication inter-processus. Du moment que le programme qui reçoit le signal sait le gérer proprement, ça n'a rien de brutal.

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Zeste de Savoir, le site qui en a dans le citron !
                                                        22 septembre 2014 à 12:38:39

                                                        Donc en gros on peux faire qqc après avoir reçu un kill ? je pensais que le kill se contenter de tuer l'application peut importe où on en est dans le programme, sans laisser faire quoi que ce soit au programme
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC
                                                          22 septembre 2014 à 14:26:58

                                                          Tout dépend du signal que tu envoies.

                                                          Un SIGKILL va arrêter le processus de façon brutale.

                                                          Un SIGTERM va demander gentiment au processus de s'arrêter.

                                                          Par défaut, le processus va réagir de la même façon à un TERM ou un KILL, mais la différence entre les deux, c'est que tu peux intercepter le TERM pour tout nettoyer proprement avant de quitter, alors qu'avec un KILL le noyau ne laisse pas le choix au processus et il le tue directement. Quand tu utilises la commande kill dans un shell, c'est un TERM qui est envoyé par défaut. Pour envoyer un SIGKILL il faut faire kill -9. Après y'a plein d'autres signaux possibles, genre SIGALRM, SIGUSR2, SIGHUP, SIGINT... mais dans ton cas le SIGTERM standard colle exactement à la sémantique de ce que tu veux faire.

                                                          Pour intercepter les signaux en Python, tu peux utiliser le module standard signals.

                                                          -
                                                          Edité par nohar 22 septembre 2014 à 14:29:32

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Zeste de Savoir, le site qui en a dans le citron !
                                                            22 septembre 2014 à 16:40:10

                                                            ah, ben si j'arrive à trouver les infos que je cherche dans cette voie, ça me conviendra parfaitement, car c'est ce que je cherchais, je fais mes recherches, et je reviens vers vous
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                            L'erreur ne devient pas vérité parce qu'elle se propage - Gandhi. CV Thibaut SEVERAC

                                                            Pas de son lors de l'éxécution en console

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown