Дмитрий
10 июля 2017 г. 13:19

Использование модуля QtTextToSpeech для синтеза речи

Библиотека Qt 5.8.0 предоставила программистам возможность использовать системный синтезатор речи. Синтезатор речи - это программа, преобразующая текст в речь. Синтезаторы речи является неотъемлемой частью любой современной операционной системы: Windows (версии 7 и выше), Mac OS, Linux, iOS и Android. Кроссплатформенный интерфейс для управления синтезом речи предоставляет модуль QtTextToSpeech библиотеки Qt.

Для работы с модулем QtTextToSpeech на ОС Windows необходимо:

  • установить библиотеку Qt c модулем QtTextToSpeech для компилятора Visual Studio 2015 или старше ( mingw работать не будет );
  • установить компилятор Visual Studio 2015 ;
  • установить библиотеку SAPI 5.1 , если по какой-то причине она отсутствует на вашем компьютере;
  • установить голоса для синтезатора речи (если у вас они отсутствуют).
  • При сборке проекта необходимо использовать теневую сборку.

Описание

Если при компиляции программы Вы видите сообщение

  1. Error loading text-to-speech plug-in "sapi"

то вы сделали что-то неправильно.

Если вы используете Android , то по умолчанию у вас работает online синтезатор. За это вы расплатитесь задержкой при синтезе и потраченным трафиком. Если это вас не устраивает, то устанавливайте offline версию. На Android 5.1 для этого необходимо перейти в «настройки» - «специальные возможности» - «синтез речи» - «синтезатор речи Google » - «установка голосовых данных» - «русский (Россия)» и жмём установить и ожидаем завершения. Кроме того, подготавливаем Qt Creator для создания Android приложений.

Теперь можно приступать к написанию программы. По ссылке вы можете скачать проект с исходным кодом программы, описанной ниже. Создаём процесс новый проект qtwidget. В файл проекта подключает необходимый модуль

  1. QT += texttospeech

Подключаем библиотеку синтезатора речи

  1. #include <QtTextToSpeech>

Создаём указатель на объект класса QTextToSpeech

  1. QTextToSpeech* speech;

а затем и сам объект

  1. speech = new QtextToSpeech;

Теперь можно генерировать речевые сигналы с помощью функции say(), в качестве аргумента которой нужно передать произносимый текст. В примерах созданных разработчиками Qt Creator приведён простой пример helloSpeech. Рассмотрите его для того, чтобы лучше понять возможности рассматриваемого модуля.

Я перейду к некоторым более сложным вещам. Программа, которую вы можете скачать по ссылке, содержит виджет класса QTextEdit для воспроизводимого текста , управляющие кнопки: старт, стоп, вперёд назад, …, окно для выбора файлов, и окна для настройки синтезатора.

void MainWindow::start(bool checked)

Запускать на воспроизведение можно и большие текстовые фрагменты. Однако это приводит к необязательным задержкам, а в случае online синтезатора на Android и к зависанию программы. Поэтому дробим текст на фрагменты, чем меньше, тем лучше. Для начала я выделяю из текста абзац ( int activeBlock ), а затем разбиваю строку на лист строк ( QStringList readList ) использую точки в качестве разделителя.

  1. void MainWindow::start(bool checked)
  2. {
  3. if(checked)
  4. {
  5. if(readList.isEmpty())
  6. {
  7. readList = ui->textEdit->document()->findBlockByNumber( activeBlock ).text().split(".");
  8. }
  9. if(!readList.isEmpty())
  10. {
  11. readString = readList.first();
  12. readList.removeFirst();
  13. if(!readString.contains(QRegularExpression("[A-Z]|[a-z]|[0-9]|[А-Я]|[а-я]")))
  14. {
  15. readString = ".";//windows не читает точки
  16. if(QSysInfo::productType() == "android")
  17. readString = " ";
  18. }
  19. speech->say( readString );
  20. scrollTo();
  21. ui->textEdit->setReadOnly(true);
  22. }
  23. }
  24. else
  25. {
  26. readList.prepend(readString);//
  27. speech->stop();
  28. ui->textEdit->setReadOnly(false);
  29. }
  30. }

void MainWindow::speechStateChange(QTextToSpeech::State state)

На синтезатор передаётся одна строчка. После завершения её воспроизведения speech генерирует сигнал stateChanged. Подключенный к ней слот speechStateChange отвечает за воспроизведение очередной строки.

  1. void MainWindow::speechStateChange( QTextToSpeech::State state)
  2. {
  3. QString mes;
  4. switch(state)
  5. {
  6. case QTextToSpeech::Ready:
  7. if(ui->pushButtonStart->isChecked())
  8. {
  9. textBlockSelection(colorClean);
  10. if(readList.isEmpty())
  11. {
  12. if( setActiveBlock( activeBlock+1 ) )
  13. start();
  14. else
  15. stop();
  16. }
  17. else
  18. {
  19. start();
  20. }
  21. }
  22. mes = "ready";
  23. break;
  24. case QTextToSpeech::Speaking:
  25. textBlockSelection(Qt::green);
  26. mes = "speaking";
  27. break;
  28. case QTextToSpeech::Paused:
  29. mes = "paused";
  30. break;
  31. case QTextToSpeech::BackendError:
  32. mes = "error";
  33. break;
  34. }
  35. }

Вспомогательные функции

Для удобства использования программы в качестве читалки были написаны две вспомогательные функции scrollTo() для прокручивания текста до выбранного абзаца и textBlockSelection( QColor ) для выделения читаемого абзаца цветом фона. Ниже приведён их исходный код.

void MainWindow::scrollTo()

  1. void MainWindow::scrollTo()
  2. {
  3. if(ui->textEdit->verticalScrollBar()->maximum() == 0)
  4. return;
  5. QTextDocument *textDoc = ui->textEdit->document();
  6. int value = 0;
  7. for(int i = 0; i < activeBlock; i++)
  8. {
  9. value +=textDoc->findBlockByNumber(i).layout()->lineCount()
  10. * textDoc->findBlockByNumber(i).layout()->lineAt(0).height()
  11. + textDoc->findBlockByNumber(i).blockFormat().bottomMargin();
  12. }
  13. if(value <= ui->textEdit->verticalScrollBar()->maximum())
  14. ui->textEdit->verticalScrollBar()->setValue(value);
  15. }

bool MainWindow::setActiveBlock(int blockNumber, bool scroll)

  1. bool MainWindow::setActiveBlock(int blockNumber, bool scroll)
  2. {
  3. readList.clear();
  4. textBlockSelection(colorClean);
  5. if(blockNumber < 0)
  6. {
  7. activeBlock = 0;
  8. if(scroll)
  9. scrollTo();
  10. return false;
  11. }
  12. if(blockNumber >= ui->textEdit->document()->blockCount())
  13. {
  14. activeBlock = ui->textEdit->document()->blockCount()-1;
  15. if(scroll)
  16. scrollTo();
  17. return false;
  18. }
  19. else
  20. {
  21. activeBlock = blockNumber;
  22. if(scroll)
  23. scrollTo();
  24. return true;
  25. }
  26. }

Ударение и Омографы

Существенной проблемой для синтезатора речи является ударение. Особенно в тех случаях, когда два слова пишутся одинаково, но имеют разные ударения (омографы). В таком случае, без применения сложных семантических алгоритмов, ударение может быть выставлено только в ручную. И Windows ( в отличии от Android) позволяет это сделать. Для этого нужно поставить знак «`» ( на одной клавиши с буквой ё ). Однако точного механизма работы этого инструмента установить не удалось.

По статье задано0вопрос(ов)

2

Вам это нравится? Поделитесь в социальных сетях!

Дмитрий
  • 23 июля 2017 г. 12:52

Если вы знаете простой способ для извлечения текста из pdf или djv файлов напишите в ответе.

Evgenii Legotckoi
  • 23 июля 2017 г. 16:10

Лично я простого не знаю способа. В обоих случаях понадобится использовать сторонние библиотеки.

В случае с pdf - это будет либа, которая работает с pdf, какой-нибудь poppler-qt.
В случае же с djvu - это уже либа по распознаванию текста в изображениях.
Но за пример такой работы ничего не скажу, не занимался таким.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь