phantasia

Phantasia - 2D SDL3 RPG prototype.
git clone git://git.beep.wimdupont.com/phantasia.git
Log | Files | Refs | README | LICENSE

audio_sdl.c (4495B)


      1 #include "engine/sdl.h"
      2 
      3 #if PH_USE_SDL
      4 enum { PH_AUDIO_CLIP_MAX = 64, PH_AUDIO_EFFECT_VOICES = 8 };
      5 
      6 typedef struct {
      7 	SDL_AudioSpec spec;
      8 	Uint8 *data;
      9 	Uint32 length;
     10 	float gain;
     11 } PhAudioClip;
     12 
     13 struct PhAudio {
     14 	SDL_AudioDeviceID device;
     15 	SDL_AudioStream *music_stream;
     16 	SDL_AudioStream *effect_streams[PH_AUDIO_EFFECT_VOICES];
     17 	SDL_AudioSpec device_spec;
     18 	PhAudioClip clips[PH_AUDIO_CLIP_MAX];
     19 	int clip_count;
     20 	int music_id;
     21 	int music_enabled;
     22 	int effects_enabled;
     23 	int next_effect_voice;
     24 };
     25 
     26 static int
     27 ph_audio_stream_clip(SDL_AudioStream *stream, const PhAudioClip *clip,
     28 	const SDL_AudioSpec *device_spec)
     29 {
     30 	if (!stream || !clip || !clip->data || !clip->length) return -1;
     31 	if (!SDL_ClearAudioStream(stream) ||
     32 			!SDL_SetAudioStreamFormat(stream, &clip->spec, device_spec) ||
     33 			!SDL_SetAudioStreamGain(stream, clip->gain) ||
     34 			!SDL_PutAudioStreamData(stream, clip->data, (int)clip->length))
     35 		return -1;
     36 	return 0;
     37 }
     38 
     39 PhAudio *
     40 ph_audio_sdl_create(const PhAudioDef *defs, int count)
     41 {
     42 	PhAudio *audio;
     43 	int i;
     44 
     45 	if (!defs || count <= 1 || count > PH_AUDIO_CLIP_MAX) return NULL;
     46 	audio = SDL_calloc(1, sizeof(*audio));
     47 	if (!audio) return NULL;
     48 	audio->clip_count = count;
     49 	audio->music_enabled = 1;
     50 	audio->effects_enabled = 1;
     51 	for (i = 1; i < count; ++i) {
     52 		audio->clips[i].gain = defs[i].gain;
     53 		if (!defs[i].path || !SDL_LoadWAV(defs[i].path, &audio->clips[i].spec,
     54 				&audio->clips[i].data, &audio->clips[i].length)) goto fail;
     55 	}
     56 	audio->device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
     57 	if (!audio->device || !SDL_GetAudioDeviceFormat(audio->device,
     58 			&audio->device_spec, NULL)) goto fail;
     59 	audio->music_stream = SDL_CreateAudioStream(&audio->clips[1].spec,
     60 		&audio->device_spec);
     61 	if (!audio->music_stream ||
     62 			!SDL_BindAudioStream(audio->device, audio->music_stream)) goto fail;
     63 	for (i = 0; i < PH_AUDIO_EFFECT_VOICES; ++i) {
     64 		audio->effect_streams[i] = SDL_CreateAudioStream(&audio->clips[1].spec,
     65 			&audio->device_spec);
     66 		if (!audio->effect_streams[i] || !SDL_BindAudioStream(audio->device,
     67 				audio->effect_streams[i])) goto fail;
     68 	}
     69 	return audio;
     70 
     71 fail:
     72 	ph_audio_destroy(audio);
     73 	return NULL;
     74 }
     75 
     76 void
     77 ph_audio_music(PhAudio *audio, int id)
     78 {
     79 	if (!audio || id <= 0 || id >= audio->clip_count ||
     80 			id == audio->music_id) return;
     81 	if (ph_audio_stream_clip(audio->music_stream, &audio->clips[id],
     82 			&audio->device_spec) < 0) return;
     83 	audio->music_id = id;
     84 	if (!audio->music_enabled) SDL_SetAudioStreamGain(audio->music_stream, 0.0f);
     85 }
     86 
     87 void
     88 ph_audio_effect(PhAudio *audio, int id, float gain)
     89 {
     90 	SDL_AudioStream *stream;
     91 
     92 	if (!audio || !audio->effects_enabled ||
     93 			id <= 0 || id >= audio->clip_count || gain <= 0.0f) return;
     94 	stream = audio->effect_streams[audio->next_effect_voice];
     95 	audio->next_effect_voice =
     96 		(audio->next_effect_voice + 1) % PH_AUDIO_EFFECT_VOICES;
     97 	if (ph_audio_stream_clip(stream, &audio->clips[id],
     98 			&audio->device_spec) == 0)
     99 		SDL_SetAudioStreamGain(stream, audio->clips[id].gain * gain);
    100 }
    101 
    102 void
    103 ph_audio_set_enabled(PhAudio *audio, int music, int effects)
    104 {
    105 	if (!audio) return;
    106 	music = !!music;
    107 	effects = !!effects;
    108 	if (audio->music_enabled != music) {
    109 		audio->music_enabled = music;
    110 		SDL_SetAudioStreamGain(audio->music_stream,
    111 			music && audio->music_id > 0 ? audio->clips[audio->music_id].gain : 0.0f);
    112 	}
    113 	if (audio->effects_enabled != effects) {
    114 		int i;
    115 
    116 		audio->effects_enabled = effects;
    117 		if (!effects)
    118 			for (i = 0; i < PH_AUDIO_EFFECT_VOICES; ++i)
    119 				SDL_ClearAudioStream(audio->effect_streams[i]);
    120 	}
    121 }
    122 
    123 void
    124 ph_audio_update(PhAudio *audio)
    125 {
    126 	const PhAudioClip *clip;
    127 
    128 	if (!audio || audio->music_id <= 0 ||
    129 			audio->music_id >= audio->clip_count) return;
    130 	clip = &audio->clips[audio->music_id];
    131 	if (SDL_GetAudioStreamQueued(audio->music_stream) < (int)clip->length / 2)
    132 		SDL_PutAudioStreamData(audio->music_stream, clip->data, (int)clip->length);
    133 }
    134 
    135 void
    136 ph_audio_destroy(PhAudio *audio)
    137 {
    138 	int i;
    139 
    140 	if (!audio) return;
    141 	if (audio->music_stream) SDL_DestroyAudioStream(audio->music_stream);
    142 	for (i = 0; i < PH_AUDIO_EFFECT_VOICES; ++i)
    143 		if (audio->effect_streams[i])
    144 			SDL_DestroyAudioStream(audio->effect_streams[i]);
    145 	if (audio->device) SDL_CloseAudioDevice(audio->device);
    146 	for (i = 0; i < audio->clip_count; ++i) SDL_free(audio->clips[i].data);
    147 	SDL_free(audio);
    148 }
    149 
    150 void
    151 ph_audio_get_enabled(const PhAudio *audio, int *music, int *effects)
    152 {
    153 	if (music) *music = audio && audio->music_enabled;
    154 	if (effects) *effects = audio && audio->effects_enabled;
    155 }
    156 #endif