diff options
author | kleines Filmröllchen <filmroellchen@serenityos.org> | 2022-11-13 18:37:46 +0100 |
---|---|---|
committer | Tim Flynn <trflynn89@pm.me> | 2023-02-08 20:07:37 -0500 |
commit | e127c4acdc081b83f21513873984e19cf4c9f6a1 (patch) | |
tree | 4074688718f10df14be9be4bded085c11e1a846f | |
parent | 392dac08187cbaadce4a9f54f684619622666603 (diff) | |
download | serenity-e127c4acdc081b83f21513873984e19cf4c9f6a1.zip |
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 :^)
-rw-r--r-- | Userland/Applications/Piano/AudioPlayerLoop.cpp | 6 | ||||
-rw-r--r-- | Userland/Applications/Piano/AudioPlayerLoop.h | 3 | ||||
-rw-r--r-- | Userland/Applications/Piano/CMakeLists.txt | 7 | ||||
-rw-r--r-- | Userland/Applications/Piano/ExportProgressWidget.gml | 22 | ||||
-rw-r--r-- | Userland/Applications/Piano/ExportProgressWindow.cpp | 55 | ||||
-rw-r--r-- | Userland/Applications/Piano/ExportProgressWindow.h | 33 | ||||
-rw-r--r-- | Userland/Applications/Piano/main.cpp | 9 |
7 files changed, 132 insertions, 3 deletions
diff --git a/Userland/Applications/Piano/AudioPlayerLoop.cpp b/Userland/Applications/Piano/AudioPlayerLoop.cpp index 2627a875b1..2a4d820410 100644 --- a/Userland/Applications/Piano/AudioPlayerLoop.cpp +++ b/Userland/Applications/Piano/AudioPlayerLoop.cpp @@ -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(); diff --git a/Userland/Applications/Piano/AudioPlayerLoop.h b/Userland/Applications/Piano/AudioPlayerLoop.h index 5544f979dc..3a6713d5d3 100644 --- a/Userland/Applications/Piano/AudioPlayerLoop.h +++ b/Userland/Applications/Piano/AudioPlayerLoop.h @@ -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; }; diff --git a/Userland/Applications/Piano/CMakeLists.txt b/Userland/Applications/Piano/CMakeLists.txt index ad8625a57d..f6811145de 100644 --- a/Userland/Applications/Piano/CMakeLists.txt +++ b/Userland/Applications/Piano/CMakeLists.txt @@ -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) diff --git a/Userland/Applications/Piano/ExportProgressWidget.gml b/Userland/Applications/Piano/ExportProgressWidget.gml new file mode 100644 index 0000000000..a5078b8d38 --- /dev/null +++ b/Userland/Applications/Piano/ExportProgressWidget.gml @@ -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 + } +} diff --git a/Userland/Applications/Piano/ExportProgressWindow.cpp b/Userland/Applications/Piano/ExportProgressWindow.cpp new file mode 100644 index 0000000000..77d8e491f9 --- /dev/null +++ b/Userland/Applications/Piano/ExportProgressWindow.cpp @@ -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(); + } +} diff --git a/Userland/Applications/Piano/ExportProgressWindow.h b/Userland/Applications/Piano/ExportProgressWindow.h new file mode 100644 index 0000000000..d5a0e6a0d5 --- /dev/null +++ b/Userland/Applications/Piano/ExportProgressWindow.h @@ -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; +}; diff --git a/Userland/Applications/Piano/main.cpp b/Userland/Applications/Piano/main.cpp index c8bcd3d37d..954d876a5a 100644 --- a/Userland/Applications/Piano/main.cpp +++ b/Userland/Applications/Piano/main.cpp @@ -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&) { |