#include #include #include "sound.h" #include "mem.h" #include "store.h" struct Sound_; typedef struct Sound_ Sound; struct Music_; typedef struct Music_ Music; struct Audio_; typedef struct Audio_ Audio; /** Wraper structure around an allegro sample. */ struct Sound_ { ALLEGRO_SAMPLE * handle; ALLEGRO_SAMPLE_ID id; }; /** Wrapper structure around an allegro sound stream. */ struct Music_ { ALLEGRO_AUDIO_STREAM * handle; }; #define AUDIO_PLAYING_SAMPLES_MAX 64 #define AUDIO_VOICES 8 /** * Wraps around the Allegro sound system, and put severything in one handy * struct. */ struct Audio_ { BOOL ok; ALLEGRO_MIXER * mixer; ALLEGRO_VOICE * voice; ALLEGRO_AUDIO_STREAM * stream; int stream_id; ALLEGRO_SAMPLE_ID playing[AUDIO_PLAYING_SAMPLES_MAX]; int playing_id[AUDIO_PLAYING_SAMPLES_MAX]; int playing_last; }; /* The "global" audio state. */ static Audio * audio_state; #ifndef SOUND_SAMPLES #define SOUND_SAMPLES 16 #endif #define AUDIO_RATE 44100 #define AUDIO_DEPTH ALLEGRO_AUDIO_DEPTH_INT16 #define AUDIO_CHANNELS ALLEGRO_CHANNEL_CONF_2 /* Call this when the use of audio is no longer needed. */ BOOL audio_done() { if (!audio_state) { return FALSE; } al_stop_samples(); if (audio_state->stream) { al_detach_audio_stream(audio_state->stream); } if (audio_state->mixer) { al_detach_mixer(audio_state->mixer); al_destroy_mixer(audio_state->mixer); } if (audio_state->voice) { al_destroy_voice(audio_state->voice); audio_state->voice = NULL; } mem_free(audio_state); al_uninstall_audio(); return TRUE; } /** Call this to alloate space for the audio system. */ Audio * audio_alloc(void) { return STRUCT_ALLOC(Audio); } int audio_playing_samples_max() { return AUDIO_PLAYING_SAMPLES_MAX; } /** Call this to start up the audio system. */ BOOL audio_init() { int index; if(!al_install_audio()) return FALSE; if(!al_init_acodec_addon()) return FALSE; audio_state = audio_alloc(); if (!audio_state) return FALSE; audio_state->mixer = al_create_mixer(AUDIO_RATE, AUDIO_DEPTH, AUDIO_CHANNELS); audio_state->voice = al_create_voice(AUDIO_RATE, AUDIO_DEPTH, AUDIO_CHANNELS); al_attach_mixer_to_voice(audio_state->mixer, audio_state->voice); al_set_default_mixer(audio_state->mixer); al_reserve_samples(SOUND_SAMPLES); audio_state->stream = NULL; audio_state->stream_id = -1; for (index = 0; index < AUDIO_PLAYING_SAMPLES_MAX; index++) { audio_state->playing_id[index] = -1; } audio_state->ok = TRUE; return TRUE; } /** Returns true if sound can be played, false if not. */ BOOL audio_ok(void) { return audio_state && audio_state->ok; } #ifndef MUSIC_BUFFERS #define MUSIC_BUFFERS 2 #endif #ifndef MUSIC_BUFSIZE #define MUSIC_BUFSIZE 2048 #endif /* Set the music with the given index as the active usic. If the index is negative, sets no music as active. */ BOOL audio_set_music(int store_id) { double length; ALLEGRO_AUDIO_STREAM * stream; if (!audio_ok()) return FALSE; if (store_id < 0) { if(audio_state->stream) { al_detach_audio_stream(audio_state->stream); } audio_state->stream = NULL; audio_state->stream_id = -1; return TRUE; } stream = store_get_audio_stream(store_id); if (!stream) { return FALSE; } audio_state->stream = stream; /* Automaticallly loop the music over it's whole length. */ length = al_get_audio_stream_length_secs(audio_state->stream); if (length > 0.0) { al_set_audio_stream_loop_secs(audio_state->stream, 0.0, length); al_set_audio_stream_playmode(audio_state->stream, ALLEGRO_PLAYMODE_LOOP); } al_attach_audio_stream_to_mixer(audio_state->stream, audio_state->mixer); return TRUE; } BOOL audio_play_music() { if (!audio_ok()) return FALSE; if(!audio_state->stream) return FALSE; return al_set_audio_stream_playing(audio_state->stream, TRUE); } BOOL audio_stop_music() { if (!audio_ok()) return FALSE; if(!audio_state->stream) return FALSE; return al_set_audio_stream_playing(audio_state->stream, FALSE); } BOOL audio_music_playing_p() { if (!audio_ok()) return FALSE; if(!audio_state->stream) return FALSE; return al_get_audio_stream_playing(audio_state->stream); } int audio_playing_music_id() { if (!audio_ok()) return -1; if(!audio_state->stream) return -1; return audio_state->stream_id; } int audio_play_sound_ex (int store_id, float gain, float pan, float speed, BOOL loop) { int play_id; ALLEGRO_SAMPLE * sample; ALLEGRO_PLAYMODE mode = (loop ? ALLEGRO_PLAYMODE_LOOP : ALLEGRO_PLAYMODE_ONCE); if (!audio_ok()) return -2; sample = store_get_sample(store_id); if (!sample) return -1; play_id = audio_state->playing_last; audio_state->playing_last++; /* Work in ring buffer style. */ if (audio_state->playing_last >= AUDIO_PLAYING_SAMPLES_MAX) { audio_state->playing_last = 0; } al_play_sample(sample, gain, pan, speed, mode, audio_state->playing + play_id); audio_state->playing_id[play_id] = store_id; return play_id; } void audio_stop_all_sounds() { al_stop_samples(); /* reset ring buffer pointer */ audio_state->playing_last = 0; } /** Plays the sound once only with default parameters. */ int audio_play_sound(int sample_id) { return audio_play_sound_ex(sample_id, 1.0, 0.0, 1.0, FALSE); } /* Stops the sound with the given play id from playing. Doesn't work if the integer handle is stale, but thesoun sould have stopped by itself then. */ BOOL audio_stop_sound(int play_id) { if (!audio_ok()) return FALSE; if (play_id < 0) return FALSE; if (play_id >= AUDIO_PLAYING_SAMPLES_MAX) return FALSE; al_stop_sample(audio_state->playing + play_id); return TRUE; }