• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeaccessibility API Reference
  • KDE Home
  • Contact Us
 

jovie

  • sources
  • kde-4.12
  • kdeaccessibility
  • jovie
  • libkttsd
talkercode.cpp
Go to the documentation of this file.
1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2  Convenience object for manipulating Talker Codes.
3  For an explanation of what a Talker Code is, see kspeech.h.
4  -------------------
5  Copyright 2005 by Gary Cramblitt <garycramblitt@comcast.net>
6  Copyright 2009 - 2010 by Jeremy Whiting <jpwhiting@kde.org>
7  -------------------
8  Original author: Gary Cramblitt <garycramblitt@comcast.net>
9 
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  ******************************************************************************/
24 
25 // TalkerCode includes.
26 #include "talkercode.h"
27 
28 // Qt includes.
29 #include <QtCore/QVector>
30 #include <QtXml/QDomDocument>
31 
32 // KDE includes.
33 #include <kglobal.h>
34 #include <klocale.h>
35 #include <kdebug.h>
36 #include <kservicetypetrader.h>
37 
38 class TalkerCodePrivate
39 {
40 public:
41  TalkerCodePrivate(TalkerCode *parent)
42  :q(parent)
43  {
44  }
45 
46  ~TalkerCodePrivate()
47  {
48  }
49 
50  QString name; /* name="xxx" */
51  QString language; /* lang="xx" */
52  int voiceType; /* voiceType="xxx" */
53  int volume; /* volume="xxx" */
54  int rate; /* rate="xxx" */
55  int pitch; /* pitch="xxx" */
56  QString voiceName; /* voiceName="xxx" */
57  QString outputModule; /* synthesizer="xxx" */
58 
59  TalkerCode *q;
60 };
61 
65 TalkerCode::TalkerCode(const QString &code/*=QString()*/, bool normal /*=false*/)
66 :d(new TalkerCodePrivate(this))
67 {
68  if (!code.isEmpty())
69  parseTalkerCode(code);
70  //if (normal)
71  // normalize();
72 }
73 
77 TalkerCode::TalkerCode(const TalkerCode& other)
78 :d(new TalkerCodePrivate(this))
79 {
80  d->name = other.name();
81  d->language = other.language();
82  d->voiceType = other.voiceType();
83  d->volume = other.volume();
84  d->rate = other.rate();
85  d->pitch = other.pitch();
86  d->voiceName = other.voiceName();
87  d->outputModule = other.outputModule();
88 }
89 
93 TalkerCode::~TalkerCode()
94 {
95  delete d;
96 }
97 
98 TalkerCode &TalkerCode::operator=(const TalkerCode &other)
99 {
100  d->name = other.name();
101  d->language = other.language();
102  d->voiceType = other.voiceType();
103  d->volume = other.volume();
104  d->rate = other.rate();
105  d->pitch = other.pitch();
106  d->voiceName = other.voiceName();
107  d->outputModule = other.outputModule();
108  return *this;
109 }
110 
114 QString TalkerCode::name() const
115 {
116  return d->name;
117 }
118 
119 QString TalkerCode::language() const
120 {
121  return d->language;
122 }
123 
124 int TalkerCode::voiceType() const
125 {
126  return d->voiceType;
127 }
128 
129 int TalkerCode::volume() const
130 {
131  return d->volume;
132 }
133 
134 int TalkerCode::rate() const
135 {
136  return d->rate;
137 }
138 
139 int TalkerCode::pitch() const
140 {
141  return d->pitch;
142 }
143 
144 QString TalkerCode::voiceName() const
145 {
146  return d->voiceName;
147 }
148 
149 QString TalkerCode::outputModule() const
150 {
151  return d->outputModule;
152 }
153 
154 void TalkerCode::setName(const QString &name)
155 {
156  d->name = name;
157 }
158 
159 void TalkerCode::setLanguage(const QString &language)
160 {
161  d->language = language;
162 }
163 
164 void TalkerCode::setVoiceType(int voiceType)
165 {
166  d->voiceType = voiceType;
167 }
168 
169 void TalkerCode::setVolume(int volume)
170 {
171  d->volume = volume;
172 }
173 
174 void TalkerCode::setRate(int rate)
175 {
176  d->rate = rate;
177 }
178 
179 void TalkerCode::setPitch(int pitch)
180 {
181  d->pitch = pitch;
182 }
183 
184 void TalkerCode::setVoiceName(const QString &voiceName)
185 {
186  d->voiceName = voiceName;
187 }
188 
189 void TalkerCode::setOutputModule(const QString &moduleName)
190 {
191  d->outputModule = moduleName;
192 }
193 
197 void TalkerCode::setTalkerCode(const QString& code)
198 {
199  parseTalkerCode(code);
200 }
201 
202 QString TalkerCode::getTalkerCode() const
203 {
204  QString xml(QLatin1String("<voice name=\"%1\" lang=\"%2\" outputModule=\"%3\""
205  " voiceName=\"%4\" voiceType=\"%5\">"
206  "<prosody volume=\"%6\" rate=\"%7\" pitch=\"%8\" /></voice>"));
207  QString code = xml.arg(d->name)
208  .arg(d->language)
209  .arg(d->outputModule)
210  .arg(d->voiceName)
211  .arg(d->voiceType)
212  .arg(d->volume)
213  .arg(d->rate)
214  .arg(d->pitch);
215  return code;
216 }
217 
221 QString TalkerCode::getTranslatedDescription() const
222 {
223  QString code;
224  if (!d->name.isEmpty())
225  {
226  code = d->name;
227  }
228  else
229  {
230  code = d->language;
231  bool prefer;
232  QString fullLangCode = d->language;
233  if (!fullLangCode.isEmpty()) code = languageCodeToLanguage( fullLangCode );
234  // TODO: The PlugInName is always English. Need a way to convert this to a translated
235  // name (possibly via DesktopEntryNameToName, but to do that, we need the desktopEntryName
236  // from the config file).
237  if (!d->outputModule.isEmpty()) code += QLatin1Char( ' ' ) + stripPrefer(d->outputModule, prefer);
238  code += QLatin1Char(' ') + translatedVoiceType(d->voiceType);
239  code += QString(QLatin1String(" volume: %1 rate: %2")).arg(d->volume).arg(d->rate);
240  code = code.trimmed();
241  }
242  if (code.isEmpty())
243  code = i18nc("Default language code", "default");
244  return code;
245 }
246 
247 QString TalkerCode::translatedVoiceType(int voiceType)
248 {
249  switch (voiceType)
250  {
251  case 1: return i18nc("The name of the first Male voice","Male 1"); break;
252  case 2: return i18n("Male 2"); break;
253  case 3: return i18n("Male 3"); break;
254  case 4: return i18nc("The name of the first Female voice", "Female 1"); break;
255  case 5: return i18n("Female 2"); break;
256  case 6: return i18n("Female 3"); break;
257  case 7: return i18nc("The name of the male child voice", "Boy"); break;
258  case 8: return i18nc("The name of the female child voice", "Girl"); break;
259  }
260  return i18nc("Somehow user has gotten a voice type that is not valid, i.e. not Male1, Male2, etc.","Invalid voice type");
261 }
262 
263 /*static*/ void TalkerCode::splitFullLanguageCode(const QString &lang, QString &languageCode, QString &countryCode)
264 {
265  QString language = lang;
266  if (language.left(1) == QLatin1String( "*" ))
267  language = language.mid(1);
268  QString modifier;
269  QString charSet;
270  KGlobal::locale()->splitLocale(language, languageCode, countryCode, modifier, charSet);
271 }
272 
273 /*static*/ QString TalkerCode::defaultTalkerCode(const QString &fullLanguageCode, const QString &moduleName)
274 {
275  TalkerCode tmpTalkerCode;
276  //tmpTalkerCode.setFullLanguageCode(fullLanguageCode);
277  tmpTalkerCode.setOutputModule(moduleName);
278  //tmpTalkerCode.normalize();
279  return tmpTalkerCode.getTalkerCode();
280 }
281 
282 /*static*/ QString TalkerCode::languageCodeToLanguage(const QString &languageCode)
283 {
284  QString langAlpha;
285  QString countryCode;
286  QString language;
287  if (languageCode == QLatin1String( "other" ))
288  language = i18nc("Other language", "Other");
289  else
290  {
291  splitFullLanguageCode(languageCode, langAlpha, countryCode);
292  language = KGlobal::locale()->languageCodeToName(langAlpha);
293  }
294  if (!countryCode.isEmpty())
295  {
296  QString countryName = KGlobal::locale()->countryCodeToName(countryCode);
297  // Some abbreviations to save screen space.
298  if (countryName == i18nc("full country name", "United States of America"))
299  countryName = i18nc("abbreviated country name", "USA");
300  if (countryName == i18nc("full country name", "United Kingdom"))
301  countryName = i18nc("abbreviated country name", "UK");
302  language += QLatin1String( " (" ) + countryName + QLatin1Char( ')' );
303  }
304  return language;
305 }
306 
311 void TalkerCode::parseTalkerCode(const QString &talkerCode)
312 {
313  QDomDocument doc;
314  doc.setContent(talkerCode);
315 
316  QDomElement voice = doc.firstChildElement(QLatin1String( "voice" ));
317  if (!voice.isNull())
318  {
319  d->name = voice.attribute(QLatin1String( "name" ));
320  d->language = voice.attribute(QLatin1String( "lang" ));
321  d->outputModule = voice.attribute(QLatin1String( "outputModule" ));
322  d->voiceName = voice.attribute(QLatin1String( "voiceName" ));
323  bool result = false;
324  d->voiceType = voice.attribute(QLatin1String( "voiceType" )).toInt(&result);
325  if (!result)
326  d->voiceType = 1;
327 
328  QDomElement prosody = voice.firstChildElement(QLatin1String( "prosody" ));
329  if (!prosody.isNull())
330  {
331  bool result = false;
332  d->volume = prosody.attribute(QLatin1String( "volume" )).toInt(&result);
333  if (!result)
334  d->volume = 0;
335  d->rate = prosody.attribute(QLatin1String( "rate" )).toInt(&result);
336  if (!result)
337  d->rate = 0;
338  d->pitch = prosody.attribute(QLatin1String( "pitch" )).toInt(&result);
339  if (!result)
340  d->pitch = 0;
341  }
342  else
343  {
344  kDebug() << "got a voice with no prosody tag";
345  }
346  }
347  else
348  {
349  kDebug() << "got a voice with no voice tag";
350  }
351 }
352 
362 /*static*/ int TalkerCode::findClosestMatchingTalker(
363  const TalkerCodeList& talkers,
364  const QString& talker,
365  bool assumeDefaultLang)
366 {
367  // kDebug() << "TalkerCode::findClosestMatchingTalker: matching on talker code " << talker;
368  // If nothing to match on, winner is top in the list.
369  if (talker.isEmpty()) return 0;
370  // Parse the given talker.
371  TalkerCode parsedTalkerCode(talker);
372  // If no language code specified, use the language code of the default talker.
373  if (assumeDefaultLang)
374  {
375  if (parsedTalkerCode.language().isEmpty()) parsedTalkerCode.setLanguage(
376  talkers[0].language());
377  }
378  // The talker that matches on the most priority attributes wins.
379  int talkersCount = int(talkers.count());
380  QVector<int> priorityMatch(talkersCount);
381  for (int ndx = 0; ndx < talkersCount; ++ndx)
382  {
383  priorityMatch[ndx] = 0;
384  // kDebug() << "Comparing language code " << parsedTalkerCode.languageCode() << " to " << d->loadedPlugIns[ndx].parsedTalkerCode.languageCode();
385  }
386  // Determine the maximum number of priority attributes that were matched.
387  int maxPriority = -1;
388  for (int ndx = 0; ndx < talkersCount; ++ndx)
389  {
390  if (priorityMatch[ndx] > maxPriority) maxPriority = priorityMatch[ndx];
391  }
392  // Find the talker(s) that matched on most priority attributes.
393  int winnerCount = 0;
394  int winner = -1;
395  for (int ndx = 0; ndx < talkersCount; ++ndx)
396  {
397  if (priorityMatch[ndx] == maxPriority)
398  {
399  ++winnerCount;
400  winner = ndx;
401  }
402  }
403  // kDebug() << "Priority phase: winnerCount = " << winnerCount
404  // << " winner = " << winner
405  // << " maxPriority = " << maxPriority << endl;
406  // If a tie, the one that matches on the most priority and preferred attributes wins.
407  // If there is still a tie, the one nearest the top of the kttsmgr display
408  // (first configured) will be chosen.
409  if (winnerCount > 1)
410  {
411  QVector<int> preferredMatch(talkersCount);
412  for (int ndx = 0; ndx < talkersCount; ++ndx)
413  {
414  preferredMatch[ndx] = 0;
415  if (priorityMatch[ndx] == maxPriority)
416  {
417  }
418  }
419  // Determine the maximum number of preferred attributes that were matched.
420  int maxPreferred = -1;
421  for (int ndx = 0; ndx < talkersCount; ++ndx)
422  {
423  if (preferredMatch[ndx] > maxPreferred) maxPreferred = preferredMatch[ndx];
424  }
425  winner = -1;
426  winnerCount = 0;
427  // Find the talker that matched on most priority and preferred attributes.
428  // Work bottom to top so topmost wins in a tie.
429  for (int ndx = talkersCount-1; ndx >= 0; --ndx)
430  {
431  if (priorityMatch[ndx] == maxPriority)
432  {
433  if (preferredMatch[ndx] == maxPreferred)
434  {
435  ++winnerCount;
436  winner = ndx;
437  }
438  }
439  }
440  // kDebug() << "Preferred phase: winnerCount = " << winnerCount
441  // << " winner = " << winner
442  // << " maxPreferred = " << maxPreferred << endl;
443  }
444  // If no winner found, use the first talker.
445  if (winner < 0) winner = 0;
446  // kDebug() << "TalkerCode::findClosestMatchingTalker: returning winner = " << winner;
447  return winner;
448 }
449 
450 /*static*/ QString TalkerCode::stripPrefer( const QString& code, bool& preferred)
451 {
452  if ( code.left(1) == QLatin1String( "*" ) )
453  {
454  preferred = true;
455  return code.mid(1);
456  } else {
457  preferred = false;
458  return code;
459  }
460 }
461 
462 bool TalkerCode::operator==(TalkerCode &other) const
463 {
464  return d->language == other.language() &&
465  d->voiceType == other.voiceType() &&
466  d->rate == other.rate() &&
467  d->volume == other.volume() &&
468  d->pitch == other.pitch() &&
469  d->voiceName == other.voiceName() &&
470  d->outputModule == other.outputModule();
471 }
472 
473 bool TalkerCode::operator!=(TalkerCode &other) const
474 {
475  return d->language != other.language() ||
476  d->voiceType != other.voiceType() ||
477  d->rate != other.rate() ||
478  d->volume != other.volume() ||
479  d->pitch != other.pitch() ||
480  d->voiceName != other.voiceName() ||
481  d->outputModule != other.outputModule();
482 }
TalkerCode::setLanguage
void setLanguage(const QString &language)
Definition: talkercode.cpp:159
TalkerCode::stripPrefer
static QString stripPrefer(const QString &code, bool &preferred)
Strips leading * from a code.
Definition: talkercode.cpp:450
TalkerCode::getTranslatedDescription
QString getTranslatedDescription() const
The Talker Code translated for display.
Definition: talkercode.cpp:221
TalkerCode::language
QString language() const
Definition: talkercode.cpp:119
TalkerCode::operator=
TalkerCode & operator=(const TalkerCode &other)
Definition: talkercode.cpp:98
TalkerCode::setOutputModule
void setOutputModule(const QString &moduleName)
Definition: talkercode.cpp:189
TalkerCode::voiceName
QString voiceName() const
Definition: talkercode.cpp:144
TalkerCode::TalkerCodeList
QList< TalkerCode > TalkerCodeList
Definition: talkercode.h:61
TalkerCode::setPitch
void setPitch(int pitch)
Definition: talkercode.cpp:179
TalkerCode::operator!=
bool operator!=(TalkerCode &other) const
Definition: talkercode.cpp:473
TalkerCode::translatedVoiceType
static QString translatedVoiceType(int voiceType)
These functions return translated Talker Code attributes.
Definition: talkercode.cpp:247
TalkerCode::setVolume
void setVolume(int volume)
Definition: talkercode.cpp:169
TalkerCode::operator==
bool operator==(TalkerCode &other) const
Definition: talkercode.cpp:462
TalkerCode::splitFullLanguageCode
static void splitFullLanguageCode(const QString &lang, QString &languageCode, QString &countryCode)
Given a language code that might contain a country code, splits the code into the two letter language...
Definition: talkercode.cpp:263
TalkerCode::volume
int volume() const
Definition: talkercode.cpp:129
talkercode.h
TalkerCode::setName
void setName(const QString &name)
Definition: talkercode.cpp:154
TalkerCode::name
QString name() const
Properties.
Definition: talkercode.cpp:114
TalkerCode::getTalkerCode
QString getTalkerCode() const
Definition: talkercode.cpp:202
TalkerCode::TalkerCode
TalkerCode(const QString &code=QString(), bool normal=false)
Constructor.
Definition: talkercode.cpp:65
TalkerCode::rate
int rate() const
Definition: talkercode.cpp:134
TalkerCode::languageCodeToLanguage
static QString languageCodeToLanguage(const QString &languageCode)
Converts a language code plus optional country code to language description.
Definition: talkercode.cpp:282
TalkerCode
Definition: talkercode.h:38
TalkerCode::voiceType
int voiceType() const
Definition: talkercode.cpp:124
TalkerCode::~TalkerCode
~TalkerCode()
Destructor.
Definition: talkercode.cpp:93
TalkerCode::outputModule
QString outputModule() const
Definition: talkercode.cpp:149
TalkerCode::setVoiceName
void setVoiceName(const QString &voiceName)
Definition: talkercode.cpp:184
TalkerCode::findClosestMatchingTalker
static int findClosestMatchingTalker(const TalkerCodeList &talkers, const QString &talker, bool assumeDefaultLang=true)
Given a list of parsed talker codes and a desired talker code, finds the closest matching talker in t...
Definition: talkercode.cpp:362
TalkerCode::pitch
int pitch() const
Definition: talkercode.cpp:139
TalkerCode::setRate
void setRate(int rate)
Definition: talkercode.cpp:174
TalkerCode::defaultTalkerCode
static QString defaultTalkerCode(const QString &fullLanguageCode, const QString &moduleName)
Given a language code and plugin name, returns a normalized default talker code.
Definition: talkercode.cpp:273
TalkerCode::setTalkerCode
void setTalkerCode(const QString &code)
The Talker Code returned in XML format.
Definition: talkercode.cpp:197
TalkerCode::setVoiceType
void setVoiceType(int voiceType)
Definition: talkercode.cpp:164
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:32:25 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

jovie

Skip menu "jovie"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeaccessibility API Reference

Skip menu "kdeaccessibility API Reference"
  • jovie

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal