Синтезаторы речи - русский синтезатор речи RHVoice

Предыдущая тема Следующая тема Перейти вниз

Синтезаторы речи - русский синтезатор речи RHVoice

Сообщение  electrik в Сб Апр 21, 2012 1:59 am

не так давно, в свет вышел очередной бесплатный синтезатор русской речи RHVoice. этот синтезатор выпускается под GNU General Public License, тоесть с открытыми исходниками.
он обладает не плохой разборчивостью, средней интонацией. пока имеет два голоса, мужской и женский.
разработала его, неповерите!, девушка - Ольга яковлева. синтезатор разрабатывает, вроде под linux'ом, и портирует еще под windows.
в первую очередь, целью стояло, разработать синтезатор с разборчивой речью, чтобы незрячие могли использовать его в программах экранного доступа.
как раз, первая версия под windows , была сделана под программу экранного доступа nvda.
сейчас же, синтезатор разрабатывается и под программу nvda, и под speech api 5- (sapi5).
естественно, он используется и в программах экранного доступа под linux.
подробно, на чем основан, ссылки на ресурсы, прочитаете в подкаталоге RHVoice-doc.
мне понравился этот синт, и я решил адаптировать заголовочные файлы под FreeBasic.
качаем синтезатор + заголовочный файл + пример программы:
http://svalka-spb.narod.ru/soft/RHVoice.rar
Я НЕСТАЛ ПЕРЕГРУЖАТЬ ПРИМЕР ПРОГРАММЫ КУЧЕЙ ФУНКЦИЙ, ВСЕ ДОЛЖНО БЫТЬ ПОНЯТНО.
ДОКУМЕНТАЦИИ К СИНТЕЗАТОРУ ПОКА НЕТ, НО ЕСЛИ ЧТО-ТО НЕ ПОЙМЕТЕ, БУДЕМ РАЗБИРАТЬСЯ.
ДАННЫЙ ПРИМЕР ПРОГРАММЫ РАБОТАЕТ ТОЛЬКО ПОД WINDOWS.
пользователям LINUX, ЕСЛИ НАЙДЕТЕ, ИЛИ САМИ СМОЖЕТЕ СОБРАТЬ БИБЛИОТЕКУ RHVoice ИЗ ИСХОДНИКОВ, ПРИДЕТСЯ СДЕЛАТЬ некоторые изменения.


файл RHVoice.bi
Код:

'/* Copyright (C) 2010, 2011  Olga Yakovleva <yakovleva.o.v@gmail.com> */

'/* This program is free software: you can redistribute it and/or modify */
'/* it under the terms of the GNU General Public License as published by */
'/* the Free Software Foundation, either version 3 of the License, or */
'/* (at your option) any later version. */

'/* This program is distributed in the hope that it will be useful, */
'/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
'/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
'/* GNU General Public License for more details. */

'/* You should have received a copy of the GNU General Public License */
'/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
' *** adapted headers for FreeBasic by electrik

#ifndef RHVOICE_bi
#define RHVOICE_bi

extern "c" lib "rhvoice"
  type RHVoice_message_s as any
  type as RHVoice_message_s ptr RHVoice_message

  enum RHVoice_init_option
    RHVoice_preload_voices=1
  end enum

  enum RHVoice_message_type
    RHVoice_message_text
    RHVoice_message_ssml
    RHVoice_message_characters
  end enum

  enum RHVoice_event_type
    RHVoice_event_word_start
    RHVoice_event_word_end
    RHVoice_event_sentence_start
    RHVoice_event_sentence_end
    RHVoice_event_mark
    RHVoice_event_play
  end enum


union id_
      as const zstring ptr name        '/* For marks and audio elements */
      as integer number              '/* For words and sentences */
end union

  type  RHVoice_event
    as RHVoice_message message
    as RHVoice_event_type type
    as integer text_position          '/* in unicode characters */
    as integer text_length            '/* in unicode characters */
    as integer audio_position
    union
