Skip to content

Commit

Permalink
Create eSpeakSynthesizer device
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterBowman committed Aug 16, 2024
1 parent 867718d commit e088a97
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 1 deletion.
3 changes: 2 additions & 1 deletion libraries/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(SpeechIDL)
add_subdirectory(Espeak)
add_subdirectory(SpeechIDL)
add_subdirectory(YarpPlugins)
2 changes: 2 additions & 0 deletions libraries/YarpPlugins/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Create devices.
add_subdirectory(eSpeakSynthesizer)
27 changes: 27 additions & 0 deletions libraries/YarpPlugins/eSpeakSynthesizer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
yarp_prepare_plugin(eSpeakSynthesizer
CATEGORY device
TYPE roboticslab::eSpeakSynthesizer
INCLUDE eSpeakSynthesizer.hpp
DEFAULT ON
DEPENDS "YARP_VERSION VERSION_GREATER_EQUAL 3.9;Espeak_FOUND")

if(NOT SKIP_eSpeakSynthesizer)

message("ESPEAK_LIBRARY: ${ESPEAK_LIBRARY}")

yarp_add_plugin(eSpeakSynthesizer eSpeakSynthesizer.hpp
DeviceDriverImpl.cpp
ISpeechSynthesizerImpl.cpp
LogComponent.hpp
LogComponent.cpp)

target_link_libraries(eSpeakSynthesizer YARP::YARP_os
YARP::YARP_dev
Espeak::Espeak)

yarp_install(TARGETS eSpeakSynthesizer
LIBRARY DESTINATION ${ROBOTICSLAB-SPEECH_DYNAMIC_PLUGINS_INSTALL_DIR}
ARCHIVE DESTINATION ${ROBOTICSLAB-SPEECH_STATIC_PLUGINS_INSTALL_DIR}
YARP_INI DESTINATION ${ROBOTICSLAB-SPEECH_PLUGIN_MANIFESTS_INSTALL_DIR})

endif()
44 changes: 44 additions & 0 deletions libraries/YarpPlugins/eSpeakSynthesizer/DeviceDriverImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-

#include "eSpeakSynthesizer.hpp"

#include <yarp/os/LogStream.h>

#include <espeak/speak_lib.h>

#include "LogComponent.hpp"

using namespace roboticslab;

// ------------------- DeviceDriver Related ------------------------------------

