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});
|
sample_positions.push_back({samples, cur_pos});
|
||||||
}
|
}
|
||||||
this->length = ((double)samples) / 96000.0;
|
this->length = samples;
|
||||||
}
|
}
|
||||||
extern SDL_AudioSpec obtained;
|
extern SDL_AudioSpec obtained;
|
||||||
void FluidSynthBackend::switch_stream(int idx) {
|
void FluidSynthBackend::switch_stream(int idx) {
|
||||||
|
@ -158,7 +158,7 @@ void FluidSynthBackend::cleanup() {
|
||||||
size_t FluidSynthBackend::render(void *buf, size_t maxlen) {
|
size_t FluidSynthBackend::render(void *buf, size_t maxlen) {
|
||||||
size_t sample_type_len = sizeof(float);
|
size_t sample_type_len = sizeof(float);
|
||||||
maxlen /= sample_type_len * 2;
|
maxlen /= sample_type_len * 2;
|
||||||
position += ((double)maxlen) / 96000.0;
|
position += maxlen;
|
||||||
maxlen *= sample_type_len * 2;
|
maxlen *= sample_type_len * 2;
|
||||||
if (fluid_synth_write_float(synth, maxlen / 2 / sample_type_len, buf, 0, 2, buf, 1, 2) == FLUID_FAILED) {
|
if (fluid_synth_write_float(synth, maxlen / 2 / sample_type_len, buf, 0, 2, buf, 1, 2) == FLUID_FAILED) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -187,9 +187,9 @@ bool FluidSynthBackend::is_fluidsynth_setting(std::string path) {
|
||||||
if (path.length() < strlen(prefix)) return false;
|
if (path.length() < strlen(prefix)) return false;
|
||||||
return path.substr(0, strlen(prefix)) == std::string(prefix);
|
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 tick = 0;
|
||||||
size_t sample = position * 96000;
|
size_t sample = position;
|
||||||
size_t prev_sample = 0;
|
size_t prev_sample = 0;
|
||||||
size_t next_sample = 0;
|
size_t next_sample = 0;
|
||||||
for (auto &pair : sample_positions) {
|
for (auto &pair : sample_positions) {
|
||||||
|
@ -197,11 +197,11 @@ void FluidSynthBackend::seek(double position) {
|
||||||
next_sample = pair.first;
|
next_sample = pair.first;
|
||||||
if (next_sample > sample) {
|
if (next_sample > sample) {
|
||||||
tick = pair.second - 1;
|
tick = pair.second - 1;
|
||||||
this->position = ((double)prev_sample) / 96000.0;
|
this->position = prev_sample;
|
||||||
break;
|
break;
|
||||||
} else if (next_sample == sample) {
|
} else if (next_sample == sample) {
|
||||||
tick = pair.second;
|
tick = pair.second;
|
||||||
this->position = ((double)next_sample) / 96000.0;
|
this->position = next_sample;
|
||||||
prev_sample = next_sample;
|
prev_sample = next_sample;
|
||||||
break;
|
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);
|
if (sample > prev_sample) fluid_synth_write_float(synth, sample - prev_sample, &fakebuf, 0, 0, &fakebuf, 0, 0);
|
||||||
this->position = position;
|
this->position = position;
|
||||||
}
|
}
|
||||||
double FluidSynthBackend::get_position() {
|
uint64_t FluidSynthBackend::get_position_samples() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
int FluidSynthBackend::get_stream_idx() {
|
int FluidSynthBackend::get_stream_idx() {
|
||||||
|
|
|
@ -127,12 +127,12 @@ class FluidSynthBackend : public PlaybackBackend {
|
||||||
return "MIDI player";
|
return "MIDI player";
|
||||||
}
|
}
|
||||||
std::vector<Property> get_property_list() 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 load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
int get_stream_idx() override;
|
int get_stream_idx() override;
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
size_t render(void *buf, size_t maxlen) override;
|
||||||
double get_position() override;
|
uint64_t get_position_samples() override;
|
||||||
inline ~FluidSynthBackend() override { }
|
inline ~FluidSynthBackend() override { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -113,7 +113,7 @@ size_t SDLMixerXBackend::render(void *buf, size_t maxlen) {
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
double SDLMixerXBackend::get_position() {
|
double SDLMixerXBackend::get_position_time() {
|
||||||
if (music == nullptr || file == nullptr) {
|
if (music == nullptr || file == nullptr) {
|
||||||
open = false;
|
open = false;
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
|
@ -16,7 +16,13 @@ class SDLMixerXBackend : public PlaybackBackend {
|
||||||
}
|
}
|
||||||
std::optional<uint64_t> get_max_samples() override;
|
std::optional<uint64_t> get_max_samples() override;
|
||||||
void seek(double position) 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 load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() 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);
|
size_t new_samples = render_vgmstream((sample_t*)(buf), (int)maxlen, vf);
|
||||||
if (maxlen > new_samples) {
|
if (maxlen > new_samples) {
|
||||||
reset_vgmstream(vf);
|
reset_vgmstream(vf);
|
||||||
position = 0.0;
|
position = 0;
|
||||||
} else {
|
} else {
|
||||||
position += (double)new_samples / (double)vf->sample_rate;
|
position += new_samples;
|
||||||
}
|
}
|
||||||
return new_samples * sizeof(sample_t);
|
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) {
|
if (vf == nullptr || sf == nullptr || file == nullptr) {
|
||||||
open = false;
|
open = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto pos32 = (int32_t)(position * vf->sample_rate);
|
auto pos32 = (int32_t)(position);
|
||||||
seek_vgmstream(vf, pos32);
|
seek_vgmstream(vf, pos32);
|
||||||
this->position = position;
|
this->position = position;
|
||||||
}
|
}
|
||||||
double VgmStreamBackend::get_position() {
|
uint64_t VgmStreamBackend::get_position_samples() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
int VgmStreamBackend::get_stream_idx() {
|
int VgmStreamBackend::get_stream_idx() {
|
||||||
|
|
|
@ -17,13 +17,13 @@ class VgmStreamBackend : public PlaybackBackend {
|
||||||
inline std::string get_name() override {
|
inline std::string get_name() override {
|
||||||
return "VGMStream";
|
return "VGMStream";
|
||||||
}
|
}
|
||||||
void seek(double position) override;
|
void seek_samples(uint64_t position) override;
|
||||||
void load(const char *filename) override;
|
void load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
int get_stream_idx() override;
|
int get_stream_idx() override;
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
size_t render(void *buf, size_t maxlen) override;
|
||||||
double get_position() override;
|
uint64_t get_position_samples() override;
|
||||||
void add_licenses() override;
|
void add_licenses() override;
|
||||||
inline ~VgmStreamBackend() override { }
|
inline ~VgmStreamBackend() override { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,31 +106,31 @@ void ZsmBackend::load(const char *filename) {
|
||||||
}
|
}
|
||||||
file->seek(music_data_start, SeekType::SET);
|
file->seek(music_data_start, SeekType::SET);
|
||||||
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
|
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
|
||||||
double prev_time = 0.0;
|
uint64_t prev_time = 0;
|
||||||
double time = 0.0;
|
uint64_t time = 0;
|
||||||
double tmpDelayTicks = 0.0;
|
double tmpDelayTicks = 0.0;
|
||||||
loop_pos = -1.0;
|
loop_pos = UINT64_MAX;
|
||||||
uint32_t prev_pos = music_data_start;
|
uint32_t prev_pos = music_data_start;
|
||||||
while (true) {
|
while (true) {
|
||||||
tmpDelayTicks -= get_delay_per_frame();
|
tmpDelayTicks -= get_delay_per_frame();
|
||||||
if (tmpDelayTicks < 0.0) {
|
if (tmpDelayTicks < 0.0) {
|
||||||
ZsmCommand cmd = get_command();
|
ZsmCommand cmd = get_command();
|
||||||
size_t cur_pos = file->get_pos();
|
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;
|
loop_pos = time;
|
||||||
this->loop_point = cur_pos;
|
this->loop_point = cur_pos;
|
||||||
}
|
}
|
||||||
if (cmd.id == ZsmEOF) {
|
if (cmd.id == ZsmEOF) {
|
||||||
break;
|
break;
|
||||||
} else if (cmd.id == Delay) {
|
} else if (cmd.id == Delay) {
|
||||||
time += ((double)cmd.delay) / ((double)(tick_rate));
|
time += (((double)cmd.delay) / ((double)(tick_rate))) * PSG_FREQ;
|
||||||
tmpDelayTicks += cmd.delay;
|
tmpDelayTicks += cmd.delay;
|
||||||
}
|
}
|
||||||
prev_pos = file->get_pos();
|
prev_pos = file->get_pos();
|
||||||
prev_time = time;
|
prev_time = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this->loop_pos < 0.0) {
|
if (this->loop_pos == UINT64_MAX) {
|
||||||
this->loop_pos = 0.0;
|
this->loop_pos = 0.0;
|
||||||
this->loop_point = music_data_start;
|
this->loop_point = music_data_start;
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ void ZsmBackend::tick(bool step) {
|
||||||
} break;
|
} break;
|
||||||
case Delay: {
|
case Delay: {
|
||||||
delayTicks += cmd.delay;
|
delayTicks += cmd.delay;
|
||||||
position += ((double)cmd.delay) / ((double)(tick_rate));
|
position += (((double)cmd.delay) / ((double)(tick_rate))) * spec.freq;
|
||||||
} break;
|
} break;
|
||||||
case ExtCmd: {
|
case ExtCmd: {
|
||||||
//cmd.extcmd.channel
|
//cmd.extcmd.channel
|
||||||
|
@ -384,16 +384,14 @@ ZsmCommand::~ZsmCommand() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ZsmBackend::seek_internal(double position, bool loop) {
|
void ZsmBackend::seek_internal(uint64_t position, bool loop) {;
|
||||||
this->position = std::floor(this->position * PSG_FREQ) / PSG_FREQ;
|
|
||||||
position = std::floor(position * PSG_FREQ) / PSG_FREQ;
|
|
||||||
if (this->position > position) {
|
if (this->position > position) {
|
||||||
switch_stream(0);
|
switch_stream(0);
|
||||||
file->seek(music_data_start, SeekType::SET);
|
file->seek(music_data_start, SeekType::SET);
|
||||||
this->cpuClocks = 0.0;
|
this->cpuClocks = 0.0;
|
||||||
this->delayTicks = 0;
|
this->delayTicks = 0;
|
||||||
this->ticks = 0.0;
|
this->ticks = 0.0;
|
||||||
this->position = 0.0;
|
this->position = 0;
|
||||||
} else if (this->position == position) {
|
} else if (this->position == position) {
|
||||||
audio_buf.clear();
|
audio_buf.clear();
|
||||||
return;
|
return;
|
||||||
|
@ -408,7 +406,7 @@ void ZsmBackend::seek_internal(double position, bool loop) {
|
||||||
this->cpuClocks = 0.0;
|
this->cpuClocks = 0.0;
|
||||||
this->delayTicks = 0;
|
this->delayTicks = 0;
|
||||||
this->ticks = 0.0;
|
this->ticks = 0.0;
|
||||||
this->position = 0.0;
|
this->position = 0;
|
||||||
audio_buf.clear();
|
audio_buf.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -419,15 +417,18 @@ void ZsmBackend::seek_internal(double position, bool loop) {
|
||||||
}
|
}
|
||||||
this->position = position;
|
this->position = position;
|
||||||
}
|
}
|
||||||
void ZsmBackend::seek(double position) {
|
void ZsmBackend::seek_samples(uint64_t position) {
|
||||||
seek_internal(position, false);
|
seek_internal(position, false);
|
||||||
}
|
}
|
||||||
double ZsmBackend::get_position() {
|
uint64_t ZsmBackend::get_position_samples() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
int ZsmBackend::get_stream_idx() {
|
int ZsmBackend::get_stream_idx() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
uint64_t ZsmBackend::get_loop_start_samples() {
|
||||||
|
return loop_start;
|
||||||
|
}
|
||||||
|
|
||||||
void ZsmBackend::audio_step(size_t samples) {
|
void ZsmBackend::audio_step(size_t samples) {
|
||||||
if (samples == 0) return;
|
if (samples == 0) return;
|
||||||
|
|
|
@ -108,7 +108,7 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
return audio_buf.pop((int16_t*)buf, len);
|
return audio_buf.pop((int16_t*)buf, len);
|
||||||
}
|
}
|
||||||
uint32_t loop_point;
|
uint32_t loop_point;
|
||||||
double loop_pos = 0.0;
|
uint64_t loop_pos = 0;
|
||||||
uint32_t pcm_offset;
|
uint32_t pcm_offset;
|
||||||
uint8_t fm_mask;
|
uint8_t fm_mask;
|
||||||
uint16_t psg_channel_mask;
|
uint16_t psg_channel_mask;
|
||||||
|
@ -123,7 +123,7 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
void tick(bool step = true);\
|
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();
|
ZsmCommand get_command();
|
||||||
public:
|
public:
|
||||||
uint64_t get_min_samples() override;
|
uint64_t get_min_samples() override;
|
||||||
|
@ -136,15 +136,16 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
}
|
}
|
||||||
void add_licenses() override;
|
void add_licenses() override;
|
||||||
std::vector<Property> get_property_list() 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 load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
int get_stream_idx() override;
|
int get_stream_idx() override;
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
size_t render(void *buf, size_t maxlen) override;
|
||||||
double get_position() override;
|
uint64_t get_position_samples() override;
|
||||||
inline double get_length() override {
|
inline uint64_t get_length_samples() override {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
uint64_t get_loop_start_samples() override;
|
||||||
inline ~ZsmBackend() override { }
|
inline ~ZsmBackend() override { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -151,13 +151,23 @@ void RendererBackend::LoopFunction() {
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
// Run the GUI
|
// Run the GUI
|
||||||
GuiFunction();
|
GuiFunction();
|
||||||
|
if (!main_menu_bar_used) {
|
||||||
|
BeginMainMenuBar();
|
||||||
|
EndMainMenuBar();
|
||||||
|
}
|
||||||
// Rendering
|
// Rendering
|
||||||
ImGui::Render();
|
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_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);
|
SDL_RenderClear(rend);
|
||||||
// Tell ImGui to render.
|
// Tell ImGui to render.
|
||||||
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), rend);
|
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.
|
// Swap the buffers, and do VSync if enabled.
|
||||||
SDL_RenderPresent(rend);
|
SDL_RenderPresent(rend);
|
||||||
|
@ -291,6 +301,10 @@ static EM_BOOL resize_callback(int event_type, const EmscriptenUiEvent *event, v
|
||||||
return EM_FALSE;
|
return EM_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
static SDL_HitTestResult hit_test(SDL_Window *window, const SDL_Point *area, void *data) {
|
||||||
|
return ((RendererBackend*)data)->HitTest(window, area);
|
||||||
|
}
|
||||||
|
|
||||||
void RendererBackend::BackendInit() {
|
void RendererBackend::BackendInit() {
|
||||||
setup_locale("neko_player");
|
setup_locale("neko_player");
|
||||||
DEBUG.writefln("Loaded locale '%s' from '%s'...", CURRENT_LANGUAGE, LOCALE_DIR);
|
DEBUG.writefln("Loaded locale '%s' from '%s'...", CURRENT_LANGUAGE, LOCALE_DIR);
|
||||||
|
@ -319,7 +333,7 @@ void RendererBackend::BackendInit() {
|
||||||
#ifdef SDL_HINT_IME_SHOW_UI
|
#ifdef SDL_HINT_IME_SHOW_UI
|
||||||
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
#endif
|
#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);
|
SDL_CreateWindowAndRenderer(window_width, window_height, window_flags, &window, &rend);
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
|
@ -330,6 +344,7 @@ void RendererBackend::BackendInit() {
|
||||||
#endif
|
#endif
|
||||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||||
SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data, icon_size), 1);
|
SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data, icon_size), 1);
|
||||||
|
icon_texture = SDL_CreateTextureFromSurface(rend, icon);
|
||||||
SDL_SetWindowIcon(window, icon);
|
SDL_SetWindowIcon(window, icon);
|
||||||
|
|
||||||
// Setup Dear ImGui context
|
// Setup Dear ImGui context
|
||||||
|
@ -389,10 +404,88 @@ void RendererBackend::BackendInit() {
|
||||||
SDL_RenderSetVSync(rend, vsync ? 1 : 0);
|
SDL_RenderSetVSync(rend, vsync ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
theme->Apply(accent_color, (float)scale);
|
theme->Apply(accent_color, (float)scale);
|
||||||
|
SDL_SetWindowHitTest(window, &hit_test, this);
|
||||||
Init();
|
Init();
|
||||||
SDL_ShowWindow(window);
|
SDL_ShowWindow(window);
|
||||||
started = true;
|
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() {
|
int RendererBackend::Run() {
|
||||||
framerate = 60;
|
framerate = 60;
|
||||||
started = false;
|
started = false;
|
||||||
|
|
|
@ -25,7 +25,14 @@ class RendererBackend {
|
||||||
bool resize_needed = true;
|
bool resize_needed = true;
|
||||||
void on_resize();
|
void on_resize();
|
||||||
bool update_scale = false;
|
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:
|
public:
|
||||||
|
int window_border_radius = 8;
|
||||||
|
SDL_HitTestResult HitTest(SDL_Window *window, const SDL_Point *area);
|
||||||
std::optional<bool> touchScreenModeOverride;
|
std::optional<bool> touchScreenModeOverride;
|
||||||
std::optional<double> scaleOverride;
|
std::optional<double> scaleOverride;
|
||||||
bool isTouchScreenMode();
|
bool isTouchScreenMode();
|
||||||
|
@ -57,6 +64,8 @@ class RendererBackend {
|
||||||
void AddFonts();
|
void AddFonts();
|
||||||
void SetWindowSize(int w, int h);
|
void SetWindowSize(int w, int h);
|
||||||
void GetWindowsize(int *w, int *h);
|
void GetWindowsize(int *w, int *h);
|
||||||
|
bool BeginMainMenuBar();
|
||||||
|
void EndMainMenuBar();
|
||||||
RendererBackend();
|
RendererBackend();
|
||||||
virtual ~RendererBackend();
|
virtual ~RendererBackend();
|
||||||
friend void main_loop();
|
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!).
|
// 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)
|
if (show_demo_window)
|
||||||
ImGui::ShowDemoWindow(&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::BeginMenu(_TRI_CTX(ICON_FK_FILE, "Main menu", "File"))) {
|
||||||
if (ImGui::MenuItem(_TRI_CTX(ICON_FK_FOLDER_OPEN, "Main menu | File", "Open"))) {
|
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.
|
// 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::EndMenu();
|
||||||
}
|
}
|
||||||
ImGui::EndMainMenuBar();
|
EndMainMenuBar();
|
||||||
}
|
}
|
||||||
ImGui::SetNextWindowDockID(dockid);
|
ImGui::SetNextWindowDockID(dockid);
|
||||||
ImGui::Begin(_TRI_CTX(ICON_FK_PLAY, "Main window title", "Player"), nullptr, 0);
|
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->setAlignment(Qt::Alignment::enum_type::AlignRight);
|
||||||
cat_disp->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
cat_disp->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||||
root_layout->addWidget(cat_disp);
|
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);
|
pause_resume_btn = new QPushButton("Pause", this);
|
||||||
QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() {
|
QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() {
|
||||||
playback->Pause();
|
playback->Pause();
|
||||||
|
@ -119,7 +123,7 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
QWidget *top_row_widget = new QWidget(this);
|
QWidget *top_row_widget = new QWidget(this);
|
||||||
top_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
top_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
||||||
top_row_widget->setLayout(top_row);
|
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);
|
QBoxLayout *bottom_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
||||||
speed_slider = new LooperSlider("speed", "Speed", 0.25, 4.0, 0.01, true);
|
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);
|
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);
|
QWidget *bottom_row_widget = new QWidget(this);
|
||||||
bottom_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
bottom_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
||||||
bottom_row_widget->setLayout(bottom_row);
|
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);
|
QTimer *timer = new QTimer(this);
|
||||||
QObject::connect(timer, &QTimer::timeout, [=,this]() {
|
QObject::connect(timer, &QTimer::timeout, [=,this]() {
|
||||||
Pulse();
|
Pulse();
|
||||||
|
|
5
main.cpp
5
main.cpp
|
@ -26,6 +26,8 @@ using namespace Looper::Log;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void quit();
|
void quit();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#include <curl/curl.h>
|
||||||
#endif
|
#endif
|
||||||
std::vector<CatData> &get_cat_data() {
|
std::vector<CatData> &get_cat_data() {
|
||||||
static std::vector<CatData> 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.add_option("-l, --log-level", LogStream::log_level, "Sets the minimum log level to display in the logs.");
|
||||||
app.allow_extras();
|
app.allow_extras();
|
||||||
init_logging();
|
init_logging();
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
//curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
#endif
|
||||||
try {
|
try {
|
||||||
app.parse(argc, argv);
|
app.parse(argc, argv);
|
||||||
executable_path = argv[0];
|
executable_path = argv[0];
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <limits.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "ipc/internal.pb.h"
|
#include "ipc/internal.pb.h"
|
||||||
|
@ -20,13 +21,13 @@ class PlaybackBackend {
|
||||||
size_t minSamples;
|
size_t minSamples;
|
||||||
size_t maxSamples;
|
size_t maxSamples;
|
||||||
protected:
|
protected:
|
||||||
double length;
|
uint64_t length;
|
||||||
std::vector<PlaybackStream> streams;
|
std::vector<PlaybackStream> streams;
|
||||||
std::string current_file;
|
std::string current_file;
|
||||||
std::string current_title;
|
std::string current_title;
|
||||||
bool open;
|
bool open;
|
||||||
SDL_AudioSpec spec;
|
SDL_AudioSpec spec;
|
||||||
double position;
|
uint64_t position;
|
||||||
std::map<std::string, google::protobuf::Any> property_defaults;
|
std::map<std::string, google::protobuf::Any> property_defaults;
|
||||||
std::map<std::string, google::protobuf::Any> properties;
|
std::map<std::string, google::protobuf::Any> properties;
|
||||||
size_t min_sample_estimate;
|
size_t min_sample_estimate;
|
||||||
|
@ -34,8 +35,8 @@ class PlaybackBackend {
|
||||||
size_t max_sample_requirement = std::numeric_limits<size_t>::max();
|
size_t max_sample_requirement = std::numeric_limits<size_t>::max();
|
||||||
size_t min_sample_requirement = std::numeric_limits<size_t>::min();
|
size_t min_sample_requirement = std::numeric_limits<size_t>::min();
|
||||||
double rate;
|
double rate;
|
||||||
double loop_start = 0.0;
|
uint64_t loop_start = 0;
|
||||||
double loop_end = -1.0;
|
uint64_t loop_end = UINT64_MAX;
|
||||||
void setMinSamples(size_t samples) {
|
void setMinSamples(size_t samples) {
|
||||||
this->minSamples = samples;
|
this->minSamples = samples;
|
||||||
adjustSampleEstimates();
|
adjustSampleEstimates();
|
||||||
|
@ -53,6 +54,12 @@ class PlaybackBackend {
|
||||||
max_sample_estimate = (size_t)ceill(tmpMaxSamples * tmpRate);
|
max_sample_estimate = (size_t)ceill(tmpMaxSamples * tmpRate);
|
||||||
if (max_sample_estimate > max_sample_requirement) max_sample_estimate = max_sample_requirement;
|
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:
|
public:
|
||||||
using map = std::map<std::string, PlaybackBackend*>;
|
using map = std::map<std::string, PlaybackBackend*>;
|
||||||
using iterator = map::iterator;
|
using iterator = map::iterator;
|
||||||
|
@ -62,8 +69,12 @@ class PlaybackBackend {
|
||||||
inline virtual void add_licenses() { }
|
inline virtual void add_licenses() { }
|
||||||
inline virtual std::string get_id() {return "";}
|
inline virtual std::string get_id() {return "";}
|
||||||
inline virtual std::string get_name() {return "";}
|
inline virtual std::string get_name() {return "";}
|
||||||
inline virtual void seek(double position) { }
|
inline virtual void seek(double position) { seek_samples(time_to_samples(position)); }
|
||||||
inline virtual double get_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;
|
return position;
|
||||||
}
|
}
|
||||||
inline virtual SDL_AudioSpec get_spec() {
|
inline virtual SDL_AudioSpec get_spec() {
|
||||||
|
@ -102,13 +113,22 @@ class PlaybackBackend {
|
||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
virtual size_t render(void *buf, size_t maxlen);
|
virtual size_t render(void *buf, size_t maxlen);
|
||||||
inline virtual double get_length() {
|
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() {
|
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() {
|
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() {
|
inline virtual std::optional<std::string> get_current_file() {
|
||||||
return open ? current_file : std::optional<std::string>();
|
return open ? current_file : std::optional<std::string>();
|
||||||
|
|
|
@ -184,7 +184,7 @@ PropertyDataOrError PlaybackProcessServiceImpl::Get(const GetProperty *request)
|
||||||
} break;
|
} break;
|
||||||
case PropertyId::PositionProperty: {
|
case PropertyId::PositionProperty: {
|
||||||
DoubleProperty pos;
|
DoubleProperty pos;
|
||||||
pos.set_value(cur_backend->get_position());
|
pos.set_value(cur_backend->get_position_time());
|
||||||
data->mutable_value()->PackFrom(pos);
|
data->mutable_value()->PackFrom(pos);
|
||||||
} break;
|
} break;
|
||||||
case PropertyId::BackendSpecific: {
|
case PropertyId::BackendSpecific: {
|
||||||
|
@ -338,6 +338,7 @@ MaybeError PlaybackProcessServiceImpl::Init(const InitCommand *cmd) {
|
||||||
}
|
}
|
||||||
lock.set(backend.second, false);
|
lock.set(backend.second, false);
|
||||||
DEBUG.writefln("Using backend: %s", backend.second->get_name().c_str());
|
DEBUG.writefln("Using backend: %s", backend.second->get_name().c_str());
|
||||||
|
backend.second->seek(0.0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!cur_backend_lock.has_value()) {
|
if (!cur_backend_lock.has_value()) {
|
||||||
|
@ -419,7 +420,11 @@ PlaybackProcess::PlaybackProcess(std::vector<std::string> args) {
|
||||||
}
|
}
|
||||||
PlaybackProcess::PlaybackProcess(std::string filename, int idx) {
|
PlaybackProcess::PlaybackProcess(std::string filename, int idx) {
|
||||||
// multi_process = Looper::Options::get_option<bool>("playback.multi_process", true);
|
// multi_process = Looper::Options::get_option<bool>("playback.multi_process", true);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
multi_process = false;
|
||||||
|
#else
|
||||||
multi_process = true;
|
multi_process = true;
|
||||||
|
#endif
|
||||||
done = false;
|
done = false;
|
||||||
this->done = false;
|
this->done = false;
|
||||||
if (multi_process) {
|
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