To największa funkcjonalność nad jaką pracowałem w CGE do tej pory. Szczególnie ważna dla gier mobilnych.
Dlaczego warto użyć strumieniowania muzyki?
Długie pliki audio dzięki kompresji takiej jak Vorbis, czy MP3 wydają się być niezbyt wymagające. Jeden utwór o długości 60 sek zakodowany w pliku OGG 96 Kbps zajmuje około 720 KB na dysku. Niestety zdekodowany w całości plik może zająć nawet 17 MB pamięci RAM. Jak duże będzie zapotrzebowanie na pamięć można łatwo wyliczyć za pomocą kalkulatora rozmiaru audio. Nawet w przypadku gier desktopowych wczytanie kilkunastu plików muzycznych o długości paru minut może skutecznie ograniczyć rozmiar dostępnej pamięci RAM.
W przypadku gier mobilnych sprawa jest dużo bardziej poważna. Nie dość że tą samą pamięć używamy do przechowywania tekstur, to każdorazowa zmiana aktywności powoduje zamkniecie kontekstu OpenAL i wyładowanie plików, a po powrocie do gry konieczne jest ponowne ich załadowanie. Dekodowanie wielu plików audio znacznie przedłuży czas uruchamia aplikacji oraz będzie mieć negatywny wpływ na baterię.
Kiedy nie używać strumieniowania?
Każde rozwiązanie ma też swoje wady. Rozpoczęcie odtwarzania strumieniowego wymaga pewnego narzutu czasu. W przypadkach, w których liczy się czas dostępu lepiej wczytać dźwięk w całości przy uruchomieniu gry. Są to przede wszystkim efekty dźwiękowe takie jak wybuchy, skoki itp. Dźwięki tego typu są zwykle uruchamiane wielokrotnie, więc odczytywanie ich z dysku w trakcie rozgrywki powodowałoby znaczący spadek wydajności/opóźnienia.
Jak użyć strumieniowania w Castle Game Engine?
Funkcja LoadBuffer zyskała dodatkowy argument typu TSoundLoading:
function LoadBuffer(const URL: string; const SoundLoading: TSoundLoading; const ExceptionOnError: Boolean = true): TSoundBuffer; overload;
Gdy ustawimy SoundLoading na slComplete klip dźwiękowy zostanie wczytany w całości przy uruchomieniu gry. Po ustawieniu na slStreaming plik dźwiękowy będzie strumieniowany w trakcie odtwarzania.
Jeżeli używasz repozytorium dźwięków XML wystarczy dodać atrybut stream
<?xml version="1.0"?> <sounds> <sound name="track1" url="track1.ogg" stream="true"/> </sounds>
Dzięki poprawkom wprowadzonym przez Michalisa strumieniowanie jest dostępne nie tylko na backendzie OpenAL (jak ja pierwotnie to zaimplementowałem), ale także na FMOD. Michalis wprowadził też wiele innych poprawek i optymalizacji.
Logowanie użytej pamięci z poziomu CGE
Jeżeli chcesz poznać ilość zajmowanej pamięci RAM przez załadowane bez strumieniowania dźwięki z poziomu silnika, wystarczy włączyć logowanie:
SoundEngine.LogSoundLoading := true;
Wtedy w konsoli lub pliku logu pojawią się wpisy podobne po poniższych:
Sound: Loaded "castle-data:/sounds/track1.ogg": audio/ogg, stereo 16, size: 44107776, frequency: 44100, duration: 250.04 Sound: Loaded "castle-data:/sounds/sfx_jump.wav": audio/x-wav, mono 16, size: 20964, frequency: 44100, duration: 0.24 Sound: Loaded "castle-data:/sounds/sfx_death.wav": audio/x-wav, mono 16, size: 59204, frequency: 44100, duration: 0.67
W powyższym przykładzie plik track1.ogg o wielkości 3,0MB (2971830B) załadowany bez strumieniowania zajmie 42,1MB (44107776).
Skąd to pobrać?
Funkcjonalność strumieniowania została wprowadzona do gałęzi master w repozytorium CGE.
Patreon
Jeżeli podoba Ci się silnik CGE i chciałbyś wesprzeć twórcę, możesz to zrobić na patreonie.