Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/21: Рейтинг темы: голосов - 21, средняя оценка - 4.52
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443

Как вывести запись аудиопотока TTS в память?

10.02.2020, 12:12. Показов 4241. Ответов 27
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
На сайте Майкрософт имеется вот такой пример:
https://docs.microsoft.com/en-... 3dvs.85%29

Пример кода ISpeechBaseStream (SAPI 5.3)

04/17/2012

Microsoft Speech API 5.3

Интерфейс: ISpeechBaseStream


Следующий код формы Visual Basic демонстрирует использование методов ISpeechBaseStream Read, Write и Seek. Эти методы ISpeechBaseStream наследуются SpCustomStream, SpFileStream и SpMemoryStream. В этом примере используется SpFileStream, но методы работают одинаково во всех трех объектах.

Чтобы запустить этот код, создайте форму со следующими элементами управления:

Две командные кнопки Command1 и Command2

Вставьте этот код в раздел объявлений формы.

Процедура Form_Load создает голосовой объект и два объекта SpFileStream. Процедура Command1_Click произносит слова «один», «точка», «пять» и «SAPI» в первый файловый поток, используя метод Seek, чтобы найти конечную позицию байта каждого слова. Затем он считывает аудиоданные для каждого слова отдельно и записывает новый поток с обратным порядком слов. Процедура Command2_Click воспроизводит два файла, созданные Command1.
В этом коде используется запись аудиопотока в файл, а мне нужно записывать в память. Они говорят, что "методы работают одинаково во всех трёх объектах". Но как именно в память-то записывать?
Просто тупо заменить везде SpFileStream на SpMemoryStream, так что ли?
На самом деле, я сейчас попробовал, VB меня обругал нехорошими словами

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Option Explicit
 
Const FILENAME1 = "c:\First.wav"
Const FILENAME2 = "c:\Second.wav"
 
Dim V As SpeechLib.SpVoice
Dim S1 As SpeechLib.SpFileStream
Dim S2 As SpeechLib.SpFileStream
 
Private Sub Command1_Click()
 
    Dim varT(3) As Variant      'text to be spoken
    Dim varP(3) As Variant      'positions in output stream
    Dim varD(3) As Variant      'audio data chunks
    Dim varStart As Variant
    Dim ii As Integer
 
    On Error GoTo EH
 
    varT(0) = "one": varT(1) = "point": varT(2) = "five": varT(3) = "SAPI"
 
    'Create WAV file of "one point five SAPI"
    'Speak the words into a single filestream object,
    'and remember the end-of-stream position of each word.
 
    S1.Open FILENAME1, SSFMCreateForWrite
    Set V.AudioOutputStream = S1
    For ii = 0 To UBound(varT)
        V.Speak varT(ii)
        varP(ii) = S1.Seek(0, SSSPTRelativeToCurrentPosition)
    Next ii
    S1.Close
 
    'Read the words from the first file into the variant array;
    'Write them back into the second file in reverse order.
 
    S1.Open FILENAME1, SSFMOpenForRead
    S2.Open FILENAME2, SSFMCreateForWrite
 
    varStart = 0
    For ii = 0 To UBound(varT)
        S1.Read varD(ii), varP(ii) - varStart
        varStart = varP(ii)
    Next ii
 
    For ii = UBound(varT) To 0 Step -1
        S2.Write varD(ii)
    Next ii
 
    S2.Close
    S1.Close
 
    'After using AudioOutputStream, reset voice AudioOutput property
    Set V.AudioOutput = V.GetAudioOutputs("").Item(0)
 
    Command1.Enabled = False
    Command2.Enabled = True
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
Private Sub Command2_Click()
    On Error GoTo EH
 
    S1.Open FILENAME1, SSFMOpenForRead
    S2.Open FILENAME2, SSFMOpenForRead
 
    'Use first male voice to announce the results
    Set V.Voice = V.GetVoices("gender=male").Item(0)
 
    V.Speak "This is the first sound file", SVSFlagsAsync
    V.SpeakStream S1, SVSFlagsAsync
 
    V.Speak "This is the second sound file", SVSFlagsAsync
    V.SpeakStream S2, SVSFlagsAsync
 
    Do
        DoEvents
    Loop Until V.WaitUntilDone(1)
 
    S1.Close
    S2.Close
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
 
Private Sub Form_Load()
    On Error GoTo EH
 
    Set V = New SpeechLib.SpVoice
    Set S1 = New SpFileStream       'Create stream1
    Set S2 = New SpFileStream       'Create stream2
    Command2.Enabled = False
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
Private Sub ShowErrMsg()
 
    ' Declare identifiers:
    Const NL = vbNewLine
    Dim T As String
 
    T = "Desc: " & Err.Description & NL
    T = T & "Err #: " & Err.Number
    MsgBox T, vbExclamation, "Run-Time Error"
    End
 
End Sub
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
10.02.2020, 12:12
Ответы с готовыми решениями:

Запись аудиопотока
Баловался с Bass, писал плееры, онлайн радио... И вот у меня появилась идея, записать аудиопоток и сохранить его как звуковой файл на...

Запись аудиопотока с системы
Здарвствуйте. Подскажите пожалуйста как можно считать аудиопоток с винды, например в файл, средствами QT. Заранее спасибо.

Как заставить Google TTS правильно ставить ударения?
Добрый день! Использую Google TTS в приложении для Android. ...

27
63 / 48 / 12
Регистрация: 28.12.2014
Сообщений: 270
10.02.2020, 13:30
Судя по всему не подключена ActiveX библиотека SpeechLib.
Записать данные в память из файла, например. Или, метод Read запишет данные в переменную из filestream.
Visual Basic
1
S1.Read varD(ii), varP(ii) - varStart
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
10.02.2020, 15:42  [ТС]
Спасибо, что откликнулись, но я ничего не понял

Цитата Сообщение от IDK Посмотреть сообщение
Судя по всему не подключена ActiveX библиотека SpeechLib.
Не, ну я создал ссылку в своём проекте на Microsoft Speech Object Library (SAPI.DLL) через пункт меню "Reference", если вы сейчас об этом толкуете.

