#include "sdl_mixer_x.hpp" #include #include #include "file_backend.hpp" #include #include #include #include #include #include std::optional SDLMixerXBackend::get_max_samples() { return 4096; } void SDLMixerXBackend::load(const char *filename) { memset(&spec, 0, sizeof(spec)); spec.callback = NULL; spec.channels = 2; spec.userdata = NULL; spec.format = AUDIO_F32SYS; spec.freq = 48000; spec.samples = get_max_samples().value(); spec.size = spec.samples * 4 * spec.channels; 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); } } DEBUG.writefln("Opening file: %s", filename); file = open_file(filename); DEBUG.writeln("Loading file..."); this->music = nullptr; Mix_Music *output = Mix_LoadMUS_RW(get_sdl_file(this->file), SDL_TRUE); if (output == nullptr) { ERROR.writefln("Error occurred: %s", Mix_GetError()); throw std::exception(); } if (Mix_PlayMusicStream(output, -1) < 0) { ERROR.writefln("Error occurred: %s", Mix_GetError()); this->music = output; throw std::exception(); } Mix_ResumeMusicStream(output); 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; initial = true; } void SDLMixerXBackend::switch_stream(int idx) { seek(0.0); } 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; } size_t i = 0; size_t bytes_per_iter = maxlen; if (bytes_per_iter > spec.size) { bytes_per_iter = spec.size; } // Remove partial sample frames. bytes_per_iter /= sizeof(float); bytes_per_iter *= sizeof(float); while (i < maxlen) { if (i + bytes_per_iter > maxlen) { bytes_per_iter = maxlen - i; // Remove partial sample frames. bytes_per_iter /= sizeof(float); bytes_per_iter *= sizeof(float); } mixer(NULL, (Uint8*)(buf) + i, bytes_per_iter); i += bytes_per_iter; } return i; } double SDLMixerXBackend::get_position() { if (music == nullptr || file == nullptr) { open = false; return 0.0; } return Mix_GetMusicPosition(music); } SDLMixerXBackend::SDLMixerXBackend() { Mix_Init(MIX_INIT_FLAC|MIX_INIT_MID|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG|MIX_INIT_OPUS|MIX_INIT_WAVPACK); } SDLMixerXBackend::~SDLMixerXBackend() { Mix_Quit(); } void SDLMixerXBackend::cleanup() { streams.clear(); position = 0.0; rate = 0.0; memset(&spec, 0, sizeof(spec)); current_file = ""; current_title = ""; length = 0.0; if (music != nullptr) { Mix_HaltMusicStream(music); Mix_FreeMusic(music); } Mix_SetSoundFonts(NULL); mixer = nullptr; music = nullptr; delete file; file = nullptr; open = false; Mix_CloseAudio(); } void SDLMixerXBackend::add_licenses() { auto &license_data = get_license_data(); auto smx = LicenseData("SDL Mixer X", "Zlib"); LOAD_LICENSE(smx, sdl_mixer_x); license_data.insert(smx); }