ネタキリラボ
ネタキリラボ[ラボ]

日本語音声合成(AquesTalk)サンプル

準備

サンプルソース

Delphiで「AquesTalk.dll」と「AquesTalkDa.dll」のラッパークラスを作成して利用しています。

「AquesTalk Win版」付属のC++のソースを参考に作りましたが、完全に同じ動作をするわけではありません。

フォーム

付属のサンプルは動作ログが出力されますが、面倒くさいんで省きました。代わりに声を変えれるように音声合成DLLを選択仕直せる機能を付けました。

AquesTalk-サンプルアプリ

リスト1 サンプルプログラム

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, AqTalk, ComCtrls, Buttons, ExtCtrls, DateUtils;

type
  TForm1 = class(TForm)
    GroupBox1: TGroupBox;
    ComboBox1: TComboBox;
    Button1: TButton;
    TrackBar1: TTrackBar;
    StopButton: TButton;
    GroupBox2: TGroupBox;
    GroupBox3: TGroupBox;
    Edit1: TEdit;
    ComboBox2: TComboBox;
    Label1: TLabel;
    Label2: TLabel;
    Button2: TButton;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    SpeedButton1: TSpeedButton;
    SpeedButton2: TSpeedButton;
    GroupBox4: TGroupBox;
    ChangeButton: TButton;
    OpenDialog1: TOpenDialog;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    SpeedLabel: TLabel;
    GroupBox5: TGroupBox;
    Memo1: TMemo;
    Button6: TButton;
    Button7: TButton;
    SaveDialog1: TSaveDialog;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure StopButtonClick(Sender: TObject);
    procedure ChangeButtonClick(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure WMUserDadone (var msg: TMessage); message WM_USR_DADONE;
    procedure PlaySheep;
  public
    { Public 宣言 }
    AquesTalk: TAquesTalk;
  end;

var
  Form1: TForm1;
  m_iSheep: Integer;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  AquesTalk := TAquesTalk.Create;
  OpenDialog1.InitialDir := ExtractFileDir(Application.ExeName);
  SpeedLabel.Caption := IntToStr(AquesTalk.Speed);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  AquesTalk.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  AquesTalk.Play(ComboBox1.Items[ComboBox1.ItemIndex]);
end;

procedure TForm1.StopButtonClick(Sender: TObject);
begin
  AquesTalk.Stop;
  m_iSheep := 0;
end;

procedure TForm1.ChangeButtonClick(Sender: TObject);
begin
  AquesTalk.VoiceChange(LabeledEdit1.Text, LabeledEdit2.Text);
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then begin
    LabeledEdit1.Text := OpenDialog1.FileName;
  end;
end;

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
  if OpenDialog1.Execute then begin
    LabeledEdit2.Text := OpenDialog1.FileName;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var koe, strNum, strUnit: string;
begin
  strNum := Edit1.Text;  //数値の取得
  strUnit := ComboBox2.Items[ComboBox2.ItemIndex];  //単位の取得
  //読み記号部分を抽出
  strUnit := Trim(Copy(strUnit, AnsiPos(' ',strUnit), Length(strUnit)));
  koe := Format('<NUMK VAL=%s COUNTER=%s>。', [strNum, strUnit]);
  AquesTalk.Play(koe);
end;

procedure TForm1.Button3Click(Sender: TObject);
var koe: string;
  n: TDateTime;
begin
  n := Now;
  koe := '<NUMK VAL=' + IntToStr(YearOf(n)) + ' COUNTER=ねん>;' +
         '<NUMK VAL=' + IntToStr(MonthOf(n)) + ' COUNTER=がつ>;' +
         '<NUMK VAL=' + IntToStr(DayOf(n)) + ' COUNTER=にち>デ_ス。';
  AquesTalk.Play(koe);
end;

procedure TForm1.Button4Click(Sender: TObject);
var koe: string;
  n: TDateTime;
begin
  n := Now;
  koe := '<NUMK VAL=' + IntToStr(HourOf(n)) + ' COUNTER=じ>;' +
         '<NUMK VAL=' + IntToStr(MinuteOf(n)) + ' COUNTER=ふん>;' +
         '<NUMK VAL=' + IntToStr(SecondOf(n)) + ' COUNTER=びょー>です。';
  AquesTalk.Play(koe);
end;

procedure TForm1.PlaySheep;
var koe: string;
begin
  case m_iSheep of
    14: koe := 'ひつじの/メ''リーさん。';
    22: koe := 'ひつじが/ころんだ。';
    27: koe := 'ひつじが/いっぱい、';
    45: koe := 'も''−;ねむく+なくな''ったよ、';
    65: koe := 'し''つじの/セバ''_スチャン。';
  else koe := Format('ひつじが/<NUMK VAL=%d COUNTER=ひき>。', [m_iSheep]);
  end;
  Inc(m_iSheep);
  AquesTalk.Play(koe, Handle, WM_USR_DADONE, ID_SHEEP);
end;

procedure TForm1.WMUserDadone(var msg: TMessage);
begin
  if (msg.LParam = ID_SHEEP) and (m_iSheep <> 0) then PlaySheep;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  m_iSheep := 1;
  PlaySheep;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  AquesTalk.Speed := TrackBar1.Position; 
  SpeedLabel.Caption := IntToStr(AquesTalk.Speed);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  AquesTalk.Play(Memo1.Lines.Text);
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
  if SaveDialog1.Execute then begin
    AquesTalk.Synthe(SaveDialog1.FileName, Memo1.Lines.Text);
  end;
end;

end.

リスト2 DLLのラッパークラス

unit AqTalk;

interface

uses
  Windows, SysUtils, Messages;

const
  WM_USR_DADONE = WM_USER + 111;
  ID_SHEEP = 999;

type
  H_AQTKDA = LongWord;

  TAquesTalk_Synthe = function (const koe: string;
    iSpeed: Integer; var size: Integer): Pointer; stdcall;
  TAquesTalk_FreeWave = procedure (wav: Pointer); stdcall;
  TAquesTalkDa_PlaySync = function (const koe: String;
    iSpeed: Integer = 100): Integer; stdcall;
  TAquesTalkDa_Create = function : H_AQTKDA; stdcall;
  TAquesTalkDa_Release = procedure (hMe: H_AQTKDA); stdcall;
  TAquesTalkDa_Play = function (
               hMe: H_AQTKDA;
         const koe: String; iSpeed: Integer = 100;
               hWnd: HWND = 0;
               msg: ULONG = 0;
               dwUser: ULONG = 0
         ): Integer; stdcall;
  TAquesTalkDa_Stop = procedure (hMe: H_AQTKDA); stdcall;
  TAquesTalkDa_IsPlay = function  (hMe: H_AQTKDA): Integer; stdcall;


  TAquesTalk = class
  private
    FhDll,
    FhDaDll: THandle;
    FHandle: THandle;
    AquesTalk_Synthe: TAquesTalk_Synthe;
    AquesTalk_FreeWave: TAquesTalk_FreeWave;
    AquesTalkDa_PlaySync: TAquesTalkDa_PlaySync;
    AquesTalkDa_Create: TAquesTalkDa_Create;
    AquesTalkDa_Release: TAquesTalkDa_Release;
    AquesTalkDa_Play: TAquesTalkDa_Play;
    AquesTalkDa_Stop: TAquesTalkDa_Stop;
    AquesTalkDa_IsPlay: TAquesTalkDa_IsPlay;
    FSpeed: Integer;
    procedure OpenDll(Dll, DaDll: string);
    procedure CloseDll;
    procedure SetSpeed(const Value: Integer);
  public
    constructor Create(Dll: string = 'AquesTalk.dll';
                     DaDll: string = 'AquesTalkDa.dll');
    destructor Destroy; override;
    function Synthe(FileName, Koe: string): Boolean;
    function PlaySync(Koe: string): Boolean;
    function Play(Koe: string; hWnd: HWND = 0; msg:
      ULONG = 0; dwUser: ULONG = 0): Boolean;
    procedure Stop;
    function IsPlay: Boolean;
    procedure VoiceChange(Dll, DaDll: string);
    property Hanele: THandle read FHandle;
    property Speed: Integer read FSpeed write SetSpeed;
  end;

implementation

{ TAquesTalk }

procedure TAquesTalk.OpenDll(Dll, DaDll: string);
begin
  CloseDll;
  FhDll := LoadLibrary(PChar(Dll));
  FhDaDll := LoadLibrary(PChar(DaDll));
  if (FhDll <> 0) and (FhDaDll <> 0) then begin
    AquesTalk_Synthe     := GetProcAddress(FhDll, 'AquesTalk_Synthe');
    AquesTalk_FreeWave   := GetProcAddress(FhDll, 'AquesTalk_FreeWave');
    AquesTalkDa_PlaySync := GetProcAddress(FhDaDll, 'AquesTalkDa_PlaySync');
    AquesTalkDa_Create   := GetProcAddress(FhDaDll, 'AquesTalkDa_Create');
    AquesTalkDa_Release  := GetProcAddress(FhDaDll, 'AquesTalkDa_Release');
    AquesTalkDa_Play     := GetProcAddress(FhDaDll, 'AquesTalkDa_Play');
    AquesTalkDa_Stop     := GetProcAddress(FhDaDll, 'AquesTalkDa_Stop');
    AquesTalkDa_IsPlay   := GetProcAddress(FhDaDll, 'AquesTalkDa_IsPlay');

    FHandle := AquesTalkDa_Create;
  end else begin
    raise Exception.Create('音声合成DLLが不正です');
  end;
end;

constructor TAquesTalk.Create(Dll, DaDll: string);
begin
  FSpeed := 100;
  OpenDll(Dll, DaDll);
end;

procedure TAquesTalk.VoiceChange(Dll, DaDll: string);
begin
  OpenDll(Dll, DaDll);
end;

procedure TAquesTalk.CloseDll;
begin
  if FHandle <> 0 then AquesTalkDa_Release(FHandle);
  if FhDll   <> 0 then FreeLibrary(FhDll);
  if FhDaDll <> 0 then FreeLibrary(FhDaDll);
end;

destructor TAquesTalk.Destroy;
begin
  CloseDll;
  inherited;
end;

function TAquesTalk.IsPlay: Boolean;
begin
  Result := AquesTalkDa_IsPlay(FHandle) = 1;
end;

function TAquesTalk.Play(Koe: string; hWnd: HWND; msg,
  dwUser: ULONG): Boolean;
begin
  Result := AquesTalkDa_Play(FHandle, Koe, FSpeed, hWnd, msg, dwUser) = 0;
end;

function TAquesTalk.PlaySync(Koe: string): Boolean;
begin
  Result := AquesTalkDa_PlaySync(Koe, FSpeed) = 0;
end;

procedure TAquesTalk.Stop;
begin
  AquesTalkDa_Stop(FHandle);
end;

function TAquesTalk.Synthe(FileName, Koe: string): Boolean;
var Size: Integer;
  Wav: Pointer;
  FileHandle : Integer;
begin
  Wav := AquesTalk_Synthe(Koe, FSpeed, Size);
  try
    Result := Wav <> nil;
    if not Result then Exit;
    FileHandle := FileCreate(FileName);
    try
      FileWrite(FileHandle, Wav^, Size);
    finally
      FileClose(FileHandle);
    end;
  finally
    AquesTalk_FreeWave(Wav);
  end;
end;

procedure TAquesTalk.SetSpeed(const Value: Integer);
begin
  if FSpeed <> Value then begin
    FSpeed := Value;
    if FSpeed < 50 then FSpeed := 50;
    if FSpeed > 300 then FSpeed := 300;
  end;
end;

end.

ダウンロード

AquesTalkサンプルソース [ Down ]
DLL入手先 AquesTalk Win版


Copyright 2003-2010 yhira All Rights Reserved`
[Server] [Delphi Tips]
最終更新:2009/09/23 00:35:13