Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.08.09;
Скачать: CL | DM;

Вниз

Щелчки при воспроизведении звука   Найти похожие ветки 

 
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 вся ветка

Текущий архив: 2009.08.09;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.013 c
8-1196371243
leonidus
2007-11-30 00:20
2009.08.09
Как отобразить одну картинку на другой?


2-1244911018
Б
2009-06-13 20:36
2009.08.09
Зачем для многих Win-структур нужно поле Size?


15-1243996706
brother
2009-06-03 06:38
2009.08.09
сайт одноклассники хакнули?


15-1244179520
DelphiN!
2009-06-05 09:25
2009.08.09
Какая какая из мышек произвела действие?


6-1205611995
art36
2008-03-15 23:13
2009.08.09
Обмен данными с тайм-сервером (сервером точного времени)