Цитата Сообщение от IDK Посмотреть сообщение
Записать данные в память из файла, например. Или, метод Read запишет данные в переменную из filestream.
Visual Basic
Выделить код
1
S1.Read varD(ii), varP(ii) - varStart
Честно говоря, я не понял. Мне бы главную идею ухватить. Эти майкрософтовцы как всегда нагородили целую кучу вместо того, чтобы лаконичным примером объяснить самую суть.
Вот если отбросить все эти выкрутасы с массивами, с чтением в обратном порядке и прочей шелухой. Вот просто текст "Привет", который произносит движок TTS, надо не вывести на динамики, не записать в файл, а записать в память в переменную Text$. Что для этого надо сделать по минимуму?

P.S. А записать в файл и потом из него считать в память, ну нет это не годится, это двройная работа получается. Как сказал классик, эдак и я тренькать могу

Добавлено через 23 минуты

Вот здесь был задан тот же самый вопрос (я нагуглил) и там ответили, но к сожалению на языке C, и поэтому не понятно
https://stackoverflow.com/ques... ve#tab-top



Look at ISpStream::SetBaseStream. Here's a little helper:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
inline HRESULT SPCreateStreamOnHGlobal(
                    HGLOBAL hGlobal,            //Memory handle for the stream object
                    BOOL fDeleteOnRelease,      //Whether to free memory when the object is released
                    const WAVEFORMATEX * pwfex, //WaveFormatEx for stream
                    ISpStream ** ppStream)      //Address of variable to receive ISpStream pointer
{
    HRESULT hr;
    IStream * pMemStream;
    *ppStream = NULL;
    hr = ::CreateStreamOnHGlobal(hGlobal, fDeleteOnRelease, &pMemStream);
    if (SUCCEEDED(hr))
    {
        hr = ::CoCreateInstance(CLSID_SpStream, NULL, CLSCTX_ALL, __uuidof(*ppStream), (void **)ppStream);
        if (SUCCEEDED(hr))
        {
            hr = (*ppStream)->SetBaseStream(pMemStream, SPDFID_WaveFormatEx, pwfex);
            if (FAILED(hr))
            {
                (*ppStream)->Release();
                *ppStream = NULL;
            }
        }
        pMemStream->Release();
    }
    return hr;
}
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
11.02.2020, 09:33
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Option Explicit
 
Private WithEvents m_cVoice As SpVoice
Private m_cStream           As SpMemoryStream
 
Private Sub cmdTest_Click()
    On Error GoTo EH
    
    Err.Clear
    
    Set m_cVoice.Voice = m_cVoice.GetVoices.Item(0)
    Set m_cVoice.AudioOutputStream = m_cStream
    
    m_cVoice.Speak "This is the first sound file", SVSFlagsAsync
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
 
Private Sub Form_Load()
    On Error GoTo EH
    
    Err.Clear
    
    Set m_cVoice = New SpVoice
    Set m_cStream = New SpMemoryStream
    
    m_cStream.Format.Type = SAFT44kHz16BitMono
    
    cmdTest.Enabled = True
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
Private Sub ShowErrMsg()
 
    Const NL = vbNewLine
    Dim T As String
 
    T = "Desc: " & Err.Description & NL
    T = T & "Err #: " & Err.Number
    MsgBox T, vbExclamation, "Run-Time Error"
 
End Sub
 
Private Sub m_cVoice_EndStream( _
            ByVal StreamNumber As Long, _
            ByVal StreamPosition As Variant)
    Dim bData() As Byte
    
    ' // Data to bData
    bData = m_cStream.GetData
    
End Sub
2
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
11.02.2020, 20:07  [ТС]
The trick, большое спасибо, очень похоже на верное решение проблемы. Но есть одно "но".
Для проверки результата попробовал скинуть весь полученный массив байтов на диск в виде .WAV файла. Скинулось, но воспроизводиться отказывается. Следовательно, вопрос: в каком формате аудиопоток хранится в памяти?

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Private Sub m_cVoice_EndStream( _
            ByVal StreamNumber As Long, _
            ByVal StreamPosition As Variant)
    Dim bData() As Byte
    
    ' // Data to bData
    bData = m_cStream.GetData
    
    Dim int_file_number As Integer
 
    int_file_number = FreeFile
 
    Open "d:\TestFile.wav" For Binary Access Write As #int_file_number
       Put #int_file_number, , bData()
    Close #int_file_number
End Sub
0
Эксперт по электронике
6557 / 3185 / 334
Регистрация: 28.10.2011
Сообщений: 12,458
Записей в блоге: 7
11.02.2020, 21:30
Цитата Сообщение от Power_Basic Посмотреть сообщение
Для проверки результата попробовал скинуть весь полученный массив байтов на диск в виде .WAV файла. Скинулось, но воспроизводиться отказывается.
Значит неправильно скинули. Если данные в потоке другие, будет неправильно воспроизводиться, но воспроизводиться.
Проверьте корректность заголовка.
1
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
11.02.2020, 22:12  [ТС]
Цитата Сообщение от locm Посмотреть сообщение
Значит неправильно скинули. Если данные в потоке другие, будет неправильно воспроизводиться, но воспроизводиться.
Проверьте корректность заголовка.
Не понял, какой заголовок имеется в виду? Если заголовок файйла "d:\TestFile.wav", то с этим-то как раз всё в порядке. Он же прекрасно записывается и весит (на удивление) больше 200 килобайт.

И если неправильно скинул, то вопрос: а как следует скинуть правильно?
Последовательность байтов у нас записалась в массив. Весь массив скидываем на диск и пытаемся вопроизвести всю эту"музыку"

Программа же перед вами, скопируйте, и сами попробуйте запустить. И у вас тоже самое получится, наверняка.
Наверно, WAV файл это не простая последовательность байтов, а упакованная как-нибудь. Надо будет мне про эти файлы почитать...

Добавлено через 8 минут
Сейчас начал читать про WAV файлы. Понял, о каком заголовке вы толкуете.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
11.02.2020, 22:22
Лучший ответ Сообщение было отмечено Power_Basic как решение

