phantasia

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

audio.c (4244B)


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