omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Voice recorder and play sound

    Pythonista
    4
    18
    3749
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • geniu
      geniu @JonB last edited by

      @JonB said:

      @geniu Player(filename) loads the file when the Player is created. So it should be clear that, since your file has not yet been recorded, the player is loading the old file.

      a better approach would be to set the play button disabled initially, and during the record function. then, enable it in stop_record. instantiate the Player as a local variable within the play button action, so it always reloads the file.

      I am not sure we have the ability to easily control which speake is used, except by using an objc approach.

      Thank you for explaining. Now it clear for me. I've tried to create Player in a play function firstly, but it doesn't seem to work. It plays nothing

      cvp 1 Reply Last reply Reply Quote 0
      • cvp
        cvp @geniu last edited by cvp

        @geniu said:

        It plays nothing

        Sure that your file exists and is not empty? Try it by tapping on it in the Pythonista files browser, then Quick Look, then the play button

        geniu 1 Reply Last reply Reply Quote 0
        • JonB
          JonB last edited by

          One problem may be that you need to keep a reference to the player object, otherwise it is deleted as soon as the action returns.

          Try creating a custom class to hold your button actions, or a custom view, then you can simply use self.player = sound.Player(file) and self.player.play() inside your action. Or, you could add an attribute to the button, using sender.

          1 Reply Last reply Reply Quote 0
          • geniu
            geniu @cvp last edited by

            @cvp said:

            @geniu said:

            It plays nothing

            Sure that your file exists and is not empty? Try it by tapping on it in the Pythonista files browser, then Quick Look, then the play button

            Yes, I am. I can play it by Quick Look.
            And print(os.listdir()) inside the play function shows that the file exists. And I can play it from console by creation a new Player instance

            cvp 2 Replies Last reply Reply Quote 0
            • cvp
              cvp @geniu last edited by

              @geniu ok, then follow @JonB 's advice

              1 Reply Last reply Reply Quote 0
              • cvp
                cvp @geniu last edited by

                @geniu something like

                import sound
                from sound import Player
                import ui
                
                def play(sender):
                  sender.player.play()
                  
                v_str = '''
                [
                  {
                    "nodes" : [
                      {
                        "nodes" : [
                
                        ],
                        "frame" : "{{80, 104}, {80, 32}}",
                        "class" : "Button",
                        "attributes" : {
                          "action" : "play",
                          "frame" : "{{80, 104}, {80, 32}}",
                          "title" : "Play",
                          "uuid" : "1D1987D9-DAFA-4228-A0D4-CCDBE54B962B",
                          "class" : "Button",
                          "name" : "play_button",
                          "font_size" : 15,
                          "border_width" : 1
                        },
                        "selected" : true
                      }
                    ],
                    "frame" : "{{0, 0}, {240, 240}}",
                    "class" : "View",
                    "attributes" : {
                      "enabled" : true,
                      "background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)",
                      "tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)",
                      "border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
                      "flex" : ""
                    },
                    "selected" : false
                  }
                ]
                '''
                
                v = ui.load_view_str(v_str)
                v['play_button'].player = Player('4.m4a')
                v.present('sheet')
                
                geniu 1 Reply Last reply Reply Quote 0
                • geniu
                  geniu @cvp last edited by

                  @cvp said:

                  @geniu something like

                  import sound
                  from sound import Player
                  import ui
                  
                  def play(sender):
                    sender.player.play()
                    
                  v_str = '''
                  [
                    {
                      "nodes" : [
                        {
                          "nodes" : [
                  
                          ],
                          "frame" : "{{80, 104}, {80, 32}}",
                          "class" : "Button",
                          "attributes" : {
                            "action" : "play",
                            "frame" : "{{80, 104}, {80, 32}}",
                            "title" : "Play",
                            "uuid" : "1D1987D9-DAFA-4228-A0D4-CCDBE54B962B",
                            "class" : "Button",
                            "name" : "play_button",
                            "font_size" : 15,
                            "border_width" : 1
                          },
                          "selected" : true
                        }
                      ],
                      "frame" : "{{0, 0}, {240, 240}}",
                      "class" : "View",
                      "attributes" : {
                        "enabled" : true,
                        "background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)",
                        "tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)",
                        "border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
                        "flex" : ""
                      },
                      "selected" : false
                    }
                  ]
                  '''
                  
                  v = ui.load_view_str(v_str)
                  v['play_button'].player = Player('4.m4a')
                  v.present('sheet')
                  

                  Thank you. I'll try and let you know if this works.

                  1 Reply Last reply Reply Quote 0
                  • geniu
                    geniu last edited by

                    @cvp this doesn't work. Play still plays after reload app.
                    @JonB, could you give an example how can I make a custom class?

                    cvp 1 Reply Last reply Reply Quote 0
                    • cvp
                      cvp @geniu last edited by

                      @geniu said:

                      Play still plays after reload app.

                      I have tested with a .m4a file of only one word, thus...

                      1 Reply Last reply Reply Quote 0
                      • geniu
                        geniu last edited by

                        Here is my new code.

                        import ui
                        from sound import Recorder
                        from sound import Player
                        
                        
                        
                        class recorderView(ui.View):
                          def __init__(self):
                            self.file = '4.m4a'
                            self.player = Player(self.file)
                            self.recorder = Recorder(self.file)
                            record_button = ui.ButtonItem()
                            record_button.title = 'record'
                            record_button.action = self.rec
                            play_button = ui.ButtonItem()
                            play_button.title = 'play'
                            play_button.tint_color = 'red'
                            play_button.action = self.play
                            self.right_button_items = [record_button, play_button]
                            
                          def rec(self, sender):
                            self.recorder.record(3)
                            print(self.recorder.recording)
                            
                          def play(self, sender):
                            print('before calling play method:', self.player.playing)
                            self.player.play()
                            
                            print('after calling play method:', self.player.playing)
                            
                          
                        v = recorderView()
                        v.name = 'Recorder'
                        v.present('sheet')
                          
                            
                        
                        

                        And here is the piece of play method’s code:

                        
                        print('before calling play method:', self.player.playing)
                            self.player.play()
                            
                            print('after calling play method:', self.player.playing)
                        
                        

                        After launch app if I firstly tap the play button sound is playing and output is:

                        before calling play method: False
                        after calling play method: True

                        But after recording sound is not playing although player exists.
                        Because I can get player’s attributes.
                        The output is:

                        before calling play method: False
                        after calling play method: False

                        JonB 1 Reply Last reply Reply Quote 0
                        • JonB
                          JonB last edited by

                          see
                          https://gist.github.com/0a8414b4d0edc8a104136f5a88c0acc1
                          for a simple implementation using a custom View Class.

                          If you want to use a custom view class with the ui designer, you need to specify the custom class name when you create the ui, then you dont need to create the buttons manually, but you would want to assign convience attributes and actions inside view_did_load... but i digress.

                          This could all be done using sender.superview to get to the root view, and just add custom attributes to the superview -- so no custom class, you would just replace self with sender.superview -- but a class makes everything much cleaner.

                          Here, i create the player as soon as the recording stops, rather than every play press -- that saves you from having to create a new Player every time. probably, you could create the Recorder once, in the init, but if you want to be able to change file name dynamically, you would create in the record callback as i did.

                          I got a little fancy, and turn the record/play into the stop button, and disable the other button while playing or recording, which eliminates the need for a third button.

                          One advantage of a custom class is you can define a custom update method, which in this case can display recorder/player times. you can also define a custom draw() method, which would let you show peak/average bars while recording.

                          1 Reply Last reply Reply Quote 1
                          • JonB
                            JonB @geniu last edited by

                            @geniu your problem was that you were still creating the Player before the file was created.

                            think of sound.Player(file) as reading the file as soon as you create the Player... because that is exactly what it does, so it can precache the sound for efficiency.

                            so, you must create the player only after the recording stops.
                            if you are using record(3) to record 3 seconds, you'd need to use ui.delay to call another method that arms the player once recorder is done (unfortunately, record doesnt have a finish handler). or create it inside the play callback, just be sure to assign it to self.player so that the object doesnt get deleted while it is playing.

                            1 Reply Last reply Reply Quote 1
                            • geniu
                              geniu last edited by

                              @JonB, i appreciate your help. Thank you. I need some time to process your answer but now I think everything will be fine.

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post
                              Powered by NodeBB Forums | Contributors