Titre: Faire parler votre application Delphi avec Acapela Multimedia (07/06/2006 Par zion)
Installation
On a déjà parlé a plusieurs reprises d'Acapela dans nos colonnes, à savoir par exemple que c'est le moteur d'Acapela qui est utilisé par le lapin Nabaztag. Imaginons maintenant que vous ayez besoin de faire parler votre application avec une voix de haute qualité avec Acapela? Est-ce compliqué?

Pour la sortie d'Acapela Multimedia 6.0, nous avons décidé de tenter le coup pour vous, et de faire une mini application de démonstration en Delphi.

images/articles/article785/001.png

Après installation des librairies Acapela, de la documentation et des exemples, il faut demander une licence de 30 jours pour la machine en lançant LicMan.exe et en cliquant sur "30 days free trial". Nous voici donc prêt pour la programmation!

images/articles/article785/002.png
On lance Delphi!
Première étape, on va importer la librairie Acapela pour pouvoir utiliser le contrôle ActiveX dans Delphi. Plus besoin de s'amuser à lire des headers en C et de tenter des les convertir, les interfaces simplifient grandement le travail.

images/articles/article785/003.png

Après avoir cliqué sur "Import ActiveX Control", il faut ensuite locliser la librairie d'Acapela dans la liste, à savoir ASASpeechCtl. Une fois cela fait, on clique ensuite sur "Create Unit" pour générer le code du composant permettant d'utiliser la librairie.

images/articles/article785/004.png

Comme pour ton nouveau composant Delphi, il faut maintenant l'installer dans un package et ensuite compiler et installer le package pour avoir accès au nouveau composant.

