diff --git a/backends/playback/fluidsynth/fluidsynth_backend.cpp b/backends/playback/fluidsynth/fluidsynth_backend.cpp index 5b25c57..d32d607 100644 --- a/backends/playback/fluidsynth/fluidsynth_backend.cpp +++ b/backends/playback/fluidsynth/fluidsynth_backend.cpp @@ -49,10 +49,10 @@ void FluidSynthBackend::fluidsynth_get_property_list(const char *name, int type) fluidsynth_properties.push_back(property); } std::vector FluidSynthBackend::get_property_list() { - return fluidsynth_properties; + return fluidsynth_properties; } void FluidSynthBackend::load(const char *filename) { - memset(&spec, 0, sizeof(spec)); + memset(&spec, 0, sizeof(spec)); current_file = filename; spec.format = AUDIO_F32SYS; spec.samples = 100; @@ -63,7 +63,7 @@ void FluidSynthBackend::load(const char *filename) { settings = new_fluid_settings(); fluid_settings_setnum(settings, "synth.sample-rate", 96000.0); fluid_settings_setnum(settings, "synth.gain", 0.5); - fluid_settings_foreach(settings, (void*)this, &fluidsynth_get_property_list_wrapper); + fluid_settings_foreach(settings, (void*)this, &fluidsynth_get_property_list_wrapper); synth = new_fluid_synth(settings); player = new_fluid_player(synth); fs::path fpath(filename); @@ -91,10 +91,34 @@ void FluidSynthBackend::load(const char *filename) { delete file; file_data = realloc(file_data, file_len); fluid_player_add_mem(player, file_data, file_len); + fluid_player_set_loop(player, -1); + fluid_player_play(player); + size_t prev_pos = 0; + size_t cur_pos = 0; + size_t samples = 0; + sample_positions.push_back({0, 0}); + float fakebuf; + fluid_player_seek(player, 0); + while (prev_pos <= cur_pos) { + size_t samples_to_add = std::floor((96000.0 * 60.0) / fluid_player_get_bpm(player)); + fluid_synth_write_float(synth, samples_to_add, &fakebuf, 0, 0, &fakebuf, 0, 0); + samples += samples_to_add; + prev_pos = cur_pos; + while (prev_pos == cur_pos) { + cur_pos = fluid_player_get_current_tick(player); + if (prev_pos == cur_pos) { + fluid_synth_write_float(synth, 1, &fakebuf, 0, 0, &fakebuf, 0, 0); + samples++; + } + } + sample_positions.push_back({samples, cur_pos}); + } + this->length = ((double)samples) / 96000.0; } extern SDL_AudioSpec obtained; void FluidSynthBackend::switch_stream(int idx) { - fluid_player_play(player); + fluid_player_seek(player, 0); + open = true; } void FluidSynthBackend::cleanup() { delete_fluid_player(player); @@ -106,14 +130,33 @@ void FluidSynthBackend::cleanup() { file_len = 0; free(file_data); file_data = nullptr; + open = false; } size_t FluidSynthBackend::render(void *buf, size_t maxlen) { size_t sample_type_len = sizeof(float); maxlen /= sample_type_len * 2; + position += ((double)maxlen) / 96000.0; maxlen *= sample_type_len * 2; if (fluid_synth_write_float(synth, maxlen / 2 / sample_type_len, buf, 0, 2, buf, 1, 2) == FLUID_FAILED) { return 0; } + if (position >= length) { + int tick = fluid_player_get_current_tick(player); + int prev_sample = 0; + int cur_sample = 0; + for (auto &pair : sample_positions) { + prev_sample = cur_sample; + cur_sample = pair.first; + if (pair.second > tick) { + position = ((double)prev_sample) / 96000.0; + break; + } else if (pair.second == tick) { + position = ((double)cur_sample) / 96000.0; + break; + } + } + } + return maxlen; } bool FluidSynthBackend::is_fluidsynth_setting(std::string path) { @@ -122,10 +165,31 @@ bool FluidSynthBackend::is_fluidsynth_setting(std::string path) { return path.substr(0, strlen(prefix)) == std::string(prefix); } void FluidSynthBackend::seek(double position) { - fluid_player_seek(player, position); + size_t tick = 0; + size_t sample = position * 96000; + size_t prev_sample = 0; + size_t next_sample = 0; + for (auto &pair : sample_positions) { + prev_sample = next_sample; + next_sample = pair.first; + if (next_sample > sample) { + tick = pair.second - 1; + this->position = ((double)prev_sample) / 96000.0; + break; + } else if (next_sample == sample) { + tick = pair.second; + this->position = ((double)next_sample) / 96000.0; + prev_sample = next_sample; + break; + } + } + fluid_player_seek(player, tick); + float fakebuf; + if (sample > prev_sample) fluid_synth_write_float(synth, sample - prev_sample, &fakebuf, 0, 0, &fakebuf, 0, 0); + this->position = position; } double FluidSynthBackend::get_position() { - return fluid_player_get_current_tick(player); + return position; } int FluidSynthBackend::get_stream_idx() { return 0; diff --git a/backends/playback/fluidsynth/fluidsynth_backend.hpp b/backends/playback/fluidsynth/fluidsynth_backend.hpp index bf88f5d..b7be803 100644 --- a/backends/playback/fluidsynth/fluidsynth_backend.hpp +++ b/backends/playback/fluidsynth/fluidsynth_backend.hpp @@ -12,6 +12,7 @@ #include #include "file_backend.hpp" #include +#include class FluidSynthBackend : public PlaybackBackend { void *file_data; size_t file_len; @@ -20,6 +21,7 @@ class FluidSynthBackend : public PlaybackBackend { fluid_settings_t *settings; fluid_synth_t *synth; fluid_player_t *player; + std::vector> sample_positions; void fluidsynth_get_property_list(const char *name, int type); public: void set_fluidsynth_property_str(std::string path, std::string val); @@ -132,8 +134,5 @@ class FluidSynthBackend : public PlaybackBackend { 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 { } };