Форум: "Media";
Текущий архив: 2009.08.09;
Скачать: [xml.tar.bz2];
ВнизЩелчки при воспроизведении звука Найти похожие ветки
← →
DeadMeat © (2007-11-27 17:05) [0]Здравсте.
Я тут уже с ума схожу.
Пытаюсь вопроизвести звук из *.WAV файла. Ну да это ладно. До этого доберусь. Для начала хотя бы просто плавный звук.
Что имеем (подготовка):
[code]
const
SoundChannels = 1;
SoundSamples = 8000;
SoundBits = 16;
SoundBufferSize = SoundSamples * (SoundBits div 8);
SoundFormat = 1;
var
SndOutHeader: TWaveFormatEx;
SndWaveOut: hWaveOut;
SndOutBufferHeaders: array [0..1] of TWaveHdr;
SndOutSoundBuffers: array [0..1] of array of byte;
SndOutCurrentBuffer: integer;
......
with SndOutHeader do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := SoundChannels;
nSamplesPerSec := SoundSamples;
wBitsPerSample := SoundBits;
nBlockAlign := (nChannels * wBitsPerSample) div 8;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0;
end;
FillChar(SndOutBufferHeaders[0], SizeOf(SndOutBufferHeaders[0]), #0);
SetLength(SndOutSoundBuffers[0], SoundSamples * (SoundBits div 8));
with SndOutBufferHeaders[0] do
begin
lpData := @SndOutSoundBuffers[0][0];
dwBufferLength := Length(SndOutSoundBuffers[0]);
end;
bufRes := waveOutOpen(@SndWaveOut, WAVE_MAPPER, @SndOutHeader, cardinal(@RecOutProc), 0, CALLBACK_FUNCTION);
if bufRes <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(bufRes, bufErr, SizeOf(bufErr));
ShowMessage("waveOutOpen" + #13#10 + bufErr);
end;
bufRes := waveOutPrepareHeader(SndWaveOut, @SndOutBufferHeaders[0], SizeOf(SndOutBufferHeaders[0]));
if bufRes <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(bufRes, bufErr, SizeOf(bufErr));
ShowMessage("waveOutPrepareHeader" + #13#10 + bufErr);
end;
[/code]
На индексы особо внимание не обращайте. Это "типа двойная буферизация". Точнее заготовка. Изначально все было на одном единственном буфере. Т.е. предположим что индекс всегда равен нулю.
Вот функция callback:
[code]
procedure RecOutProc(hwi: HWAVEOUT; Msg: UINT; Inst, par1, par2: DWORD); stdcall;
var
bufHeader: TWaveHdr;
begin
if Msg <> WOM_DONE then
Exit;
bufHeader := SndOutBufferHeaders[SndOutCurrentBuffer];
waveOutWrite(SndWaveOut, @bufHeader, SizeOf(bufHeader));
end;
[/code]
Т.е. как "сказал" драйвер, что пора... так мы сразу отдаем ему ТОТЖЕ буфер. Ничего не меняя.
Вот "первый запуск":
[code]
FillChar(SndOutSoundBuffers[0][0], Length(SndOutSoundBuffers[0]), #128);
SndOutCurrentBuffer := 0;
bufRes := waveOutWrite(SndWaveOut, @SndOutBufferHeaders[SndOutCurrentBuffer], SizeOf(SndOutBufferHeaders[SndOutCurrentBuffer]));
if bufRes <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(bufRes, bufErr, SizeOf(bufErr));
ShowMessage("waveOutWrite" + #13#10 + bufErr);
end;
[/code]
В колонках появляется характерный писк.. Все супер. Но при этом и появились паразитические щелчки.
Не могу никак понять их природу. Ведь я не трачу никакого времени на заполнение буфера или переключение... Пауз по идее нет. Я сразу отправляю тотже самый буфер "назад". Откуда щелчки? Грешил на размер буфера, но вроде как он 16000 равен, при моно звуке 8000 Гц и 16 бит.
Вообщем не дайте мне умереть за клавой.. Пол инета перерыл... везде рекомендуют использовать двойную буферизацию... а вот ЗАЧЕМ ее использовать.. никто не говорит.. Нигде не описывается именно ПРИРОДА этих щелчков.
← →
DeadMeat © (2007-11-27 17:07) [1]Ой... ну вот... с тэгами напутал.. дурья моя бошка.. Щас перепишу части кода.
const
SoundChannels = 1;
SoundSamples = 8000;
SoundBits = 16;
SoundBufferSize = SoundSamples * (SoundBits div 8);
SoundFormat = 1;
var
SndOutHeader: TWaveFormatEx;
SndWaveOut: hWaveOut;
SndOutBufferHeaders: array [0..1] of TWaveHdr;
SndOutSoundBuffers: array [0..1] of array of byte;
SndOutCurrentBuffer: integer;
......
with SndOutHeader do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := SoundChannels;
nSamplesPerSec := SoundSamples;
wBitsPerSample := SoundBits;
nBlockAlign := (nChannels * wBitsPerSample) div 8;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0;
end;
FillChar(SndOutBufferHeaders[0], SizeOf(SndOutBufferHeaders[0]), #0);
SetLength(SndOutSoundBuffers[0], SoundSamples * (SoundBits div 8));
with SndOutBufferHeaders[0] do
begin
lpData := @SndOutSoundBuffers[0][0];
dwBufferLength := Length(SndOutSoundBuffers[0]);
end;
bufRes := waveOutOpen(@SndWaveOut, WAVE_MAPPER, @SndOutHeader, cardinal(@RecOutProc), 0, CALLBACK_FUNCTION);
if bufRes <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(bufRes, bufErr, SizeOf(bufErr));
ShowMessage("waveOutOpen" + #13#10 + bufErr);
end;
bufRes := waveOutPrepareHeader(SndWaveOut, @SndOutBufferHeaders[0], SizeOf(SndOutBufferHeaders[0]));
if bufRes <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(bufRes, bufErr, SizeOf(bufErr));
ShowMessage("waveOutPrepareHeader" + #13#10 + bufErr);
end;
......
procedure RecOutProc(hwi: HWAVEOUT; Msg: UINT; Inst, par1, par2: DWORD); stdcall;
var
bufHeader: TWaveHdr;
begin
if Msg <> WOM_DONE then
Exit;
bufHeader := SndOutBufferHeaders[SndOutCurrentBuffer];
waveOutWrite(SndWaveOut, @bufHeader, SizeOf(bufHeader));
end;
......
FillChar(SndOutSoundBuffers[0][0], Length(SndOutSoundBuffers[0]), #128);
SndOutCurrentBuffer := 0;
bufRes := waveOutWrite(SndWaveOut, @SndOutBufferHeaders[SndOutCurrentBuffer], SizeOf(SndOutBufferHeaders[SndOutCurrentBuffer]));
if bufRes <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(bufRes, bufErr, SizeOf(bufErr));
ShowMessage("waveOutWrite" + #13#10 + bufErr);
end;
← →
Сергей М. © (2007-11-28 10:17) [2]Для начала вникни в:
http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.mmedia/2006-09/msg00041.html
Учитывай, что колбэк осуществляется в доп.потоке, создаваемом при вызове waveOutWrite. Это крайне важно при мультибуферизации вывода.
В теле колбэка параметр lParam есть ссылка на заголовок, буфер из которого драйвер скопировал и поставил в очередь на воспроизведение. В этом заголовоке драйвер также изменил состояние ряда флагов, поэтому заголовок перед повторным использованием следует депрепарировать и вновь препарировать перед передачей в waveOutWrite
← →
DeadMeat (2007-11-30 21:06) [3]Премного благодарен. Вы, Сергей, как всегда выручаете. Задача решена. Вот только один вопрос остался. А почему об этом в MSDN (который с D2006) нету? Или я не там смотрел?
← →
Сергей М. © (2007-12-01 11:38) [4]
> DeadMeat (30.11.07 21:06) [3]
>почему
Понятия не имею.
Все что я тебе сказал - это две минуты "пошарить в Гугле".
Страницы: 1 вся ветка
Форум: "Media";
Текущий архив: 2009.08.09;
Скачать: [xml.tar.bz2];
Память: 0.47 MB
Время: 0.005 c