Главная страница
    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
15-1244233802
Юрий
2009-06-06 00:30
2009.08.09
С днем рождения ! 6 июня 2009 суббота


15-1244387849
cyber-pilot
2009-06-07 19:17
2009.08.09
MapReduce на Delphi


2-1242669062
winsockuser
2009-05-18 21:51
2009.08.09
WinSock, передача файлов, клиент получает в два раза больше


2-1245002203
Mimi
2009-06-14 21:56
2009.08.09
Создание "Справки" и "О программе"


15-1244734543
12
2009-06-11 19:35
2009.08.09
Кодировка в неком мобильном устройстве + ADOquery





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский