#pragma once #include "playback_backend.hpp" #include #include #include #include #include #include #include #include #include #include #include "file_backend.hpp" #include class FluidSynthBackend : public PlaybackBackend { void *file_data; size_t file_len; static void fluidsynth_get_property_list_wrapper(void *udata, const char *name, int type); std::vector fluidsynth_properties; fluid_settings_t *settings; fluid_synth_t *synth; fluid_player_t *player; 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); std::optional get_fluidsynth_property_str(std::string path); std::optional get_fluidsynth_property_num(std::string path); std::optional get_fluidsynth_property_int(std::string path); void reset_fluidsynth_property(std::string path); bool is_fluidsynth_setting(std::string path); inline std::optional get_property_string(google::protobuf::Any value) { try { StringProperty * property = resolve_any(value); std::string output = property->value(); delete property; return output; } catch (std::exception e) { } return {}; } inline std::optional get_property_double(google::protobuf::Any value) { try { DoubleProperty *property = resolve_any(value); double output = property->value(); delete property; return output; } catch (std::exception e) { } return {}; } inline std::optional get_property_int(google::protobuf::Any value) { try { IntProperty *property = resolve_any(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 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 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); } inline std::string get_id() override { return "fluidsynth"; } inline std::string get_name() override { return "MIDI player"; } std::vector 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 { return 0.0; } inline ~FluidSynthBackend() override { } };