aboutsummaryrefslogtreecommitdiff
path: root/backends/text-to-speech
diff options
context:
space:
mode:
authorJaromir Wysoglad2019-08-02 17:03:17 +0200
committerFilippos Karapetis2019-09-01 22:47:55 +0300
commit21fb4cef06ab84f90d200d448e9742cb75d3f53a (patch)
treea935c8ffc17f654a0efddd2a07585c7a09f9074c /backends/text-to-speech
parent7613bcaa5f10f7537210bd7abd74d1d3ec7e7ac3 (diff)
downloadscummvm-rg350-21fb4cef06ab84f90d200d448e9742cb75d3f53a.tar.gz
scummvm-rg350-21fb4cef06ab84f90d200d448e9742cb75d3f53a.tar.bz2
scummvm-rg350-21fb4cef06ab84f90d200d448e9742cb75d3f53a.zip
TTS: Implement our own queuing for linux
It seems like, that at least some versions of speech-dispatcher aren't able to successfuly pause and resume. For me, when trying to pause, it still finishes the speech just being said instead of pausing it and then it puts it at the end of the speech queue with some speech-dispatcher internal commands added to it, which are also hearable. There is no way to find out where the speech ended when calling pause, so it is just stopped and when resume is called it is read from it's start again.
Diffstat (limited to 'backends/text-to-speech')
-rw-r--r--backends/text-to-speech/linux/linux-text-to-speech.cpp79
-rw-r--r--backends/text-to-speech/linux/linux-text-to-speech.h16
2 files changed, 68 insertions, 27 deletions
diff --git a/backends/text-to-speech/linux/linux-text-to-speech.cpp b/backends/text-to-speech/linux/linux-text-to-speech.cpp
index 97d05a67c1..20ba07d74d 100644
--- a/backends/text-to-speech/linux/linux-text-to-speech.cpp
+++ b/backends/text-to-speech/linux/linux-text-to-speech.cpp
@@ -28,45 +28,42 @@
#if defined(USE_LINUX_TTS)
#include <speech-dispatcher/libspeechd.h>
#include "backends/platform/sdl/sdl-sys.h"
-//#include <iconv.h>
#include "common/translation.h"
#include "common/system.h"
#include "common/ustr.h"
#include "common/config-manager.h"
+
SPDConnection *_connection;
void speech_begin_callback(size_t msg_id, size_t client_id, SPDNotificationType state){
LinuxTextToSpeechManager *manager =
static_cast<LinuxTextToSpeechManager *> (g_system->getTextToSpeechManager());
- manager->updateState(LinuxTextToSpeechManager::SPEAKING);
+ manager->updateState(LinuxTextToSpeechManager::SPEECH_BEGUN);
}
void speech_end_callback(size_t msg_id, size_t client_id, SPDNotificationType state){
LinuxTextToSpeechManager *manager =
static_cast<LinuxTextToSpeechManager *> (g_system->getTextToSpeechManager());
- manager->updateState(LinuxTextToSpeechManager::READY);
+ manager->updateState(LinuxTextToSpeechManager::SPEECH_ENDED);
}
void speech_cancel_callback(size_t msg_id, size_t client_id, SPDNotificationType state){
LinuxTextToSpeechManager *manager =
static_cast<LinuxTextToSpeechManager *> (g_system->getTextToSpeechManager());
- if (manager->isSpeaking())
- manager->updateState(LinuxTextToSpeechManager::READY);
- if (manager->isPaused())
- manager->updateState(LinuxTextToSpeechManager::PAUSED);
+ manager->updateState(LinuxTextToSpeechManager::SPEECH_CANCELED);
}
void speech_resume_callback(size_t msg_id, size_t client_id, SPDNotificationType state){
LinuxTextToSpeechManager *manager =
static_cast<LinuxTextToSpeechManager *> (g_system->getTextToSpeechManager());
- manager->updateState(LinuxTextToSpeechManager::SPEAKING);
+ manager->updateState(LinuxTextToSpeechManager::SPEECH_RESUMED);
}
void speech_pause_callback(size_t msg_id, size_t client_id, SPDNotificationType state){
LinuxTextToSpeechManager *manager =
static_cast<LinuxTextToSpeechManager *> (g_system->getTextToSpeechManager());
- manager->updateState(LinuxTextToSpeechManager::PAUSED);
+ manager->updateState(LinuxTextToSpeechManager::SPEECH_PAUSED);
}
LinuxTextToSpeechManager::LinuxTextToSpeechManager()
@@ -101,6 +98,7 @@ void LinuxTextToSpeechManager::init() {
#else
setLanguage("en");
#endif
+ _speechQueue.clear();
}
LinuxTextToSpeechManager::~LinuxTextToSpeechManager() {
@@ -108,8 +106,29 @@ LinuxTextToSpeechManager::~LinuxTextToSpeechManager() {
spd_close(_connection);
}
-void LinuxTextToSpeechManager::updateState(LinuxTextToSpeechManager::SpeechState state) {
- _speechState = state;
+void LinuxTextToSpeechManager::updateState(LinuxTextToSpeechManager::SpeechEvent event) {
+ if (_speechState == BROKEN)
+ return;
+ switch(event) {
+ case SPEECH_ENDED:
+ _speechQueue.pop_front();
+ if (_speechQueue.size() == 0)
+ _speechState = READY;
+ break;
+ case SPEECH_PAUSED:
+ _speechState = PAUSED;
+ break;
+ case SPEECH_CANCELED:
+ if (_speechState != PAUSED) {
+ _speechState = READY;
+ }
+ break;
+ case SPEECH_RESUMED:
+ break;
+ case SPEECH_BEGUN:
+ _speechState = SPEAKING;
+ break;
+ }
}
Common::String LinuxTextToSpeechManager::strToUtf8(Common::String str, Common::String charset) {
@@ -155,17 +174,19 @@ bool LinuxTextToSpeechManager::say(Common::String str, Action action, Common::St
str = strToUtf8(str, charset);
- if (isSpeaking() && action == INTERRUPT || action == INTERRUPT_NO_REPEAT)
+ if (isSpeaking() && (action == INTERRUPT || action == INTERRUPT_NO_REPEAT))
stop();
- if (str.size() != 0)
+ if (!str.empty()) {
_speechState = SPEAKING;
- _lastSaid = str;
- if(spd_say(_connection, SPD_MESSAGE, str.c_str()) == -1) {
- //restart the connection
- if (_connection != 0)
- spd_close(_connection);
- init();
- return true;
+ _speechQueue.push_back(str);
+ _lastSaid = str;
+ if(spd_say(_connection, SPD_MESSAGE, str.c_str()) == -1) {
+ //restart the connection
+ if (_connection != 0)
+ spd_close(_connection);
+ init();
+ return true;
+ }
}
return false;
@@ -175,27 +196,35 @@ bool LinuxTextToSpeechManager::stop() {
if (_speechState == READY || _speechState == BROKEN)
return true;
_speechState = READY;
+ _speechQueue.clear();
return spd_cancel(_connection) == -1;
}
bool LinuxTextToSpeechManager::pause() {
if (_speechState == READY || _speechState == PAUSED || _speechState == BROKEN)
return true;
- bool result = spd_pause_all(_connection) == -1;
+ _speechState = PAUSED;
+ bool result = spd_cancel_all(_connection) == -1;
if (result)
return true;
- result = spd_stop(_connection) == -1;
if (result)
return true;
- _speechState = PAUSED;
return false;
}
bool LinuxTextToSpeechManager::resume() {
if (_speechState == READY || _speechState == SPEAKING || _speechState == BROKEN)
return true;
- _speechState = SPEAKING;
- return spd_resume(_connection) == -1;
+ if (_speechQueue.size()) {
+ _speechState = SPEAKING;
+ for (Common::List<Common::String>::iterator i = _speechQueue.begin(); i != _speechQueue.end(); i++) {
+ if (spd_say(_connection, SPD_MESSAGE, i->c_str()) == -1)
+ return true;
+ }
+ }
+ else
+ _speechState = READY;
+ return false;
}
bool LinuxTextToSpeechManager::isSpeaking() {
diff --git a/backends/text-to-speech/linux/linux-text-to-speech.h b/backends/text-to-speech/linux/linux-text-to-speech.h
index 30fa9b878c..23c35c33f6 100644
--- a/backends/text-to-speech/linux/linux-text-to-speech.h
+++ b/backends/text-to-speech/linux/linux-text-to-speech.h
@@ -29,6 +29,7 @@
#include "common/text-to-speech.h"
#include "common/str.h"
+#include "common/list.h"
class LinuxTextToSpeechManager : public Common::TextToSpeechManager {
public:
@@ -39,6 +40,14 @@ public:
BROKEN
};
+ enum SpeechEvent {
+ SPEECH_ENDED,
+ SPEECH_PAUSED,
+ SPEECH_CANCELED,
+ SPEECH_RESUMED,
+ SPEECH_BEGUN
+ };
+
LinuxTextToSpeechManager();
virtual ~LinuxTextToSpeechManager();
@@ -62,7 +71,7 @@ public:
virtual void setLanguage(Common::String language);
- void updateState(SpeechState state);
+ void updateState(SpeechEvent event);
virtual void freeVoiceData(void *data);
@@ -70,9 +79,12 @@ private:
void init();
virtual void updateVoices();
void createVoice(int typeNumber, Common::TTSVoice::Gender, Common::TTSVoice::Age, char *description);
- SpeechState _speechState;
Common::String strToUtf8(Common::String str, Common::String charset);
+ bool spdSay(const char *str);
+
+ SpeechState _speechState;
Common::String _lastSaid;
+ Common::List<Common::String> _speechQueue;
};
#endif