SAPI — Каждая следующая фраза занимает больше времени, чем предыдущая

#delphi #sapi

Вопрос:

Я работаю с МИСС САПИ в Delphi7. Моя цель:

  • проговорите список фраз в память
  • получить количество байтов, занимаемых каждой фразой (для создания субтитров SRT)
  • вывод данных из памяти в WAV-файл.

Все работает нормально, но я вижу, что каждая следующая фраза занимает больше времени, чем предыдущая (см. Скриншот). Я этого не понимаю. Есть ли какой-либо способ изменить это поведение?

 uses ...SpeechLib_TLB...

procedure TForm1.Button2Click(Sender: TObject);
var
    SpVoice: TSpVoice;
    SpMemoryStream: TSpMemoryStream;
    SpFileStream: TSpFileStream;
    SavedCW: Word;
    i: integer;
    list: tstrings;
    time1, time2, bytes1, bytes2: dword;
begin
    ListBox1.Clear;
    list:=tstringlist.create;
    list.loadfromfile(extractfilepath(paramstr(0))   'test1.txt');

    SpVoice:=TSpVoice.create(nil);

    SpMemoryStream:=TSpMemoryStream.Create(nil);
    SpMemoryStream.Format.type_:=SAFT44kHz16BitMono;

    SpVoice.AudioOutputStream:=SpMemoryStream.DefaultInterface;

    SpFileStream:=TSpFilestream.Create(nil);
    SpFileStream.Format.type_:=SAFT44kHz16BitMono;
    SpFileStream.Open(ExtractFilePath(ParamStr(0)) 'test1.wav', SSFMCreateForWrite, FALSE);

    SavedCW := Get8087CW;
    Set8087CW(SavedCW or $4);
    for i:=0 to list.count-1 do begin
        time1:=gettickcount;
        bytes1:=VarArrayHighBound(SpMemoryStream.GetData, 1);
        SpVoice.Speak(list[i], 0);
        time2:=gettickcount;
        bytes2:=VarArrayHighBound(SpMemoryStream.GetData, 1);
        ListBox1.items.Add(Format('%d ms   %d Bytes   %s', [time2-time1, bytes2-bytes1, list[i]]));
        Label1.caption:=format('Item %d From %d', [i 1, list.count]);
        Application.ProcessMessages;
    end;
    Set8087CW(SavedCW);

    SpFileStream.Write(SpMemoryStream.GetData);
    SpFileStream.Free;
    SpMemoryStream.Free;
    SpVoice.free;
    list.free;

    showmessage('All done');
end;
 

Вывод:

Комментарии:

1. Поскольку это поток , а не массив : каждый раз, когда он обрабатывается как массив , все его байты должны анализироваться с самого начала. Почему бы просто не использовать .Seek( 0 ) , чтобы всегда проверять текущую позицию?

2. @AmigoJack Я пробовал это: SpMemoryStream. Seek(0, SSSPTRelativeToStart); SpFileStream. Запись (SpMemoryStream. getData); после каждого выступления. Но этот способ приводит к повреждению файла WAV

3. Проблема не в проверке байтов, занятых вызовом VarArrayHighBound(SpMemoryStream . getData, 1); Даже если я удалю весь код, кроме SpVoice. Говорите (…) проблема остается.

4. SSSPTRelativeToCurrentPosition конечно: вы хотите получить текущую позицию, не меняя ее.

5. @AmigoJack я понимаю, о чем ты говоришь. Ваше предложение позволяет получить количество байтов, не рассматривая поток как массив. Но я говорю о чем-то другом. Даже если я оставлю только . Произнесите (…) и удалите весь остальной код, каждая следующая фраза занимает все больше и больше времени. Это основная проблема.