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