diff --git a/backends/playback/fluidsynth/fluidsynth_backend.cpp b/backends/playback/fluidsynth/fluidsynth_backend.cpp index 2c8e23a..cf01861 100644 --- a/backends/playback/fluidsynth/fluidsynth_backend.cpp +++ b/backends/playback/fluidsynth/fluidsynth_backend.cpp @@ -136,7 +136,7 @@ void FluidSynthBackend::load(const char *filename) { } sample_positions.push_back({samples, cur_pos}); } - this->length = ((double)samples) / 96000.0; + this->length = samples; } extern SDL_AudioSpec obtained; void FluidSynthBackend::switch_stream(int idx) { @@ -158,7 +158,7 @@ void FluidSynthBackend::cleanup() { 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; + position += maxlen; 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; @@ -187,9 +187,9 @@ bool FluidSynthBackend::is_fluidsynth_setting(std::string path) { if (path.length() < strlen(prefix)) return false; return path.substr(0, strlen(prefix)) == std::string(prefix); } -void FluidSynthBackend::seek(double position) { +void FluidSynthBackend::seek_samples(uint64_t position) { size_t tick = 0; - size_t sample = position * 96000; + size_t sample = position; size_t prev_sample = 0; size_t next_sample = 0; for (auto &pair : sample_positions) { @@ -197,11 +197,11 @@ void FluidSynthBackend::seek(double position) { next_sample = pair.first; if (next_sample > sample) { tick = pair.second - 1; - this->position = ((double)prev_sample) / 96000.0; + this->position = prev_sample; break; } else if (next_sample == sample) { tick = pair.second; - this->position = ((double)next_sample) / 96000.0; + this->position = next_sample; prev_sample = next_sample; break; } @@ -211,7 +211,7 @@ void FluidSynthBackend::seek(double position) { 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() { +uint64_t FluidSynthBackend::get_position_samples() { return position; } int FluidSynthBackend::get_stream_idx() { diff --git a/backends/playback/fluidsynth/fluidsynth_backend.hpp b/backends/playback/fluidsynth/fluidsynth_backend.hpp index b7be803..a100715 100644 --- a/backends/playback/fluidsynth/fluidsynth_backend.hpp +++ b/backends/playback/fluidsynth/fluidsynth_backend.hpp @@ -127,12 +127,12 @@ class FluidSynthBackend : public PlaybackBackend { return "MIDI player"; } std::vector get_property_list() override; - void seek(double position) override; + void seek_samples(uint64_t 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; + uint64_t get_position_samples() override; inline ~FluidSynthBackend() override { } }; diff --git a/backends/playback/sdl_mixer_x/sdl_mixer_x.cpp b/backends/playback/sdl_mixer_x/sdl_mixer_x.cpp index 59a6f7f..e74af9d 100644 --- a/backends/playback/sdl_mixer_x/sdl_mixer_x.cpp +++ b/backends/playback/sdl_mixer_x/sdl_mixer_x.cpp @@ -113,7 +113,7 @@ size_t SDLMixerXBackend::render(void *buf, size_t maxlen) { } return i; } -double SDLMixerXBackend::get_position() { +double SDLMixerXBackend::get_position_time() { if (music == nullptr || file == nullptr) { open = false; return 0.0; diff --git a/backends/playback/sdl_mixer_x/sdl_mixer_x.hpp b/backends/playback/sdl_mixer_x/sdl_mixer_x.hpp index fc42678..fa41e37 100644 --- a/backends/playback/sdl_mixer_x/sdl_mixer_x.hpp +++ b/backends/playback/sdl_mixer_x/sdl_mixer_x.hpp @@ -16,7 +16,13 @@ class SDLMixerXBackend : public PlaybackBackend { } std::optional get_max_samples() override; void seek(double position) override; - double get_position() override; + inline void seek_samples(uint64_t position) override { + seek(samples_to_time(position)); + } + double get_position_time() override; + inline uint64_t get_position_samples() override { + return time_to_samples(get_position_time()); + } void load(const char *filename) override; void switch_stream(int idx) override; void cleanup() override; diff --git a/backends/playback/vgmstream/vgmstream.cpp b/backends/playback/vgmstream/vgmstream.cpp index ee17eda..69a356c 100644 --- a/backends/playback/vgmstream/vgmstream.cpp +++ b/backends/playback/vgmstream/vgmstream.cpp @@ -115,23 +115,23 @@ size_t VgmStreamBackend::render(void *buf, size_t maxlen) { size_t new_samples = render_vgmstream((sample_t*)(buf), (int)maxlen, vf); if (maxlen > new_samples) { reset_vgmstream(vf); - position = 0.0; + position = 0; } else { - position += (double)new_samples / (double)vf->sample_rate; + position += new_samples; } return new_samples * sizeof(sample_t); } -void VgmStreamBackend::seek(double position) { +void VgmStreamBackend::seek_samples(uint64_t position) { if (vf == nullptr || sf == nullptr || file == nullptr) { open = false; return; } - auto pos32 = (int32_t)(position * vf->sample_rate); + auto pos32 = (int32_t)(position); seek_vgmstream(vf, pos32); this->position = position; } -double VgmStreamBackend::get_position() { +uint64_t VgmStreamBackend::get_position_samples() { return position; } int VgmStreamBackend::get_stream_idx() { diff --git a/backends/playback/vgmstream/vgmstream.hpp b/backends/playback/vgmstream/vgmstream.hpp index 1a2e475..f1754ad 100644 --- a/backends/playback/vgmstream/vgmstream.hpp +++ b/backends/playback/vgmstream/vgmstream.hpp @@ -17,13 +17,13 @@ class VgmStreamBackend : public PlaybackBackend { inline std::string get_name() override { return "VGMStream"; } - void seek(double position) override; + void seek_samples(uint64_t 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; + uint64_t get_position_samples() override; void add_licenses() override; inline ~VgmStreamBackend() override { } }; diff --git a/backends/playback/zsm/zsm_backend.cpp b/backends/playback/zsm/zsm_backend.cpp index 0916614..780ebeb 100644 --- a/backends/playback/zsm/zsm_backend.cpp +++ b/backends/playback/zsm/zsm_backend.cpp @@ -106,31 +106,31 @@ void ZsmBackend::load(const char *filename) { } file->seek(music_data_start, SeekType::SET); this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start); - double prev_time = 0.0; - double time = 0.0; + uint64_t prev_time = 0; + uint64_t time = 0; double tmpDelayTicks = 0.0; - loop_pos = -1.0; + loop_pos = UINT64_MAX; uint32_t prev_pos = music_data_start; while (true) { tmpDelayTicks -= get_delay_per_frame(); if (tmpDelayTicks < 0.0) { ZsmCommand cmd = get_command(); size_t cur_pos = file->get_pos(); - if (cur_pos >= this->loop_point && this->loop_pos < 0) { + if (cur_pos >= this->loop_point && this->loop_pos == UINT64_MAX) { loop_pos = time; this->loop_point = cur_pos; } if (cmd.id == ZsmEOF) { break; } else if (cmd.id == Delay) { - time += ((double)cmd.delay) / ((double)(tick_rate)); + time += (((double)cmd.delay) / ((double)(tick_rate))) * PSG_FREQ; tmpDelayTicks += cmd.delay; } prev_pos = file->get_pos(); prev_time = time; } } - if (this->loop_pos < 0.0) { + if (this->loop_pos == UINT64_MAX) { this->loop_pos = 0.0; this->loop_point = music_data_start; } @@ -223,7 +223,7 @@ void ZsmBackend::tick(bool step) { } break; case Delay: { delayTicks += cmd.delay; - position += ((double)cmd.delay) / ((double)(tick_rate)); + position += (((double)cmd.delay) / ((double)(tick_rate))) * spec.freq; } break; case ExtCmd: { //cmd.extcmd.channel @@ -384,16 +384,14 @@ ZsmCommand::~ZsmCommand() { } } } -void ZsmBackend::seek_internal(double position, bool loop) { - this->position = std::floor(this->position * PSG_FREQ) / PSG_FREQ; - position = std::floor(position * PSG_FREQ) / PSG_FREQ; +void ZsmBackend::seek_internal(uint64_t position, bool loop) {; if (this->position > position) { switch_stream(0); file->seek(music_data_start, SeekType::SET); this->cpuClocks = 0.0; this->delayTicks = 0; this->ticks = 0.0; - this->position = 0.0; + this->position = 0; } else if (this->position == position) { audio_buf.clear(); return; @@ -408,7 +406,7 @@ void ZsmBackend::seek_internal(double position, bool loop) { this->cpuClocks = 0.0; this->delayTicks = 0; this->ticks = 0.0; - this->position = 0.0; + this->position = 0; audio_buf.clear(); return; } @@ -419,15 +417,18 @@ void ZsmBackend::seek_internal(double position, bool loop) { } this->position = position; } -void ZsmBackend::seek(double position) { +void ZsmBackend::seek_samples(uint64_t position) { seek_internal(position, false); } -double ZsmBackend::get_position() { +uint64_t ZsmBackend::get_position_samples() { return position; } int ZsmBackend::get_stream_idx() { return 0; } +uint64_t ZsmBackend::get_loop_start_samples() { + return loop_start; +} void ZsmBackend::audio_step(size_t samples) { if (samples == 0) return; diff --git a/backends/playback/zsm/zsm_backend.hpp b/backends/playback/zsm/zsm_backend.hpp index a7cf566..af71e96 100644 --- a/backends/playback/zsm/zsm_backend.hpp +++ b/backends/playback/zsm/zsm_backend.hpp @@ -108,7 +108,7 @@ class ZsmBackend : public PlaybackBackend { return audio_buf.pop((int16_t*)buf, len); } uint32_t loop_point; - double loop_pos = 0.0; + uint64_t loop_pos = 0; uint32_t pcm_offset; uint8_t fm_mask; uint16_t psg_channel_mask; @@ -123,7 +123,7 @@ class ZsmBackend : public PlaybackBackend { return 1.0; } void tick(bool step = true);\ - void seek_internal(double position, bool loop = true); + void seek_internal(uint64_t position, bool loop = true); ZsmCommand get_command(); public: uint64_t get_min_samples() override; @@ -136,15 +136,16 @@ class ZsmBackend : public PlaybackBackend { } void add_licenses() override; std::vector get_property_list() override; - void seek(double position) override; + void seek_samples(uint64_t 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 { + uint64_t get_position_samples() override; + inline uint64_t get_length_samples() override { return length; } + uint64_t get_loop_start_samples() override; inline ~ZsmBackend() override { } }; diff --git a/backends/ui/imgui/RendererBackend.cpp b/backends/ui/imgui/RendererBackend.cpp index 789f52d..7ee4850 100644 --- a/backends/ui/imgui/RendererBackend.cpp +++ b/backends/ui/imgui/RendererBackend.cpp @@ -151,13 +151,23 @@ void RendererBackend::LoopFunction() { ImGui::NewFrame(); // Run the GUI GuiFunction(); + if (!main_menu_bar_used) { + BeginMainMenuBar(); + EndMainMenuBar(); + } // Rendering ImGui::Render(); SDL_SetRenderDrawColor(rend, (Uint8)(clear_color.x * clear_color.w * 255), (Uint8)(clear_color.y * clear_color.w * 255), (Uint8)(clear_color.z * clear_color.w * 255), (Uint8)(clear_color.w * 255)); SDL_RenderClear(rend); // Tell ImGui to render. ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), rend); - + SDL_Rect rect; + SDL_GetWindowSize(window, &rect.w, &rect.h); + rect.x = 0; + rect.y = 0; + ImVec4 color = ImGui::GetStyle().Colors[ImGuiCol_Border]; + SDL_SetRenderDrawColor(rend, color.x * 255, color.y * 255, color.z * 255, color.w * 255); + SDL_RenderDrawRect(rend, &rect); // Swap the buffers, and do VSync if enabled. SDL_RenderPresent(rend); @@ -291,6 +301,10 @@ static EM_BOOL resize_callback(int event_type, const EmscriptenUiEvent *event, v return EM_FALSE; } #endif +static SDL_HitTestResult hit_test(SDL_Window *window, const SDL_Point *area, void *data) { + return ((RendererBackend*)data)->HitTest(window, area); +} + void RendererBackend::BackendInit() { setup_locale("neko_player"); DEBUG.writefln("Loaded locale '%s' from '%s'...", CURRENT_LANGUAGE, LOCALE_DIR); @@ -319,7 +333,7 @@ void RendererBackend::BackendInit() { #ifdef SDL_HINT_IME_SHOW_UI SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); #endif - SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); + SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_BORDERLESS); SDL_CreateWindowAndRenderer(window_width, window_height, window_flags, &window, &rend); #ifndef __ANDROID__ @@ -330,6 +344,7 @@ void RendererBackend::BackendInit() { #endif SDL_EventState(SDL_DROPFILE, SDL_ENABLE); SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data, icon_size), 1); + icon_texture = SDL_CreateTextureFromSurface(rend, icon); SDL_SetWindowIcon(window, icon); // Setup Dear ImGui context @@ -389,10 +404,88 @@ void RendererBackend::BackendInit() { SDL_RenderSetVSync(rend, vsync ? 1 : 0); #endif theme->Apply(accent_color, (float)scale); + SDL_SetWindowHitTest(window, &hit_test, this); Init(); SDL_ShowWindow(window); started = true; } +bool RendererBackend::BeginMainMenuBar() { + main_menu_bar_used = true; + if (ImGui::BeginMainMenuBar()) { + ImVec2 winsize = ImGui::GetWindowSize(); + float texsize = winsize.y; + ImGui::SetCursorPosX(0); + ImGui::SetCursorPosY(0); + ImGui::Image((ImTextureID)(icon_texture), ImVec2(texsize, texsize)); + //ImGui::SetCursorPosY((winsize.y - ImGui::GetFrameHeight()) / 2); + ImGui::TextUnformatted(SDL_GetWindowTitle(window)); + menubar_start = ImGui::GetCursorPosX(); + return true; + } else { + return false; + } +} +SDL_HitTestResult RendererBackend::HitTest(SDL_Window *window, const SDL_Point *area) { + int w, h; + bool rtop, rbottom, rleft, rright; + SDL_GetWindowSize(window, &w, &h); + rtop = area->y <= 4; + rleft = area->x <= 4; + rright = area->x >= w-5; + rbottom = area->y >= h-5; + if (rtop) { + if (rright) { + return SDL_HITTEST_RESIZE_TOPRIGHT; + } else if (rleft) { + return SDL_HITTEST_RESIZE_TOPLEFT; + } else { + return SDL_HITTEST_RESIZE_TOP; + } + } else if (rbottom) { + if (rright) { + return SDL_HITTEST_RESIZE_BOTTOMRIGHT; + } else if (rleft) { + return SDL_HITTEST_RESIZE_BOTTOMLEFT; + } else { + return SDL_HITTEST_RESIZE_BOTTOM; + } + } else if (rleft) { + return SDL_HITTEST_RESIZE_LEFT; + } else if (rright) { + return SDL_HITTEST_RESIZE_RIGHT; + } else if (area->y < (16 * this->scale) && (area->x < menubar_start || (area->x > menubar_end && area->x < title_btn_start))) { + return SDL_HITTEST_DRAGGABLE; + } else { + return SDL_HITTEST_NORMAL; + } + +} +void RendererBackend::EndMainMenuBar() { +#ifndef __EMSCRIPTEN + menubar_end = ImGui::GetCursorPosX(); + ImVec2 size = ImGui::GetWindowSize(); + float btnw = size.y; + int btn_count = 3; + ImVec2 btn_size(btnw, btnw); + ImGui::SetCursorPosY(0); + ImGui::SetCursorPosX(size.x - (btnw * 3)); + if (ImGui::Button(ICON_FK_WINDOW_MINIMIZE, btn_size)) { + SDL_MinimizeWindow(window); + } + ImGui::SetCursorPosX(size.x - (btnw * 2)); + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED) { + if (ImGui::Button(ICON_FK_WINDOW_RESTORE, btn_size)) SDL_RestoreWindow(window); + } else { + if (ImGui::Button(ICON_FK_WINDOW_MAXIMIZE, btn_size)) SDL_MaximizeWindow(window); + } + ImGui::SetCursorPosX(size.x - btnw); + if (ImGui::Button(ICON_FK_WINDOW_CLOSE, btn_size)) { + done = true; + } + title_btn_start = size.x - (btnw * 3); +#endif + ImGui::EndMainMenuBar(); +} int RendererBackend::Run() { framerate = 60; started = false; diff --git a/backends/ui/imgui/RendererBackend.h b/backends/ui/imgui/RendererBackend.h index 98a1048..200e4ef 100644 --- a/backends/ui/imgui/RendererBackend.h +++ b/backends/ui/imgui/RendererBackend.h @@ -25,7 +25,14 @@ class RendererBackend { bool resize_needed = true; void on_resize(); bool update_scale = false; + SDL_Texture *icon_texture; + bool main_menu_bar_used = false; + int menubar_start; + int menubar_end; + int title_btn_start; public: + int window_border_radius = 8; + SDL_HitTestResult HitTest(SDL_Window *window, const SDL_Point *area); std::optional touchScreenModeOverride; std::optional scaleOverride; bool isTouchScreenMode(); @@ -57,6 +64,8 @@ class RendererBackend { void AddFonts(); void SetWindowSize(int w, int h); void GetWindowsize(int *w, int *h); + bool BeginMainMenuBar(); + void EndMainMenuBar(); RendererBackend(); virtual ~RendererBackend(); friend void main_loop(); diff --git a/backends/ui/imgui/main.cpp b/backends/ui/imgui/main.cpp index 374cbe3..7625013 100644 --- a/backends/ui/imgui/main.cpp +++ b/backends/ui/imgui/main.cpp @@ -225,7 +225,7 @@ void MainLoop::GuiFunction() { // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). if (show_demo_window) ImGui::ShowDemoWindow(&show_demo_window); - if (ImGui::BeginMainMenuBar()) { + if (BeginMainMenuBar()) { if (ImGui::BeginMenu(_TRI_CTX(ICON_FK_FILE, "Main menu", "File"))) { if (ImGui::MenuItem(_TRI_CTX(ICON_FK_FOLDER_OPEN, "Main menu | File", "Open"))) { // Set translatable strings here so that they are in the correct language even when it changes at runtime. @@ -274,7 +274,7 @@ void MainLoop::GuiFunction() { } ImGui::EndMenu(); } - ImGui::EndMainMenuBar(); + EndMainMenuBar(); } ImGui::SetNextWindowDockID(dockid); ImGui::Begin(_TRI_CTX(ICON_FK_PLAY, "Main window title", "Player"), nullptr, 0); diff --git a/backends/ui/qt/main_window.cpp b/backends/ui/qt/main_window.cpp index 733e2e1..40f4bac 100644 --- a/backends/ui/qt/main_window.cpp +++ b/backends/ui/qt/main_window.cpp @@ -87,7 +87,11 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() { cat_disp->setAlignment(Qt::Alignment::enum_type::AlignRight); cat_disp->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); root_layout->addWidget(cat_disp); - QBoxLayout *top_row = new QBoxLayout(QBoxLayout::LeftToRight, this); + QWidget *controls_widget = new QWidget(this); + QBoxLayout *controls_layout = new QBoxLayout(QBoxLayout::TopToBottom, controls_widget); + controls_widget->setLayout(controls_layout); + controls_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + QBoxLayout *top_row = new QBoxLayout(QBoxLayout::LeftToRight, controls_widget); pause_resume_btn = new QPushButton("Pause", this); QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() { playback->Pause(); @@ -119,7 +123,7 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() { QWidget *top_row_widget = new QWidget(this); top_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); top_row_widget->setLayout(top_row); - root_layout->addWidget(top_row_widget); + controls_layout->addWidget(top_row_widget); QBoxLayout *bottom_row = new QBoxLayout(QBoxLayout::LeftToRight, this); speed_slider = new LooperSlider("speed", "Speed", 0.25, 4.0, 0.01, true); pitch_slider = new LooperSlider("pitch", "Pitch", 0.25, 4.0, 0.01, true); @@ -142,7 +146,8 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() { QWidget *bottom_row_widget = new QWidget(this); bottom_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); bottom_row_widget->setLayout(bottom_row); - root_layout->addWidget(bottom_row_widget); + controls_layout->addWidget(bottom_row_widget); + root_layout->addWidget(controls_widget); QTimer *timer = new QTimer(this); QObject::connect(timer, &QTimer::timeout, [=,this]() { Pulse(); diff --git a/main.cpp b/main.cpp index 9fb9e47..44c6dd4 100644 --- a/main.cpp +++ b/main.cpp @@ -26,6 +26,8 @@ using namespace Looper::Log; extern "C" { void quit(); } +#else +#include #endif std::vector &get_cat_data() { static std::vector data; @@ -373,6 +375,9 @@ int main(int argc, char **argv) { app.add_option("-l, --log-level", LogStream::log_level, "Sets the minimum log level to display in the logs."); app.allow_extras(); init_logging(); +#ifndef __EMSCRIPTEN__ + //curl_global_init(CURL_GLOBAL_ALL); +#endif try { app.parse(argc, argv); executable_path = argv[0]; diff --git a/playback_backend.hpp b/playback_backend.hpp index 05c6723..769190b 100644 --- a/playback_backend.hpp +++ b/playback_backend.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "util.hpp" #include "ipc/internal.pb.h" @@ -20,13 +21,13 @@ class PlaybackBackend { size_t minSamples; size_t maxSamples; protected: - double length; + uint64_t length; std::vector streams; std::string current_file; std::string current_title; bool open; SDL_AudioSpec spec; - double position; + uint64_t position; std::map property_defaults; std::map properties; size_t min_sample_estimate; @@ -34,8 +35,8 @@ class PlaybackBackend { size_t max_sample_requirement = std::numeric_limits::max(); size_t min_sample_requirement = std::numeric_limits::min(); double rate; - double loop_start = 0.0; - double loop_end = -1.0; + uint64_t loop_start = 0; + uint64_t loop_end = UINT64_MAX; void setMinSamples(size_t samples) { this->minSamples = samples; adjustSampleEstimates(); @@ -53,6 +54,12 @@ class PlaybackBackend { max_sample_estimate = (size_t)ceill(tmpMaxSamples * tmpRate); if (max_sample_estimate > max_sample_requirement) max_sample_estimate = max_sample_requirement; } + inline double samples_to_time(uint64_t samples) { + return ((double)samples) / ((double)spec.freq); + } + inline uint64_t time_to_samples(double time) { + return time * spec.freq; + } public: using map = std::map; using iterator = map::iterator; @@ -62,8 +69,12 @@ class PlaybackBackend { inline virtual void add_licenses() { } 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() { + inline virtual void seek(double position) { seek_samples(time_to_samples(position)); } + inline virtual void seek_samples(uint64_t position) { } + inline virtual double get_position_time() { + return ((double)position) / ((double)spec.freq); + } + inline virtual uint64_t get_position_samples() { return position; } inline virtual SDL_AudioSpec get_spec() { @@ -102,13 +113,22 @@ class PlaybackBackend { virtual void cleanup(); virtual size_t render(void *buf, size_t maxlen); inline virtual double get_length() { - return open ? length : 0.0; + return samples_to_time(get_length_samples()); + } + inline virtual uint64_t get_length_samples() { + return open ? length : 0; + } + inline virtual uint64_t get_loop_start_samples() { + return open ? loop_start : 0; } inline virtual double get_loop_start() { - return open ? loop_start : 0.0; + return samples_to_time(get_loop_start_samples()); + } + inline virtual uint64_t get_loop_end_samples() { + return open ? loop_end == UINT64_MAX ? get_length_samples() : loop_end : 0; } inline virtual double get_loop_end() { - return open ? loop_end < 0.0 ? get_length() : loop_end : 0.0; + return samples_to_time(get_loop_end_samples()); } inline virtual std::optional get_current_file() { return open ? current_file : std::optional(); diff --git a/playback_process.cpp b/playback_process.cpp index 46a7625..c20a76f 100644 --- a/playback_process.cpp +++ b/playback_process.cpp @@ -184,7 +184,7 @@ PropertyDataOrError PlaybackProcessServiceImpl::Get(const GetProperty *request) } break; case PropertyId::PositionProperty: { DoubleProperty pos; - pos.set_value(cur_backend->get_position()); + pos.set_value(cur_backend->get_position_time()); data->mutable_value()->PackFrom(pos); } break; case PropertyId::BackendSpecific: { @@ -338,6 +338,7 @@ MaybeError PlaybackProcessServiceImpl::Init(const InitCommand *cmd) { } lock.set(backend.second, false); DEBUG.writefln("Using backend: %s", backend.second->get_name().c_str()); + backend.second->seek(0.0); break; } if (!cur_backend_lock.has_value()) { @@ -419,7 +420,11 @@ PlaybackProcess::PlaybackProcess(std::vector args) { } PlaybackProcess::PlaybackProcess(std::string filename, int idx) { // multi_process = Looper::Options::get_option("playback.multi_process", true); +#ifdef __EMSCRIPTEN__ + multi_process = false; +#else multi_process = true; +#endif done = false; this->done = false; if (multi_process) { diff --git a/subprojects/SDL-Mixer-X b/subprojects/SDL-Mixer-X index 22aed1f..0f7e551 160000 --- a/subprojects/SDL-Mixer-X +++ b/subprojects/SDL-Mixer-X @@ -1 +1 @@ -Subproject commit 22aed1f6bcfa6912a34d3241edf3bd90498a6bc2 +Subproject commit 0f7e551b59372cdad6c7475d50b6d0b8a9ac2765 diff --git a/subprojects/fmt b/subprojects/fmt index 0379bf3..e3ddede 160000 --- a/subprojects/fmt +++ b/subprojects/fmt @@ -1 +1 @@ -Subproject commit 0379bf3a5d52d8542aec1874677c9df5ff9ba5f9 +Subproject commit e3ddede6c4ee818825c4e5a6dfa1d384860c27d9 diff --git a/subprojects/jsoncpp b/subprojects/jsoncpp index 8214f71..dca8a24 160000 --- a/subprojects/jsoncpp +++ b/subprojects/jsoncpp @@ -1 +1 @@ -Subproject commit 8214f717e7c7d361f002b6c3d1b1086ddd096315 +Subproject commit dca8a24cf8da1fc61b5cf0422cad03474124196c