#include "playback.h" #include "SDL_mixer.h" #include #include #include using namespace std::chrono; Mix_Music *Playback::Load(const char *file) { Mix_Music *output = Mix_LoadMUS(file); if (!output) { printf("Error loading music '%s': %s\n", file, Mix_GetError()); throw std::exception(); } Mix_PlayMusicStream(output, -1); length = Mix_MusicDuration(output); update.store(true); return output; } void Playback::Unload(Mix_Music *music) { Mix_HaltMusicStream(music); Mix_FreeMusic(music); } void Playback::ThreadFunc() { Mix_Init(MIX_INIT_FLAC|MIX_INIT_MID|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG|MIX_INIT_OPUS|MIX_INIT_WAVPACK); Mix_OpenAudioDevice(48000, AUDIO_S16SYS, 2, 4096, NULL, 0); Mix_Music *music = Load(filePath.c_str()); while (running) { if (file_changed.exchange(false)) { Unload(music); music = Load(filePath.c_str()); } if (flag_mutex.try_lock()) { if (seeking.exchange(false)) { Mix_SetMusicPositionStream(music, position); } if (paused) { Mix_PauseMusicStream(music); } else { Mix_ResumeMusicStream(music); } if (update.exchange(false)) { Mix_VolumeMusicStream(music, (volume / 100.0 * MIX_MAX_VOLUME)); } flag_mutex.unlock(); } position = Mix_GetMusicPosition(music); std::this_thread::sleep_for(20ms); } // ==== Unload(music); Mix_CloseAudio(); Mix_Quit(); free(buf); } Playback::Playback() { running = false; paused = true; position = 0; length = 0; volume = 100.0; speed = 1.0; } Playback::~Playback() { Stop(); } void Playback::Start(std::string filePath) { this->filePath = filePath; printf("Playing %s...\n", filePath.c_str()); flag_mutex.lock(); paused = false; Update(); if (running.exchange(true)) { file_changed.store(true); } else { thread = std::thread(&Playback::ThreadFunc, this); } flag_mutex.unlock(); } double Playback::GetPosition() { return position; } double Playback::GetLength() { return length; } void Playback::Seek(double position) { flag_mutex.lock(); this->position = position; seeking.store(true); flag_mutex.unlock(); } void Playback::Pause() { flag_mutex.lock(); paused = !paused; flag_mutex.unlock(); } bool Playback::IsPaused() { return paused; } void Playback::Stop() { if (running.exchange(false)) { thread.join(); } } void Playback::Update() { update.store(true); } bool Playback::IsStopped() { return !running; }