Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.16.66.206] |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Изучаю возможности программного вывода звука.
С получением звука с микрофона вроде всё нормально, а вот вывод ни к чёрту.) Маленький кусок кода: unit U4_1; interface uses Windows, Math, Messages, Classes, Forms, MMSystem; const discret = 8000; SizeBufOut = 400; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); public procedure WCard; end; var hMapFile:THandle; lpBaseAddress:PChar; Vdata: array [0..SizeBufOut-1] of integer; Form1: TForm1; WaveFormatEx: TWaveFormatEx; WaveOut:HWAVEOUT; hEvent: THandle; woh: WAVEHDR; Bits16: boolean; hBuf: THandle; BufHead: TWaveHdr; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin WCard; end; procedure TForm1.WCard; var BufLen: word; buf: pointer; n: word; begin bits16 := True; with WaveFormatEx do begin wFormatTag := WAVE_FORMAT_PCM; nChannels := 1; nSamplesPerSec := discret; wBitsPerSample := integer(Bits16) * 8 + 8; nBlockAlign := nChannels * (wBitsPerSample div 8); nAvgBytesPerSec := nSamplesPerSec * nBlockAlign; end; hEvent := CreateEvent(nil, false, false, nil); WaveOutOpen(Addr(WaveOut), 0, addr(WaveFormatEx), hEvent, 0,CALLBACK_EVENT); for n:=0 to SizeBufOut-1 do Vdata[n]:=RandomRange(1,1000); BufLen := WaveFormatEx.nBlockAlign * SizeBufOut; with BufHead do begin woh.lpData := addr(Vdata); woh.dwBufferLength := BufLen; end; waveOutPrepareHeader(WaveOut, addr(woh), sizeof(woh)); waveOutWrite(WaveOut, addr(woh), sizeof(woh)); end; end. Вроде звук одного блока получил, а вот как его зациклить (для начала), чтобы это был единый поток не получается. |
Сообщ.
#2
,
|
|
|
Цитата Ivan123 @ чтобы это был единый поток не получается. Вопрос решён |
Сообщ.
#3
,
|
|
|
Вот что получилось кому интересно
unit U7_1; interface uses Windows, Math, Messages, Classes, Forms, MMSystem; procedure Execute; const discret = 8000; SizeBufOut = 400; MMFName: pAnsiChar = 'MP'; a=0; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); public procedure WCard; end; var hMapFile:THandle; lpBaseAddress:PChar; Vdata: array [0..SizeBufOut-1] of smallint; Form1: TForm1; WaveFormatEx: TWaveFormatEx; WaveOut:HWAVEOUT; hEvent: THandle; woh: WAVEHDR; BufHead: TWaveHdr; n: word; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin WCard; Execute; end; procedure TForm1.WCard; var BufLen: word; n: word; begin with WaveFormatEx do begin wFormatTag := WAVE_FORMAT_PCM; nChannels := 1; nSamplesPerSec := discret; wBitsPerSample := 16; nBlockAlign := nChannels * (wBitsPerSample div 8); end; hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS,False,MMFName); lpBaseAddress := MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1); hEvent := CreateEvent(nil, false, false, nil); WaveOutOpen(Addr(WaveOut), 0, addr(WaveFormatEx), hEvent, 0,CALLBACK_EVENT); waveOutPrepareHeader(WaveOut, addr(woh),SizeOf(woh)); BufLen := WaveFormatEx.nBlockAlign * SizeBufOut; with BufHead do begin woh.lpData := addr(Vdata); woh.dwBufferLength := BufLen; end; end; procedure Execute; begin while a<1 do begin; //CopyMemory(addr(Vdata), lpBaseAddress, SizeBufOut*2); for n:=0 to SizeBufOut-1 do Vdata[n]:=RandomRange(1,32000); waveOutWrite(WaveOut, addr(woh), SizeOf(woh)); waveOutReset(WaveOut); end; end; end. Прикреплённый файлDF9.rar (171,62 Кбайт, скачиваний: 880) |
Сообщ.
#4
,
|
|
|
type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); private { Private declarations } public { Public declarations } end; const discret = 8000; SizeBufOut = 400; bufcount = 3; play = 1; stop = 0; var Form1 : TForm1; WaveOut : HWAVEOUT; mode : integer; actbufcount : cardinal; implementation {$R *.dfm} Procedure FillBuf(var buf); var ps : psmallint; i : cardinal; begin ps:=pointer(buf); for i:=0 to sizebufout-1 do begin ps^:=Random(32000)-16000; inc(ps); end; end; procedure waveOutProc( hwo:HWAVEOUT; uMsg,dwinstance,dwParam1,dwParam2:dword);stdcall; Begin case umsg of WOM_OPEN:; WOM_CLOSE:; WOM_DONE: if mode<>stop then begin fillbuf(PWaveHdr(dwParam1)^.lpData); waveoutwrite(waveout,PWaveHdr(dwParam1),sizeof(TwaveHdr)); end else begin waveoutunprepareheader(waveout,PWaveHdr(dwParam1),sizeof(TwaveHdr)); freemem(PWaveHdr(dwParam1)^.lpData); freemem(PWaveHdr(dwParam1)); dec(actbufcount); end; end; End; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin mode:=stop; repeat until actbufcount=0; waveoutclose(waveout); canclose:=true; end; procedure TForm1.FormCreate(Sender: TObject); var fmt : TWaveFormatEx; pwhdr : PWaveHdr; i : cardinal; begin mode:=stop; actbufcount:=0; with fmt do begin wFormatTag := WAVE_FORMAT_PCM; nChannels := 1; nSamplesPerSec := discret; wBitsPerSample := 16; nBlockAlign := nChannels * (wBitsPerSample div 8); nAvgBytesPerSec :=nBlockAlign*nSamplesPerSec; cbsize :=0; end; WaveOutOpen(@WaveOut, 0, @fmt, dword(@waveoutproc), 0,CALLBACK_FUNCTION); WaveOutPause(WaveOut); for i:=0 to bufcount-1 do begin pwhdr:=allocmem(sizeof(TWaveHdr)); pwhdr.lpData:=allocmem(SizeBufOut*fmt.nBlockAlign); pwhdr.dwBufferLength:= SizeBufOut*fmt.nBlockAlign; waveOutPrepareHeader(WaveOut, pwhdr,SizeOf(TWaveHdr)); fillbuf(pwhdr.lpData); waveoutwrite(waveout,pwhdr,sizeof(TwaveHdr)); inc(actbufcount); end; mode:=play; waveoutrestart(waveout); // end; |
Сообщ.
#5
,
|
|
|
Спасибо за пример, наверно так профессионально.
Я писал просто чтобы получить хоть какой положительный результат) у вас это произведение, учиться никогда не поздно. |
Сообщ.
#6
,
|
|
|
Пример самый обычный, для песочницы, для теста, для проверки идеи. Как один из возможных вариантов. Ваш пример совсем нехорош. Он не решает задачу, не обеспечивает непрерывность звукового потока.
|
Сообщ.
#7
,
|
|
|
Цитата Ivan123 @ не обеспечивает непрерывность звукового потока Согласен, но на тот момент задача стояла услышать программно любой звук, да и функции мультимедия я видел впервые, так что я только учусь и спасибо за помощь) |
Сообщ.
#8
,
|
|
|
Цитата Prince @ Как один из возможных вариантов Ещё один вопрос про ещё один вариант. А как этот кусок будет выглядеть для консоли? К сожалению из консоли у меня никак не получается добраться до аудио буфера. Или может какую литературу подскажите по теме? |
Сообщ.
#9
,
|
|
|
Литература в FAQ раздела. Рекомендую книги Секунова и Кинтцеля.
Консольный вариант будет аналогичным. В консольном приложении сначала выполните код из метода create, потом будет пустой цикл, с выходом по нажатию клавиши, а за ним то, что в closequery. |
Сообщ.
#10
,
|
|
|
Цитата Prince @ bufcount = 3; 1. Можете пояснить зачем нужен этот цикл, и почему 3, не 1, не 4 и тд? Если я правильно понимаю, чтобы просто разделить процесс записи в буфер и процесс воспроизведения из буфера, но тогда почему 3, а не 2? 2. И каков максимальный размер блока аудиоданных? Или для каждого устройства он разный и его надо предварительно определять? и сколько таких блоков (вернее какой суммарный объём байтов) можно запихнуть в этот буфер? |
Сообщ.
#11
,
|
|
|
1. Минимум необходимы 2 буфера, для обеспечения непрерывности звука. Они же могут быть и достаточны. Я выбрал 3, мне так больше нравится. Максимум...любое вменяемое количество, но ограниченное объемом памяти. 100500 - бессмысленно.
2. Максимальный размер блока [может быть] ограничен объемом памяти, организацией памяти, драйвером, разрядностью DWORD(?)... не проверял, потому как смысла нет. Буфер - он же и есть блок данных. Размер выбираете сами. Снизу размер/длительность ограничены быстродействием железа и многопоточностью винды(разрешением системного таймера, например), сверху - объемом памяти. На практике примерно 20 мс минимум, если повезет. Надежней 50 мс. Совсем хорошо - 100 мс. Зависит от задачи. Верхний предел 200-1000 мс. Можно больше, зависит от задачи. Читайте литературу. Когда поймете принцип работы с блоками, размеры и количества встанут на свои места. Для них нет однозначных жестких ограничений. За исключением, пожалуй, минимального количества блоков. Хотя и это ограничение можно обойти. Но тогда потеряется простота работы с ними. Точнее, один буфер противоречит самой логике работы интерфейса. |
Сообщ.
#12
,
|
|
|
Я бы поставил штуки 4 общим объёмом в секунду, чтоб не париться, что называется (для надёжности).
По 50 мс как-то маловато (по мне), мало ли подвиснет система на десятые доли секунды. Хотя вон ASIO работает по 32 семпла (1.5 мсек) и ничего, не глючит, а 64 – вообще огонь (хотя, там технология другая, тут буферы по 64 семпла вряд ли будут нормально звучать) Тут действительно кто во что горазд и какие задачи. Может, у вас там целая эпопея делается длительностью в полсекунды перед чтением очередного блока |
Сообщ.
#13
,
|
|
|
Цитата Prince @ Минимум необходимы 2 буфера Переписал свой код для захвата звука под консоль и с учётом ваших рекомендаций по структуре вывода белого шума (расположен выше) procedure FillBuf(var buf); var ps : psmallint; i : cardinal; begin ps:=pointer(buf); for i:=0 to SizeBufIn-1 do begin ps^:=PData16(pwhdr.lpData)^[i]; Vdata[i]:=ps^; inc(ps); end; end; procedure waveInProc( hwo:HWAVEIN; uMsg, dwinstance, dwParam1, dwParam2:dword); stdcall; begin if uMsg = WIM_DATA then begin fillbuf(PWaveHdr(dwParam1)^.lpData); WaveInAddBuffer(waveIn,PWaveHdr(dwParam1),sizeof(TwaveHdr)); end; end; procedure Create; var fmt : TWaveFormatEx; a,i : cardinal; buf : psmallint; begin with fmt do begin wFormatTag := WAVE_FORMAT_PCM; nChannels := 1; nSamplesPerSec := discret; wBitsPerSample := 16; nBlockAlign := nChannels * (wBitsPerSample div 8); nAvgBytesPerSec :=nBlockAlign * nSamplesPerSec; end; WaveInOpen(@WaveIn, WAVE_MAPPER, @fmt, dword(@waveInProc), 0, CALLBACK_FUNCTION); for i:=0 to bufcount-1 do begin pwhdr:=allocmem(sizeof(TWaveHdr)); pwhdr.lpData:=allocmem(SizeBufIn * fmt.nBlockAlign); pwhdr.dwBufferLength:= SizeBufIn * fmt.nBlockAlign; pwhdr.dwBytesRecorded:=0; pwhdr.dwFlags:= 0; WaveInPrepareHeader(WaveIn, pwhdr, SizeOf(TWaveHdr)); fillbuf(pwhdr.lpData); WaveInAddBuffer(waveIn, pwhdr, sizeof(TwaveHdr)); end; WaveInStart(WaveIn); a:=0; Repeat FillBuf(buf); until a > 0; end; И здесь у меня возникло два вопроса: 1. почему то у меня не получается организовать 2 буфера, вернее получается , но при первом цикле первый заполняется не полностью, а в последующем данные дублируются и во второй буфер. При bufcount=1 всё получается красиво с данными, но скорее всего это будет не непрерывный сигнал. 2. Вопрос касается другой темы, где я решал вопрос с микшером. Можно ли убить отправку данных на драйвер в этом коде каким нибудь хитрым способом, например заполнив перед WaveInAddBuffer буфер нулями. |
Сообщ.
#14
,
|
|
|
Цитата Ivan123 @ Переписал свой код для захвата звука под консоль и с учётом ваших рекомендаций по структуре вывода белого шума Белый шум по определению так устроен, что на нём не будут заметны никакие сбои, он плохо подходит для тестирования непрерывного воспроизведения. |
Сообщ.
#15
,
|
|
|
Что вы хотите получить в итоге. Куда сливается аудиопоток? В vdata...а дальше?
procedure FillBuf(var buf); var ps : psmallint; i : cardinal; begin ps:=pointer(buf); for i:=0 to SizeBufIn-1 do begin ps^:=PData16(pwhdr.lpData)^[i]; //что оно должно делать?????? Vdata[i]:=ps^; inc(ps); Если вам нужно (для чего-то) переписать буфер в другой массив, используйте функцию Move; WaveInPrepareHeader(WaveIn, pwhdr, SizeOf(TWaveHdr)); fillbuf(pwhdr.lpData); WaveInAddBuffer(waveIn, pwhdr, sizeof(TwaveHdr)); fillbuf здесь не к месту. Буфер ещё не заполнен данными аудио. Там пока нули, поскольку память выделялась через allocmem. Если бы память выделялась как-то иначе, возможно, был бы мусор. Но там еще нет аудио. Аудио ловится только в waveinproc по WIM_DATA и нигде больше. Цитата a:=0; Repeat FillBuf(buf); until a > 0; Это вообще ерунда какая-то. readln; заменит эту конструкцию. fillbuf снова не в тему, на выходе приложения черте-что окажется вместо непрерывного аудио потока. Код неполный, но и так видно, что он работает неправильно. |