images/articles/article785/005.png

  1. type 
  2. // *********************************************************************// 
  3. // Forward declaration of types defined in TypeLibrary  
  4. // *********************************************************************// 
  5.   _IAASpeechCtrlEvents = dispinterface
  6.   IAAVoiceCtrl = interface
  7.   IAAVoiceCtrlDisp = dispinterface
  8.   IAASpeechCtrl = interface
  9.   IAASpeechCtrlDisp = dispinterface
  10. // *********************************************************************// 
  11. // Declaration of CoClasses defined in Type Library  
  12. // (NOTE: Here we map each CoClass to its Default Interface)  
  13. // *********************************************************************// 
  14.   AASpeechCtrl = IAASpeechCtrl; 
  15.   AAVoiceCtrl = IAAVoiceCtrl; 
  16. // *********************************************************************// 
  17. // DispIntf: _IAASpeechCtrlEvents 
  18. // Flags: (4096) Dispatchable 
  19. // GUID: {68C6D73C-A7EB-4899-BFA7-960793CF0EF6} 
  20. // *********************************************************************// 
  21.   _IAASpeechCtrlEvents = dispinterface 
  22.     ['{68C6D73C-A7EB-4899-BFA7-960793CF0EF6}'
  23.     procedure AudioOpen; dispid 1
  24.     procedure AudioClose; dispid 2
  25.     procedure TextStart(lTextId: Integer); dispid 3
  26.     procedure TextEnd(lTextId: Integer); dispid 4
  27.     procedure WordPosition(lTextId: Integer; lWordPos: Integer; lByteCount: Integer); dispid 5
  28.     procedure Phoneme(lTextId: Integer; sEnginePhoneme1: Smallint; sEnginePhoneme2: Smallint;  
  29.                       sIPAPhoneme1: Smallint; sIPAPhoneme2: Smallint; lDuration: Integer;  
  30.                       lByteCount: Integer); dispid 6
  31.     procedure AudioData(lTextId: Integer; lDataCount: Integer; lDataSize: Integer); dispid 7
  32.     procedure LastError(lErrorCode: Integer); dispid 8
  33.     procedure AcaPhoneme(lTextId: Integer; sEnginePhoneme1: Smallint; sEnginePhoneme2: Smallint;  
  34.                          sEnginePhoneme3: Smallint; sEnginePhoneme4: Smallint;  
  35.                          sIPAPhoneme1: Smallint; lDuration: Integer; lByteCount: Integer); dispid 9
  36.     procedure MouthPosition(lTextId: Integer; sIPAPhoneme1: Smallint; sMouthPos1: Smallint;  
  37.                             sMouthPos2: Smallint; sMouthPos3: Smallint; sMouthPos4: Smallint;  
  38.                             sMouthPos5: Smallint; sMouthPos6: Smallint; sMouthPos7: Smallint;  
  39.                             sMouthPos8: Smallint; lDuration: Integer; lByteCount: Integer); dispid 10
  40.   end
  41. // *********************************************************************// 
  42. // Interface: IAAVoiceCtrl 
  43. // Flags: (4416) Dual OleAutomation Dispatchable 
  44. // GUID: {B94DA5AB-91C0-4B1A-B0E4-E45A0075905F} 
  45. // *********************************************************************// 
  46.   IAAVoiceCtrl = interface(IDispatch) 
  47.     ['{B94DA5AB-91C0-4B1A-B0E4-E45A0075905F}'
  48.     function Get_Cmd: WideString; safecall; 
  49.     function Get_Gender: Smallint; safecall; 
  50.     function Get_Language: Integer; safecall; 
  51.     function Get_Speaker: WideString; safecall; 
  52.     function Get_Index: Smallint; safecall; 
  53.     function Get_Frequency: Integer; safecall; 
  54.     property Cmd: WideString read Get_Cmd; 
  55.     property Gender: Smallint read Get_Gender; 
  56.     property Language: Integer read Get_Language; 
  57.     property Speaker: WideString read Get_Speaker; 
  58.     property Index: Smallint read Get_Index; 
  59.     property Frequency: Integer read Get_Frequency; 
  60.   end
  61. // *********************************************************************// 
  62. // DispIntf: IAAVoiceCtrlDisp 
  63. // Flags: (4416) Dual OleAutomation Dispatchable 
  64. // GUID: {B94DA5AB-91C0-4B1A-B0E4-E45A0075905F} 
  65. // *********************************************************************// 
  66.   IAAVoiceCtrlDisp = dispinterface 
  67.     ['{B94DA5AB-91C0-4B1A-B0E4-E45A0075905F}'
  68.     property Cmd: WideString readonly dispid 1
  69.     property Gender: Smallint readonly dispid 3
  70.     property Language: Integer readonly dispid 4
  71.     property Speaker: WideString readonly dispid 5
  72.     property Index: Smallint readonly dispid 6
  73.     property Frequency: Integer readonly dispid 7
  74.   end
  75. // *********************************************************************// 
  76. // Interface: IAASpeechCtrl 
  77. // Flags: (4416) Dual OleAutomation Dispatchable 
  78. // GUID: {543BD792-CB83-4E88-8868-FC8392ABD9D6} 
  79. // *********************************************************************// 
  80.   IAASpeechCtrl = interface(IDispatch) 
  81.     ['{543BD792-CB83-4E88-8868-FC8392ABD9D6}'
  82.     function ConnectEngine(nConnectionMode: SYSINT; nPort: SYSINT;  
  83.                            const bstrServerAddress: WideString): Integer; safecall; 
  84.     function DisconnectEngine: Integer; safecall; 
  85.     function Enumerate: Integer; safecall; 
  86.     function Load(const bstrCmd: WideString): Integer; safecall; 
  87.     function Unload: Integer; safecall; 
  88.     function Speak(const bstrText: WideString; lTextId: Integer): Integer; safecall; 
  89.     function Stop: Integer; safecall; 
  90.     function Pause: Integer; safecall; 
  91.     function Resume: Integer; safecall; 
  92.     function EventMask(ulEvtMask: Integer): Integer; safecall; 
  93.     function GetVarAudioData(vData: OleVariant): Integer; safecall; 
  94.     function GetAudioData(var pData: Integer; lDataSize: Integer): Integer; safecall; 
  95.     function Get_Voice(nIndex: SYSINT): IAAVoiceCtrl; safecall; 
  96.     function Get_CurrentVoice: IAAVoiceCtrl; safecall; 
  97.     function Get_VoiceCount: Smallint; safecall; 
  98.     function Get_Output: Smallint; safecall; 
  99.     procedure Set_Output(pVal: Smallint); safecall; 
  100.     function Get_FileName: WideString; safecall; 
  101.     procedure Set_FileName(const pbstrFileName: WideString); safecall; 
  102.     function Get_Volume: Smallint; safecall; 
  103.     procedure Set_Volume(pVal: Smallint); safecall; 
  104.     function Get_Pitch: Smallint; safecall; 
  105.     procedure Set_Pitch(pVal: Smallint); safecall; 
  106.     function Get_Speed: Smallint; safecall; 
  107.     procedure Set_Speed(pVal: Smallint); safecall; 
  108.     function Get_Status: Smallint; safecall; 
  109.     function Get_LastError: Integer; safecall; 
  110.     procedure Set_OEMKey(const Param1: WideString); safecall; 
  111.     procedure ServerShutdown(nState: SYSINT); safecall; 
  112.     property Voice[nIndex: SYSINT]: IAAVoiceCtrl read Get_Voice; 
  113.     property CurrentVoice: IAAVoiceCtrl read Get_CurrentVoice; 
  114.     property VoiceCount: Smallint read Get_VoiceCount; 
  115.     property Output: Smallint read Get_Output write Set_Output; 
  116.     property FileName: WideString read Get_FileName write Set_FileName; 
  117.     property Volume: Smallint read Get_Volume write Set_Volume; 
  118.     property Pitch: Smallint read Get_Pitch write Set_Pitch; 
  119.     property Speed: Smallint read Get_Speed write Set_Speed; 
  120.     property Status: Smallint read Get_Status; 
  121.     property LastError: Integer read Get_LastError; 
  122.     property OEMKey: WideString write Set_OEMKey; 
  123.   end
  124. // *********************************************************************// 
  125. // DispIntf: IAASpeechCtrlDisp 
  126. // Flags: (4416) Dual OleAutomation Dispatchable 
  127. // GUID: {543BD792-CB83-4E88-8868-FC8392ABD9D6} 
  128. // *********************************************************************// 
  129.   IAASpeechCtrlDisp = dispinterface 
  130.     ['{543BD792-CB83-4E88-8868-FC8392ABD9D6}'
  131.     function ConnectEngine(nConnectionMode: SYSINT; nPort: SYSINT;  
  132.                            const bstrServerAddress: WideString): Integer; dispid 1
  133.     function DisconnectEngine: Integer; dispid 2
  134.     function Enumerate: Integer; dispid 3
  135.     function Load(const bstrCmd: WideString): Integer; dispid 4
  136.     function Unload: Integer; dispid 5
  137.     function Speak(const bstrText: WideString; lTextId: Integer): Integer; dispid 6
  138.     function Stop: Integer; dispid 7
  139.     function Pause: Integer; dispid 8
  140.     function Resume: Integer; dispid 9
  141.     function EventMask(ulEvtMask: Integer): Integer; dispid 10
  142.     function GetVarAudioData(vData: OleVariant): Integer; dispid 11
  143.     function GetAudioData(var pData: Integer; lDataSize: Integer): Integer; dispid 12
  144.     property Voice[nIndex: SYSINT]: IAAVoiceCtrl readonly dispid 13
  145.     property CurrentVoice: IAAVoiceCtrl readonly dispid 14
  146.     property VoiceCount: Smallint readonly dispid 15
  147.     property Output: Smallint dispid 16
  148.     property FileName: WideString dispid 17
  149.     property Volume: Smallint dispid 18
  150.     property Pitch: Smallint dispid 19
  151.     property Speed: Smallint dispid 20
  152.     property Status: Smallint readonly dispid 21
  153.     property LastError: Integer readonly dispid 22
  154.     property OEMKey: WideString writeonly dispid 23
  155.     procedure ServerShutdown(nState: SYSINT); dispid 24
  156.   end
  157. // *********************************************************************// 
  158. // OLE Control Proxy class declaration 
  159. // Control Name : TAASpeechCtrl 
  160. // Help String : AASpeechCtrl Class 
  161. // Default Interface: IAASpeechCtrl 
  162. // Def. Intf. DISP? : No 
  163. // Event Interface: _IAASpeechCtrlEvents 
  164. // TypeFlags : (2) CanCreate 
  165. // *********************************************************************// 
  166.   TAASpeechCtrlTextStart = procedure(ASender: TObject; lTextId: Integer) of object
  167.   TAASpeechCtrlTextEnd = procedure(ASender: TObject; lTextId: Integer) of object
  168.   TAASpeechCtrlWordPosition = procedure(ASender: TObject; lTextId: Integer; lWordPos: Integer;  
  169.                                                           lByteCount: Integer) of object
  170.   TAASpeechCtrlPhoneme = procedure(ASender: TObject; lTextId: Integer; sEnginePhoneme1: Smallint; 
  171.                                                      sEnginePhoneme2: Smallint;  
  172.                                                      sIPAPhoneme1: Smallint;  
  173.                                                      sIPAPhoneme2: Smallint; lDuration: Integer;  
  174.                                                      lByteCount: Integer) of object
  175.   TAASpeechCtrlAudioData = procedure(ASender: TObject; lTextId: Integer; lDataCount: Integer;  
  176.                                                        lDataSize: Integer) of object
  177.   TAASpeechCtrlLastError = procedure(ASender: TObject; lErrorCode: Integer) of object
  178.   TAASpeechCtrlAcaPhoneme = procedure(ASender: TObject; lTextId: Integer;  
  179.                                                         sEnginePhoneme1: Smallint;  
  180.                                                         sEnginePhoneme2: Smallint;  
  181.                                                         sEnginePhoneme3: Smallint;  
  182.                                                         sEnginePhoneme4: Smallint;  
  183.                                                         sIPAPhoneme1: Smallint; lDuration: Integer;  
  184.                                                         lByteCount: Integer) of object
  185.   TAASpeechCtrlMouthPosition = procedure(ASender: TObject; lTextId: Integer;  
  186.                                                            sIPAPhoneme1: Smallint;  
  187.                                                            sMouthPos1: Smallint;  
  188.                                                            sMouthPos2: Smallint;  
  189.                                                            sMouthPos3: Smallint;  
  190.                                                            sMouthPos4: Smallint;  
  191.                                                            sMouthPos5: Smallint;  
  192.                                                            sMouthPos6: Smallint;  
  193.                                                            sMouthPos7: Smallint;  
  194.                                                            sMouthPos8: Smallint;  
  195.                                                            lDuration: Integer; lByteCount: Integer) of object
  196.   TAASpeechCtrl = class(TOleControl) 
  197.   private 
  198.     FOnAudioOpen: TNotifyEvent; 
  199.     FOnAudioClose: TNotifyEvent; 
  200.     FOnTextStart: TAASpeechCtrlTextStart; 
  201.     FOnTextEnd: TAASpeechCtrlTextEnd; 
  202.     FOnWordPosition: TAASpeechCtrlWordPosition; 
  203.     FOnPhoneme: TAASpeechCtrlPhoneme; 
  204.     FOnAudioData: TAASpeechCtrlAudioData; 
  205.     FOnLastError: TAASpeechCtrlLastError; 
  206.     FOnAcaPhoneme: TAASpeechCtrlAcaPhoneme; 
  207.     FOnMouthPosition: TAASpeechCtrlMouthPosition; 
  208.     FIntf: IAASpeechCtrl; 
  209.     function  GetControlInterface: IAASpeechCtrl; 
  210.   protected 
  211.     procedure CreateControl; 
  212.     procedure InitControlData; override; 
  213.     function Get_Voice(nIndex: SYSINT): IAAVoiceCtrl; 
  214.     function Get_CurrentVoice: IAAVoiceCtrl; 
  215.   public 
  216.     function ConnectEngine(nConnectionMode: SYSINT; nPort: SYSINT;  
  217.                            const bstrServerAddress: WideString): Integer; 
  218.     function DisconnectEngine: Integer; 
  219.     function Enumerate: Integer; 
  220.     function Load(const bstrCmd: WideString): Integer; 
  221.     function Unload: Integer; 
  222.     function Speak(const bstrText: WideString; lTextId: Integer): Integer; 
  223.     function Stop: Integer; 
  224.     function Pause: Integer; 
  225.     function Resume: Integer; 
  226.     function EventMask(ulEvtMask: Integer): Integer; 
  227.     function GetVarAudioData(vData: OleVariant): Integer; 
  228.     function GetAudioData(var pData: Integer; lDataSize: Integer): Integer; 
  229.     procedure ServerShutdown(nState: SYSINT); 
  230.     property  ControlInterface: IAASpeechCtrl read GetControlInterface; 
  231.     property  DefaultInterface: IAASpeechCtrl read GetControlInterface; 
  232.     property Voice[nIndex: SYSINT]: IAAVoiceCtrl read Get_Voice; 
  233.     property CurrentVoice: IAAVoiceCtrl read Get_CurrentVoice; 
  234.     property VoiceCount: Smallint index 15 read GetSmallintProp; 
  235.     property Status: Smallint index 21 read GetSmallintProp; 
  236.     property LastError: Integer index 22 read GetIntegerProp; 
  237.     property OEMKey: WideString index 23 write SetWideStringProp; 
  238.   published 
  239.     property Anchors; 
  240.     property  TabStop; 
  241.     property  Align; 
  242.     property  DragCursor; 
  243.     property  DragMode; 
  244.     property  ParentShowHint; 
  245.     property  PopupMenu; 
  246.     property  ShowHint; 
  247.     property  TabOrder; 
  248.     property  Visible; 
  249.     property  OnDragDrop; 
  250.     property  OnDragOver; 
  251.     property  OnEndDrag; 
  252.     property  OnEnter; 
  253.     property  OnExit; 
  254.     property  OnStartDrag; 
  255.     property Output: Smallint index 16 read GetSmallintProp write SetSmallintProp stored False; 
  256.     property FileName: WideString index 17 read GetWideStringProp write SetWideStringProp stored False; 
  257.     property Volume: Smallint index 18 read GetSmallintProp write SetSmallintProp stored False; 
  258.     property Pitch: Smallint index 19 read GetSmallintProp write SetSmallintProp stored False; 
  259.     property Speed: Smallint index 20 read GetSmallintProp write SetSmallintProp stored False; 
  260.     property OnAudioOpen: TNotifyEvent read FOnAudioOpen write FOnAudioOpen; 
  261.     property OnAudioClose: TNotifyEvent read FOnAudioClose write FOnAudioClose; 
  262.     property OnTextStart: TAASpeechCtrlTextStart read FOnTextStart write FOnTextStart; 
  263.     property OnTextEnd: TAASpeechCtrlTextEnd read FOnTextEnd write FOnTextEnd; 
  264.     property OnWordPosition: TAASpeechCtrlWordPosition read FOnWordPosition write FOnWordPosition; 
  265.     property OnPhoneme: TAASpeechCtrlPhoneme read FOnPhoneme write FOnPhoneme; 
  266.     property OnAudioData: TAASpeechCtrlAudioData read FOnAudioData write FOnAudioData; 
  267.     property OnLastError: TAASpeechCtrlLastError read FOnLastError write FOnLastError; 
  268.     property OnAcaPhoneme: TAASpeechCtrlAcaPhoneme read FOnAcaPhoneme write FOnAcaPhoneme; 
  269.     property OnMouthPosition: TAASpeechCtrlMouthPosition read FOnMouthPosition write FOnMouthPosition; 
  270.   end
  271. // *********************************************************************// 
  272. // The Class CoAAVoiceCtrl provides a Create and CreateRemote method to  
  273. // create instances of the default interface IAAVoiceCtrl exposed by  
  274. // the CoClass AAVoiceCtrl. The functions are intended to be used by  
  275. // clients wishing to automate the CoClass objects exposed by the  
  276. // server of this typelibrary.  
  277. // *********************************************************************// 
  278.   CoAAVoiceCtrl = class 
  279.     class function Create: IAAVoiceCtrl; 
  280.     class function CreateRemote(const MachineName: string): IAAVoiceCtrl; 
  281.   end;

Et si on codait?
On est donc parti! On va donc commencer par créer le composant dans le FormCreate.

Le ConnectEngine est obligatoire pour pouvoir commencer à utiliser Acapela. Les 3 paramètres sont obligatoires et ne peuvent être que ces valeurs, pas trop de problème donc pour le moment.

  1. procedure TForm1.FormCreate(Sender: TObject); 
  2. begin 
  3.   FSpeech := TAASpeechCtrl.Create(self); 
  4.   if FSpeech.ConnectEngine(10'') <> 0 then 
  5.     raise Exception.Create('Unable to connect to the API'); 
  6.   FSpeechVoice := -1
  7. end;


Après création du contrôle, on peut maintenant faire la liste des voix disponibles. Pour la démonstration, seules les voix francophones ont été installées, mais il existe des dizaines de voix dans toutes les langues les plus courantes.

  1. procedure TForm1.Button1Click(Sender: TObject); 
  2. var 
  3.  i: Integer; 
  4. begin 
  5.   case FSpeech.Enumerate of 
  6.     EAS_NOT_CONNECTED: 
  7.       raise Exception.Create('API Not connected'); 
  8.     EAS_NOT_ENOUGH_MEMORY: 
  9.       raise Exception.Create('Not enough memory'); 
  10.     EAS_SRV_NOTRUNNING: 
  11.       raise Exception.Create('SRV Not Running'); 
  12.   end
  13.   for i:=0 to FSpeech.VoiceCount-1 do 
  14.     ListBox1.Items.Add(FSpeech.Voice[ i ].Speaker); 
  15. end;


Si tout s'est bien déroulé jusqu'ici, il ne reste maintenant plus qu'à faire parler notre application... Et rien de plus simple à vrai dire.

On sélectionne tout d'abord la voix dans la listbox et on utilise le .cmd au lieu du .speaker. Une fois la voix chargée, il suffit d'utiliser la fonction speak avec le texte à annoncer.

  1. procedure TForm1.Button2Click(Sender: TObject); 
  2. begin 
  3.   if ListBox1.ItemIndex = -1 then 
  4.     raise Exception.Create('Please select a voice first'); 
  5.   if FSpeechVoice <> ListBox1.ItemIndex then 
  6.   begin 
  7.     if FSpeechVoice <> -1 then 
  8.       FSpeech.Unload; 
  9.     FSpeechVoice := ListBox1.ItemIndex; 
  10.     FSpeechVoiceID := FSpeech.Load(FSpeech.Voice[FSpeechVoice].Cmd); 
  11.   end
  12.   FSpeech.Speak(Memo1.Text, FSpeechVoiceID); 
  13. end;


Pour être un tant soit peu soigneux, il ne faudrait pas non plus oublier d'unloader de moteur TTS (Text To Speech), d'appeler la méthode de fermeture du moteur et de le libérer.

  1. procedure TForm1.FormDestroy(Sender: TObject); 
  2. begin 
  3.   FSpeech.Unload; 
  4.   FSpeech.DisconnectEngine; 
  5.   FreeAndNil(FSpeech); 
  6. end;


C'était un bref aperçu, on peut utiliser ce code pour commencer à faire parler son application Delphi, mais il est encore possible de paramétrer pleins de choses comme la vitesse, le pitch, le volume et de réagir à toute une série d'événement pour savoir quand le TTS a terminé de parler, etc, etc...

Tout cela est parfaitement documenté dans le fichier AcaMul-ActiveX-6.pdf d'Acapela.
Et ça donne?
Pas de magnifique interface, c'est à vous de jouer. Le premier bouton à gauche rempli la ListBox des voix disponibles. Le deuxièle à droite envoie le texte au moteur Acapela en ayant chargé la voix sélectionnée dans la ListBox.

images/articles/article785/006.png

Il va de soit que l'exemple ici est un peu précaire, il n'y a que peu de protections et il n'est pas très fonctionnel, il est donc conseillé de faire un peu plus attention à ce qui pourrait mal se passer à chaque étape.

Les sources du programme
Bruno HQ
Caroline HD
Claire HQ
Pierre HD

Alors, conquis?
Retour