summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkleines Filmröllchen <filmroellchen@serenityos.org>2022-11-13 18:37:46 +0100
committerTim Flynn <trflynn89@pm.me>2023-02-08 20:07:37 -0500
commite127c4acdc081b83f21513873984e19cf4c9f6a1 (patch)
tree4074688718f10df14be9be4bded085c11e1a846f
parent392dac08187cbaadce4a9f54f684619622666603 (diff)
downloadserenity-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.cpp6
-rw-r--r--Userland/Applications/Piano/AudioPlayerLoop.h3
-rw-r--r--Userland/Applications/Piano/CMakeLists.txt7
-rw-r--r--Userland/Applications/Piano/ExportProgressWidget.gml22
-rw-r--r--Userland/Applications/Piano/ExportProgressWindow.cpp55
-rw-r--r--Userland/Applications/Piano/ExportProgressWindow.h33
-rw-r--r--Userland/Applications/Piano/main.cpp9
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&) {