#pragma once #include #include #include #include #include #include #include #include #include #include #include #include using namespace soundtouch; using std::span; using std::optional; using std::vector; using std::queue; enum { PlaybackSignalNone = 0, PlaybackSignalFileChanged = 1 << 0, PlaybackSignalSpeedChanged = 1 << 1, PlaybackSignalTempoChanged = 1 << 2, PlaybackSignalPitchChanged = 1 << 3, PlaybackSignalPaused = 1 << 4, PlaybackSignalResumed = 1 << 5, PlaybackSignalStopped = 1 << 6, PlaybackSignalErrorOccurred = 1 << 7, PlaybackSignalSeeked = 1 << 8, PlaybackSignalStarted = 1 << 9 }; class Playback { public: inline Playback() {}; inline virtual ~Playback() {} inline virtual std::optional get_current_file() { return {}; } inline virtual std::optional get_current_title() { return {}; } inline virtual double GetPosition() { return 0.0; } inline virtual double GetLength() { return 0.0; } inline virtual void Seek(double position) {} inline virtual void Start(std::string filePath) {} inline virtual bool IsPaused() { return true; } inline virtual void Pause() {} inline virtual void Stop() {} inline virtual bool IsStopped() { return true; } inline virtual void SetTempo(float tempo) {} inline virtual void SetSpeed(float speed) {} inline virtual void SetPitch(float pitch) {} inline virtual void SetVolume(float volume) {} inline virtual float GetTempo() { return 1.0; } inline virtual float GetSpeed() { return 1.0; } inline virtual float GetPitch() { return 1.0; } inline virtual float GetVolume() { return 1.0; } inline virtual uint16_t handle_signals(uint16_t signal) { return 0; } inline virtual optional GetError() { return {}; } inline virtual bool ErrorExists() { return false; } inline virtual void SetPaused(bool paused) { if (IsPaused() != paused) { Pause(); } } }; class DBusAPISender; class PlaybackRemote : public Playback { private: DBusAPISender *sender; public: double GetPosition() override; double GetLength() override; void Seek(double position) override; void Start(std::string filePath) override; bool IsPaused() override; void Pause() override; void Stop() override; void Update(); bool IsStopped() override; void SetTempo(float tempo) override; void SetPitch(float pitch) override; void SetSpeed(float speed) override; void SetVolume(float volume) override; float GetTempo() override; float GetPitch() override; float GetSpeed() override; float GetVolume() override; uint16_t handle_signals(uint16_t signal) override; optional GetError() override; bool ErrorExists() override; PlaybackRemote(); }; class PlaybackInstance : public Playback { private: std::string filePath; std::atomic_bool running; std::atomic_bool file_changed; std::atomic_bool seeking; std::atomic_bool update; std::atomic_bool restart; std::atomic_bool playback_ready; std::atomic_bool speed_changed; std::atomic_bool tempo_changed; std::atomic_bool pitch_changed; std::atomic_bool pause_changed; std::mutex flag_mutex; std::mutex error_mutex; std::thread thread; double position; double length; bool paused; Uint8* buf; size_t bufsize; Mix_CommonMixer_t general_mixer; SDL_AudioDeviceID device; SoundTouch *st; SDL_AudioSpec spec; /// @brief A fake SDL_AudioSpec used to trick SDL Mixer X into allocating a bigger buffer. SDL_AudioSpec fakespec; void SDLCallbackInner(Uint8 *stream, int len); static void SDLCallback(void *userdata, Uint8 *stream, int len); Mix_Music *Load(const char* file); void Unload(Mix_Music* music); void ThreadFunc(); void UpdateST(); double GetMaxSeconds(); queue errors; std::mutex current_file_mutex; std::optional current_file; std::optional current_title; uint16_t signals_occurred = PlaybackSignalNone; std::mutex signal_mutex; void set_signal(uint16_t signal); float prev_pitch, prev_speed, prev_tempo; public: PlaybackInstance(); ~PlaybackInstance() override; std::optional get_current_file() override; std::optional get_current_title() override; double GetPosition() override; double GetLength() override; void Seek(double position) override; void Start(std::string filePath) override; bool IsPaused() override; void Pause() override; void Stop() override; void Update(); bool IsStopped() override; void SetTempo(float tempo) override; void SetPitch(float pitch) override; void SetSpeed(float speed) override; void SetVolume(float volume) override; float GetTempo() override; float GetPitch() override; float GetSpeed() override; float GetVolume() override; float volume; float speed; float tempo; float pitch; float MaxSeconds = 100.0; float MaxSpeed = 4.0; float MaxPitch = 4.0; float MaxTempo = 4.0; float MinSpeed = 0.25; float MinPitch = 0.25; float MinTempo = 0.25; uint16_t handle_signals(uint16_t signal) override; optional GetError() override; bool ErrorExists() override; };