Библиотека Sonic

Предыдущая тема Следующая тема Перейти вниз

Библиотека Sonic

Сообщение  electrik в Пт Сен 07, 2012 12:38 am

сониц- бесплатная кросс-платформенная библиотека с открытыми исходниками. написана на ansi c- биллом коксом (Bill Cox, ).
скомпилированный вариант и заголовочный файл с примером для FreeBasic качаем:
http://svalka-spb.narod.ru/soft/sonic-0.1.18_fb.rar
для чего все это. эта библиотека предназначена для ускорения или замедления скорости аудио без изменения высоты.
так же она может изменять высоту с сохранением формантов.
распространяется как исходник, который нужно подключать к проекту.
я откомпилировал в статическую библиотеку, и сделал заголовочный файл. но есть проблема. mingw не хочет использовать некоторые сопроцессор функции: sin и т.д.
у билла, есть два варианта, через сопроцессор,, и его реализации. пришлось выбрать второй вариант, ибо первый, вызывал бы sin через rtl из msvcrt.dll.
соответственно, поскольку все работает абы как, и алгоритм дольше работает.
ниже исходник сырой, но рабочей программы. она проигрывает на звуковуху wave файлы. основана на моём простом плеере wplay. стрелками влево/вправо, регулируется скорость, вверх/вниз- высота.
высота, кривовато, но это алгоритм билла. больше мне понравилось ускорение, тут даже больше чем в два раза классно делает. аудиокниги переганять на быструю скорость в самый раз.
поскольку программа сырая, я не делал оптимизаций, будут прерывания звука, особенно когда сильно понизить скорость, или накрутить питч и скорость.
такие вещи реализовываются не последовательно, а в потоках. пока играет одна очередь буферов, в другом потоке готовится другая, тогда прерываться звук не будет. алгоритм тяжелый, на последовательный засыл на звуковуху не успевает.
что, если переписать эту библиотеку на FreeBasic, естественно, авторство алгоритмов за биллом, но как потом это распространять. понятно, что под gnu, но можно ли портировать чужие алгоритмы на другие языки?
тогда и синус через сопроцессор пойдёт, да и народ незнающий c, сможет изменять алгоритм. а может кто-то заоптимизирует или еще лучше сделает.
я могу за это взяться, если есть в этом смысл. там кода мало- примерно на тысячу строк.

код программы:
Код:

'windows player(wplay)
'или wave play wplay - называйте как угодно
'плеер для проигрывания стандардных pcm wave файлов
'(c) electrik 2008-2012
'email: svalka-spb@yandex.ru
'web: http://svalka-spb.narod.ru
' библиотека sonic - Copyright Bill Cox
'плеер написан в процессе самообучения звуковой подсистемы winmm
'компилировать: fbc.exe -s gui wplay.bas
'использовать: wplay.exe имяФайла.wav

#include once "windows.bi"
#include "win/mmsystem.bi"
#include "sonic.bi"

#define WAVE_MAPPER -1
#define bufsize 65536
#define buffers 2
type WaveHeader 'описатель заголовка wav файла
as zstring * 4 id_riff 'потпись riff
len_riff as integer 'размер оставшейся части файла без riff

'chuck
id_chuck as zstring * 4 'потпись wave
fmt as zstring * 4 'потпись fmt
len_chuck as integer 'размер заголовка id_riff+len_riff+id_chuck+fmt=16

'wave
WaveFormat as short 'формат данных, 1= pcm
channels as short 'число каналов
SamplesPerSec as integer 'частота дискретизации
bytes as integer 'частота выдачи байт
align as short 'выравнивание
bits as short 'число бит

'sample wave
samplewave as zstring * 4 'data 'потпись data
len_data as integer 'размер звуковых данных без заголовка
end type 'конец описателя заголовка wav файла

dim shared hFile as handle 'дескриптор файла
dim shared hEvent as HANDLE ' хэндл объекта события
dim shared hOut as hWaveOut 'тут будет лежать идентификатор устройства
dim shared ss as sonicStream ' поток sonic
dim shared wFormat as WaveFormatEx 'тип(описатель) wave формата
dim shared wHeader as WaveHeader 'описатель заголовка wav файла
dim shared wHdr(buffers) as wavehdr 'описатель заголовка буфера
dim shared inbuf(buffers) as zstring * bufsize ' входные буферы звуковых данных
dim shared outbuf(buffers+8192) as zstring * bufsize ' выходные буферы звуковых данных
dim shared bufferSize as integer = bufsize
dim shared snumbuf as integer = 0 ' счетчик
dim shared bytesRead as integer 'число действительно прочитанных байт из файла
dim shared samplesWritten as integer ' число  семплов для записи на звуковое устройство
dim shared FilePosition as integer 'хранение позиции в файле
dim shared argv as zstring * 260 ' коммандная строка
dim shared argc as integer ' число параметров коммандной строки
cls
argc=__fb_argc__ 'получим число параметров командной строки
if argc =1 then 'если нет аргументов
?!"Использование: wplay.exe имя файла.wav.\nпрограмма поддерживает только Pcm wave файлы."
end 1
end if

