Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(tts): use bitbots_tts consistently #529

Merged
merged 1 commit into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 13 additions & 31 deletions bitbots_misc/bitbots_tts/bitbots_tts/tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import rclpy
import requests
from ament_index_python import get_package_prefix
from rcl_interfaces.msg import Parameter, SetParametersResult
from rclpy.node import Node
from rclpy.publisher import Publisher
Expand All @@ -24,6 +25,13 @@ def speak(text: str, publisher: Publisher, priority: int = 20, speaking_active:
publisher.publish(msg)


def say(text: str) -> None:
"""Start the shell `say.sh` script to output given text with mimic3. Beware: this is blocking."""
script_path = os.path.join(get_package_prefix("bitbots_tts"), "lib/bitbots_tts/say.sh")
process = subprocess.Popen((script_path, text))
process.wait()


class Speaker(Node):
"""
Uses tts to say messages from the speak topic.
Expand All @@ -50,17 +58,6 @@ def __init__(self) -> None:
# Callback for parameter changes
self.add_on_set_parameters_callback(self.on_set_parameters)

# Mapping from robot name to voice name
self.robot_voice_mapping = {
"amy": "en_US/vctk_low",
"donna": "en_US/vctk_low",
"jack": "en_UK/apope_low",
"melody": "en_US/vctk_low",
"rory": "en_UK/apope_low",
}

self.robot_speed_mapping = {"amy": 2.2, "donna": 2.2, "jack": 1.0, "melody": 2.2, "rory": 1.0}

# Subscribe to the speak topic
self.create_subscription(Audio, "speak", self.speak_cb, 10)

Expand Down Expand Up @@ -92,30 +89,15 @@ def on_set_parameters(self, parameters: List[Parameter]) -> SetParametersResult:
return SetParametersResult(successful=True)

def run_speaker(self) -> None:
"""Continously checks the queue and speaks the next message."""
"""Continuously checks the queue and speaks the next message."""
# Check if there is a message in the queue
if len(self.prio_queue) > 0:
# Get the next message and speak it
text, _ = self.prio_queue.pop(0)
self.say(text)

def say(self, text: str) -> None:
"""Speak this specific text."""
# Get the voice name from the environment variable ROBOT_NAME or use the default voice if it's not set
voice = self.robot_voice_mapping.get(os.getenv("ROBOT_NAME"), "en_US/vctk_low")
# Get the speed for the given robot or use the default speed if no robot name is set
speed = self.robot_speed_mapping.get(os.getenv("ROBOT_NAME"), 2.2)
try:
# Generate the speech with mimic
mimic_subprocess = subprocess.Popen(
("mimic3", "--remote", "--voice", voice, "--length-scale", str(speed), text), stdout=subprocess.PIPE
)
# Play the audio from the previous process with aplay
aplay_subprocess = subprocess.Popen(("aplay", "-"), stdin=mimic_subprocess.stdout, stdout=subprocess.PIPE)
# Wait for the process to finish
aplay_subprocess.wait()
except OSError:
self.get_logger().error(str(traceback.format_exc()))
try:
say(text)
except OSError:
self.get_logger().error(str(traceback.format_exc()))

def speak_cb(self, msg: Audio) -> None:
"""Handles incoming msg on speak topic."""
Expand Down
4 changes: 3 additions & 1 deletion bitbots_misc/bitbots_tts/launch/tts.launch
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<launch>
<executable cmd="mimic3-server --preload-voice en_US/vctk_low --cache-dir $(env HOME)/.cache/mimic3/" name="mimic3-server" output="screen"/>
<!-- Do not launch mimic3-server on robot, as it is running as a systemd service -->
<executable unless="$(env IS_ROBOT)" cmd="mimic3-server --preload-voice en_US/vctk_low --preload-voice en_UK/apope_low --cache-dir $(env HOME)/.cache/mimic3/" name="mimic3-server" output="screen"/>

<node name="bitbots_tts" pkg="bitbots_tts" exec="tts">
<param from="$(find-pkg-share bitbots_tts)/config/tts_config.yaml"/>
</node>
Expand Down
30 changes: 30 additions & 0 deletions bitbots_misc/bitbots_tts/scripts/say.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -eEuo pipefail

ROBOT_NAME="${ROBOT_NAME:-}"

# Mapping robot name to voice and speed
case "$ROBOT_NAME" in
"jack"|"rory")
voice="en_UK/apope_low"
speed=1.0
;;
"amy"|"donna"|"melody"|"rose")
voice="en_US/vctk_low"
speed=1.7
;;
*)
echo "Unknown robot: '$ROBOT_NAME', using default female voice"
voice="en_US/vctk_low"
speed=1.7
;;
esac

text="$1"
if [ -z "$text" ]; then
echo "No text provided!"
exit 1
fi

# Generate the speech with mimic and play it with alsa
mimic3 --remote --voice "$voice" --length-scale "$speed" "$text" | aplay -q -
19 changes: 19 additions & 0 deletions bitbots_misc/bitbots_tts/scripts/speak_ip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python3

import os
from socket import gethostname

from bitbots_tts.tts import say
from netifaces import AF_INET, ifaddresses, interfaces

ip_address = "not set"

wifi_interface = next(filter(lambda i: i.startswith("wlp"), interfaces()), None)
if wifi_interface and AF_INET in ifaddresses(wifi_interface):
ip_address = ifaddresses(wifi_interface)[AF_INET][0]["addr"]

ip = " dot ".join(ip_address.split("."))

robot_name = os.getenv("ROBOT_NAME") or gethostname()
msg = f"Startup complete: {robot_name}. My wifi IP is {ip}."
say(msg)
2 changes: 1 addition & 1 deletion bitbots_misc/bitbots_tts/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
install_requires=[
"setuptools",
],
scripts=["scripts/send_text.py"],
scripts=glob.glob("scripts/*"),
entry_points={
"console_scripts": [
"tts = bitbots_tts.tts:main",
Expand Down
26 changes: 0 additions & 26 deletions bitbots_misc/bitbots_utils/scripts/speak_ip.py

This file was deleted.

Loading