looper/playback.h

197 lines
5.6 KiB
C
Raw Normal View History

2023-04-24 13:45:06 -07:00
#pragma once
#include <SDL_mixer.h>
2023-04-24 13:45:06 -07:00
#include <thread>
#include <SDL.h>
#include <SDL_audio.h>
2023-04-24 13:45:06 -07:00
#include <string>
#include <atomic>
#include <mutex>
#include <SoundTouch.h>
#include <span>
#include <optional>
#include <vector>
#include <queue>
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
};
2023-04-24 13:45:06 -07:00
class Playback {
2024-03-26 18:39:02 -07:00
public:
inline Playback() {};
inline virtual ~Playback() {}
inline virtual std::optional<std::string> get_current_file() {
return {};
}
inline virtual std::optional<std::string> 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<std::string> 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<std::string> GetError() override;
bool ErrorExists() override;
PlaybackRemote();
};
class PlaybackInstance : public Playback {
2023-04-24 13:45:06 -07:00
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;
2023-04-24 13:45:06 -07:00
std::mutex flag_mutex;
std::mutex error_mutex;
2023-04-24 13:45:06 -07:00
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);
2023-04-24 13:45:06 -07:00
void ThreadFunc();
void UpdateST();
double GetMaxSeconds();
queue<std::string> errors;
std::mutex current_file_mutex;
std::optional<std::string> current_file;
2024-03-26 18:39:02 -07:00
std::optional<std::string> current_title;
uint16_t signals_occurred = PlaybackSignalNone;
std::mutex signal_mutex;
void set_signal(uint16_t signal);
float prev_pitch, prev_speed, prev_tempo;
2024-03-26 18:39:02 -07:00
2023-04-24 13:45:06 -07:00
public:
2024-03-26 18:39:02 -07:00
PlaybackInstance();
~PlaybackInstance() override;
std::optional<std::string> get_current_file() override;
std::optional<std::string> 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;
2023-04-24 13:45:06 -07:00
void Update();
2024-03-26 18:39:02 -07:00
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;
2023-04-24 13:45:06 -07:00
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;
2024-03-26 18:39:02 -07:00
uint16_t handle_signals(uint16_t signal) override;
optional<std::string> GetError() override;
bool ErrorExists() override;
2023-04-24 13:45:06 -07:00
};