diff --git a/sound_play/msg/SoundRequest.msg b/sound_play/msg/SoundRequest.msg index 241628c7..ad51069b 100644 --- a/sound_play/msg/SoundRequest.msg +++ b/sound_play/msg/SoundRequest.msg @@ -25,6 +25,7 @@ int8 command # Indicates what to do with the sound # Volume at which to play the sound, with 0 as mute and 1.0 as 100%. float32 volume +float32 reverb string arg # file name or text to say string arg2 # other arguments diff --git a/sound_play/scripts/soundplay_node.py b/sound_play/scripts/soundplay_node.py index 4e7eaf50..f8db81d3 100755 --- a/sound_play/scripts/soundplay_node.py +++ b/sound_play/scripts/soundplay_node.py @@ -86,12 +86,13 @@ def stopall(self): def select_sound(self, data): if data.sound == SoundRequest.PLAY_FILE: if not data.arg2: - if data.arg not in self.filesounds.keys(): + if data.arg not in self.filesounds.keys()\ + or self.filesounds[data.arg].reverb != data.reverb: rospy.logdebug( 'command for uncached wave: "%s"' % data.arg) try: self.filesounds[data.arg] = SoundType( - data.arg, self.device, data.volume) + data.arg, self.device, data.volume, data.reverb) except Exception: rospy.logerr( 'Error setting up to play "%s".' @@ -115,7 +116,7 @@ def select_sound(self, data): 'command for uncached wave: "%s"' % absfilename) try: self.filesounds[absfilename] = SoundType( - absfilename, self.device, data.volume) + absfilename, self.device, data.volume, data.reverb) except Exception: rospy.logerr( 'Error setting up to play "%s" from package "%s".' @@ -135,7 +136,8 @@ def select_sound(self, data): sound = self.filesounds[absfilename] elif data.sound == SoundRequest.SAY: voice_key = data.arg + '---' + data.arg2 - if voice_key not in self.voicesounds.keys(): + if voice_key not in self.voicesounds.keys()\ + or self.voicesounds[voice_key].reverb != data.reverb: rospy.logdebug('command for uncached text: "%s"' % voice_key) if self.plugin is None: rospy.logerr( @@ -151,7 +153,7 @@ def select_sound(self, data): rospy.logerr('Failed to generate wavfile.') else: self.voicesounds[voice_key] = SoundType( - wavfilename, self.device, data.volume) + wavfilename, self.device, data.volume, data.reverb) else: rospy.logdebug('command for cached text: "%s"' % voice_key) voicesound = self.voicesounds[voice_key] @@ -171,7 +173,7 @@ def select_sound(self, data): if params[1] != 1: volume = (volume + params[1])/2 self.builtinsounds[data.sound] = SoundType( - params[0], self.device, volume) + params[0], self.device, volume, data.reverb) sound = self.builtinsounds[data.sound] if sound.staleness != 0 and data.command != SoundRequest.PLAY_STOP: # This sound isn't counted in active_sounds diff --git a/sound_play/src/sound_play/libsoundplay.py b/sound_play/src/sound_play/libsoundplay.py index fa693a14..87a146aa 100644 --- a/sound_play/src/sound_play/libsoundplay.py +++ b/sound_play/src/sound_play/libsoundplay.py @@ -163,9 +163,9 @@ def builtinSound(self, id, volume=1.0): ## ## \param text String to say - def say(self,text, voice='', volume=1.0, **kwargs): + def say(self,text, voice='', volume=1.0, reverb=0.0, **kwargs): self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_ONCE, text, voice, - volume, **kwargs) + volume, reverb, **kwargs) ## \brief Say a string repeatedly ## @@ -303,7 +303,7 @@ def stopAll(self): self.stop(SoundRequest.ALL) def sendMsg( - self, snd, cmd, s, arg2="", vol=1.0, replace=True, + self, snd, cmd, s, arg2="", vol=1.0, rv=0.0, replace=True, server_timeout=None, result_timeout=None, **kwargs ): @@ -324,6 +324,7 @@ def sendMsg( msg.sound = snd # Threshold volume between 0 and 1. msg.volume = max(0, min(1, vol)) + msg.reverb = max(0, min(1, rv)) msg.command = cmd msg.arg = s msg.arg2 = arg2 diff --git a/sound_play/src/sound_play/sound_type.py b/sound_play/src/sound_play/sound_type.py index e5f089bf..d4a1144f 100644 --- a/sound_play/src/sound_play/sound_type.py +++ b/sound_play/src/sound_play/sound_type.py @@ -1,4 +1,7 @@ import os +from pedalboard.io import AudioFile +from pedalboard import Pedalboard, Reverb +import tempfile import threading import rospy @@ -25,7 +28,7 @@ class SoundType(object): LOOPING = 1 COUNTING = 2 - def __init__(self, file, device, volume=1.0): + def __init__(self, file, device, volume=1.0, reverb=0.0): self.lock = threading.RLock() self.state = self.STOPPED self.sound = Gst.ElementFactory.make("playbin", None) @@ -38,17 +41,33 @@ def __init__(self, file, device, volume=1.0): self.sound.set_property("audio-sink", self.sink) if (":" in file): - uri = file + input_file = file.replace("file://") elif os.path.isfile(file): - uri = "file://" + os.path.abspath(file) + input_file = file else: rospy.logerr('Error: URI is invalid: %s' % file) + if reverb > 0.0: + (wavfile, wavfilename) = tempfile.mkstemp( + prefix='sound_play', suffix='.wav') + os.close(wavfile) + board = Pedalboard([Reverb(room_size=reverb)]) + with AudioFile(input_file) as f: + with AudioFile(wavfilename, 'w', f.samplerate, f.num_channels) as o: + while f.tell() < f.frames: + chunk = f.read(f.samplerate) + effected = board(chunk, f.samplerate, reset=False) + o.write(effected) + uri = "file://" + os.path.abspath(wavfilename) + else: + uri = "file://" + os.path.abspath(input_file) + self.uri = uri self.volume = volume self.sound.set_property('uri', uri) self.sound.set_property("volume", volume) self.staleness = 1 + self.reverb = reverb self.file = file self.bus = self.sound.get_bus()