PlaySound bez ścięć

2009-07-31 17:03

Chcąc w prosty sposób odtworzyć dźwięk w programie pod Windows, możemy skorzystać z funkcji WinAPI o nazwie PlaySound. Wystarczy podać jej nazwę pliku dźwiękowego, by ten został odegrany:

  1. PlaySound (TEXT("C:\\Windows\\Media\\ding.wav"), NULL, 0);

Jak to jednak bywa w przypadku metod najprostszych, nie jest to rozwiązanie doskonałe. Jedną z jego wad jest bowiem to, że próbka dźwiękowa jest tutaj wczytywana z dysku tuż przed jej pierwszym odtworzeniem. W większości przypadków trwa to chwilę, którą da się zauważyć jako krótkie opóźnienie przed usłyszeniem dźwięku.
W grach (i nie tylko) jest to oczywiście niedopuszczalne, więc zwykle najlepszym wyjściem jest użycie wyspecjalizowanych bibliotek dźwiękowych. Jeśli jednak nie chcemy dołączać dodatkowych plików DLL lub wykorzystywać DirectX-a, możemy temu opóźnieniu zaradzić.

Funkcja PlaySound pozwala bowiem na odtworzenie dźwięku nie tylko z pliku, ale też z pamięci operacyjnej:

  1. PlaySound ((LPCTSTR)pSound, NULL, SND_MEMORY);

W tym celu posłużyć się trzeba flagą SND_MEMORY i podać wskaźnik do bloku pamięci, w którym znajduje się nasza próbką dźwiękowa. Skąd go wziąć? Ano chociażby wczytać plik dźwiękowy z dysku do pamięci:

  1. const void* LoadSound(const TCHAR* fileName)
  2. {
  3.     // uwaga: brak obsługi błędów
  4.     HANDLE file = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ,
  5.                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  6.     DWORD size = GetFileSize(file, NULL);    // max. 2GB
  7.  
  8.     char* sample = new char [size];
  9.     char* p = sample;
  10.     DWORD bytesRead;
  11.     do
  12.     {
  13.         ReadFile (file, p, size, &bytesRead, NULL);
  14.         p += bytesRead;
  15.     } while (bytesRead > 0);
  16.  
  17.     CloseHandle (file);
  18.     return sample;
  19. }

“Trik” polega na tym, że operację wczytywania możemy przeprowadzić wcześniej, a więc w trakcie ładowania całej gry, pojedynczego etapu, pokoju, krainy, itp. – czyli wtedy, gdy jej potencjalnie długi czas nie będzie nikomu przeszkadzał. Potem zaś da się ją odtworzyć z pamięci i nie doświadczać żadnych opóźnień.
Trzeba tylko pamiętać, żeby na koniec zwolnić pamięć przeznaczoną na wczytaną próbkę.

Be Sociable, Share!
Be Sociable, Share!
Tags: ,
Author: Xion, posted under Programming »


6 comments for post “PlaySound bez ścięć”.
  1. vashpan:
    August 1st, 2009 o 9:08

    Moze nieco odejde od tematu posta, ale…

    Po co w ogole stosowac ukosniki w tej postaci “\\” – ani to przenosne ani ladne… :) A “/” Dziala zarowno pod Windowsem jak i kazdym innym systemem czy kompilatorem. ( Przynajmniej pod MSVCPP i GCC )

  2. Jacek Złydach, TeMPOraL:
    August 1st, 2009 o 9:38

    O ile pamiętam, PlaySound() domyślnie odtwarza dźwięk synchronicznie, tj. funkcja oddaje sterowanie dopiero po zakończeniu odtwarzania dźwięku. Zwykle tego nie chcemy, więc aby odtworzyć dźwięk asynchronicznie należy dodać flagę SND_ASYNC; ostatecznie dostaniemy więc:

    PlaySound ((LPCTSTR)pSound, NULL, SND_MEMORY | SND_ASYNC);

  3. Misiek:
    August 1st, 2009 o 14:27

    TeMPOraL:
    Gdy zastosowałem taką kombinację flag, z moich głośników nic nie usłyszałem. Może wiecie dlaczego?

  4. revo:
    August 3rd, 2009 o 10:17

    Odtwarzanie dźwięku za pomocą PlaySound jest do bani — nie można odtwarzać jednocześnie kilku dźwięków. Już chyba lepiej użyć MCI ;)

  5. Xion:
    August 3rd, 2009 o 18:06

    @vashpan: Nie wiem, co ma tu do rzeczy kompilator. Wg mnie liczy się bardziej to, że przekazujemy ścieżkę do funkcji Windows API, wobec czego całkiem rozsądne jest używanie standardowych windowsowych separatorów ścieżki, czyż nie? :)

    @revo: Ano oczywiście, że najczęściej używa się bibliotek typu BASS czy DirectSound. Ale o tym pozwoliłem sobie też wspomnieć ;)

  6. revo:
    August 7th, 2009 o 8:43

    @Xion, MCI jest systemowe — pod wieczór może wrzucę notkę o tym u siebie ;)

Comments are disabled.
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.