'соберем командную строку в одно целое
for i as integer =1 to argc - 1
lstrcat(argv,__fb_argv__[i])
lstrcat(argv," ")
next

'откроем файл только для чтения, из командной строки как бинарник
hFile = CreateFile(argv,GENERIC_READ, _
FILE_SHARE_READ,NULL, OPEN_EXISTING, _
FILE_ATTRIBUTE_ARCHIVE,NULL)

'если возникла ошибка при открытии файла
if hFile = INVALID_HANDLE_VALUE  then
?"Файл задан не правильно"
end 1
end if

'прочитаем заголовок wav файла
readfile(hFile,@wHeader,44,@bytesRead,0)
if bytesRead < 44 then
?"Файл меньше длины заголовка wave файла. возможно вы открываете не pcm Wave файл или файл поврежден"
end 1
end if
FilePosition+=bytesRead
if not CompareString(0,0,wHeader.id_riff,4, "RIFF",4) = 2 and not CompareString(0,0,wHeader.id_chuck,4,"WAVE",4) = 2 and _
not CompareString(0,0,wHeader.fmt,4,"fmt ",4) = 2 and not CompareString(0,0,wHeader.samplewave,4,"data",4) = 2 then
?"Заголовок поврежден или вы открываете не Pcm wave файл"
end 1
end if

'описатель заголовка формата wave
wFormat.wFormatTag=wHeader.WaveFormat ' формат звуковых данных
wFormat.nChannels= wHeader.channels 'число каналов
wFormat.nSamplesPerSec = wHeader.SamplesPerSec 'частота дискретизации
wFormat.nAvgBytesPerSec = wHeader.bytes 'частота выдачи байт драйверу
wFormat.nBlockAlign= wHeader.align 'выравнивание
wFormat.wBitsPerSample = wHeader.bits 'число бит на семпл
'конец описателя заголовка formata wave

' создадим объект события
'первый параметр, хэндл события
  hEvent = CreateEvent(NULL,false,false,NULL)
'откроем звуковое устройство. первый параметр функции waveOutOpen- это указатель
'на переменную hOut, и если с устройством нет проблем,
'то в переменную запишется идентификатор открытого устройства
'второй параметр, номер устройства. обычно туда пишут WAVE_MAPPER,
'для автоматического определения звуковухи по умолчанию.
'третий параметр, указатель на описатель заголовка wave формата.
'четвертый параметр, хэндл объекта события
'шестой параметр, задает флаг, общения с драйвером, в нашем случае- это CALLBACK_EVENT, объект события
if waveOutOpen(@hOut, -1,@wFormat,cptr(DWORD,hEvent),0,CALLBACK_EVENT) then
?"Устройство не поддерживает данный Wave формат, или проблема открытия устройства"
end 1
end if
   
' создадим поток sonic
ss = sonicCreateStream _
(wHeader.SamplesPerSec, _ 'частота дискретизации
wHeader.channels) 'число каналов
if ss = 0 then
?"ошибка создания потока sonic"
end 1
end if
sonicsetchordpitch(ss,1) ' чтобы питч менялся не как на ленте а с сохранением формант
for numbuf as integer = 0 to buffers 'счетчик
' заполним поля структуры заголовка
wHdr(numbuf).lpData = @outbuf(numbuf) 'указатель на буфер со звуковыми данными
wHdr(numbuf).dwBufferLength = buffersize
' подготовим заголовки
'первый параметр, идентификатор устройства.
'второй параметр, указатель на заголовок для буфера.
'третий параметр, длина заголовка
if waveOutPrepareHeader(hOut,@wHdr(numbuf),32) then
?"Ошибка подготовки заголовка"
beep
end 1
end if
next 'пусть повторяет

dim key as string
do
key=inkey
for numbuf as integer = 0 to 2 'счетчик
if key = chr(27) then exit do
if key = chr(255,77) then SonicSetspeed(ss,sonicgetspeed(ss)+0.2)
if key = chr(255,75) then SonicSetspeed(ss,sonicgetspeed(ss)-0.2)
if key = chr(255,80) then SonicSetpitch(ss,sonicgetpitch(ss)+0.2)
if key = chr(255,72) then SonicSetpitch(ss,sonicgetpitch(ss)-0.2)
if sonicgetspeed(ss) > 4.0 then sonicsetspeed(ss,4.0)
if sonicgetspeed(ss) < 0.1 then sonicsetspeed(ss, 0.1)
if sonicgetpitch(ss) > 4.0 then sonicsetpitch(ss,4.0)
if sonicgetpitch(ss) < 0.1 then sonicsetpitch(ss,0.1)
readfile(hFile,@inbuf(numbuf),bufsize,@bytesRead,0) ' читаем во входной буфер данные из файла
if bytesRead = 0 then ' если нечего читать из файла
       sonicFlushStream(ss) '
