looper/playback_backend.hpp

192 lines
6.3 KiB
C++
Raw Normal View History

2024-08-08 13:12:37 -07:00
#pragma once
#include <stddef.h>
#include <vector>
#include <string>
#include <map>
#include <optional>
#include <SDL.h>
#include <iterator>
#include "ipc/internal.pb.h"
struct PlaybackStream {
double length;
std::string name;
int id;
};
class PlaybackBackendHelper;
class PlaybackBackend {
protected:
double length;
std::vector<PlaybackStream> streams;
std::string current_file;
std::string current_title;
bool open;
SDL_AudioSpec spec;
double position;
std::map<std::string, google::protobuf::Any> property_defaults;
std::map<std::string, google::protobuf::Any> properties;
public:
using map = std::map<std::string, PlaybackBackend*>;
using iterator = map::iterator;
using const_iterator = map::const_iterator;
using reverse_iterator = map::reverse_iterator;
using const_reverse_iterator = map::const_reverse_iterator;
inline virtual std::string get_id() {return "";}
inline virtual std::string get_name() {return "";}
inline virtual void seek(double position) { }
inline virtual double get_position() {
return position;
}
inline virtual SDL_AudioSpec get_spec() {
return spec;
}
inline virtual bool set(std::string path, google::protobuf::Any value) {properties[path] = value; return true;}
inline virtual std::optional<google::protobuf::Any> get(std::string path) {return properties.contains(path) ? properties[path] : std::optional<google::protobuf::Any>();}
inline virtual std::optional<google::protobuf::Any> reset(std::string path) {
if (property_defaults.contains(path)) {
properties[path] = property_defaults[path];
} else {
properties.erase(path);
}
return get(path);
}
virtual void load(const char *filename);
virtual void init(const char *filename, int idx = 0);
virtual void switch_stream(int idx);
inline virtual std::vector<PlaybackStream> get_streams() {
return streams;
}
inline virtual uint64_t get_min_samples() {return 0;}
inline virtual std::optional<uint64_t> get_max_samples() {return {};}
virtual void cleanup();
virtual size_t render(void *buf, size_t maxlen);
inline virtual double get_length() {
return open ? length : 0.0;
}
inline virtual std::optional<std::string> get_current_file() {
return open ? current_file : std::optional<std::string>();
}
inline virtual std::optional<std::string> get_title() {
return open ? current_title : std::optional<std::string>();
}
inline virtual int get_stream_idx() {return 0;}
inline virtual ~PlaybackBackend() { }
static map backends;
template<class T>
static inline std::string get_backend_id() {
PlaybackBackend *backend = new T();
auto output = backend->get_id();
delete backend;
return output;
}
static inline PlaybackBackend* get_first_backend() {
if (backends.empty()) {
return nullptr;
}
return (*backends.begin()).second;
}
static void register_backend(PlaybackBackend *backend) {
std::string backend_id = backend->get_id();
if (backends.contains(backend_id)) { // Guard against potential memory leak due to reassigning a new pointer without deallocating the previous one
delete backend;
return;
}
backends[backend_id] = backend;
}
template<class T>
static void register_backend() {
PlaybackBackend *backend = new T();
backend->register_self();
}
static inline void unregister_backend(std::string id) {
if (backends.contains(id)) {
auto backend = backends[id];
delete backend;
backends.erase(id);
}
}
inline void unregister_self() {
PlaybackBackend::unregister_backend(get_id());
}
inline void register_self() {
PlaybackBackend::register_backend(this);
}
template<class T>
static void unregister_backend() {
unregister_backend(get_backend_id<T>());
}
static void deinit_backends();
static inline std::optional<PlaybackBackend*> get_backend(std::string id) {
if (backends.contains(id)) {
return backends[id];
} else {
return {};
}
}
template<class T>
static inline std::optional<T*> get_backend() {
auto id = get_backend_id<T>();
auto output = get_backend(id);
if (output.has_value()) {
return (T*)output.value();
} else {
return {};
}
}
};
class PlaybackBackendHelper {
using iterator = PlaybackBackend::iterator;
using const_iterator = PlaybackBackend::const_iterator;
using reverse_iterator = PlaybackBackend::reverse_iterator;
using const_reverse_iterator = PlaybackBackend::const_reverse_iterator;
public:
inline iterator begin() {
return PlaybackBackend::backends.begin();
}
inline const_iterator cbegin() const {
return PlaybackBackend::backends.cbegin();
}
inline iterator end() {
return PlaybackBackend::backends.end();
}
inline const_iterator cend() const {
return PlaybackBackend::backends.cend();
}
inline reverse_iterator rbegin() {
return PlaybackBackend::backends.rbegin();
}
inline const_reverse_iterator crbegin() const {
return PlaybackBackend::backends.crbegin();
}
inline reverse_iterator rend() {
return PlaybackBackend::backends.rend();
}
inline const_reverse_iterator crend() const {
return PlaybackBackend::backends.crend();
}
inline size_t size() {
return PlaybackBackend::backends.size();
}
inline bool empty() {
return PlaybackBackend::backends.empty();
}
};
void init_playback_backends();
struct audio_data_t {
size_t size;
bool endian;
bool is_signed;
bool is_float;
};
void init_audio_data();
size_t size_of_sample_type(int type);
bool sample_type_has_endian(int type);
bool sample_type_endian_msb(int type);
bool sample_type_endian_lsb(int type);
bool sample_type_is_float(int type);
bool smaple_type_is_integer(int type);
bool sample_type_is_signed(int type);
bool sample_type_is_unsigned(int type);
int sample_spec_to_sdl(audio_data_t spec);
audio_data_t sdl_to_sample_spec(int type);
std::string sdl_to_str(int type);