id as id_
    end union
  end type

  type RHVoice_callback as function (byval samples as const short ptr,byval num_samples as integer,byval events as const RHVoice_event ptr,byval num_events as integer,byval message as RHVoice_message) as integer

  enum RHVoice_position_type
    RHVoice_position_word
    RHVoice_position_sentence
    RHVoice_position_mark
  end enum

    union id2
      as integer number
      as const zstring ptr name
    end union

  type RHVoice_position
    as RHVoice_position_type ptype
union
id as id2
end union
  end type

  enum RHVoice_punctuation_mode
    RHVoice_punctuation_none
    RHVoice_punctuation_all
    RHVoice_punctuation_some
  end enum

  enum RHVoice_voice_gender
    RHVoice_voice_gender_unknown
    RHVoice_voice_gender_male
    RHVoice_voice_gender_female
  end enum

  '/* This mode applies to reading by characters. */
  enum RHVoice_capitals_mode
    RHVoice_capitals_off
    RHVoice_capitals_pitch
    RHVoice_capitals_sound
  end enum

  '/* Under Windows we assume that the paths are in UTF-8 */
  '/* This function returns sample rate on success and 0 on error */
declare function RHVoice_initialize(byval data_path as const zstring ptr,byval callback as RHVoice_callback ptr,byval cfg_path as const zstring ptr,byval options as uinteger) as integer
declare sub RHVoice_terminate()

  '/* The following three functions accept only valid unicode strings */
  declare function RHVoice_new_message_utf8(byval text as const any ptr,byval length as integer,byval mtype as RHVoice_message_type) as RHVoice_message
  declare function RHVoice_new_message_utf16(byval text as const any ptr,byval length as integer,byval mtype as RHVoice_message_type) as RHVoice_message
  declare function RHVoice_new_message_utf32(byval text as const any ptr,byval length as integer,byval mtype as RHVoice_message_type) as RHVoice_message

  declare sub RHVoice_delete_message(byval message as RHVoice_message)
  declare function RHVoice_speak(byval message as RHVoice_message) as integer
  declare function RHVoice_get_xml_base(byval message as RHVoice_message) as const zstring ptr
  declare function RHVoice_set_position(byval message as RHVoice_message,byval position as const RHVoice_position ptr) as integer
  declare function RHVoice_get_word_count(byval message as RHVoice_message) as integer
  declare function RHVoice_get_sentence_count(byval message as RHVoice_message) as integer
  declare sub  RHVoice_set_rate(byval rate as single)
  declare function RHVoice_get_rate() as single
  declare sub RHVoice_set_pitch(byval pitch as single)
  declare function RHVoice_get_pitch() as single
  declare sub RHVoice_set_volume(byval volume as single)
  declare function RHVoice_get_volume() as single
  declare function RHVoice_get_min_rate() as single
  declare function RHVoice_get_default_rate() as single
  declare function RHVoice_get_max_rate() as single
  declare function RHVoice_get_min_pitch() as single
  declare function RHVoice_get_default_pitch() as single
  declare function RHVoice_get_max_pitch() as single
  declare function RHVoice_get_default_volume() as single
  declare function RHVoice_get_max_volume() as single

  declare sub RHVoice_set_variant(byval variant as integer)
  declare function RHVoice_get_variant() as integer
  declare function RHVoice_get_variant_count() as integer
  declare function RHVoice_get_variant_name(byval variant as integer) as const zstring ptr
  declare function RHVoice_find_variant(byval name as const zstring ptr) as integer

  declare function RHVoice_get_voice_count() as integer
  declare function RHVoice_get_voice_name(byval id as integer) as const zstring ptr
  declare function RHVoice_get_voice_gender(byval id as integer) as RHVoice_voice_gender
  declare function RHVoice_find_voice(byval name as const zstring ptr) as integer
  declare sub RHVoice_set_voice(byval id as integer)
  declare function RHVoice_get_voice() as integer

  declare sub RHVoice_set_punctuation_mode(byval mode as RHVoice_punctuation_mode)
  declare function RHVoice_get_punctuation_mode() as RHVoice_punctuation_mode
  declare sub RHVoice_set_punctuation_list(byval list as const zstring ptr)

  declare sub RHVoice_set_capitals_mode(mode as RHVoice_capitals_mode)
  declare function RHVoice_get_capitals_mode() as RHVoice_capitals_mode

  declare sub RHVoice_set_user_data(byval message as RHVoice_message,byval data as any ptr)
  declare function RHVoice_get_user_data(byval message as RHVoice_message) as any ptr

  declare sub RHVoice_set_message_rate(byval message as RHVoice_message,byval rate as single)
  declare sub RHVoice_set_message_pitch(byval message as RHVoice_message,byval pitch as single)
  declare sub RHVoice_set_message_volume(byval message as RHVoice_message,byval volume as single)

  declare function RHVoice_get_version() as const zstring ptr