else
filePosition+=bytesRead ' добавляем к позиции файла число прочитанных байт
if filePosition >= wHeader.len_data+sizeof(wHeader) then ' если позиция файла >= длине звуковых данных + заголовок файла
bufferSize = bytesRead - (filePosition - wHeader.len_data) ' длина буфера =число прочитанных байт - (позиция файла - длина звуковых данных)
end if

' проверим разрядность файла.
if wHeader.bits = 8 then ' если число бит на семпл = 8
' посылаем звуковые данные на поток sonic
sonicWriteUnsignedCharToStream _
(ss, _ ' поток сониц
inbuf(numbuf), _ ' буфер со звуковыми данными
bufferSize/wHeader.channels) ' число семплов разделить на число каналов
   
do

' читаем поток sonic
       samplesWritten = sonicReadUnsignedCharFromStream _
(ss, _ ' поток sonic
outbuf(snumbuf), _ ' выходной буфер
bufferSize/wHeader.channels) ' максимальное число семплов. длина буфера разделить  на число каналов
       if samplesWritten > 0 then ' если есть что писать
wHdr(numbuf).dwBufferLength = samplesWritten*wHeader.channels ' длина буфера = число семплов умножить на число каналов
'подаем драйверу всё подготовленное хозяйство.
'первый параметр, идентификатор устройства.
'второй параметр, указатель на заголовок для буфера.
'третий параметр, длина заголовка
WaveOutWrite(hOut,@wHdr(snumbuf),32)
WaitForSingleObject(hEvent, INFINITE) ' ожидаем, пока драйвер проиграет буфер
snumbuf+=1
if snumbuf > buffers then snumbuf=0

end if
loop while samplesWritten > 0
ElseIf wHeader.bits = 16 then ' если число бит на семпл = 16

' посылаем звуковые данные на поток sonic
sonicWriteShortToStream _
(ss, _ ' поток сониц
cast(short ptr,@inbuf(numbuf)), _ ' буфер со звуковыми данными
bufferSize/wHeader.channels/2) ' число семплов. для 16 бит длина буфера разделить  на число каналов разделить на 2

   do
key = inkey
' читаем поток sonic
       samplesWritten = sonicReadShortFromStream _
(ss, _ ' поток sonic
cast(short Ptr,@outbuf(snumbuf)), _ ' выходной буфер
bufferSize/wHeader.channels/2) ' максимальное число семплов. длина буфера разделить  на число каналов разделить на 2
if samplesWritten > 0 then
wHdr(snumbuf).dwBufferLength = samplesWritten*wHeader.channels*2 ' длина буфера = число семплов уумножить на число каналов умножить на 2

'подаем драйверу всё подготовленное хозяйство.
'первый параметр, идентификатор устройства.
'второй параметр, указатель на заголовок для буфера.
'третий параметр, длина заголовка
WaveOutWrite(hOut,@wHdr(snumbuf),32)
WaitForSingleObject(hEvent, INFINITE) ' ожидаем, пока драйвер проиграет буфер
snumbuf+=1
if snumbuf > buffers then snumbuf=0
end if
loop while samplesWritten > 0
end if
end if
next ' пусть повторяет
loop while bytesRead > 0

CloseHandle(hFile) 'закроем файл

for numbuf as integer = 0 to buffers 'счетчик

'снимем заголовки
'первый параметр, идентификатор устройства.
'второй параметр, указатель на заголовок для буфера.
'третий параметр, длина заголовка
WaveOutUnprepareHeader(hOut,@whdr(numbuf), 32)
next 'пусть повторяет
WaveOutClose(hOut) 'закроем устройство
WaitForSingleObject(hEvent, INFINITE) ' ждем пока не закроется устройство, это чтоб в конце не обрубилось воспроизведение
CloseHandle(hEvent) ' закроем хэндл объекта события

electrik

Сообщения : 394
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Библиотека Sonic

Сообщение  trew в Пт Сен 07, 2012 9:23 am

Я не знаю точно насчет правовой стороны. Мне кажется если ты сделаешь как описал, нарушений нет. Для примера D.J. Peters сделал обертку из своих функций над библиотекой DUMB (статическую либу), но так же указал авторство. А они на западе в отличие от нас , привыкли к лицензиям относиться с серьезностью. Твой случай схож.

trew

Сообщения : 331
Дата регистрации : 2010-10-14

Посмотреть профиль

Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения