Библиотека 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 , если по какой-то причине она отсутствует на вашем компьютере;
- установить голоса для синтезатора речи (если у вас они отсутствуют).
- При сборке проекта необходимо использовать теневую сборку.
Описание
Если при компиляции программы Вы видите сообщение
- Error loading text-to-speech plug-in "sapi"
то вы сделали что-то неправильно.
Если вы используете Android , то по умолчанию у вас работает online синтезатор. За это вы расплатитесь задержкой при синтезе и потраченным трафиком. Если это вас не устраивает, то устанавливайте offline версию. На Android 5.1 для этого необходимо перейти в «настройки» - «специальные возможности» - «синтез речи» - «синтезатор речи Google » - «установка голосовых данных» - «русский (Россия)» и жмём установить и ожидаем завершения. Кроме того, подготавливаем Qt Creator для создания Android приложений.
Теперь можно приступать к написанию программы. По ссылке вы можете скачать проект с исходным кодом программы, описанной ниже. Создаём процесс новый проект qtwidget. В файл проекта подключает необходимый модуль
- QT += texttospeech
Подключаем библиотеку синтезатора речи
- #include <QtTextToSpeech>
Создаём указатель на объект класса QTextToSpeech
- QTextToSpeech* speech;
а затем и сам объект
- speech = new QtextToSpeech;
Теперь можно генерировать речевые сигналы с помощью функции say(), в качестве аргумента которой нужно передать произносимый текст. В примерах созданных разработчиками Qt Creator приведён простой пример helloSpeech. Рассмотрите его для того, чтобы лучше понять возможности рассматриваемого модуля.
Я перейду к некоторым более сложным вещам. Программа, которую вы можете скачать по ссылке, содержит виджет класса QTextEdit для воспроизводимого текста , управляющие кнопки: старт, стоп, вперёд назад, …, окно для выбора файлов, и окна для настройки синтезатора.
void MainWindow::start(bool checked)
Запускать на воспроизведение можно и большие текстовые фрагменты. Однако это приводит к необязательным задержкам, а в случае online синтезатора на Android и к зависанию программы. Поэтому дробим текст на фрагменты, чем меньше, тем лучше. Для начала я выделяю из текста абзац ( int activeBlock ), а затем разбиваю строку на лист строк ( QStringList readList ) использую точки в качестве разделителя.
- void MainWindow::start(bool checked)
- {
- if(checked)
- {
- if(readList.isEmpty())
- {
- readList = ui->textEdit->document()->findBlockByNumber( activeBlock ).text().split(".");
- }
- if(!readList.isEmpty())
- {
- readString = readList.first();
- readList.removeFirst();
- if(!readString.contains(QRegularExpression("[A-Z]|[a-z]|[0-9]|[А-Я]|[а-я]")))
- {
- readString = ".";//windows не читает точки
- if(QSysInfo::productType() == "android")
- readString = " ";
- }
- speech->say( readString );
- scrollTo();
- ui->textEdit->setReadOnly(true);
- }
- }
- else
- {
- readList.prepend(readString);//
- speech->stop();
- ui->textEdit->setReadOnly(false);
- }
- }
void MainWindow::speechStateChange(QTextToSpeech::State state)
На синтезатор передаётся одна строчка. После завершения её воспроизведения speech генерирует сигнал stateChanged. Подключенный к ней слот speechStateChange отвечает за воспроизведение очередной строки.
- void MainWindow::speechStateChange( QTextToSpeech::State state)
- {
- QString mes;
- switch(state)
- {
- case QTextToSpeech::Ready:
- if(ui->pushButtonStart->isChecked())
- {
- textBlockSelection(colorClean);
- if(readList.isEmpty())
- {
- if( setActiveBlock( activeBlock+1 ) )
- start();
- else
- stop();
- }
- else
- {
- start();
- }
- }
- mes = "ready";
- break;
- case QTextToSpeech::Speaking:
- textBlockSelection(Qt::green);
- mes = "speaking";
- break;
- case QTextToSpeech::Paused:
- mes = "paused";
- break;
- case QTextToSpeech::BackendError:
- mes = "error";
- break;
- }
- }
Вспомогательные функции
Для удобства использования программы в качестве читалки были написаны две вспомогательные функции scrollTo() для прокручивания текста до выбранного абзаца и textBlockSelection( QColor ) для выделения читаемого абзаца цветом фона. Ниже приведён их исходный код.
void MainWindow::scrollTo()
- void MainWindow::scrollTo()
- {
- if(ui->textEdit->verticalScrollBar()->maximum() == 0)
- return;
- QTextDocument *textDoc = ui->textEdit->document();
- int value = 0;
- for(int i = 0; i < activeBlock; i++)
- {
- value +=textDoc->findBlockByNumber(i).layout()->lineCount()
- * textDoc->findBlockByNumber(i).layout()->lineAt(0).height()
- + textDoc->findBlockByNumber(i).blockFormat().bottomMargin();
- }
- if(value <= ui->textEdit->verticalScrollBar()->maximum())
- ui->textEdit->verticalScrollBar()->setValue(value);
- }
bool MainWindow::setActiveBlock(int blockNumber, bool scroll)
- bool MainWindow::setActiveBlock(int blockNumber, bool scroll)
- {
- readList.clear();
- textBlockSelection(colorClean);
- if(blockNumber < 0)
- {
- activeBlock = 0;
- if(scroll)
- scrollTo();
- return false;
- }
- if(blockNumber >= ui->textEdit->document()->blockCount())
- {
- activeBlock = ui->textEdit->document()->blockCount()-1;
- if(scroll)
- scrollTo();
- return false;
- }
- else
- {
- activeBlock = blockNumber;
- if(scroll)
- scrollTo();
- return true;
- }
- }
Ударение и Омографы
Существенной проблемой для синтезатора речи является ударение. Особенно в тех случаях, когда два слова пишутся одинаково, но имеют разные ударения (омографы). В таком случае, без применения сложных семантических алгоритмов, ударение может быть выставлено только в ручную. И Windows ( в отличии от Android) позволяет это сделать. Для этого нужно поставить знак «`» ( на одной клавиши с буквой ё ). Однако точного механизма работы этого инструмента установить не удалось.
Если вы знаете простой способ для извлечения текста из pdf или djv файлов напишите в ответе.
Лично я простого не знаю способа. В обоих случаях понадобится использовать сторонние библиотеки.