kutils: implement per-application (client) settings for KSpeech

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-09-29 16:00:48 +03:00
parent d47d62e503
commit 5fce9429a4
2 changed files with 163 additions and 19 deletions

View file

@ -20,6 +20,8 @@
#include <QCoreApplication>
#include <kdebug.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#if defined(HAVE_SPEECHD)
# include <speech-dispatcher/libspeechd.h>
@ -38,6 +40,7 @@ public:
~KSpeechPrivate();
#if defined(HAVE_SPEECHD)
void initSpeechD();
static void speechCallback(size_t msg_id, size_t client_id, SPDNotificationType state);
#endif
@ -71,6 +74,37 @@ KSpeechPrivate::~KSpeechPrivate()
}
#if defined(HAVE_SPEECHD)
void KSpeechPrivate::initSpeechD()
{
if (!m_speechd) {
m_speechd = spd_open(m_speechid.constData(), "main", NULL, SPD_MODE_THREADED);
if (Q_UNLIKELY(!m_speechd)) {
kWarning() << "Could not open speech-dispatcher connection";
return;
}
m_speechd->callback_begin = KSpeechPrivate::speechCallback;
m_speechd->callback_end = KSpeechPrivate::speechCallback;
m_speechd->callback_cancel = KSpeechPrivate::speechCallback;
spd_set_notification_on(m_speechd, SPD_BEGIN);
spd_set_notification_on(m_speechd, SPD_END);
spd_set_notification_on(m_speechd, SPD_CANCEL);
KConfig kconfig("kspeechrc", KConfig::SimpleConfig);
KConfigGroup kconfiggroup = kconfig.group(m_speechid);
const int volume = kconfiggroup.readEntry("volume", 100);
const int pitch = kconfiggroup.readEntry("pitch", 1);
const QByteArray voice = kconfiggroup.readEntry("voice", QByteArray());
// qDebug() << Q_FUNC_INFO << m_speechid << volume << pitch << voice;
KSpeech* kspeech = qobject_cast<KSpeech*>(parent());
Q_ASSERT(kspeech);
kspeech->setVolume(volume);
kspeech->setPitch(pitch);
kspeech->setVoice(voice);
}
}
void KSpeechPrivate::speechCallback(size_t msg_id, size_t client_id, SPDNotificationType state)
{
Q_UNUSED(client_id);
@ -110,6 +144,8 @@ KSpeech::KSpeech(QObject* parent)
d, SIGNAL(signalJobStateChanged(int,int)),
this, SLOT(_jobStateChanged(int,int))
);
// qDebug() << Q_FUNC_INFO << volume() << pitch() << voices();
}
KSpeech::~KSpeech()
@ -133,25 +169,123 @@ void KSpeech::setSpeechID(const QString &id)
d->m_speechid = id.toUtf8();
}
int KSpeech::say(const QString &text)
int KSpeech::volume() const
{
#if defined(HAVE_SPEECHD)
if (!d->m_speechd) {
d->m_speechd = spd_open(d->m_speechid.constData(), "main", NULL, SPD_MODE_THREADED);
d->initSpeechD();
if (Q_UNLIKELY(!d->m_speechd)) {
kWarning() << "Could not open speech-dispatcher connection";
kDebug() << "Null speech-dispatcher pointer";
return 0;
}
d->m_speechd->callback_begin = KSpeechPrivate::speechCallback;
d->m_speechd->callback_end = KSpeechPrivate::speechCallback;
d->m_speechd->callback_cancel = KSpeechPrivate::speechCallback;
spd_set_notification_on(d->m_speechd, SPD_BEGIN);
spd_set_notification_on(d->m_speechd, SPD_END);
spd_set_notification_on(d->m_speechd, SPD_CANCEL);
return spd_get_volume(d->m_speechd);
#else
return 0;
#endif
}
bool KSpeech::setVolume(const int volume)
{
#if defined(HAVE_SPEECHD)
d->initSpeechD();
if (Q_UNLIKELY(!d->m_speechd)) {
kDebug() << "Null speech-dispatcher pointer";
return false;
}
// TODO: error check
(void)spd_set_volume(d->m_speechd, volume);
return true;
#else
return false;
#endif
}
int KSpeech::pitch() const
{
#if defined(HAVE_SPEECHD)
d->initSpeechD();
if (Q_UNLIKELY(!d->m_speechd)) {
kDebug() << "Null speech-dispatcher pointer";
return 0;
}
return spd_get_voice_pitch(d->m_speechd);
#else
return 0;
#endif
}
bool KSpeech::setPitch(const int pitch)
{
#if defined(HAVE_SPEECHD)
d->initSpeechD();
if (Q_UNLIKELY(!d->m_speechd)) {
kDebug() << "Null speech-dispatcher pointer";
return false;
}
// TODO: error check
(void)spd_set_voice_pitch(d->m_speechd, pitch);
return true;
#else
return false;
#endif
}
QList<QByteArray> KSpeech::voices() const
{
QList<QByteArray> result;
#if defined(HAVE_SPEECHD)
d->initSpeechD();
if (Q_UNLIKELY(!d->m_speechd)) {
kDebug() << "Null speech-dispatcher pointer";
return result;
}
SPDVoice** speechdvoices = spd_list_synthesis_voices(d->m_speechd);
if (!speechdvoices) {
kWarning() << "Null speech-dispatcher voices pointer";
return result;
}
int i = 0;
while (speechdvoices[i]) {
result.append(speechdvoices[i]->name);
i++;
}
free_spd_voices(speechdvoices);
#endif
return result;
}
bool KSpeech::setVoice(const QByteArray &voice)
{
#if defined(HAVE_SPEECHD)
d->initSpeechD();
if (Q_UNLIKELY(!d->m_speechd)) {
kDebug() << "Null speech-dispatcher pointer";
return false;
}
// TODO: error check
(void)spd_set_synthesis_voice(d->m_speechd, voice.constData());
return true;
#else
return false;
#endif
}
int KSpeech::say(const QString &text)
{
#if defined(HAVE_SPEECHD)
d->initSpeechD();
const QByteArray textbytes = text.toUtf8();
const int jobNum = spd_say(d->m_speechd, SPD_TEXT, textbytes.constData());
if (jobNum < 0) {
@ -175,7 +309,8 @@ void KSpeech::removeAllJobs()
return;
}
spd_stop(d->m_speechd);
// TODO: error check
(void)spd_stop(d->m_speechd);
spd_close(d->m_speechd);
d->m_speechd = nullptr;
#endif
@ -189,7 +324,8 @@ void KSpeech::removeJob(int jobNum)
return;
}
spd_stop_uid(d->m_speechd, jobNum);
// TODO: error check
(void)spd_stop_uid(d->m_speechd, jobNum);
#endif
}

View file

@ -26,11 +26,10 @@
class KSpeechPrivate;
/*!
Class for Text To Speech.
Class for Text-To-Speech.
@since 4.22
@warning the API is subject to change
@todo implement configuration options
*/
class KSPEECH_EXPORT KSpeech : public QObject
{
@ -49,6 +48,15 @@ public:
void setSpeechID(const QString &id);
int volume() const;
bool setVolume(const int volume);
int pitch() const;
bool setPitch(const int pitch);
QList<QByteArray> voices() const;
bool setVoice(const QByteArray &voice);
public Q_SLOTS:
int say(const QString &text);