end extern
#endif

тестовая программа - файл RHVoice.bas
Код:

#include "windows.bi"
#include "win/mmsystem.bi"
#include "crt.bi"
#include "RHVoice.bi"

  declare function  callback cdecl (byval samples as const short ptr,byval num_samples as integer,byval events as const RHVoice_event ptr,byval num_events as integer,byval message as RHVoice_message) as integer
declare sub ShowErrorMessage()
#define nhdr 3
dim shared wFormat as WaveFormatEx ' структура формата звуковых данных
dim  shared wHdr(nhdr) as wavehdr ' структура заголовка буфера
dim shared buf(nhdr) as zstring * 9600 ' буфер для звуковых данных
dim shared numbuf as integer = 0
dim shared lenBuf as integer ' длина буфера
dim shared hOut as HANDLE ' хэндл звукового устройства
dim shared hEvent as HANDLE ' хэндл объекта события
  dim msg as RHVoice_message = 0 ' сообщения RHVoice
dim prog_path as const string = ExePath() ' получим путь к  директории из которой запущена программа
dim Data_path as const string = prog_path & "/RHVoice-data" ' путь к данным синтезатора - там хранятся голоса
dim cfg_path as const string = prog_path & "/RHVoice-config" 'путь к настройкам и словарям синтезатора

dim sample_rate as uInteger ' частота дискретизации

  ' инициализируем RHVoice. функция возвращает частоту дискретизации.  в случае ошибки нуль.
      sample_rate=RHVoice_initialize _
(Data_path, _ ' путь к данным синтезатора
cast(RHvoice_callback ptr, @callback), _ ' указатель на функцию обратного вызова
cfg_path, _ ' путь к настройкам синтезатора
RHVoice_preload_voices) ' опция инициализации - предзагрузка голосов
if sample_rate = 0 then
print "can't initialize RHVoice"
end 1
end if
  ' заполним структуру формата звуковых данных
wFormat.wFormatTag=1 ' данные в формате pcm
wFormat.nChannels= 1 'число каналов 1
wFormat.nSamplesPerSec = sample_rate ' частота дискретизации
wFormat.nAvgBytesPerSec = sample_rate*2 ' частота выдачи байт
wFormat.nBlockAlign= 2 ' выравнивание
wFormat.wBitsPerSample = 16 ' 16 бит на семпл
  ' создадим объект события
hEvent = CreateEvent(NULL,false,false,NULL)
if waveOutOpen(@hOut, -1,@wFormat,cptr(DWORD,hEvent),0,CALLBACK_EVENT) then ' если при открытии устройства произошла ошибка
ShowErrorMessage() ' покажем сообщение об ошибке
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if


dim voice as integer =          RHVoice_find_voice("Aleksandr") ' найдем голос по имени Aleksandr
if voice > 0 then ' если номер голоса больше нуль, значит голос найден
            RHVoice_set_voice(voice) ' установим голос по  номеру
else
print "no voice"
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if

