Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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
1-1211900401
viperv
2008-05-27 19:00
2009.08.09
скачать файл из инета


2-1244723130
Mishechka
2009-06-11 16:25
2009.08.09
Как программно связать поле в отчёте FR с полем БД?


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


2-1244697316
Pavlov
2009-06-11 09:15
2009.08.09
повторный запуск MDIChild и передача параметров


15-1244537205
Neket
2009-06-09 12:46
2009.08.09
Классификация БД





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский