mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
Piano: Show a progress window when exporting WAV
This exposes that the export is pretty slow, but it's much nicer than having the GUI lock up for 20s :^)
This commit is contained in:
parent
392dac0818
commit
e127c4acdc
Notes:
sideshowbarker
2024-07-17 05:03:11 +09:00
Author: https://github.com/kleinesfilmroellchen Commit: https://github.com/SerenityOS/serenity/commit/e127c4acdc Pull-request: https://github.com/SerenityOS/serenity/pull/16509 Reviewed-by: https://github.com/BenWiederhake Reviewed-by: https://github.com/gmta Reviewed-by: https://github.com/trflynn89
@ -47,7 +47,7 @@ struct AudioLoopDeferredInvoker final : public IPC::DeferredInvoker {
|
||||
Vector<Function<void()>, INLINE_FUNCTIONS> deferred_functions;
|
||||
};
|
||||
|
||||
AudioPlayerLoop::AudioPlayerLoop(TrackManager& track_manager, Atomic<bool>& need_to_write_wav, Threading::MutexProtected<Audio::WavWriter>& wav_writer)
|
||||
AudioPlayerLoop::AudioPlayerLoop(TrackManager& track_manager, Atomic<bool>& need_to_write_wav, Atomic<int>& wav_percent_written, Threading::MutexProtected<Audio::WavWriter>& wav_writer)
|
||||
: m_track_manager(track_manager)
|
||||
, m_buffer(FixedArray<DSP::Sample>::must_create_but_fixme_should_propagate_errors(sample_count))
|
||||
, m_pipeline_thread(Threading::Thread::construct([this]() {
|
||||
@ -55,6 +55,7 @@ AudioPlayerLoop::AudioPlayerLoop(TrackManager& track_manager, Atomic<bool>& need
|
||||
},
|
||||
"Audio pipeline"sv))
|
||||
, m_need_to_write_wav(need_to_write_wav)
|
||||
, m_wav_percent_written(wav_percent_written)
|
||||
, m_wav_writer(wav_writer)
|
||||
{
|
||||
m_audio_client = Audio::ConnectionToServer::try_create().release_value_but_fixme_should_propagate_errors();
|
||||
@ -139,10 +140,13 @@ void AudioPlayerLoop::write_wav_if_needed()
|
||||
m_track_manager.reset();
|
||||
m_track_manager.set_should_loop(false);
|
||||
do {
|
||||
// FIXME: This progress detection is crude, but it works for now.
|
||||
m_wav_percent_written.store(static_cast<int>(static_cast<float>(m_track_manager.transport()->time()) / roll_length * 100.0f));
|
||||
m_track_manager.fill_buffer(m_buffer);
|
||||
wav_writer.write_samples(m_buffer.span());
|
||||
} while (m_track_manager.transport()->time());
|
||||
// FIXME: Make sure that the new TrackManager APIs aren't as bad.
|
||||
m_wav_percent_written.store(100);
|
||||
m_track_manager.reset();
|
||||
m_track_manager.set_should_loop(true);
|
||||
wav_writer.finalize();
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
bool is_playing() const { return m_should_play_audio; }
|
||||
|
||||
private:
|
||||
AudioPlayerLoop(TrackManager& track_manager, Atomic<bool>& need_to_write_wav, Threading::MutexProtected<Audio::WavWriter>& wav_writer);
|
||||
AudioPlayerLoop(TrackManager& track_manager, Atomic<bool>& need_to_write_wav, Atomic<int>& wav_percent_written, Threading::MutexProtected<Audio::WavWriter>& wav_writer);
|
||||
|
||||
intptr_t pipeline_thread_main();
|
||||
ErrorOr<void> send_audio_to_server();
|
||||
@ -47,5 +47,6 @@ private:
|
||||
Atomic<bool> m_exit_requested { false };
|
||||
|
||||
Atomic<bool>& m_need_to_write_wav;
|
||||
Atomic<int>& m_wav_percent_written;
|
||||
Threading::MutexProtected<Audio::WavWriter>& m_wav_writer;
|
||||
};
|
||||
|
@ -5,8 +5,11 @@ serenity_component(
|
||||
DEPENDS AudioServer
|
||||
)
|
||||
|
||||
compile_gml(ExportProgressWidget.gml ExportProgressWidget.h export_progress_widget)
|
||||
|
||||
set(SOURCES
|
||||
AudioPlayerLoop.cpp
|
||||
ExportProgressWindow.cpp
|
||||
KeysWidget.cpp
|
||||
KnobsWidget.cpp
|
||||
main.cpp
|
||||
@ -20,5 +23,9 @@ set(SOURCES
|
||||
ProcessorParameterWidget/Slider.cpp
|
||||
)
|
||||
|
||||
set(GENERATED_SOURCES
|
||||
ExportProgressWidget.h
|
||||
)
|
||||
|
||||
serenity_app(Piano ICON app-piano)
|
||||
target_link_libraries(Piano PRIVATE LibAudio LibCore LibDSP LibGfx LibGUI LibIPC LibMain LibThreading)
|
||||
|
22
Userland/Applications/Piano/ExportProgressWidget.gml
Normal file
22
Userland/Applications/Piano/ExportProgressWidget.gml
Normal file
@ -0,0 +1,22 @@
|
||||
@GUI::Widget {
|
||||
fill_with_background_color: true
|
||||
layout: @GUI::VerticalBoxLayout {
|
||||
margins: [4]
|
||||
}
|
||||
|
||||
@GUI::Label {
|
||||
name: "export_message"
|
||||
text_alignment: "Center"
|
||||
// FIXME: Change to dynamic width once that works.
|
||||
min_width: 300
|
||||
preferred_height: "fit"
|
||||
}
|
||||
|
||||
@GUI::HorizontalProgressbar {
|
||||
name: "progress_bar"
|
||||
min: 0
|
||||
max: 100
|
||||
preferred_width: "grow"
|
||||
min_height: 40
|
||||
}
|
||||
}
|
55
Userland/Applications/Piano/ExportProgressWindow.cpp
Normal file
55
Userland/Applications/Piano/ExportProgressWindow.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "ExportProgressWindow.h"
|
||||
#include "LibGUI/Icon.h"
|
||||
#include <AK/DeprecatedString.h>
|
||||
#include <Applications/Piano/ExportProgressWidget.h>
|
||||
#include <LibGUI/Label.h>
|
||||
#include <LibGUI/Widget.h>
|
||||
#include <LibGUI/Window.h>
|
||||
|
||||
ExportProgressWindow::ExportProgressWindow(GUI::Window& parent_window, Atomic<int>& wav_percent_written)
|
||||
: GUI::Dialog(&parent_window)
|
||||
, m_wav_percent_written(wav_percent_written)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<void> ExportProgressWindow::initialize_fallibles()
|
||||
{
|
||||
auto main_widget = TRY(set_main_widget<GUI::Widget>());
|
||||
TRY(main_widget->load_from_gml(export_progress_widget));
|
||||
|
||||
set_resizable(false);
|
||||
set_closeable(false);
|
||||
set_title("Rendering audio");
|
||||
set_icon(GUI::Icon::default_icon("app-piano"sv).bitmap_for_size(16));
|
||||
|
||||
m_progress_bar = *main_widget->find_descendant_of_type_named<GUI::HorizontalProgressbar>("progress_bar");
|
||||
m_label = *main_widget->find_descendant_of_type_named<GUI::Label>("export_message");
|
||||
|
||||
start_timer(250);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ExportProgressWindow::set_filename(StringView filename)
|
||||
{
|
||||
m_label->set_text(DeprecatedString::formatted("Rendering audio to {}…", filename));
|
||||
update();
|
||||
}
|
||||
|
||||
void ExportProgressWindow::timer_event(Core::TimerEvent&)
|
||||
{
|
||||
m_progress_bar->set_value(m_wav_percent_written.load());
|
||||
if (window_id() != 0)
|
||||
set_progress(m_wav_percent_written.load());
|
||||
|
||||
if (m_wav_percent_written.load() == 100) {
|
||||
m_wav_percent_written.store(0);
|
||||
close();
|
||||
}
|
||||
}
|
33
Userland/Applications/Piano/ExportProgressWindow.h
Normal file
33
Userland/Applications/Piano/ExportProgressWindow.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibCore/Event.h>
|
||||
#include <LibGUI/Dialog.h>
|
||||
#include <LibGUI/Label.h>
|
||||
#include <LibGUI/Progressbar.h>
|
||||
|
||||
class ExportProgressWindow : public GUI::Dialog {
|
||||
C_OBJECT(ExportProgressWindow);
|
||||
|
||||
public:
|
||||
virtual ~ExportProgressWindow() override = default;
|
||||
|
||||
ErrorOr<void> initialize_fallibles();
|
||||
|
||||
virtual void timer_event(Core::TimerEvent&) override;
|
||||
|
||||
void set_filename(StringView filename);
|
||||
|
||||
private:
|
||||
ExportProgressWindow(Window& parent_window, Atomic<int>& wav_percent_written);
|
||||
|
||||
Atomic<int>& m_wav_percent_written;
|
||||
|
||||
RefPtr<GUI::HorizontalProgressbar> m_progress_bar;
|
||||
RefPtr<GUI::Label> m_label;
|
||||
};
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "AudioPlayerLoop.h"
|
||||
#include "ExportProgressWindow.h"
|
||||
#include "MainWidget.h"
|
||||
#include "TrackManager.h"
|
||||
#include <AK/Atomic.h>
|
||||
@ -37,8 +38,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
Threading::MutexProtected<Audio::WavWriter> wav_writer;
|
||||
Optional<DeprecatedString> save_path;
|
||||
Atomic<bool> need_to_write_wav = false;
|
||||
Atomic<int> wav_percent_written = 0;
|
||||
|
||||
auto audio_loop = AudioPlayerLoop::construct(track_manager, need_to_write_wav, wav_writer);
|
||||
auto audio_loop = AudioPlayerLoop::construct(track_manager, need_to_write_wav, wav_percent_written, wav_writer);
|
||||
|
||||
auto app_icon = GUI::Icon::default_icon("app-piano"sv);
|
||||
auto window = TRY(GUI::Window::try_create());
|
||||
@ -47,6 +49,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
window->resize(840, 600);
|
||||
window->set_icon(app_icon.bitmap_for_size(16));
|
||||
|
||||
auto wav_progress_window = ExportProgressWindow::construct(*window, wav_percent_written);
|
||||
TRY(wav_progress_window->initialize_fallibles());
|
||||
|
||||
auto main_widget_updater = TRY(Core::Timer::create_repeating(static_cast<int>((1 / 30.0) * 1000), [&] {
|
||||
if (window->is_active())
|
||||
Core::EventLoop::current().post_event(main_widget, make<Core::CustomEvent>(0));
|
||||
@ -71,6 +76,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
return;
|
||||
}
|
||||
need_to_write_wav = true;
|
||||
wav_progress_window->set_filename(save_path.value());
|
||||
wav_progress_window->show();
|
||||
})));
|
||||
TRY(file_menu->try_add_separator());
|
||||
TRY(file_menu->try_add_action(GUI::CommonActions::make_quit_action([](auto&) {
|
||||
|
Loading…
Reference in New Issue
Block a user