dim testString as string * 512 = "привет. меня зовут александр. я русский синтезатор речи RHVoice. сотворила меня ольга яковлева, за что ей огромное спасибо! "
dim wideString as wstring * 1024 ' юникодовая строка
MultiByteToWideChar(CP_ACP,0,strPtr(testString),len(testString),wideString,len(testString)*2) ' перекодируем анси в юникод
      msg=RHVoice_new_message_utf16 _ ' подготовим текст, который будем говорить
(cast(any ptr,@wideString), _ ' строка с текстом
len(wideString), _ ' длина строки в юникоде
RHVoice_message_text) ' тип сообщения
      if msg= 0 then ' если ошибка
          RHVoice_terminate() ' завершаем работу RHVOICE '
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if
      RHVoice_speak(msg) ' скажем наш текст
      RHVoice_delete_message(msg) ' удаляем сообщение

' выберем другой голос
voice =          RHVoice_find_voice("Elena") ' найдем голос по имени Elena
if voice > 0 then ' если номер голоса больше нуль, значит голос найден
            RHVoice_set_voice(voice) ' установим голос по  номеру
else
print "no voice"
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if

testString = "а меня завут елена. я женский голос синтезатора RHVoice. меня тоже создала ольга."

MultiByteToWideChar(CP_ACP,0,strPtr(testString),len(testString),wideString,len(testString)*2)
      msg=RHVoice_new_message_utf16 _ ' подготовим текст, который будем говорить
(cast(any ptr,@wideString), _ ' строка с текстом
len(wideString), _ ' длина строки
RHVoice_message_text) ' тип сообщения
      if msg= 0 then ' если ошибка
          RHVoice_terminate() ' завершаем работу RHVOICE '
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if
      RHVoice_speak(msg) ' скажем наш текст
      RHVoice_delete_message(msg) ' удаляем сообщение

' вернемся опять к александру
voice =          RHVoice_find_voice("Aleksandr") ' найдем голос по имени Aleksandr
if voice > 0 then ' если номер голоса больше нуль, значит голос найден
            RHVoice_set_voice(voice) ' установим голос по  номеру
else
print "no voice"
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if
RHVoice_set_rate(0.5) ' установим скорость помедленнее
testString = "Я такой пьяный, что язык не ворочается. надо еще за бутылкой сходить."
MultiByteToWideChar(CP_ACP,0,strPtr(testString),len(testString),wideString,len(testString)*2)
      msg=RHVoice_new_message_utf16 _ ' подготовим текст, который будем говорить
(cast(any ptr,@wideString), _ ' строка с текстом
len(wideString), _ ' длина строки
RHVoice_message_text) ' тип сообщения
      if msg= 0 then ' если ошибка
          RHVoice_terminate() ' завершаем работу RHVOICE '
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if
      RHVoice_speak(msg) ' скажем наш текст
      RHVoice_delete_message(msg) ' удаляем сообщение

RHVoice_set_pitch(0.0) ' установим питч по нулям
testString = "ё маё! я уже совсем допился, голос сел нафиг. что же дальше со мной будет! страшно как-то, но за третьей всё равно пойду."
MultiByteToWideChar(CP_ACP,0,strPtr(testString),len(testString),wideString,len(testString)*2)
      msg=RHVoice_new_message_utf16 _ ' подготовим текст, который будем говорить
(cast(any ptr,@wideString), _ ' строка с текстом
len(wideString), _ ' длина строки
RHVoice_message_text) ' тип сообщения
      if msg= 0 then ' если ошибка
          RHVoice_terminate() ' завершаем работу RHVOICE '
closeHandle(hOut)
CloseHandle(hEvent) ' закроем хэндл объекта события
end 1
end if
      RHVoice_speak(msg) ' скажем наш текст
      RHVoice_delete_message(msg) ' удаляем сообщение


      RHVoice_terminate() ' завершим работу RHVoice
WaveOutClose(hOut) ' закроем устройство воспроизведения
CloseHandle(hEvent) ' закроем хэндл объекта события
end

  ' функция обратного вызова
  ' в ней мы будем выводить звуковые данные на звуковую карту
function  callback cdecl _
(byval samples as const short ptr, _ ' указатель на буфер со звуковыми данными
byval num_samples as integer, _ ' число семплов(отсчетов) - в нашем случае один семпл 16 бит - 2 байта(short)
byval events as const RHVoice_event ptr, _ ' указатель на события
byval num_events as integer, _ ' число событий
byval message as RHVoice_message) as integer ' сообщение

lenBuf = num_samples*sizeof(short)
memcpy(@buf(numbuf),cast(any ptr,samples),lenbuf)
  ' заполним структуру заголовка буфера воспроизведения
wHdr(numbuf).lpData = @buf(numbuf)
wHdr(numbuf).dwBufferLength = lenbuf

  ' подготовим заголовок буфера
waveOutPrepareHeader(hOut,@wHdr(numbuf),32)

    ' проиграем буфер
WaveOutWrite(hOut,@wHdr(numbuf),32)
WaitForSingleObject(hEvent, infinite) ' ждем пока драйвер не вернет буфер

WaveOutUnprepareHeader(hOut,@wHdr(numbuf),32)

numbuf +=1
if numbuf > 3 then numbuf = 0

return 1
end function

sub ShowErrorMessage()
dim as dword errid = GetLastError()
dim as zstring * 1024 formatString
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,errid,0,@formatString,1023,0)
messageBox(0,formatString,"RTC",MB_ICONERROR or MB_TASKMODAL)
end sub

electrik

Сообщения : 394
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Синтезаторы речи - русский синтезатор речи RHVoice

Сообщение  trew в Сб Апр 21, 2012 8:36 am

Дааа.. Я в шоке! Умница Ольга! Реалистичность голоса на хорошем уровне. Женский голос (по крайней мере та фраза, которая в примере) вообще кажется реальным. Спасибо ей. И конечно спасибо тебе electrik за адаптацию проекта. Теперь при желании можно кое-какие подсказки в своих прогах озвучивать, да и вообще с таким голосом читалку не стыдно сделать.

Единственно у меня в пути до проекта с движком были русские символы. С таким подходом инициализация не выполняется. Так что размещать движок надо строго в английской директории.

P.S. Если не против, размещу адаптированный проект на своем сайте для скачивания.

trew

Сообщения : 331
Дата регистрации : 2010-10-14

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Синтезаторы речи - русский синтезатор речи RHVoice

Сообщение  electrik в Сб Апр 21, 2012 11:06 am

привет. конечно можно, даже нужно. ведь ваш сайт уже много народу посещает,
поповоду русских букв, я еще не разобрался. в комментариях к функции инициализации,написано, что кодировка путей должна быть в utf-8.
'/* Under Windows we assume that the paths are in UTF-8 */
пока я не знаю, как в utf-8 кодируются русские буквы.
а так можно, сделать перекодировку строки и вперед.
синтезатор может читать из кодировок utf-8?, utf-16 и utf-32.
вообще, надо обертки сделать, просто типа:
speak("hello world")

electrik

Сообщения : 394
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Синтезаторы речи - русский синтезатор речи RHVoice

Сообщение  trew в Сб Апр 21, 2012 2:17 pm

вообще, надо обертки сделать, просто типа:
speak("hello world")

Ты уже решил это делать или неопределенно? Если решил, тогда я подожду выкладывать, потом сразу готовое с обертками выложу.

trew

Сообщения : 331
Дата регистрации : 2010-10-14

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Синтезаторы речи - русский синтезатор речи RHVoice

Сообщение  electrik в Сб Апр 21, 2012 3:44 pm

пока нет. я думаю, тут уж каждый сам под себя сделает. кто-то любит процедурное программирование, а кто-то объектноорентированное.

electrik

Сообщения : 394
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Синтезаторы речи - русский синтезатор речи RHVoice

Сообщение  Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения