Показать сообщение отдельно
Старый 29.02.2012, 18:14   #3
Платон Александрович
Нуждающийся
 
Аватар для Платон Александрович
 
Регистрация: 05.10.2011
Адрес: Россия, Южно-Сахалинск
Сообщений: 66
Написано 42 полезных сообщений
(для 83 пользователей)
Ответ: Кто напишет функцию записи звука?

Сообщение от executer Посмотреть сообщение
не работает функция BASS_StreamCreateFile
Если я правильно понял справку, то Stream не предназначен для такого, нужно вручную писать файл, WAV, либо через функцию обратного вызова в BASS_RecordStart, либо через BASS_ChannelGetData.

ЗЫ
Гыгы, ради прикола попробовал
; Константы параметров записи
Const Frequency% = 44100
Const BitsPerSample% = 16
Const Channels% = 2
Const BlockAlign% = Channels * BitsPerSample / 8

; Инициализируем рекордер
BASS_RecordInit (-1 )

; Формируем банк с заголовком WAV файла
Local RecHeader% = CreateBank ( 44 )

; Сигнатура 'RIFF'
PokeInt ( RecHeader, 0, 1179011410 )
; Размер заголовка + размер данных, пока оставим нуль
PokeInt ( RecHeader, 4, 0 )
; Сигнатура 'WAVE'
PokeInt ( RecHeader, 8, 1163280727 )
; Сигнатура 'fmt '
PokeInt ( RecHeader, 12, 544501094 )
; Размер структуры WAVEFORMATEX
PokeInt ( RecHeader, 16, 16 )
; Поле WAVEFORMATEX\wFormatTag
PokeShort ( RecHeader, 20, 1 )
; Поле WAVEFORMATEX\nChannels
PokeShort ( RecHeader, 22, Channels )
; Поле WAVEFORMATEX\nSamplesPerSec
PokeInt ( RecHeader, 24, Frequency )
; Поле WAVEFORMATEX\nAvgBytesPerSec
PokeInt ( RecHeader, 28, Frequency * BlockAlign)
; Поле WAVEFORMATEX\nBlockAlign
PokeShort ( RecHeader, 32, BlockAlign)
; Поле WAVEFORMATEX\wBitsPerSample
PokeShort ( RecHeader, 34, BitsPerSample )
; Сигнатура 'data'
PokeInt ( RecHeader, 36, 1635017060 )
; Размер блока данных
PokeInt ( RecHeader, 40, 0 ); Data length

; Создаем файл для записи
Local RecFile% = WriteFile ( "output.wav" )

; Записываем заголовок
WriteBytes ( RecHeader, RecFile, 0, 44 )

;
; т.к. в Блиц-Бейсике нет возможности получить адрес функции (имею ввиду встроеной возможности),
; а один из механизмов записи данных в BASS это функции обратного вызова
; то можно записать бинарное представление этой функции в банк памяти и передать адрес на его данные
;
; исходя из заголовка функции (в справке):
;   - она имеет stdcall соглашение вызова ( т.е. должна сама восстанавливать смещение стека )
;   - предоставляет 4 параметра: хендл канала, адрес буфера с данными, длина данных и параметр указаный пользователем
;   - должна возвращать True для продолжения записи
; для такой функции типично сразу передавать буфер с данными в файл
; блиц умеет передавать только банк памяти WriteBytes
; нижеописанный код получен путем дизассемблирования WriteBytes и небольшого анализа полученого кода
; 
; да-да, я извращенец :)
;

; выделяем банк под код функции обратного вызова
Local RecProc% = CreateBank ( 27 )

; mov eax, [ esp + 12 ] "Length"
PokeByte ( RecProc, 0, $8B )
PokeByte ( RecProc, 1, $44 )
PokeByte ( RecProc, 2, $24 )
PokeByte ( RecProc, 3, $0C )

; push eax
PokeByte ( RecProc, 4, $50 )

; mov eax, [ esp + 12 ] "Buffer"
PokeByte ( RecProc, 5, $8B )
PokeByte ( RecProc, 6, $44 )
PokeByte ( RecProc, 7, $24 )
PokeByte ( RecProc, 8, $0C )

; push eax
PokeByte ( RecProc, 9, $50 )

; mov ecx, [ esp + 24 ] "File"
PokeByte ( RecProc, 10, $8B )
PokeByte ( RecProc, 11, $4C )
PokeByte ( RecProc, 12, $24 )
PokeByte ( RecProc, 13, $18 )

; mov eax, [ ecx ] "File -> This"
PokeByte ( RecProc, 14, $8B )
PokeByte ( RecProc, 15, $01 )

; call [ eax + 8 ] "This -> WriteData"
PokeByte ( RecProc, 16, $FF )
PokeByte ( RecProc, 17, $50 )
PokeByte ( RecProc, 18, $08 )

; mov eax, 1 "Return True"
PokeByte ( RecProc, 19, $B8 )
PokeByte ( RecProc, 20, $01 )
PokeByte ( RecProc, 21, $00 )
PokeByte ( RecProc, 22, $00 )
PokeByte ( RecProc, 23, $00 )

; ret 16
PokeByte ( RecProc, 24, $C2 )
PokeByte ( RecProc, 25, $10 )
PokeByte ( RecProc, 26, $00 )

; временный банк памяти для возвращения старого аттрибута памяти
Local RecTemp% = CreateBank ( 4 )

Const PAGE_EXECUTE_READWRITE% = 64

; для того чтобы DEP системы не дал по рукам за "выполнение данных"
; сменим атрибут памяти, указав что он предназначен для запуска
VirtualProtect ( RecProc, 27, PAGE_EXECUTE_READWRITE, RecTemp )

FreeBank ( RecTemp )

; запускаем рекордер, передаем параметры, банк с функцией обратного вызова
; и тот самый параметр пользователя - хендл файла, в который будет происходить запись
; в функции обратного вызова
Local RecChannel% = BASS_RecordStart ( Frequency, Channels, 0, RecProc, RecFile )

; ожидающий цикл
Repeat
	Delay ( 100 )
Until KeyDown ( 1 )

; останавливаем рекордер
BASS_ChannelStop ( RecChannel )

; освобождаем ресурсы
BASS_RecordFree ( )

; получаем размер файла
Local RecLength% = FilePos ( RecFile )

; записываем размеры в заголовок
SeekFile ( RecFile, 4 )
WriteInt ( RecFile, RecLength - 8 )
SeekFile ( RecFile, 40 )
WriteInt ( RecFile, RecLength - ( 36 + 8 ) )

; закрываем файл
CloseFile ( RecFile )

End
и decls
.lib "kernel32.dll"
VirtualProtect%(Address*, Size%, NewProtect%, OldProtect*)
.lib "bass.dll"
BASS_RecordInit%(Device%)
BASS_RecordStart%(Frequency%, Mode%, Flags%, Func*, Context%)
BASS_ChannelStop%(Handle%)
BASS_RecordFree()
(Offline)
 
Ответить с цитированием