forked from len0rd/rockbox
Add capability to speak directly from the TTS engine.
The OS X TTS engine (and likely others) allows outputting its speech directly to the sound system. This avoids the extra step of creating a temporary file to play for TTS preview. Currently implemented as TTS capability reported. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29672 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
76c112ce6e
commit
746f01dd77
3 changed files with 48 additions and 36 deletions
|
|
@ -36,7 +36,7 @@ class TTSBase : public EncTtsSettingInterface
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Capability { None = 0, RunInParallel = 1 };
|
||||
enum Capability { None = 0, RunInParallel = 1, CanSpeak = 2 };
|
||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
||||
|
||||
TTSBase(QObject *parent);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ TTSCarbon::TTSCarbon(QObject* parent) : TTSBase(parent)
|
|||
|
||||
TTSBase::Capabilities TTSCarbon::capabilities()
|
||||
{
|
||||
return None;
|
||||
return TTSBase::CanSpeak;
|
||||
}
|
||||
|
||||
bool TTSCarbon::configOk()
|
||||
|
|
@ -75,7 +75,7 @@ bool TTSCarbon::start(QString *errStr)
|
|||
if(voiceIndex == numVoices) {
|
||||
// voice not found. Add user notification here and proceed with
|
||||
// system default voice.
|
||||
qDebug() << "selected voice not found, using system default!";
|
||||
qDebug() << "[TTSCarbon] Selected voice not found, using system default!";
|
||||
GetVoiceDescription(&vspec, &vdesc, sizeof(vdesc));
|
||||
if(vdesc.script != -1)
|
||||
m_voiceScript = (CFStringBuiltInEncodings)vdesc.script;
|
||||
|
|
@ -160,18 +160,21 @@ TTSStatus TTSCarbon::voice(QString text, QString wavfile, QString* errStr)
|
|||
TTSStatus status = NoError;
|
||||
OSErr error;
|
||||
|
||||
QString aifffile = wavfile + ".aiff";
|
||||
// FIXME: find out why we need to do this.
|
||||
// Create a local copy of the temporary file filename.
|
||||
// Not doing so causes weird issues (path contains trailing spaces)
|
||||
unsigned int len = aifffile.size() + 1;
|
||||
char* tmpfile = (char*)malloc(len * sizeof(char));
|
||||
strncpy(tmpfile, aifffile.toLocal8Bit().constData(), len);
|
||||
CFStringRef tmpfileref = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
tmpfile, kCFStringEncodingUTF8);
|
||||
CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
||||
tmpfileref, kCFURLPOSIXPathStyle, false);
|
||||
SetSpeechInfo(m_channel, soOutputToFileWithCFURL, urlref);
|
||||
char* tmpfile;
|
||||
if(!wavfile.isEmpty()) {
|
||||
QString aifffile = wavfile + ".aiff";
|
||||
// FIXME: find out why we need to do this.
|
||||
// Create a local copy of the temporary file filename.
|
||||
// Not doing so causes weird issues (path contains trailing spaces)
|
||||
unsigned int len = aifffile.size() + 1;
|
||||
tmpfile = (char*)malloc(len * sizeof(char));
|
||||
strncpy(tmpfile, aifffile.toLocal8Bit().constData(), len);
|
||||
CFStringRef tmpfileref = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
tmpfile, kCFStringEncodingUTF8);
|
||||
CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
||||
tmpfileref, kCFURLPOSIXPathStyle, false);
|
||||
SetSpeechInfo(m_channel, soOutputToFileWithCFURL, urlref);
|
||||
}
|
||||
|
||||
// speak it.
|
||||
// Convert the string to the encoding requested by the voice. Do this
|
||||
|
|
@ -206,15 +209,17 @@ TTSStatus TTSCarbon::voice(QString text, QString wavfile, QString* errStr)
|
|||
free(textbuf);
|
||||
CFRelease(cfstring);
|
||||
|
||||
// convert the temporary aiff file to wav
|
||||
if(status == NoError
|
||||
&& convertAiffToWav(tmpfile, wavfile.toLocal8Bit().constData()) != 0) {
|
||||
*errStr = tr("Could not convert intermediate file");
|
||||
status = FatalError;
|
||||
if(!wavfile.isEmpty()) {
|
||||
// convert the temporary aiff file to wav
|
||||
if(status == NoError
|
||||
&& convertAiffToWav(tmpfile, wavfile.toLocal8Bit().constData()) != 0) {
|
||||
*errStr = tr("Could not convert intermediate file");
|
||||
status = FatalError;
|
||||
}
|
||||
// remove temporary aiff file
|
||||
unlink(tmpfile);
|
||||
free(tmpfile);
|
||||
}
|
||||
// remove temporary aiff file
|
||||
unlink(tmpfile);
|
||||
free(tmpfile);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -731,14 +731,16 @@ void Config::testTts()
|
|||
{
|
||||
QString errstr;
|
||||
int index = ui.comboTts->currentIndex();
|
||||
TTSBase* tts = TTSBase::getTTS(this,ui.comboTts->itemData(index).toString());
|
||||
TTSBase* tts;
|
||||
|
||||
ui.testTTS->setEnabled(false);
|
||||
tts = TTSBase::getTTS(this,ui.comboTts->itemData(index).toString());
|
||||
if(!tts->configOk())
|
||||
{
|
||||
QMessageBox::warning(this,tr("TTS configuration invalid"),
|
||||
tr("TTS configuration invalid. \n Please configure TTS engine."));
|
||||
return;
|
||||
}
|
||||
ui.testTTS->setEnabled(false);
|
||||
if(!tts->start(&errstr))
|
||||
{
|
||||
QMessageBox::warning(this,tr("Could not start TTS engine."),
|
||||
|
|
@ -748,10 +750,13 @@ void Config::testTts()
|
|||
return;
|
||||
}
|
||||
|
||||
QTemporaryFile file(this);
|
||||
file.open();
|
||||
QString filename = file.fileName();
|
||||
file.close();
|
||||
QString filename;
|
||||
if(!(tts->capabilities() & TTSBase::CanSpeak)) {
|
||||
QTemporaryFile file(this);
|
||||
file.open();
|
||||
filename = file.fileName();
|
||||
file.close();
|
||||
}
|
||||
|
||||
if(tts->voice(tr("Rockbox Utility Voice Test"),filename,&errstr) == FatalError)
|
||||
{
|
||||
|
|
@ -763,16 +768,18 @@ void Config::testTts()
|
|||
return;
|
||||
}
|
||||
tts->stop();
|
||||
if(!(tts->capabilities() & TTSBase::CanSpeak)) {
|
||||
#if defined(Q_OS_LINUX)
|
||||
QString exe = Utils::findExecutable("aplay");
|
||||
if(exe == "") exe = Utils::findExecutable("play");
|
||||
if(exe != "")
|
||||
{
|
||||
QProcess::execute(exe+" "+filename);
|
||||
}
|
||||
QString exe = Utils::findExecutable("aplay");
|
||||
if(exe == "") exe = Utils::findExecutable("play");
|
||||
if(exe != "")
|
||||
{
|
||||
QProcess::execute(exe+" "+filename);
|
||||
}
|
||||
#else
|
||||
QSound::play(filename);
|
||||
QSound::play(filename);
|
||||
#endif
|
||||
}
|
||||
ui.testTTS->setEnabled(true);
|
||||
delete tts; /* Config objects are never deleted (in fact, they are
|
||||
leaked..), so we can't rely on QObject, since that would
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue