Skip to content
Open
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
54 changes: 54 additions & 0 deletions components/TTS/src/genericworker.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,47 @@

class GenericWorker(QtCore.QObject):

"""
Initializes a worker object that can be controlled by signals and slots,
enabling it to be killed remotely via a "kill" signal. It also allows setting
a timer period in milliseconds, restarting it as needed.

Attributes:
kill (QtCoreSignal): Initialized with a value of `QtCore.Signal()`. It
represents a signal emitted by the worker to indicate that it should
be terminated.
emotionalmotor_proxy (Dict[str,QObject]): Initialized from a dictionary
`mprx`. It references a proxy object for Emotional Motor functionality,
likely related to motor control or manipulation.
recorder_proxy (Dict[str,any]|Dict[str,object]): Initialized with a value
from the dictionary `mprx`. It is assigned the proxy to a recorder
object. The specific details are not shown in this code snippet.
mutex (QtCoreQMutex): Created to be used as a mutex (short for mutual
exclusion), a synchronization primitive that allows only one thread
to access shared resources at a time, providing data protection.
Period (int): 30 by default, representing a timer period in milliseconds
that controls when events are triggered.
timer (QtCoreQTimer|None): Used to trigger a signal at regular intervals
based on its Period value. It is set up to start when the Period is
updated or initially configured with a Period of 30 seconds.

"""
kill = QtCore.Signal()

def __init__(self, mprx):
"""
Initializes and sets up an instance with its parent object, assigning
specified proxies to specific attributes, creating a mutex for thread
safety, setting a timer interval, and instantiating a QTimer object
associated with the GenericWorker instance.

Args:
mprx (Dict[str, object]): Expected to be a dictionary containing proxies
for other objects. Specifically, it contains keys "EmotionalMotorProxy"
and "RecorderProxy", each associated with an instance of a class
implementing those interfaces.

"""
super(GenericWorker, self).__init__()

self.emotionalmotor_proxy = mprx["EmotionalMotorProxy"]
Expand All @@ -51,13 +89,29 @@ def __init__(self, mprx):

@QtCore.Slot()
def killYourSelf(self):
"""
Emits a signal to kill itself, logging a debug message "Killing myself"
before doing so. This implies self-termination upon a certain condition
or user request.

"""
rDebug("Killing myself")
self.kill.emit()

# \brief Change compute period
# @param per Period in ms
@QtCore.Slot(int)
def setPeriod(self, p):
"""
Updates the period value, prints a message with the new period value, and
starts a timer with the updated period.

Args:
p (int): Referenced as a period value. It is intended to represent an
interval duration, possibly for timing-related purposes within the
class's functionality.

"""
print("Period changed", p)
self.Period = p
self.timer.start(self.Period)
134 changes: 134 additions & 0 deletions components/TTS/src/specificworker.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,56 @@
# import librobocomp_innermodel

class SpecificWorker(GenericWorker):
"""
Implements a worker that reads text from a queue, processes it using various
speech synthesis engines (Festival or Google TTS), and outputs synthesized
speech to an emotional motor proxy. It also handles startup checks, timer
events, and parameter updates.

Attributes:
Period (int): 2000 by default. It is used to specify the interval, in
milliseconds, at which the worker's `compute` method will be executed
when the `timer` starts.
audioenviado (bool): Initialized to False in the `__init__` method. It
does not seem to be used anywhere else in the code, implying it might
be a leftover or unused variable.
pitch (float|int): Initialized to a value of 1. It controls the pitch
adjustment applied to speech synthesis, with its value being multiplied
by 4 when set via the `Speech_setPitch` method.
tempo (float): 1 by default, representing the playback speed of speech
generated using `pyttshtts`. It can be modified by calling the
`Speech_setTempo` method.
text_queue (Queue[maxsize]): Initialized with a maximum size equal to
max_queue, which is not defined within this code snippet. It stores
text items to be processed by the `compute` method.
startup_check (bool): Used as a parameter for its constructor (`__init__`).
It determines whether the startup check method is called or not when
creating an instance of this class.
timer (QTimer|None): Initialized with a default value of None, which is
then set to a QTimer object when the `startup_check` flag is False in
the `__init__` method.
compute (QtCorepyqtSignal|None): Associated with the slot method of the
same name, which is connected to a QTimer's timeout signal. It is
called when the timer times out.

"""
def __init__(self, proxy_map, startup_check=False):
"""
Initializes its attributes and sets up event handling for a timer, which
triggers the compute function at regular intervals when startup checking
is not enabled. Startup checking is an optional feature that can be disabled
or enabled during initialization.

Args:
proxy_map (Dict[str, int]): Passed to the superclass's `__init__`
method. The key-value pairs of this map are used for initializing
the object with proxy information.
startup_check (bool): Set to False by default. It determines whether
or not to perform a startup check, which can be implemented in the
`self.startup_check()` method if True. Otherwise, it enables timer
functionality.

"""
super(SpecificWorker, self).__init__(proxy_map)
self.Period = 2000
self.audioenviado = False
Expand All @@ -60,6 +109,22 @@ def __del__(self):
print('SpecificWorker destructor')

def setParams(self, params):
"""
Sets or updates the value of the `_tts` attribute based on the presence
of a "tts" key in the params dictionary. If present, it assigns the tts
parameter to _tts; otherwise, it defaults to "festival". The function
returns True.

Args:
params (Dict[str, str | bool | int]): Used to set various parameters
for an object. It contains key-value pairs where keys are strings
and values can be strings, boolean values, or integers.

Returns:
bool: True, regardless of whether the input parameters are valid or
not. The code ignores any potential exceptions and continues executing.

"""
if "tts" in params:
self._tts = params["tts"]
else:
Expand All @@ -74,6 +139,12 @@ def setParams(self, params):

@QtCore.Slot()
def compute(self):
"""
Retrieves text from a queue, replaces specific characters with their escaped
versions, and then passes it to another method called `habla`. This process
is executed when there are items available in the queue.

"""
if self.text_queue.empty():
pass
else:
Expand All @@ -84,6 +155,18 @@ def compute(self):
self.habla(text_to_say)

def habla(self, text):
"""
Initiates voice synthesis by printing a given text, engaging an emotional
motor proxy, generating speech using pyttsx, and then disengaging the
emotional motor proxy.

Args:
text (str | None): Used as input for printing, Google TTS synthesis
via pyttshtts, and emotional motor interaction. Its presence is
checked by default due to Python's syntax rules requiring a value
in each argument position.

"""
try:
print(text)
self.emotionalmotor_proxy.talking(True)
Expand All @@ -97,12 +180,41 @@ def habla(self, text):
print("\033[91m You can try to install it with pip install gTTS playsound\033[00m")

def Speech_say(self, text, owerwrite):
"""
Adds text to a queue for speech processing. If overwrite is True, it clears
any existing items from the queue before adding the new text. The method
returns True upon successful execution.

Args:
text (str | bytes): A message to be queued for speech output. It
represents the actual text to be spoken, which can be either a
string or bytes object.
owerwrite (bool): Used to determine whether to reset the text queue
or not when set to True, indicating that it should be overwritten
with new text on each invocation.

Returns:
bool: `True`. This indicates that the text has been successfully added
to the queue. The function always returns `True` regardless of whether
the overwrite flag is set or not.

"""
if owerwrite:
self.text_queue = Queue(max_queue)
self.text_queue.put(text)
return True

def pyttshtts(self, text):
"""
Plays a synthesized text-to-speech output in Spanish, with custom pitch
and tempo settings determined by the instance's pitch and tempo attributes.
It utilizes the Speech object to generate speech from the input text.

Args:
text (str | bytes): Required, but its exact description cannot be
determined from this snippet alone.

"""
lang = "es"
speech = Speech(text, lang)
# speech.play()
Expand All @@ -116,11 +228,33 @@ def pyttshtts(self, text):

def Speech_setPitch(self, pitch):

"""
Sets and prints the pitch value to a local attribute, increasing it by a
factor of four times the input value. This modification effectively amplifies
the pitch before storing and displaying it. The method does not directly
affect external speech properties.

Args:
pitch (float | int): Used to modify or set the pitch property, which
controls the frequency or tone of the speech. Its value is multiplied
by 4 and stored in an instance variable.

"""
self.pitch = pitch*4
print(self.pitch)

def Speech_setTempo(self, tempo):

"""
Sets a tempo value for speech, taking an input tempo and dividing it by
10 to adjust it to an internal representation, then prints the adjusted value.

Args:
tempo (float | int): Intended to represent a tempo value, with a scaling
factor implicitly applied within the function body. It appears to
be normalized by a division by 10.

"""
self.tempo = tempo/10
print(self.tempo)

12 changes: 12 additions & 0 deletions components/TTS/src/speechI.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@
from RoboCompSpeech import *

class SpeechI(Speech):
"""
Delegates speech-related functionality to its worker object. It provides two
methods: `isBusy` checks if the worker is busy and `say` sends a text message
through the worker, optionally overwriting existing messages. These operations
are proxied from the underlying worker's methods.

Attributes:
worker (Speech): Referenced to a worker object that supports speech
functionality, providing methods for checking if it's busy and speaking.
It appears to be an instance of another class inheriting from `Speech`.

"""
def __init__(self, worker):
self.worker = worker

Expand Down