bool eSpeakSynthesizer::open(yarp::os::Searchable & config)
{
espeak_AUDIO_OUTPUT output = AUDIO_OUTPUT_PLAYBACK;
int buflength = 500;
char * path = nullptr;
int options = 0;

if (espeak_Initialize(output, buflength, path, options) == EE_INTERNAL_ERROR)
{
yCError(ESS) << "espeak_Initialize() failed";
return false;
}

return true;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::close()
{
if (espeak_Terminate() != EE_OK)
{
yCError(ESS) << "espeak_Terminate() failed";
return false;
}

return true;
}

// -----------------------------------------------------------------------------
120 changes: 120 additions & 0 deletions libraries/YarpPlugins/eSpeakSynthesizer/ISpeechSynthesizerImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-

#include "eSpeakSynthesizer.hpp"

#include <algorithm> // std::clamp

#include <yarp/os/LogStream.h>

#include <espeak/speak_lib.h>

#include "LogComponent.hpp"

using namespace roboticslab;

namespace
{
constexpr auto MIN_SPEED = 80;
constexpr auto MAX_SPEED = 450;

inline int userToLibSpeed(double userSpeed)
{
return static_cast<int>(MIN_SPEED + (MAX_SPEED - MIN_SPEED) * userSpeed);
}

inline double libToUserSpeed(int libSpeed)
{
return static_cast<double>(libSpeed - MIN_SPEED) / (MAX_SPEED - MIN_SPEED);
}

inline int userToLibPitch(double userPitch)
{
return static_cast<int>(userPitch * 100.0);
}

inline double libToUserPitch(int libPitch)
{
return static_cast<double>(libPitch) / 100.0;
}
}

// ------------------- ISpeechSynthesizer Related ------------------------------------

bool eSpeakSynthesizer::setLanguage(const std::string & language)
{
yCInfo(ESS) << "Setting language to:" << language;
espeak_VOICE voice_spec = {};
voice_spec.languages = language.c_str();
return espeak_SetVoiceByProperties(&voice_spec) == EE_OK;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::getLanguage(std::string & language)
{
const auto * voice = espeak_GetCurrentVoice();
language = voice->languages;
return true;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::setVoice(const std::string & voice_name)
{
yCInfo(ESS) << "Setting voice to:" << voice_name;
return espeak_SetVoiceByName(voice_name.c_str()) == EE_OK;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::getVoice(std::string & voice_name)
{
const auto * voice = espeak_GetCurrentVoice();
voice_name = voice->name;
return true;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::setSpeed(const double speed)
{
auto clamped = std::clamp(speed, 0.0, 1.0);
yCInfo(ESS) << "Setting speed to:" << clamped;
return espeak_SetParameter(espeakRATE, userToLibSpeed(clamped), 0) == EE_OK;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::getSpeed(double & speed)
{
auto original = espeak_GetParameter(espeakRATE, 1);
speed = libToUserSpeed(original);
return true;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::setPitch(const double pitch)
{
auto clamped = std::clamp(pitch, 0.0, 1.0);
yCInfo(ESS) << "Setting pitch to:" << clamped;
return espeak_SetParameter(espeakPITCH, userToLibPitch(clamped), 0) == EE_OK;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::getPitch(double & pitch)
{
auto original = espeak_GetParameter(espeakPITCH, 1);
pitch = libToUserPitch(original);
return true;
}

// -----------------------------------------------------------------------------

bool eSpeakSynthesizer::synthesize(const std::string & text, yarp::sig::Sound & sound)
{
return false;
}

// -----------------------------------------------------------------------------
3 changes: 3 additions & 0 deletions libraries/YarpPlugins/eSpeakSynthesizer/LogComponent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "LogComponent.hpp"

YARP_LOG_COMPONENT(ESS, "rl.eSpeakSynthesizer")
8 changes: 8 additions & 0 deletions libraries/YarpPlugins/eSpeakSynthesizer/LogComponent.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef __ESPEAK_SYNTHESIZER_LOG_COMPONENT_HPP__
#define __ESPEAK_SYNTHESIZER_LOG_COMPONENT_HPP__

#include <yarp/os/LogComponent.h>

YARP_DECLARE_LOG_COMPONENT(ESS)

#endif // __ESPEAK_SYNTHESIZER_LOG_COMPONENT_HPP__
47 changes: 47 additions & 0 deletions libraries/YarpPlugins/eSpeakSynthesizer/eSpeakSynthesizer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-

#ifndef __ESPEAK_SYNTHESIZER_HPP__
#define __ESPEAK_SYNTHESIZER_HPP__

#include <yarp/dev/DeviceDriver.h>
#include <yarp/dev/ISpeechSynthesizer.h>

namespace roboticslab
{

/**
* @ingroup YarpPlugins
* @defgroup eSpeakSynthesizer
*
* @brief Contains roboticslab::eSpeakSynthesizer.
*/

/**
* @ingroup eSpeakSynthesizer
* @brief The eSpeakSynthesizer class implements ISpeechSynthesizer.
*/
class eSpeakSynthesizer : public yarp::dev::DeviceDriver,
public yarp::dev::ISpeechSynthesizer
{
public:
// -- ISpeechSynthesizer declarations. Implementation in ISpeechSynthesizerImpl.cpp --
bool setLanguage(const std::string & language = "auto") override;
bool getLanguage(std::string & language) override;
bool setVoice(const std::string & voice_name = "auto") override;
bool getVoice(std::string & voice_name) override;
bool setSpeed(const double speed = 0) override;
bool getSpeed(double & speed) override;
bool setPitch(const double pitch) override;
bool getPitch(double & pitch) override;
bool synthesize(const std::string & text, yarp::sig::Sound & sound) override;

// -------- DeviceDriver declarations. Implementation in DeviceDriverImpl.cpp --------
bool open(yarp::os::Searchable & config) override;
bool close() override;

private:
};

} // namespace roboticslab

#endif // __ESPEAK_SYNTHESIZER_HPP__

0 comments on commit e088a97

Please sign in to comment.