瀏覽代碼

[Feature] #234 player modularity : converting mp3 to wav using param

Done : 
-> Travis back using python requirements instead of setup.py
-> convert_to_wav param
ThiBuff 8 年之前
父節點
當前提交
6be81ca1b7

+ 1 - 2
.travis.yml

@@ -21,8 +21,7 @@ before_install:
 - sudo python get-pip.py
 
 install:
-  - sudo python setup.py install
-  # - pip install -r install/files/python_requirements.txt
+  - pip install -r install/files/python_requirements.txt
   - pip install python2-pythondialog || pip install pythondialog
   - pip install coveralls
 

+ 1 - 0
install/files/deb-packages_requirements.txt

@@ -20,3 +20,4 @@ build-essential
 sox
 libatlas3-base
 mplayer
+ffmpeg

+ 41 - 0
kalliope/PlayerModule.py

@@ -0,0 +1,41 @@
+# coding: utf8
+import logging
+import os
+import subprocess
+
+from kalliope.core.Utils.FileManager import FileManager
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+
+
+class PlayerModule(object):
+    """
+    Mother class of Players. 
+    Ability to convert mp3 to wave format.
+    """
+
+    def __init__(self, **kwargs):
+
+        # set parameter from what we receive from the settings
+        self.convert = kwargs.get('convert_to_wav', True)
+
+    @staticmethod
+    def convert_mp3_to_wav(file_path_mp3):
+        """ 
+        PyAudio, AlsaPlayer, sounddevices  do not support mp3 files 
+        MP3 files must be converted to a wave in order to be played
+        This function assumes ffmpeg is available on the system
+        :param file_path_mp3: the file path to convert from mp3 to wav
+        """
+        logger.debug("Converting mp3 file to wav file: %s" % file_path_mp3)
+        fnull = open(os.devnull, 'w')
+        # temp file
+        tmp_file_wav = file_path_mp3 + ".wav"
+        # Convert mp3 to wave
+        subprocess.call(['ffmpeg', '-y', '-i', file_path_mp3, tmp_file_wav],
+                        stdout=fnull, stderr=fnull)
+        # remove the original file
+        FileManager.remove_file(file_path_mp3)
+        # rename the temp file with the same name as the original file
+        os.rename(tmp_file_wav, file_path_mp3)

+ 1 - 21
kalliope/core/TTS/TTSModule.py

@@ -157,24 +157,4 @@ class TTSModule(object):
             logger.debug("TTSModule, File already in cache: %s" % file_path)
         else:
             logger.debug("TTSModule, File not yet in cache: %s" % file_path)
-        return exist_in_cache
-
-    @staticmethod
-    def convert_mp3_to_wav(file_path_mp3):
-        """ 
-        PyAudio does not support mp3 files 
-        MP3 files must be converted to a wave in order to be played
-        This function assumes ffmpeg is available on the system
-        :param file_path_mp3: the file path to convert from mp3 to wav
-        """
-        logger.debug("Converting mp3 file to wav file: %s" % file_path_mp3)
-        fnull = open(os.devnull, 'w')
-        # temp file
-        tmp_file_wav = file_path_mp3 + ".wav"
-        # Convert mp3 to wave
-        subprocess.call(['ffmpeg', '-y', '-i', file_path_mp3, tmp_file_wav],
-                           stdout=fnull, stderr=fnull)
-        # remove the original file
-        FileManager.remove_file(file_path_mp3)
-        # rename the temp file with the same name as the original file
-        os.rename(tmp_file_wav, file_path_mp3)
+        return exist_in_cache

+ 9 - 6
kalliope/players/pyalsaaudio/pyalsaaudio.py

@@ -3,6 +3,8 @@ import alsaaudio
 import logging
 import wave
 
+from kalliope.PlayerModule import PlayerModule
+
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 
@@ -30,12 +32,13 @@ def bits_to_samplefmt(bits):
         raise ValueError('Unsupported format')
 
 
-class Pyalsaaudio(object):
+class Pyalsaaudio(PlayerModule):
     """
     This Class is representing the Player Object used to play the all sound of the system.
     """
 
     def __init__(self, **kwargs):
+        super(Pyalsaaudio, self).__init__(**kwargs)
         # List devices
         logger.debug("[pyalsaaudio.__init__] instance")
         logger.debug("[pyalsaaudio.__init__] devices : %s " % (str(self.get_devices(DEVICE_TYPE_OUTPUT))))
@@ -58,14 +61,13 @@ class Pyalsaaudio(object):
 
     def play(self, file_path):
 
+        if self.convert:
+            self.convert_mp3_to_wav(file_path_mp3=file_path)
         f = wave.open(file_path, 'rb')
         pcm_type = alsaaudio.PCM_PLAYBACK
         stream = alsaaudio.PCM(type=pcm_type,
                                mode=alsaaudio.PCM_NORMAL,
-                               device=self.device)  # this is just for testing
-                               # device='sysdefault:CARD=ALSA')  # this is just for testing
-                                # on RPI3 this is fine; pulse (usually also default) is not working
-                                # device should be configurable; default schould be "default"
+                               device=self.device)
         # Set attributes
         stream.setchannels(f.getnchannels())
         stream.setrate(f.getframerate())
@@ -74,7 +76,8 @@ class Pyalsaaudio(object):
         stream.setperiodsize(CHUNK)
         
         logger.debug("[PyAlsaAudioPlayer] %d channels, %d sampling rate, %d bit" % (f.getnchannels(),
-                                                                            f.getframerate(),  bits))
+                                                                                    f.getframerate(),
+                                                                                    bits))
         
         data = f.readframes(CHUNK)
         while data:

+ 7 - 3
kalliope/players/pyaudioplayer/pyaudioplayer.py

@@ -4,28 +4,32 @@ import wave
 
 import pyaudio
 
+from kalliope.PlayerModule import PlayerModule
+
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 
 CHUNK = 1024
 
 
-class Pyaudioplayer(object):
+class Pyaudioplayer(PlayerModule):
     """
     This Class is representing the Player Object used to play the all sound of the system.
     """
 
     def __init__(self, **kwargs):
+        super(Pyaudioplayer, self).__init__(**kwargs)
         logger.debug("[Pyaudioplayer.__init__] instance")
         logger.debug("[Pyaudioplayer.__init__] args : %s " % str(kwargs))
 
-    @classmethod
-    def play(cls, file_path):
+    def play(self, file_path):
         """
         Play the sound located in the provided file_path
         :param file_path: The file path of the sound to play. Must be wav format
         :type file_path: str              
         """
+        if self.convert:
+            self.convert_mp3_to_wav(file_path_mp3=file_path)
         # open the wave file
         wf = wave.open(file_path, 'rb')
 

+ 7 - 3
kalliope/players/sounddeviceplayer/sounddeviceplayer.py

@@ -3,24 +3,28 @@ import sounddevice as sd
 import soundfile as sf
 import logging
 
+from kalliope.PlayerModule import PlayerModule
+
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 
 FS = 48000
 
 
-class Sounddeviceplayer(object):
+class Sounddeviceplayer(PlayerModule):
     """
     This Class is representing the Player Object used to play the all sound of the system.
     """
 
     def __init__(self, **kwargs):
+        super(Sounddeviceplayer, self).__init__(**kwargs)
         logger.debug("[Sounddeviceplayer.__init__] instance")
         logger.debug("[Sounddeviceplayer.__init__] args : %s " % str(kwargs))
 
-    @classmethod
-    def play(cls, file_path):
+    def play(self, file_path):
 
+        if self.convert:
+            self.convert_mp3_to_wav(file_path_mp3=file_path)
         data, fs = sf.read(file_path)
         sd.play(data, fs)
         sd.wait()

+ 16 - 14
kalliope/settings.yml

@@ -37,15 +37,15 @@ speech_to_text:
   - google:
       language: "fr-FR"
   - wit:
-      key: "B5JI3YUSLYOYWNIDBINBVM34XUODME2K"
+      key: "fakekey" # example : "B5JI3YUSLYOYWNIDBINBVM34XUODME2K"
   - bing: # API not working : credential fails ..
-      key: "9e48ddaf75904838bedc11aea6b36fb0"
+      key: "fakekey" # example : "9e48ddaf75904838bedc11aea6b36fb0"
   - apiai:
-      key: "e0cbff154af44944a6b9f82c0668b527"
+      key: "fakekey" # example : "e0cbff154af44944a6b9f82c0668b527"
       language: "fr"
   - houndify:
-      key: "7zj90T7qAV74OYXk4X4vI2Xhk7wPsJu4aEZ0G5Ll-BMmV1JGtFpCxtSH9SmTY4G3bpEJ7a5y_GTQid-CAKI6vw=="
-      client_id: "lN4JXeaSticbSo9-llczbA=="
+      key: "fakekey" # example : "7zj90T7qAV74OYXk4X4vI2Xhk7wPsJu4aEZ0G5Ll-BMmV1JGtFpCxtSH9SmTY4G3bpEJ7a5y_GTQid-CAKI6vw=="
+      client_id: "fakeclientid" # example : "lN4JXeaSticbSo9-llczbA=="
   #- cmusphinx
 
 
@@ -60,10 +60,9 @@ cache_path: "/tmp/kalliope_tts_cache"
 # Text to Speech engines configuration
 # Available engine are:
 # - pico2wave
-# - acapela
-# - pico2wave
-# - googletts
-# - voicerss
+# - acapela     # MP3
+# - googletts   # MP3
+# - voicerss    # MP3
 text_to_speech:
   - pico2wave:
       language: "fr-FR"
@@ -88,15 +87,18 @@ default_player: "mplayer"
 # players configuration
 # Available engine are:
 # - mplayer
-# - pyalsaaudio
-# - pyaudioplayer
-# - sounddeviceplayer
+# - pyalsaaudio       # no mp3
+# - pyaudioplayer     # no mp3
+# - sounddeviceplayer # no mp3
 players:
   - mplayer: {}
   - pyalsaaudio:
      device: "default"
-  - pyaudioplayer: {}
-  - sounddeviceplayer: {}
+     convert_to_wav: True
+  - pyaudioplayer:
+     convert_to_wav: True
+  - sounddeviceplayer:
+     convert_to_wav: True
 
 # ---------------------------
 # Wake up answers

+ 0 - 3
kalliope/tts/acapela/acapela.py

@@ -77,9 +77,6 @@ class Acapela(TTSModule):
         # OK we get the audio we can write the sound file
         FileManager.write_in_file(self.file_path, r.content)
 
-        # the received file use MP3 format. It must be converted to wav in order to be played by pyaudio
-        self.convert_mp3_to_wav(self.file_path)
-
     def get_payload(self):
         """
         Generic method used load the payload used to access the remote api

+ 1 - 1
setup.py

@@ -67,7 +67,7 @@ setup(
         'markupsafe>=1.0',
         'pyaudio>=0.2.10',
         'pyasn1>=0.2.3',
-        'ansible>=2.2',
+        'ansible>=2.3',
         py2_prefix + 'pythondialog>=3.4.0',
         'jinja2>=2.8,<=2.9.6',
         'cffi>=1.9.1',