2010-06-13 50 views
11

Antes que nada: esto no es un duplicado de Delphi and SAPI. Tengo un problema específico con el tema "SAPI en Delphi".Delphi SAPI Text-To-Speech

He utilizado la excelente guía Import Type-Library en Delphi 2009 para obtener un componente TSpVoice en la paleta de componentes. Esto funciona genial Con

var 
    SpVoice: TSpVoice; 

Puedo escribir

SpVoice.Speak('This is an example.', 1); 

para obtener salida de audio asíncrono.

Primera pregunta

Según la documentación, que sería capaz de escribir

SpVoice.Speak('This is an example.', 0); 

para obtener salida de audio sincrónica, pero en lugar de eso obtener una excepción EZeroDivide. ¿Porque eso?

Segunda pregunta

Pero lo más importante, me gustaría ser capaz de crear el objeto SpVoice dinámicamente (creo que esto es llamado a "late-bind" el objeto SpVoice), en parte debido a que sólo una fracción muy pequeña de todas las sesiones de mi aplicación lo usará, y en parte porque no quiero suponer la existencia del servidor SAPI en el sistema del usuario final.

Con este fin, he intentado

procedure TForm1.FormClick(Sender: TObject); 
var 
    SpVoice: Variant; 
begin 
    SpVoice := CreateOleObject('SAPI.SpVoice'); 
    SpVoice.Speak('this is a test', 0); 
end; 

que aparentemente no hace nada en absoluto! (Sustitución de la 0 a 1 me da la excepción EZeroDivide.)

Negación

Soy bastante nuevo en la automatización COM/OLE. Lo siento por cualquier ignorancia o estupidez mostrado por mí en este post ...

actualización

Para el beneficio de todos encontrarse con el mismo problema que yo, el video por François explicó que hay un error en el SAPI/Windows (alguna incompatibilidad alguna parte), lo que hace que el siguiente código elevar la excepción EZeroDivide:

procedure TForm1.FormClick(Sender: TObject); 
var 
    SpVoice: variant; 
begin 
    SpVoice := CreateOleObject('SAPI.SpVoice'); 
    SpVoice.Speak('This is a text.'); 
end; 

la solución, según lo presentado por el video, es alterar la palabra de control FPU:

procedure TForm1.FormClick(Sender: TObject); 
var 
    SpVoice: variant; 
    SavedCW: Word; 
begin 
    SpVoice := CreateOleObject('SAPI.SpVoice'); 
    SavedCW := Get8087CW; 
    Set8087CW(SavedCW or $4); 
    SpVoice.Speak('This is a text.'); 
    Set8087CW(SavedCW); 
end; 

Y, además, si desea reproducir un sonido de forma asíncrona, ¡entonces debe asegurarse de que el reproductor no se salga de alcance!

Respuesta

4

Le puede interesar ver this CodeRage 4 session en "Speech Enabling Delphi Applications (zip)" Obtendrá el "cómo hacerlo" que está buscando ... (y supongo que está en Vista o + ya que la división cero no se produjo en XP)

+0

Ah, muchas gracias! Entonces, ¡no era solo que yo fuera estúpido! –

+0

BTW: ¡No dude en eliminar el signo de interrogación al lado de su nombre si desea atribuirse el mérito del video! :) –

1

Estaba teniendo el mismo problema en Delphi XE2. La solución Set8087CW(SavedCW or $4) presentada en la pregunta no funcionó para mí. Simplemente reemplazó la división por excepción cero con otra excepción de coma flotante.

Lo que funcionó para mí es la siguiente:

SavedCW := Get8087CW; 
SetFPUExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]); 
SpVoice.Speak('All floating point exceptions disabled!', 0); 
Set8087CW(SavedCW);