Решение

Цитата Сообщение от Power_Basic Посмотреть сообщение
Для проверки результата попробовал скинуть весь полученный массив байтов на диск в виде .WAV файла. Скинулось, но воспроизводиться отказывается. Следовательно, вопрос: в каком формате аудиопоток хранится в памяти?
Правильно написал locm - нужен wav заголовок. Приблизительный код (без проверок ошибок):
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
Option Explicit
 
Private Const MMIO_CREATE       As Long = &H1000            '  create new file (or truncate file)
Private Const MMIO_WRITE        As Long = &H1               '  open file for writing only
Private Const MMIO_CREATERIFF   As Long = &H20
 
Private Type WAVEFORMATEX
    wFormatTag          As Integer
    nChannels           As Integer
    nSamplesPerSec      As Long
    nAvgBytesPerSec     As Long
    nBlockAlign         As Integer
    wBitsPerSample      As Integer
    cbSize              As Integer
End Type
 
Private Type MMCKINFO
    ckid                As Long
    ckSize              As Long
    fccType             As Long
    dwDataOffset        As Long
    dwFlags             As Long
End Type
 
Private Type MMIOINFO
    dwFlags             As Long
    fccIOProc           As Long
    pIOProc             As Long
    wErrorRet           As Long
    htask               As Long
    cchBuffer           As Long
    pchBuffer           As Long
    pchNext             As Long
    pchEndRead          As Long
    pchEndWrite         As Long
    lBufOffset          As Long
    lDiskOffset         As Long
    adwInfo(4)          As Long
    dwReserved1         As Long
    dwReserved2         As Long
    hmmio               As Long
End Type
 
Private Declare Function mmioClose Lib "winmm.dll" ( _
                         ByVal hmmio As Long, _
                         Optional ByVal uFlags As Long) As Long
Private Declare Function mmioOpen Lib "winmm.dll" _
                         Alias "mmioOpenW" ( _
                         ByVal szFileName As Long, _
                         ByRef lpmmioinfo As Any, _
                         ByVal dwOpenFlags As Long) As Long
Private Declare Function mmioStringToFOURCC Lib "winmm.dll" _
                         Alias "mmioStringToFOURCCA" ( _
                         ByVal sz As String, _
                         ByVal uFlags As Long) As Long
Private Declare Function mmioAscend Lib "winmm.dll" ( _
                         ByVal hmmio As Long, _
                         ByRef lpck As MMCKINFO, _
                         ByVal uFlags As Long) As Long
Private Declare Function mmioCreateChunk Lib "winmm.dll" ( _
                         ByVal hmmio As Long, _
                         ByRef lpck As MMCKINFO, _
                         ByVal uFlags As Long) As Long
Private Declare Function mmioWrite Lib "winmm.dll" ( _
                         ByVal hmmio As Long, _
                         ByRef pch As Any, _
                         ByVal cch As Long) As Long
                         
 
Private WithEvents m_cVoice As SpVoice
Private m_cStream           As SpMemoryStream
 
Private Sub cmdTest_Click()
    On Error GoTo EH
    
    Err.Clear
    
    Set m_cVoice.Voice = m_cVoice.GetVoices.Item(0)
    Set m_cVoice.AudioOutputStream = m_cStream
    
    m_cVoice.Speak "This is the first sound file", SVSFlagsAsync
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
 
Private Sub Form_Load()
    On Error GoTo EH
    
    Err.Clear
    
    Set m_cVoice = New SpVoice
    Set m_cStream = New SpMemoryStream
    
    m_cStream.Format.Type = SAFT44kHz16BitMono
    
    cmdTest.Enabled = True
 
EH:
    If Err.Number Then ShowErrMsg
End Sub
 
Private Sub ShowErrMsg()
 
    Const NL = vbNewLine
    Dim T As String
 
    T = "Desc: " & Err.Description & NL
    T = T & "Err #: " & Err.Number
    MsgBox T, vbExclamation, "Run-Time Error"
 
End Sub
 
Private Sub m_cVoice_EndStream( _
            ByVal StreamNumber As Long, _
            ByVal StreamPosition As Variant)
    Dim bData() As Byte
    Dim hWave   As Long
    Dim chkRIFF As MMCKINFO
    Dim chkData As MMCKINFO
    Dim tFmt    As WAVEFORMATEX
    
    ' // Data to bData
    bData = m_cStream.GetData
    
    hWave = mmioOpen(StrPtr("C:\test.wav"), ByVal 0&, MMIO_WRITE Or MMIO_CREATE)
    chkRIFF.fccType = mmioStringToFOURCC("WAVE", 0)
    mmioCreateChunk hWave, chkRIFF, MMIO_CREATERIFF
    chkData.ckid = mmioStringToFOURCC("fmt", 0)
    mmioCreateChunk hWave, chkData, 0
    
    tFmt.wFormatTag = 1
    tFmt.nChannels = 1
    tFmt.nSamplesPerSec = 44100
    tFmt.wBitsPerSample = 16
    tFmt.nBlockAlign = tFmt.wBitsPerSample \ 8 * tFmt.nChannels
    tFmt.nAvgBytesPerSec = tFmt.nBlockAlign * tFmt.nSamplesPerSec
    
    mmioWrite hWave, tFmt, Len(tFmt)
    mmioAscend hWave, chkData, 0
    chkData.ckid = mmioStringToFOURCC("data", 0)
    mmioCreateChunk hWave, chkData, 0
    mmioWrite hWave, bData(0), UBound(bData) + 1
    mmioAscend hWave, chkData, 0
    mmioAscend hWave, chkRIFF, 0
    mmioClose hWave
    
End Sub
3
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
12.02.2020, 12:13  [ТС]
The trick, спасибо, работает идеально!
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
19.02.2020, 13:55  [ТС]
The trick, вот не поверите, я с тех самых пор (то есть уже целую неделю) бьюсь над проблемой перевода вашего кода с языка Visual Basic на язык Power Basic. Получается какая-то хрень
В COM-программировании я не особо силён, поэтому делаю по аналогии с вашим кодом, но учитывая специфику Power Basic-а.
Вроде бы делаю всё как надо, но вместо нормального аудиофайла получается визгливое пищание приблизительно на половину всего времени звучания, ну а потом действительно воспроизводится нужный текст, но обрезается последняя часть. Тестовый текст у меня вот такой: "Проверка связи, проверка связи...". А воспроизведение выглядит вот так приблизительно: "<писк> Проверка связи, провер".
Ну то есть получается какой-то сдвиг. Откуда он берётся, понять не могу никак

Сначала я грешил на то, что хэдер составляю и прикрепляю неправильно. Но нет... Сейчас вот специально установил SOUND.FORGE, а там есть функция воспроизведения "сырых" аудиофайлов. Ну то есть когда на диск скинут аудиопоток без хэдера вовсе. Ну и звучание абсолютно такое же, как я описал выше.
Я, конечно, понимаю, что Power Basic в этой ветке как бы не совсем уместен, но может быть всё-таки что нибудь подскажете? Откуда берётся это злополучный сдвиг?


Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#COMPILE EXE
#DIM ALL
#INCLUDE "win32api.inc"
 
global gobj_ISpeechMemoryStream As ISpeechMemoryStream
 
FUNCTION PBMAIN () AS LONG
  local obj_ISpVoice As ISpeechVoice
  local obj_SAPI_ISpeechVoiceEvents As SAPI_ISpeechVoiceEvents
  local lng_Dummy as long
  local lng_StreamNumber as long
  local wstr_Text_to_speak as WSTRING
  local lng_msTimeout as long
         
  obj_ISpVoice = NEWCOM "SAPI.SpVoice" ' Create an instance of the ISpeechVoice Interface
  ' Was the object refrence succesful?
  IF ISFALSE(ISOBJECT(obj_ISpVoice)) THEN MSGBOX "Не смог создать ссылку на iSpVoice Interface."
 
  gobj_ISpeechMemoryStream = NEWCOM $PROGID_SpeechLib_SpMemoryStream ' Create an instance of the ISpeechMemoryStream Interface
  ' Was the object refrence succesful?
  IF ISFALSE(ISOBJECT(gobj_ISpeechMemoryStream)) THEN MSGBOX "Не смог создать ссылку на ISpeechMemoryStream Interface."
 
  lng_Dummy = %SpeechAudioFormatType.SAFT44kHz16BitMono
  OBJECT let gobj_ISpeechMemoryStream.Format.Type = lng_Dummy
 
  OBJECT sET obj_ISpVoice.AudioOutputStream  = gobj_ISpeechMemoryStream
  wstr_Text_to_speak = "Проверка связи, проверка связи..." & chr$(0)& chr$(0)
 
  
  lng_msTimeout = 600000   
  OBJECT call obj_ISpVoice.WaitUntilDone (lng_msTimeout)
 
  obj_SAPI_ISpeechVoiceEvents = CLASS "Class_SAPI_ISpeechVoiceEvents"
  ' Was the object refrence succesful?
  IF ISFALSE(ISOBJECT(obj_SAPI_ISpeechVoiceEvents)) THEN MSGBOX "Не смог создать ссылку на SAPI_ISpeechVoiceEvents Interface."
 
  lng_Dummy = %SpeechVoiceSpeakFlags.SVSFlagsAsync
  EVENTS FROM obj_ISpVoice CALL obj_SAPI_ISpeechVoiceEvents
    OBJECT call obj_ISpVoice.Speak (wstr_Text_to_speak, lng_Dummy) to lng_StreamNumber
  EVENTS END obj_SAPI_ISpeechVoiceEvents
END FUNCTION
 
Class Class_SAPI_ISpeechVoiceEvents $CLSID_SpeechLib_Event__ISpeechVoiceEvents As Event
  Interface SAPI_ISpeechVoiceEvents $IID_SpeechLib_SAPI_ISpeechVoiceEvents
    Inherit IDispatch
 
    Method EndStream <2> (Byval StreamNumber As Long, Byval StreamPosition As Variant)
       local vnt_Dummy as variant
       dim MyArray() as byte
       local MyString As String   
       local int_file_number as integer   
                
      OBJECT call gobj_ISpeechMemoryStream.GetData to vnt_Dummy
      MyArray() = vnt_Dummy
      MyString = Peek$(VarPtr(MyArray(0)), UBOUND(MyArray)+1)
 
      int_file_number = freefile
 
      OPEN EXE.PATH$ & "01.raw" FOR BINARY AS # int_file_number
        put$ # int_file_number, MyString
      CLOSE # int_file_number
    End Method
  End Interface
End Class
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
19.02.2020, 14:34
Visual Basic
1
2
      MyArray() = vnt_Dummy
      MyString = Peek$(VarPtr(MyArray(0)), UBOUND(MyArray)+1)
Для чего это? Для чего конвертация в строку? Пиши сразу байтовый массив в файл.
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
19.02.2020, 19:04  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Для чего это? Для чего конвертация в строку? Пиши сразу байтовый массив в файл.
Конвертировать полученный массив байтов в строку так или иначе надо, потому что соль всего замысла состоит в том, что мы максимально снижаем нагрузку на диск и плюс сильно ускоряем работу за счёт того, что все операции производятся именно в оперативной памяти. Ну, короче, общий расклад такой:
это программа для чтения текстов, в которых перемешаны русские и английские слова. Русские фрагменты читает русский движок, английские - английский. Чередования фрагментов очень частые, потому что это тексты по программированию

Ну и задумано так, что все эти "куски" преобразуем в большую-пребольшую строку, которая постепенно "накапливается" в памяти, а когда она достигает критической массы, вот тогда-то мы её и скидываем на диск, предварительно приделав к ней хэдер.

Поэтому нужны именно строки...
Хотя если можно как-то "суммировать как строки" массивы байтов, тогда можно обойтись совсем без строк, но мне не приходит в голову, как это можно сделать.

На самом деле, у меня сейчас почему-то не получается даже прсто скинуть на диск полученный массив байтов. Если делаю вот так:

PureBasic
1
2
3
  OPEN EXE.PATH$ & "01.raw" FOR BINARY AS # int_file_number
      put # int_file_number, 1, MyArray()
  CLOSE # int_file_number
на диске появляется только файл нулевой длины.

А если делаю вот так:

Visual Basic
1
2
3
  OPEN EXE.PATH$ & "01.raw" FOR BINARY AS # int_file_number
      put$ # int_file_number, MyArray ()
  CLOSE # int_file_number
тогда компиллятор требует, чтобы MyArray () был массивом строк.

Добавлено через 41 минуту
P.S. Хотя вот сейчас я, пожалуй, всё-таки сообразил, как можно "суммировать" массивы байтов. Мы же знаем их размеры, следовательно можно располагать их в памяти друг за другом с помощью POKE, ну а потом уже считать накопившийся огромный массив байтов сразу на диск, предварительно приделав к нему спереди хэдер.

Добавлено через 2 часа 32 минуты
P.P.S. Так и не сообразил, как можно грамотно скинуть на диск полученный массив байтов без использования строки.
Поэтому (исключительно для проверки гипотезы) скинул "по рабоче-крестьянски" с помощью цикла:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
   local int_file_number as integer
   local i as long
   
  int_file_number = freefile
 
  OPEN EXE.PATH$ & "01.raw" FOR BINARY AS # int_file_number
      for i = 0 to UBOUND(MyArray)+1
        put # int_file_number, , MyArray (i)
      next i
      
  CLOSE # int_file_number
Ну и, как и следовало ожидать, получен в точности тот же самый результат, а именно, половина файла писк и скрежет, а вторая половина - начало произнесения тестовой фразы. Следовательно, конвертация массива в строку не виновата, проблема в самом COM. Что-то я делаю неправильно
0
sleep
 Аватар для I can
4925 / 4574 / 840
Регистрация: 13.04.2015
Сообщений: 9,724
19.02.2020, 19:17
А разве без цикла не работает ?
Visual Basic
1
2
3
  Open EXE.Path$ & "01.raw" For Binary As #int_file_number
          Put #int_file_number, , MyArray
  Close #int_file_number
Добавлено через 57 секунд
Цитата Сообщение от Power_Basic Посмотреть сообщение
Что-то я делаю неправильно
В заголовке скорее всего накосячили.
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
19.02.2020, 21:14  [ТС]
Цитата Сообщение от I can Посмотреть сообщение
В заголовке скорее всего накосячили.
Да нет, заголовок-то уж точно не при чём, поскольку и с заголовком (через стандартное воспроизведение WAV-файла), и без заголовка (через воспроизведение аудиопотока в "сыром" виде (то есть без заголовка вообще!) в программе SOUND FORGE) получаем совершенно одинаковый результат.

Цитата Сообщение от I can Посмотреть сообщение
А разве без цикла не работает ?
Visual Basic
1
2
3
Open EXE.Path$ & "01.raw" For Binary As #int_file_number
 Put #int_file_number, , MyArray
 Close #int_file_number
Если так вот просто убрать скобки от MyArray () в этом выражении, тогда компиллятор воспринимает MyArray как новую необъявленную переменную и ругается вот так:
Миниатюры
Как вывести запись аудиопотока TTS в память?  
0
sleep
 Аватар для I can
4925 / 4574 / 840
Регистрация: 13.04.2015
Сообщений: 9,724
19.02.2020, 21:44
Цитата Сообщение от Power_Basic Посмотреть сообщение
компиллятор воспринимает MyArray как новую необъявленную переменную
Ну тогда я не знаю, я проверял в Visual Basic, там без скобок надо писать. А в Power Basic-е могут быть свои тараканы.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
19.02.2020, 22:50
Цитата Сообщение от Power_Basic Посмотреть сообщение
Конвертировать полученный массив байтов в строку так или иначе надо, потому что соль всего замысла состоит в том, что мы максимально снижаем нагрузку на диск и плюс сильно ускоряем работу за счёт того, что все операции производятся именно в оперативной памяти.
Все еще не пойму для чего использовать строку. Строки нужны для хранения строк, а не звуковых данных. Для данных нужно использовать байтовые массивы.

Цитата Сообщение от Power_Basic Посмотреть сообщение
На самом деле, у меня сейчас почему-то не получается даже прсто скинуть на диск полученный массив байтов. Если делаю вот так:
Ну там же ошибка, второй аргумент не массив, а позиция.

Добавлено через 1 минуту
Цитата Сообщение от Power_Basic Посмотреть сообщение
Ну и, как и следовало ожидать, получен в точности тот же самый результат, а именно, половина файла писк и скрежет, а вторая половина - начало произнесения тестовой фразы.
Скинь файл. Еще EXE тоже можно.
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
20.02.2020, 14:45  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Все еще не пойму для чего использовать строку. Строки нужны для хранения строк, а не звуковых данных. Для данных нужно использовать байтовые массивы.
На самом деле, я самоучка, а не профессионал вовсе
Просто где-то когда-то прочитал, что это удобно, вот с тех пор и пользуюсь
Не, ну правда, в строке же каждый символ кодируется значением от нуля до 255, ну а это же и есть байт. Строки очень удобно соединять между собой (в отличие от тех же массивов байтов). Ну то есть строку можно рассматривать как упорядоченный набор байтов, которым удобно манипулировать. И мы вовсе не собираемся её когда-нибудь распечатывать

Цитата Сообщение от The trick Посмотреть сообщение
Ну там же ошибка, второй аргумент не массив, а позиция.
Ну да, позиция. Второй аргумент опциональный и по умолчанию как раз единица. Это позиция, начиная с которой данные будут распечатаны в файл. Штука в том, что я уже очень давно пользуюсь именно строками для хранения байтов, и столкнувшись с этой проблемой, впал в лёгкую панику. Разгадка где-то рядом, все мысли сосредоточены на поиске проблем именно в COM фрагментах, а тут ещё добавилась эта проблема с казалось бы простым скидыванием массива данных на файл. Ну вот и стал в панике вставлять туда-сюда разные значения, уже надеясь просто на авось
Сейчас в отдельной простенькой программке получилось запросто вот так:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
FUNCTION PBMAIN () AS LONG
   dim TheData(1 to 5) as byte
 
   TheData(1) = 1
   TheData(2) = 100
   TheData(3) =13
   TheData(4) = 255
   TheData(5) = 11
 
   OPEN "01.xxx" FOR binary AS #1
      PUT #1,, TheData()
   CLOSE #1
END FUNCTION
Виноват

Цитата Сообщение от The trick Посмотреть сообщение
Скинь файл. Еще EXE тоже можно.
С удовольствием скидываю всё, что могу скинуть

Заодно скидываю примерное звучание записанных аудиофрагментов. Загадочным образом они получаются разными, но всё-таки очень похожими: сначала душераздирающий скрежет, потом голос диктора, которого всякий раз обрывают на полуслове


А вот весь исходник для тех, кому лень скачивать

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
'''Следующая таблица показывает структуру заголовка:
 
'''МЕСТОПОЛОЖЕНИЕ   ПОЛЕ              ОПИСАНИЕ
'''0…3 (4 байта)   chunkId             Содержит символы «RIFF» в ASCII кодировке 0x52494646. Является началом RIFF-цепочки.
'''4…7 (4 байта)   chunkSize         Это оставшийся размер цепочки, начиная с этой позиции. Иначе говоря,
'''                                   это размер файла минус 8, то есть, исключены поля chunkId и chunkSize.
'''8…11 (4 байта)      format              Содержит символы «WAVE» 0x57415645
'''12…15 (4 байта)   subchunk1Id       Содержит символы "fmt " 0x666d7420
'''16…19 (4 байта)   subchunk1Size       16 для формата PCM. Это оставшийся размер подцепочки, начиная с этой позиции.
'''20…21 (2 байта)   audioFormat       Аудио формат, список допустипых форматов. Для PCM = 1 (то есть, Линейное квантование).
'''                                   Значения, отличающиеся от 1, обозначают некоторый формат сжатия.
'''22…23 (2 байта)   numChannels       Количество каналов. Моно = 1, Стерео = 2 и т.д.
'''24…27 (4 байта)   sampleRate        Частота дискретизации. 8000 Гц, 44100 Гц и т.д.
'''28…31 (4 байта)   byteRate            Количество байтов, переданных за секунду воспроизведения: (= blockAlign * sampleRate)
'''32…33 (2 байта)   blockAlign        Количество байт для одного сэмпла, включая все каналы: (= bitsPerSample \ 8 * numChannels)
'''34…35 (2 байта)   bitsPerSample       Количество бит в сэмпле. Так называемая «глубина» или точность звучания. 8 бит, 16 бит и т.д.
'''36…39 (4 байта)   subchunk2Id       Содержит символы «data» 0x64617461
'''40…43 (4 байта)   subchunk2Size       Количество байтов в области данных.
'''44…                data                Непосредственно WAV-данные.
'''
'''Общая длина заголовка составляет 44 байта.
 
#COMPILE EXE                    'Это команда компиллировать именно EXE, а не DLL
#DIM ALL                        'Это полный аналог команды "Option Explicite" в Visual Basic'е
#INCLUDE once "win32api.inc"    'Это большая библиотека, где хранятся файлы важных констант, структур,
                                'деклараций функций WinAPI и т.п.
#INCLUDE once "my_sapi.inc"     'Это файл, автоматически сформированный с помощью Обджект браузера Power Basic'а
 
TYPE udt_type_WAV_file_header            'всего 44 байта.
   fstr_chunkId as string * 4
   lng_chunkSize as LONG
   fstr_format as string * 4
   fstr_subchunk1Id as string * 4
   lng_subchunk1Size as LONG
   int_audioFormat as integer
   int_numChannels as integer
   lng_sampleRate as LONG
   lng_byteRate as LONG
   int_blockAlign as integer
   int_bitsPerSample as integer
   fstr_subchunk2Id as string * 4
   lng_subchunk2Size as LONG
END TYPE
 
$PROGID_SpeechLib_SpVoice = "SAPI.SpVoice"
 
global gobj_ISpeechMemoryStream As ISpeechMemoryStream
 
Class Class_SAPI_ISpeechVoiceEvents $CLSID_SpeechLib_Event__ISpeechVoiceEvents As Event
    Interface SAPI_ISpeechVoiceEvents $IID_SpeechLib_SAPI_ISpeechVoiceEvents
        Inherit IDispatch
 
        Method StartStream <1> (Byval StreamNumber As Long, Byval StreamPosition As Variant)
          'msgbox "Событие StartStream"
        End Method
 
        Method EndStream <2> (Byval StreamNumber As Long, Byval StreamPosition As Variant)
          local vnt_Dummy as variant
          dim MyArray() as byte
          local MyString As String
          local str_Total_audio_stream as string
          local udt_WAV_file_header as udt_type_WAV_file_header
          local int_file_number as integer
 
          msgbox "Событие EndStream"                                  'Просто для информации о том, что событие "поймано"
 
          OBJECT call gobj_ISpeechMemoryStream.GetData to vnt_Dummy   'Запись аудиопотока в Variant
          MyArray() = vnt_Dummy                                       'Преобразуем Variant вмассив байтов
          MyString = Peek$(VarPtr(MyArray(0)), UBOUND(MyArray)+1)     'Считываем все байты аудиопотока из массива в строку
 
'*******************************************************************************************************************
          udt_WAV_file_header.fstr_chunkId = "RIFF"                    'Заполняем поля заголовка
          udt_WAV_file_header.lng_chunkSize = len(MyString) + 44 - 8
          udt_WAV_file_header.fstr_format = "WAVE"
          udt_WAV_file_header.fstr_subchunk1Id = "fmt "
          udt_WAV_file_header.lng_subchunk1Size = 16
          udt_WAV_file_header.int_audioFormat = 1
          udt_WAV_file_header.int_numChannels = 1
          udt_WAV_file_header.lng_sampleRate = 44100
          udt_WAV_file_header.int_bitsPerSample = 16
          udt_WAV_file_header.int_blockAlign = (udt_WAV_file_header.int_bitsPerSample \ 8) _
                               * udt_WAV_file_header.int_numChannels                 '(= bitsPerSample \ 8 * numChannels)
          udt_WAV_file_header.lng_byteRate = udt_WAV_file_header.int_blockAlign _
                                * udt_WAV_file_header.lng_sampleRate                 '(= blockAlign * sampleRate)
          udt_WAV_file_header.fstr_subchunk2Id = "data"
          udt_WAV_file_header.lng_subchunk2Size = len(MyString)
'*******************************************************************************************************************
 
          str_Total_audio_stream = Peek$(VarPtr(udt_WAV_file_header), 44) & MyString   'Добавляем заголовок в строку байтов
 
'*******************************************************************************************************************
          int_file_number = freefile                                                   'Сбрасываем аудиофайл на диск
 
          OPEN EXE.PATH$ & "01.wav" FOR BINARY AS # int_file_number
              put$ # int_file_number, str_Total_audio_stream
          CLOSE # int_file_number
'*******************************************************************************************************************
        End Method
 
        Method VoiceChange <3> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval VoiceObjectToken As _
        ISpeechObjectToken)
            'msgbox "VoiceChange"
        End Method
 
        Method Bookmark <4> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval Bookmark As WString, Byval _
        BookmarkId As Long)
            'msgbox "Bookmark"
        End Method
 
        Method Word <5> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval CharacterPosition As Long, Byval _
        Length As Long)
            'msgbox "Word"
        End Method
 
        Method Sentence <7> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval CharacterPosition As Long, Byval _
        Length As Long)
             'msgbox "Sentence"
        End Method
 
        Method Phoneme <6> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval Duration As Long, Byval _
        NextPhoneId As Integer, Byval Feature As Long, Byval CurrentPhoneId As Integer)
             'msgbox "Phoneme"
        End Method
 
        Method Viseme <8> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval Duration As Long, Byval _
        NextVisemeId As Long, Byval Feature As Long, Byval CurrentVisemeId As Long)
             'msgbox "Viseme"
        End Method
 
        Method AudioLevel <9> (Byval StreamNumber As Long, Byval StreamPosition As Variant, Byval AudioLevel As Long)
              'msgbox "AudioLevel"
        End Method
 
        Method EnginePrivate <10> (Byval StreamNumber As Long, Byval StreamPosition As Long, Byval EngineData As Variant)
              'msgbox "EnginePrivate"
        End Method
 
    End Interface
End Class
 
 
FUNCTION PBMAIN () AS LONG
  local obj_ISpVoice As ISpeechVoice
  local obj_SAPI_ISpeechVoiceEvents As SAPI_ISpeechVoiceEvents
  local lng_Dummy as long
  local lng_StreamNumber as long
  local wstr_Text_to_speak as WSTRING
  local lng_msTimeout as long
 
  obj_ISpVoice = NEWCOM $PROGID_SpeechLib_SpVoice ' Create an instance of the ISpeechVoice Interface
  ' Was the object refrence succesful?
  IF ISFALSE(ISOBJECT(obj_ISpVoice)) THEN MSGBOX "Не смог создать ссылку на iSpVoice Interface."
 
  gobj_ISpeechMemoryStream = NEWCOM $PROGID_SpeechLib_SpMemoryStream ' Create an instance of the ISpeechMemoryStream Interface
  ' Was the object refrence succesful?
  IF ISFALSE(ISOBJECT(gobj_ISpeechMemoryStream)) THEN MSGBOX "Не смог создать ссылку на ISpeechMemoryStream Interface"
 
  lng_Dummy = %SpeechAudioFormatType.SAFT44kHz16BitMono
  OBJECT let gobj_ISpeechMemoryStream.Format.Type = lng_Dummy
 
  OBJECT sET obj_ISpVoice.AudioOutputStream  = gobj_ISpeechMemoryStream
 
  wstr_Text_to_speak = "Проверка связи, проверка связи..." & chr$(0)& chr$(0)
  lng_msTimeout = 600000
 
  obj_SAPI_ISpeechVoiceEvents = CLASS "Class_SAPI_ISpeechVoiceEvents"
  ' Was the object refrence succesful?
  IF ISFALSE(ISOBJECT(obj_SAPI_ISpeechVoiceEvents)) THEN MSGBOX "Не смог создать ссылку на SAPI_ISpeechVoiceEvents Interface"
 
  lng_Dummy = %SpeechVoiceSpeakFlags.SVSFDefault
 
  EVENTS FROM obj_ISpVoice CALL obj_SAPI_ISpeechVoiceEvents
    OBJECT call obj_ISpVoice.Speak (wstr_Text_to_speak, lng_Dummy) to lng_StreamNumber
    OBJECT call obj_ISpVoice.WaitUntilDone (lng_msTimeout) 'Не знаю, нужен ли вообще этот оператор, а если нужен,
                                                           'то куда именно его следует вставить
 
    msgbox("Запись файла завершена")   'Странно, но без этого оператора события вообще не ловятся почему-то. Почему?!?!
  EVENTS END obj_SAPI_ISpeechVoiceEvents
END FUNCTION
Вложения
Тип файла: zip Все_файлы_кроме_аудио.zip (37.6 Кб, 3 просмотров)
Тип файла: zip Варианты звучания (7 файлов по 330 кБ).zip (922.9 Кб, 2 просмотров)
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
20.02.2020, 18:23  [ТС]
Не понимаю, что происходит

Пробую сейчас вставить (дополнительно) вот такой фрагмент кода

Visual Basic
1
2
3
4
    int_file_number = freefile 
          OPEN EXE.PATH$ & "01.raw" FOR binary AS # int_file_number
              put # int_file_number,, MyArray()
          CLOSE # int_file_number
в совершенно разные места программы, но всегда получаю один и тот же результат: файл 01.wav записывается всегда, а вот файл 01.raw тоже всегда "записывается", но всегда имеет нулевую длину почему-то
Вот так у меня и тогда было, я припоминаю, поэтому я и решил тогда, что скинуть массив байтов на диск у меня не получится.

Добавлено через 2 часа 2 минуты
Цитата Сообщение от I can Посмотреть сообщение
Ну тогда я не знаю, я проверял в Visual Basic, там без скобок надо писать. А в Power Basic-е могут быть свои тараканы.
Проблема, наверняка, не в самом Power Basic-е, а в том, что я что-то неправильно делаю в COM-программировании, и это как-то влияет отрицательно. В отдельной-то небольшой программке (где нет никаких COM-обращений) всё работает замечательно, как сегодня выяснилось.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
21.02.2020, 09:32
Лучший ответ Сообщение было отмечено Power_Basic как решение

Решение

Цитата Сообщение от Power_Basic Посмотреть сообщение
Не, ну правда, в строке же каждый символ кодируется значением от нуля до 255, ну а это же и есть байт.
Это неправда. http://www.cyberforum.ru/blogs/33029/blog5139.html

Цитата Сообщение от Power_Basic Посмотреть сообщение
С удовольствием скидываю всё, что могу скинуть
Ну в общем посмотрел. Не знаю баг ли это Power Basic'а или какую-то инициализацию нужно делать, но баг заключается в следующем. Когда идет присвоение Variant массива массиву байт MyArray то MyArray еще неинициализирован и его дескриптор содержит одни нули. Дескриптор содержит в себе много данных таких как указатель на данные, размер массива, нижняя и верхняя границы, а также размер одного элемента в байтах. Так вот, когда идет присвоение то поскольку массив неинициализирован размер одного элемента равен 0, и при выделении памяти размер равен (Ubound(vnt_Dummy) + 1) * РазмерЭлемента, а поскольку размер равен нулю то и размер выделяемой памяти также равен 0. Скорее всего это баг компилятора. Из-за этого в переменную писался мусор, а то что небольшой фрагмент попадал туда - чистая случайность, т.к. данные лежат рядом. Исправить можно просто проинициализировав дескриптор по типу:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        METHOD EndStream <2> (BYVAL StreamNumber AS LONG, BYVAL StreamPosition AS VARIANT)
          LOCAL vnt_Dummy AS VARIANT
          DIM MyArray() AS BYTE
          LOCAL MyString AS STRING
          LOCAL str_Total_audio_stream AS STRING
          LOCAL udt_WAV_file_header AS udt_type_WAV_file_header
          LOCAL int_file_number AS INTEGER
 
          MSGBOX "Событие EndStream"                                  'Просто для информации о том, что событие "поймано"
 
          OBJECT CALL gobj_ISpeechMemoryStream.GetData TO vnt_Dummy   'Запись аудиопотока в Variant
          REDIM MyArray(1) ' // Инициализируем дескриптор
          MyArray() = vnt_Dummy                                       'Преобразуем Variant вмассив байтов
          MyString = PEEK$(VARPTR(MyArray(0)), UBOUND(MyArray)+1)     'Считываем все байты аудиопотока из массива в строку
1
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
21.02.2020, 12:04  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Исправить можно просто проинициализировав дескриптор
Не, ну это просто гениально!
Один лёгкий штрих и всё заработало!

Но как вы могли проверить свою догадку на практике?!?
Методом дедукции приходим к выводу, что у вас там тоже имеется под рукой компилятор Power Basic'а, и это меня сильно радует, поскольку мне уже казалось, что я теперь один такой "невымерший мамонт" на всём белом свете

Цитата Сообщение от The trick Посмотреть сообщение
Должен признаться, что я Юникод не люблю вообще в принципе и всеми силами стараюсь его избегать по мере возможности. Именно поэтому у меня во всех программах почти все строки АНСИ-шные, ну и как раз подходят для хранения последовательности байтов.

Кстати, я сейчас припоминаю, что вычитал о такой возможности где-то в справочной системе Power Basic'а, но только сейчас вот поискал и не смог найти это место. Короче, там смысл был приблизительно такой, что то ли в COM-программировании, то ли в процессе работы в WinAPI функциями, то ли при конвертации массивов Visual Basic'а в массивы Power Basic'а используется SAFEARRAY. И чтобы обойти все возникающие сложности как раз-то и рекомендовалось использовать этот хитрый трюк - упаковывать массивы байтов в строки.
На самом деле, для меня все эти SAFEARRAY это сложно, пробовал когда-то разобраться, но почему-то не получилось
А может быть и не о SAFEARRAY там шла речь, сейчас уже точно не помню. Но это рекомендовалось именно для обхода каких-то сложностей. Метод мне понравился и запомнился. Ну и на практике-то ведь работает же!
Ведь в нашей совместной программе аудиопоток идеально сохранился именно в строке!

Ну и да, разумеется, строки должны быть именно АНСИ-шные и ещё важно не промахнуться со считыванием именно содержимого самой строки, а не содержимого её дескриптора (ну то есть использовать функцию STRPTR, а не VARPTR, как для строк фиксированной длины, например).
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.02.2020, 12:04
Помогаю со студенческими работами здесь

Как вытащить звук из аудиопотока?
Доброго времени суток всем! Я работаю во Flex 4 (новичек). Можно лиимея видеопоток, воспроизводить один звук (без изображения) ? Есть...

После того, как вытянул/вставил оперативную память высветилась странная запись.
День добрый или ночь. Умная голова не удержала шустрые руки.Теперь о главном: Хочу повысить оперативку,Вытащил оперативку прочесть номер...

Как проверить, если запись есть в таблице, то вывести ошибку "Запись существует"
как проверить если запись есть в таблице (datagridview) то вывести ошибку &quot;Запись существует&quot;, использую access Точнее: например в...

Речевое воспроизведение текста! TTS
Помогите с поиском информации по речевому воспроизведению текста. Может где движок такой можно скачать?

Синтез голоса из строки (TTS)
Доброго времени суток, форумчаны. Интересует тема синтеза речи из текста на микроконтроллера из архитектурой ARM CORTEX M3. (Английский) ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru