Use CSD in ImGui backend, update QT backend, prepare for sample-based positioning, and disable multiprocess on Emscripten
Some checks failed
Build / build-gentoo (push) Successful in 1m56s
Build / download-system-deps (push) Successful in 5m25s
Build / get-source-code (push) Successful in 12m33s
Build / build-deb (push) Failing after 5m56s
Build / build-appimage (push) Successful in 4m47s
Build / build-android (push) Failing after 3m11s
Build / build-windows (push) Has been cancelled
Some checks failed
Build / build-gentoo (push) Successful in 1m56s
Build / download-system-deps (push) Successful in 5m25s
Build / get-source-code (push) Successful in 12m33s
Build / build-deb (push) Failing after 5m56s
Build / build-appimage (push) Successful in 4m47s
Build / build-android (push) Failing after 3m11s
Build / build-windows (push) Has been cancelled
This commit is contained in:
parent
6920d3c0ff
commit
0b2b6bc459
18 changed files with 202 additions and 57 deletions
|
@ -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() {
|
||||
|
|
|
@ -127,12 +127,12 @@ class FluidSynthBackend : public PlaybackBackend {
|
|||
return "MIDI player";
|
||||
}
|
||||
std::vector<Property> 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 { }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -16,7 +16,13 @@ class SDLMixerXBackend : public PlaybackBackend {
|
|||
}
|
||||
std::optional<uint64_t> 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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 { }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Property> 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 { }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<bool> touchScreenModeOverride;
|
||||
std::optional<double> 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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
5
main.cpp
5
main.cpp
|
@ -26,6 +26,8 @@ using namespace Looper::Log;
|
|||
extern "C" {
|
||||
void quit();
|
||||
}
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
std::vector<CatData> &get_cat_data() {
|
||||
static std::vector<CatData> 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];
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <optional>
|
||||
#include <SDL.h>
|
||||
#include <iterator>
|
||||
#include <limits.h>
|
||||
#include <limits>
|
||||
#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<PlaybackStream> streams;
|
||||
std::string current_file;
|
||||
std::string current_title;
|
||||
bool open;
|
||||
SDL_AudioSpec spec;
|
||||
double position;
|
||||
uint64_t position;
|
||||
std::map<std::string, google::protobuf::Any> property_defaults;
|
||||
std::map<std::string, google::protobuf::Any> properties;
|
||||
size_t min_sample_estimate;
|
||||
|
@ -34,8 +35,8 @@ class PlaybackBackend {
|
|||
size_t max_sample_requirement = std::numeric_limits<size_t>::max();
|
||||
size_t min_sample_requirement = std::numeric_limits<size_t>::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<std::string, PlaybackBackend*>;
|
||||
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<std::string> get_current_file() {
|
||||
return open ? current_file : std::optional<std::string>();
|
||||
|
|
|
@ -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<std::string> args) {
|
|||
}
|
||||
PlaybackProcess::PlaybackProcess(std::string filename, int idx) {
|
||||
// multi_process = Looper::Options::get_option<bool>("playback.multi_process", true);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
multi_process = false;
|
||||
#else
|
||||
multi_process = true;
|
||||
#endif
|
||||
done = false;
|
||||
this->done = false;
|
||||
if (multi_process) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 22aed1f6bcfa6912a34d3241edf3bd90498a6bc2
|
||||
Subproject commit 0f7e551b59372cdad6c7475d50b6d0b8a9ac2765
|
|
@ -1 +1 @@
|
|||
Subproject commit 0379bf3a5d52d8542aec1874677c9df5ff9ba5f9
|
||||
Subproject commit e3ddede6c4ee818825c4e5a6dfa1d384860c27d9
|
|
@ -1 +1 @@
|
|||
Subproject commit 8214f717e7c7d361f002b6c3d1b1086ddd096315
|
||||
Subproject commit dca8a24cf8da1fc61b5cf0422cad03474124196c
|
Loading…
Reference in a new issue