z_mirror/sdl-osu

git clone https://git.raiguard.me/z_mirror/sdl-osu

Caleb HeuerUse custom log categories instead of internal SDL categories4bbec0e

trunk
3.9 KiB110 linesraw
1#include "audio.h"
2#include "defines.h"
3#include "hitobject.h"
4#include "hitsound.h"
5#include "util.h"
6#include <SDL3/SDL_properties.h>
7#include <SDL3_mixer/SDL_mixer.h>
8#include <stdio.h>
9#include <stdlib.h>
10
11struct Osu_Audio* Osu_CreateAudio(const char* dataPath) {
12    SDL_SAFECALL(MIX_Init);
13
14    struct Osu_Audio* audio = calloc(1, sizeof(struct Osu_Audio));
15
16    SDL_SAFEASSN(audio->mixer, MIX_CreateMixerDevice, SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
17    SDL_SAFEASSN(audio->musicTrack, MIX_CreateTrack, audio->mixer);
18
19    char path[512];
20    snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitnormal.wav", dataPath);
21    SDL_SAFEASSN(audio->hitNormal, MIX_LoadAudio, audio->mixer, path, true);
22    snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitwhistle.wav", dataPath);
23    SDL_SAFEASSN(audio->hitWhistle, MIX_LoadAudio, audio->mixer, path, true);
24    snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitfinish.wav", dataPath);
25    SDL_SAFEASSN(audio->hitFinish, MIX_LoadAudio, audio->mixer, path, true);
26    snprintf(path, 512, "%s" OSU_PATHSEP "skins" OSU_PATHSEP OSU_ACTIVE_SKIN OSU_PATHSEP "normal-hitclap.wav", dataPath);
27    SDL_SAFEASSN(audio->hitClap, MIX_LoadAudio, audio->mixer, path, true);
28
29    return audio;
30}
31
32void Osu_DestroyAudio(struct Osu_Audio* audio) {
33    if (audio->music) {
34        MIX_DestroyAudio(audio->music);
35    }
36    MIX_DestroyTrack(audio->musicTrack);
37    if (audio->musicPath) {
38        free(audio->musicPath);
39    }
40
41    MIX_DestroyAudio(audio->hitNormal);
42    MIX_DestroyAudio(audio->hitWhistle);
43    MIX_DestroyAudio(audio->hitFinish);
44    MIX_DestroyAudio(audio->hitClap);
45
46    MIX_Quit();
47
48    free(audio);
49}
50
51void Osu_SetMusic(struct Osu_Audio* audio, const char* path, Sint32 offset, bool repeat) {
52    if (audio->music) {
53        MIX_StopTrack(audio->musicTrack, 0);
54        MIX_DestroyAudio(audio->music);
55        audio->music = NULL;
56    }
57    if (audio->musicPath) {
58        free(audio->musicPath);
59        audio->musicPath = NULL;
60    }
61    if (!path) {
62        return;
63    }
64    audio->music = MIX_LoadAudio(audio->mixer, path, false);
65    if (!audio->music) {
66        SDL_LogError(OSU_LOG_CATEGORY_AUDIO, "Failed to open music: %s", SDL_GetError());
67        return;
68    }
69    SDL_asprintf(&audio->musicPath, "%s", path);
70
71    MIX_SetTrackAudio(audio->musicTrack, audio->music);
72
73    if (audio->musicProps) {
74        SDL_DestroyProperties(audio->musicProps);
75    }
76    SDL_SAFEASSN(audio->musicProps, SDL_CreateProperties);
77
78    SDL_SAFECALL(SDL_SetNumberProperty, audio->musicProps, MIX_PROP_PLAY_START_MILLISECOND_NUMBER, offset);
79
80    if (repeat) {
81        SDL_SAFECALL(SDL_SetNumberProperty, audio->musicProps, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
82        SDL_SAFECALL(SDL_SetNumberProperty, audio->musicProps, MIX_PROP_PLAY_LOOP_START_MILLISECOND_NUMBER, offset);
83    }
84}
85
86void Osu_PlayMusic(struct Osu_Audio* audio) {
87    if (MIX_TrackPlaying(audio->musicTrack) || !audio->music) {
88        return;
89    }
90
91    if (!MIX_PlayTrack(audio->musicTrack, audio->musicProps)) {
92        SDL_LogError(OSU_LOG_CATEGORY_AUDIO, "Failed to play music: %s", SDL_GetError());
93        return;
94    }
95}
96
97void Osu_PlayHitSounds(struct Osu_Audio* audio, struct Osu_HitObject* hitObject) {
98    // TODO: Read LayeredHitSounds property from skin instead of assuming it is true
99    // if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_NORMAL))
100    MIX_PlayAudio(audio->mixer, audio->hitNormal);
101    if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_WHISTLE)) {
102        MIX_PlayAudio(audio->mixer, audio->hitWhistle);
103    }
104    if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_FINISH)) {
105        MIX_PlayAudio(audio->mixer, audio->hitFinish);
106    }
107    if (Osu_ShouldPlayHitSound(hitObject->hitSounds, OSU_HITSOUND_CLAP)) {
108        MIX_PlayAudio(audio->mixer, audio->hitClap);
109    }
110}