2024-10-24 11:33:08 -07:00
|
|
|
#pragma once
|
|
|
|
#include "playback_backend.hpp"
|
|
|
|
#include <omp.h>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <streambuf>
|
|
|
|
#include <vector>
|
|
|
|
#include <util.hpp>
|
|
|
|
#include <SDL.h>
|
|
|
|
#include "file_backend.hpp"
|
2024-10-26 09:01:06 -07:00
|
|
|
#include <fluidsynth.h>
|
2024-10-24 11:33:08 -07:00
|
|
|
class FluidSynthBackend : public PlaybackBackend {
|
2024-12-11 12:56:17 -08:00
|
|
|
void *file_data;
|
|
|
|
size_t file_len;
|
2024-10-26 09:01:06 -07:00
|
|
|
static void fluidsynth_get_property_list_wrapper(void *udata, const char *name, int type);
|
2024-10-24 11:33:08 -07:00
|
|
|
std::vector<Property> fluidsynth_properties;
|
|
|
|
fluid_settings_t *settings;
|
2024-12-11 12:56:17 -08:00
|
|
|
fluid_synth_t *synth;
|
|
|
|
fluid_player_t *player;
|
2024-10-24 11:33:08 -07:00
|
|
|
void fluidsynth_get_property_list(const char *name, int type);
|
|
|
|
public:
|
|
|
|
void set_fluidsynth_property_str(std::string path, std::string val);
|
|
|
|
void set_fluidsynth_property_num(std::string path, double val);
|
|
|
|
void set_fluidsynth_property_int(std::string path, int val);
|
2024-12-11 12:56:17 -08:00
|
|
|
std::optional<std::string> get_fluidsynth_property_str(std::string path);
|
|
|
|
std::optional<double> get_fluidsynth_property_num(std::string path);
|
|
|
|
std::optional<int> get_fluidsynth_property_int(std::string path);
|
|
|
|
void reset_fluidsynth_property(std::string path);
|
|
|
|
bool is_fluidsynth_setting(std::string path);
|
|
|
|
inline std::optional<std::string> get_property_string(google::protobuf::Any value) {
|
|
|
|
try {
|
|
|
|
StringProperty * property = resolve_any<StringProperty>(value);
|
|
|
|
std::string output = property->value();
|
|
|
|
delete property;
|
|
|
|
return output;
|
|
|
|
} catch (std::exception e) {
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
inline std::optional<double> get_property_double(google::protobuf::Any value) {
|
|
|
|
try {
|
|
|
|
DoubleProperty *property = resolve_any<DoubleProperty>(value);
|
|
|
|
double output = property->value();
|
|
|
|
delete property;
|
|
|
|
return output;
|
|
|
|
} catch (std::exception e) {
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
inline std::optional<int> get_property_int(google::protobuf::Any value) {
|
|
|
|
try {
|
|
|
|
IntProperty *property = resolve_any<IntProperty>(value);
|
|
|
|
int output = property->value();
|
|
|
|
delete property;
|
|
|
|
return output;
|
|
|
|
} catch (std::exception e) {
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
inline bool set(std::string path, google::protobuf::Any value) override {
|
|
|
|
if (!is_fluidsynth_setting(path)) {
|
|
|
|
return PlaybackBackend::set(path, value);
|
|
|
|
}
|
|
|
|
std::string fluidsynth_path = path.substr(strlen("fluidsynth/"));
|
|
|
|
auto maybe_num = get_property_double(value);
|
|
|
|
if (maybe_num.has_value()) {
|
|
|
|
set_fluidsynth_property_num(fluidsynth_path, maybe_num.value());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
auto maybe_int = get_property_int(value);
|
|
|
|
if (maybe_int.has_value()) {
|
|
|
|
set_fluidsynth_property_int(fluidsynth_path, maybe_int.value());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
auto maybe_string = get_property_string(value);
|
|
|
|
if (maybe_string.has_value()) {
|
|
|
|
set_fluidsynth_property_str(fluidsynth_path, maybe_string.value());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
inline std::optional<google::protobuf::Any> get(std::string path) override {
|
|
|
|
if (!is_fluidsynth_setting(path)) return PlaybackBackend::get(path);
|
|
|
|
std::string fluidsynth_path = path.substr(strlen("fluidsynth/"));
|
|
|
|
google::protobuf::Any output;
|
|
|
|
switch (fluid_settings_get_type(settings, fluidsynth_path.c_str())) {
|
|
|
|
case FLUID_INT_TYPE: {
|
|
|
|
IntProperty prop;
|
|
|
|
auto val = get_fluidsynth_property_int(fluidsynth_path);
|
|
|
|
if (!val.has_value()) return {};
|
|
|
|
prop.set_value(val.value());
|
|
|
|
output.PackFrom(prop);
|
|
|
|
} break;
|
|
|
|
case FLUID_STR_TYPE: {
|
|
|
|
StringProperty prop;
|
|
|
|
auto val = get_fluidsynth_property_str(fluidsynth_path);
|
|
|
|
if (!val.has_value()) return {};
|
|
|
|
prop.set_value(val.value());
|
|
|
|
output.PackFrom(prop);
|
|
|
|
} break;
|
|
|
|
case FLUID_NUM_TYPE: {
|
|
|
|
DoubleProperty prop;
|
|
|
|
auto val = get_fluidsynth_property_num(fluidsynth_path);
|
|
|
|
if (!val.has_value()) return {};
|
|
|
|
prop.set_value(val.value());
|
|
|
|
output.PackFrom(prop);
|
|
|
|
} break;
|
|
|
|
default: return {};
|
|
|
|
}
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
inline std::optional<google::protobuf::Any> reset(std::string path) override {
|
|
|
|
if (!is_fluidsynth_setting(path)) return PlaybackBackend::reset(path);
|
|
|
|
std::string fluidsynth_path = path.substr(strlen("fluidsynth/"));
|
|
|
|
reset_fluidsynth_property(fluidsynth_path);
|
|
|
|
return get(path);
|
|
|
|
}
|
2024-10-24 11:33:08 -07:00
|
|
|
inline std::string get_id() override {
|
|
|
|
return "fluidsynth";
|
|
|
|
}
|
|
|
|
inline std::string get_name() override {
|
|
|
|
return "MIDI player";
|
|
|
|
}
|
|
|
|
std::vector<Property> get_property_list() override;
|
|
|
|
void seek(double position) override;
|
|
|
|
void load(const char *filename) override;
|
|
|
|
void switch_stream(int idx) override;
|
|
|
|
void cleanup() override;
|
|
|
|
int get_stream_idx() override;
|
|
|
|
size_t render(void *buf, size_t maxlen) override;
|
|
|
|
double get_position() override;
|
|
|
|
inline double get_length() override {
|
2024-12-11 12:56:17 -08:00
|
|
|
return 0.0;
|
2024-10-24 11:33:08 -07:00
|
|
|
}
|
2024-10-26 09:01:06 -07:00
|
|
|
inline ~FluidSynthBackend() override { }
|
2024-10-24 11:33:08 -07:00
|
|
|
};
|