Implemented load audio and music files as well the basic audio playback

functionality.
This commit is contained in:
abdelrahman committed 2022-09-25 02:19:21 +01:00
1 parent dfee36ffe9
commit e3f4f9c94f
9 files changed
+464 -61

No files matched your search

+360 -10
View File
@@ -6,6 +6,7 @@
#include "SDL_error.h"
#include "SDL_events.h"
#include "SDL_image.h"
#include "SDL_mixer.h"
#include "SDL_pixels.h"
#include "SDL_render.h"
#include "SDL_timer.h"
@@ -13,8 +14,8 @@
#include "constants.h"
#include "engine_build_config.h"
#include "reusable_ids.h"
#include <SDL2/SDL_mixer.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
@@ -32,8 +33,9 @@ INTERNAL struct game_engine {
AssetManager *asset_manager;
} GameEngine;
bool init_game(const char *game_name, int window_width, int window_height,
SDL_Color window_background_color, bool full_screen) {
bool init_game(const char *game_name, uint32_t window_width,
uint32_t window_height, SDL_Color window_background_color,
bool full_screen, uint8_t audio_tracks) {
bool initialisation_complete = true;
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
@@ -47,11 +49,36 @@ bool init_game(const char *game_name, int window_width, int window_height,
uint32_t img_flags = IMG_INIT_PNG | IMG_INIT_TIF;
if ((IMG_Init(img_flags) & img_flags) != img_flags) {
#ifdef DEBUG_ENGINE
printf("Failed to initialise SDL. Error: %s\n", IMG_GetError());
printf("Failed to initialise SDL_image. Error: %s\n", IMG_GetError());
#endif /* DEBUG_ENGINE */
initialisation_complete = false;
}
// We're only interested in initialising SDL_mixer with WAVE files, so no
// need to pass any flags
if (Mix_Init(0) != 0) {
#ifdef DEBUG_ENGINE
printf("Failed to initialise SDL_mixer. Error: %s\n", Mix_GetError());
#endif /* DEBUG_ENGINE */
initialisation_complete = false;
}
if (Mix_OpenAudio(48000, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
#ifdef DEBUG_ENGINE
printf("Failed to open audio device. Error: %s\n", Mix_GetError());
#endif /* DEBUG_ENGINE */
initialisation_complete = false;
}
if (audio_tracks > 0) {
if (Mix_AllocateChannels(audio_tracks) != audio_tracks) {
#ifdef DEBUG_ENGINE
printf("Failed to allocate the required tracks.\n");
#endif /* DEBUG_ENGINE */
initialisation_complete = false;
}
}
if (!init_window(&(GameEngine.window), game_name, window_width, window_height,
window_background_color, full_screen)) {
#ifdef DEBUG_ENGINE
@@ -62,13 +89,11 @@ bool init_game(const char *game_name, int window_width, int window_height,
}
GameEngine.object_store = create_object_store();
if (!(GameEngine.object_store)) {
initialisation_complete = false;
}
GameEngine.asset_manager = create_asset_manager();
if (!(GameEngine.asset_manager)) {
initialisation_complete = false;
}
@@ -125,10 +150,333 @@ void render_texture_asset(AssetID id, float x, float y, float w, float h) {
SDL_Texture *texture = get_texture(GameEngine.asset_manager, id);
if (!texture) {
return;
}
render_texture(GameEngine.window.renderer, texture, x, y, w, h);
}
int8_t play_audio_asset(AssetID id, int16_t loops, bool fade_in,
uint32_t fade_length_in_ms) {
if (id < 0) {
return -1;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return -1;
}
if (fade_in) {
return Mix_FadeInChannel(-1, chunk, loops, fade_length_in_ms);
} else {
return Mix_PlayChannel(-1, chunk, loops);
}
}
void pause_audio_asset_on_track(AssetID id, uint8_t track) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk || chunk != Mix_GetChunk(track)) {
return;
}
Mix_Pause(track);
}
void resume_audio_asset_on_track(AssetID id, uint8_t track) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk || chunk != Mix_GetChunk(track)) {
return;
}
Mix_Resume(track);
}
void stop_audio_asset_on_track(AssetID id, uint8_t track) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk || chunk != Mix_GetChunk(track)) {
return;
}
Mix_HaltChannel(track);
}
void fade_out_audio_asset_on_track(AssetID id, uint8_t track,
uint32_t fade_length_in_ms) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk || chunk != Mix_GetChunk(track)) {
return;
}
Mix_FadeOutChannel(track, fade_length_in_ms);
}
void pause_all_instances_of_audio_asset(AssetID id) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return;
}
size_t channel_count = Mix_AllocateChannels(-1);
for (size_t i = 0; i < channel_count; ++i) {
if (chunk == Mix_GetChunk(i)) {
Mix_Pause(i);
}
}
}
void resume_all_instances_of_audio_asset(AssetID id) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return;
}
size_t channel_count = Mix_AllocateChannels(-1);
for (size_t i = 0; i < channel_count; ++i) {
if (chunk == Mix_GetChunk(i)) {
Mix_Resume(i);
}
}
}
void stop_all_instances_of_audio_asset(AssetID id) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return;
}
size_t channel_count = Mix_AllocateChannels(-1);
for (size_t i = 0; i < channel_count; ++i) {
if (chunk == Mix_GetChunk(i)) {
Mix_HaltChannel(i);
}
}
}
void fade_out_all_instances_of_audio_asset(AssetID id,
uint32_t fade_length_in_ms) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return;
}
size_t channel_count = Mix_AllocateChannels(-1);
for (size_t i = 0; i < channel_count; ++i) {
if (chunk == Mix_GetChunk(i)) {
Mix_FadeOutChannel(i, fade_length_in_ms);
}
}
}
int8_t get_audio_asset_volume(AssetID id) {
if (id < 0) {
return -1;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return -1;
}
return chunk->volume;
}
void set_audio_asset_volume(AssetID id, int8_t volume) {
if (id < 0) {
return;
}
Mix_Chunk *chunk = get_audio_chunk(GameEngine.asset_manager, id);
if (!chunk) {
return;
}
Mix_VolumeChunk(chunk, volume);
}
void play_music_asset(AssetID id, int16_t loops, bool fade_in,
uint32_t fade_length_in_ms) {
if (id < 0 || is_music_asset_playing(id)) {
return;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return;
}
if (fade_in) {
Mix_FadeInMusic(music, loops, fade_length_in_ms);
} else {
Mix_PlayMusic(music, loops);
}
}
void pause_music_asset(AssetID id) {
if (id < 0 || !is_music_asset_playing(id)) {
return;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return;
}
Mix_PauseMusic();
}
void resume_music_asset(AssetID id) {
if (id < 0 || !is_music_asset_playing(id)) {
return;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return;
}
Mix_ResumeMusic();
}
void stop_music_asset(AssetID id) {
if (id < 0 || !is_music_asset_playing(id)) {
return;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return;
}
Mix_HaltMusic();
}
void fade_out_music_asset(AssetID id, uint32_t fade_length_in_ms) {
if (id < 0 || !is_music_asset_playing(id)) {
return;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return;
}
Mix_FadeOutMusic(fade_length_in_ms);
}
int8_t get_music_asset_volume(AssetID id) {
if (id < 0) {
return -1;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return -1;
}
return Mix_GetMusicVolume(music);
}
void set_music_asset_volume(AssetID id, int8_t volume) {
if (id < 0 || !is_music_asset_playing(id)) {
return;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return;
}
Mix_VolumeMusic(volume);
}
bool is_music_object_playing(Mix_Music *music) {
if (!Mix_PlayingMusic()) {
return false;
}
// The Mix_GetMusic* functions used here all return the result for the
// currently playing music when passed a NULL pointer. We use that to compare
// the data of the Mix_Music object passed to the function to the data of the
// currently playing music.
//
// TODO (Abdelrahman): This is a bit of a hack. Figure out if there is
// a better alternative to check if a Mix_Music object is currently playing.
return Mix_GetMusicType(music) == Mix_GetMusicType(NULL) &&
Mix_GetMusicTitle(music) == Mix_GetMusicTitle(NULL) &&
Mix_GetMusicArtistTag(music) == Mix_GetMusicArtistTag(NULL) &&
Mix_GetMusicAlbumTag(music) == Mix_GetMusicAlbumTag(NULL);
}
bool is_music_asset_playing(AssetID id) {
if (id < 0) {
return false;
}
Mix_Music *music = get_music(GameEngine.asset_manager, id);
if (!music) {
return false;
}
return is_music_object_playing(music);
}
void pause_playing_music() { Mix_PauseMusic(); }
void resume_playing_music() { Mix_ResumeMusic(); }
void stop_playing_music() { Mix_HaltMusic(); }
void fade_out_playing_music(uint32_t fade_length_in_ms) {
Mix_FadeOutMusic(fade_length_in_ms);
}
void set_playing_music_volume(int8_t volume) { Mix_VolumeMusic(volume); }
bool is_music_playing() { return Mix_PlayingMusic(); }
void close_asset(AssetID *id) {
if (*id < 0) {
return;
}
remove_asset_from_manager(GameEngine.asset_manager, id);
}
@@ -183,11 +531,9 @@ void render() {
}
void close_game() {
destroy_asset_manager(GameEngine.asset_manager);
GameEngine.asset_manager = NULL;
destroy_asset_manager(&(GameEngine.asset_manager));
destroy_object_store(GameEngine.object_store);
GameEngine.object_store = NULL;
destroy_object_store(&(GameEngine.object_store));
destroy_window(&(GameEngine.window));
@@ -197,6 +543,10 @@ void close_game() {
GameEngine.running = false;
Mix_CloseAudio();
Mix_Quit();
IMG_Quit();
SDL_Quit();