#include "audio.h" #include "defines.h" #include "hitobject.h" #include "hitsound.h" #include "util.h" #include #include #include #include struct Osu_Audio* Osu_CreateAudio(const char* dataPath) { SDL_SAFECALL(MIX_Init); struct Osu_Audio* audio = calloc(1, sizeof(struct Osu_Audio)); SDL_SAFEASSN(audio->mixer, MIX_CreateMixerDevice, SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL); SDL_SAFEASSN(audio->musicTrack, MIX_CreateTrack, audio->mixer); char path[512]; snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitnormal.wav", dataPath); SDL_SAFEASSN(audio->hitNormal, MIX_LoadAudio, audio->mixer, path, true); snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitwhistle.wav", dataPath); SDL_SAFEASSN(audio->hitWhistle, MIX_LoadAudio, audio->mixer, path, true); snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitfinish.wav", dataPath); SDL_SAFEASSN(audio->hitFinish, MIX_LoadAudio, audio->mixer, path, true); snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitclap.wav", dataPath); SDL_SAFEASSN(audio->hitClap, MIX_LoadAudio, audio->mixer, path, true); return audio; } void Osu_DestroyAudio(struct Osu_Audio* audio) { if (audio->music) { MIX_DestroyAudio(audio->music); } MIX_DestroyTrack(audio->musicTrack); if (audio->musicPath) { free(audio->musicPath); } MIX_DestroyAudio(audio->hitNormal); MIX_DestroyAudio(audio->hitWhistle); MIX_DestroyAudio(audio->hitFinish); MIX_DestroyAudio(audio->hitClap); MIX_Quit(); free(audio); } void Osu_SetMusic(struct Osu_Audio* audio, const char* path, Sint32 offset, bool repeat) { if (audio->music) { MIX_StopTrack(audio->musicTrack, 0); MIX_DestroyAudio(audio->music); audio->music = NULL; } if (audio->musicPath) { free(audio->musicPath); audio->musicPath = NULL; } if (!path) { return; } audio->music = MIX_LoadAudio(audio->mixer, path, false); if (!audio->music) { SDL_LogError(OSU_LOG_CATEGORY_AUDIO, "Failed to open music: %s", SDL_GetError()); return; } SDL_asprintf(&audio->musicPath, "%s", path); MIX_SetTrackAudio(audio->musicTrack, audio->music); if (audio->musicProps) { SDL_DestroyProperties(audio->musicProps); } SDL_SAFEASSN(audio->musicProps, SDL_CreateProperties); SDL_SAFECALL(SDL_SetNumberProperty, audio->musicProps, MIX_PROP_PLAY_START_MILLISECOND_NUMBER, offset); if (repeat) { SDL_SAFECALL(SDL_SetNumberProperty, audio->musicProps, MIX_PROP_PLAY_LOOPS_NUMBER, -1); SDL_SAFECALL(SDL_SetNumberProperty, audio->musicProps, MIX_PROP_PLAY_LOOP_START_MILLISECOND_NUMBER, offset); } } void Osu_PlayMusic(struct Osu_Audio* audio) { if (MIX_TrackPlaying(audio->musicTrack) || !audio->music) { return; } if (!MIX_PlayTrack(audio->musicTrack, audio->musicProps)) { SDL_LogError(OSU_LOG_CATEGORY_AUDIO, "Failed to play music: %s", SDL_GetError()); return; } } void Osu_PlayHitSounds(struct Osu_Audio* audio, struct Osu_HitObject* hitObject) { // TODO: Read LayeredHitSounds property from skin instead of assuming it is true // if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_NORMAL)) MIX_PlayAudio(audio->mixer, audio->hitNormal); if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_WHISTLE)) { MIX_PlayAudio(audio->mixer, audio->hitWhistle); } if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_FINISH)) { MIX_PlayAudio(audio->mixer, audio->hitFinish); } if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_CLAP)) { MIX_PlayAudio(audio->mixer, audio->hitClap); } }