#include "sdl_mixer_x.hpp" #include #include "file_backend.hpp" #include #include std::optional SDLMixerXBackend::get_max_samples() { return 100; } void SDLMixerXBackend::load(const char *filename) { Mix_Init(MIX_INIT_FLAC|MIX_INIT_MID|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG|MIX_INIT_OPUS|MIX_INIT_WAVPACK); memset(&spec, 0, sizeof(spec)); spec.callback = NULL; spec.channels = 2; spec.format = AUDIO_F32SYS; spec.freq = 48000; spec.samples = get_max_samples().value(); spec.size = spec.samples * sizeof(float); Mix_InitMixer(&spec, SDL_FALSE); mixer = Mix_GetGeneralMixer(); { std::filesystem::path fpath = std::string(filename); fpath = fpath.parent_path() / fpath.stem(); std::string fpath_str = fpath.string(); std::vector soundfonts = {fpath_str + ".sf2", fpath_str + ".dls"}; std::string sf_path_str = ""; bool any_path_exists = false; for (auto sf_path : soundfonts) { if (std::filesystem::exists(sf_path)) { any_path_exists = true; sf_path_str += ";" + sf_path; } } if (any_path_exists) { sf_path_str = sf_path_str.substr(1); Mix_SetSoundFonts(sf_path_str.c_str()); } else { Mix_SetSoundFonts(NULL); } } file = open_file(filename); Mix_Music *output = Mix_LoadMUS_RW(get_sdl_file(this->file), 0); if (output == nullptr) { throw std::exception(); } Mix_PlayMusicStream(output, -1); length = Mix_MusicDuration(output); current_file = std::string(filename); const char *title_tag = Mix_GetMusicTitleTag(output); // Check for an empty string, which indicates there's no title tag. if (title_tag[0] == '\0') { std::filesystem::path path(current_file); current_title = path.stem().string(); } else { current_title = std::string(title_tag); } this->music = output; streams.clear(); PlaybackStream stream; stream.id = 0; stream.length = Mix_MusicDuration(output); stream.name = current_title; streams.push_back(stream); open = true; } void SDLMixerXBackend::switch_stream(int idx) { } void SDLMixerXBackend::seek(double position) { if (music == nullptr || file == nullptr) { open = false; return; } Mix_SetMusicPositionStream(music, position); } size_t SDLMixerXBackend::render(void *buf, size_t maxlen) { if (music == nullptr || file == nullptr) { open = false; return 0; } if (maxlen > spec.size) { maxlen = spec.size; } // Remove partial sample frames. maxlen /= sizeof(float); maxlen *= sizeof(float); mixer(NULL, (Uint8*)buf, maxlen); return maxlen; } double SDLMixerXBackend::get_position() { if (music == nullptr || file == nullptr) { open = false; return 0.0; } return Mix_GetMusicPosition(music); } void SDLMixerXBackend::cleanup() { streams.clear(); Mix_HaltMusicStream(music); Mix_FreeMusic(music); delete file; file = nullptr; Mix_Quit(); open = false; }