summaryrefslogtreecommitdiff
path: root/Applications
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-09-04 20:18:41 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-09-04 20:18:41 +0200
commit1188a036e9b5e7a28a563ffbadae9b24ea8c4c67 (patch)
treeff5ab804ffe8fad23510ca1afb4aebeb0ae2d95c /Applications
parent6693e56603888fcfe29a669acc24bd21079f33d2 (diff)
downloadserenity-1188a036e9b5e7a28a563ffbadae9b24ea8c4c67.zip
SoundPlayer: Start working on a GUI sound player application
This can play anything that AWavLoader can load (so obviously only WAV files at the moment.) It works by having a timer that wakes up every 100ms and tries to send a sample buffer to the AudioServer. If our server-side queue is full then we wait until the next timer iteration and try again. We display the most recently enqueued sample buffer in a nice little widget that just plots the samples in green-on-black. :^)
Diffstat (limited to 'Applications')
-rw-r--r--Applications/SoundPlayer/Makefile9
-rw-r--r--Applications/SoundPlayer/SampleWidget.cpp45
-rw-r--r--Applications/SoundPlayer/SampleWidget.h19
-rw-r--r--Applications/SoundPlayer/main.cpp72
4 files changed, 145 insertions, 0 deletions
diff --git a/Applications/SoundPlayer/Makefile b/Applications/SoundPlayer/Makefile
new file mode 100644
index 0000000000..930f535dbc
--- /dev/null
+++ b/Applications/SoundPlayer/Makefile
@@ -0,0 +1,9 @@
+include ../../Makefile.common
+
+OBJS = \
+ SampleWidget.o \
+ main.o
+
+APP = SoundPlayer
+
+include ../Makefile.common
diff --git a/Applications/SoundPlayer/SampleWidget.cpp b/Applications/SoundPlayer/SampleWidget.cpp
new file mode 100644
index 0000000000..f171cdeb24
--- /dev/null
+++ b/Applications/SoundPlayer/SampleWidget.cpp
@@ -0,0 +1,45 @@
+#include "SampleWidget.h"
+#include <LibAudio/ABuffer.h>
+#include <LibGUI/GPainter.h>
+
+SampleWidget::SampleWidget(GWidget* parent)
+ : GFrame(parent)
+{
+ set_frame_shape(FrameShape::Container);
+ set_frame_shadow(FrameShadow::Sunken);
+ set_frame_thickness(2);
+}
+
+SampleWidget::~SampleWidget()
+{
+}
+
+void SampleWidget::paint_event(GPaintEvent& event)
+{
+ GFrame::paint_event(event);
+ GPainter painter(*this);
+ painter.add_clip_rect(event.rect());
+
+ painter.fill_rect(frame_inner_rect(), Color::Black);
+
+ if (!m_buffer)
+ return;
+
+ // FIXME: Right now we only display as many samples from the buffer as we can fit
+ // in the frame_inner_rect(). Maybe scale the samples or something?
+ int samples_to_draw = min(m_buffer->sample_count(), frame_inner_rect().width());
+ for (int x = 0; x < samples_to_draw; ++x) {
+ // FIXME: This might look nicer if drawn as lines.
+ auto& sample = m_buffer->samples()[x];
+ Point p = { x, frame_inner_rect().center().y() + (int)(sample.left * frame_inner_rect().height()) };
+ painter.set_pixel(p, Color::Green);
+ }
+}
+
+void SampleWidget::set_buffer(ABuffer* buffer)
+{
+ if (m_buffer == buffer)
+ return;
+ m_buffer = buffer;
+ update();
+}
diff --git a/Applications/SoundPlayer/SampleWidget.h b/Applications/SoundPlayer/SampleWidget.h
new file mode 100644
index 0000000000..3325f3d6c9
--- /dev/null
+++ b/Applications/SoundPlayer/SampleWidget.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <LibGUI/GFrame.h>
+
+class ABuffer;
+
+class SampleWidget final : public GFrame {
+ C_OBJECT(SampleWidget)
+public:
+ explicit SampleWidget(GWidget* parent);
+ virtual ~SampleWidget() override;
+
+ void set_buffer(ABuffer*);
+
+private:
+ virtual void paint_event(GPaintEvent&) override;
+
+ RefPtr<ABuffer> m_buffer;
+};
diff --git a/Applications/SoundPlayer/main.cpp b/Applications/SoundPlayer/main.cpp
new file mode 100644
index 0000000000..4fe842dfe8
--- /dev/null
+++ b/Applications/SoundPlayer/main.cpp
@@ -0,0 +1,72 @@
+#include "SampleWidget.h"
+#include <LibAudio/ABuffer.h>
+#include <LibAudio/AClientConnection.h>
+#include <LibAudio/AWavLoader.h>
+#include <LibCore/CTimer.h>
+#include <LibGUI/GApplication.h>
+#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GButton.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+ if (argc != 2) {
+ printf("usage: %s <wav-file>\n", argv[0]);
+ return 0;
+ }
+
+ GApplication app(argc, argv);
+
+ String path = argv[1];
+ AWavLoader loader(path);
+
+ if (loader.has_error()) {
+ fprintf(stderr, "Failed to load WAV file: %s (%s)\n", path.characters(), loader.error_string());
+ return 1;
+ }
+
+ AClientConnection audio_client;
+ audio_client.handshake();
+
+ auto* window = new GWindow;
+ window->set_title("SoundPlayer");
+ window->set_rect(300, 300, 300, 200);
+
+ auto* widget = new GWidget;
+ window->set_main_widget(widget);
+
+ widget->set_fill_with_background_color(true);
+ widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
+ widget->layout()->set_margins({ 2, 2, 2, 2 });
+
+ auto* sample_widget = new SampleWidget(widget);
+
+ auto* button = new GButton("Quit", widget);
+ button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+ button->set_preferred_size(0, 20);
+ button->on_click = [&](auto&) {
+ app.quit();
+ };
+
+ auto next_sample_buffer = loader.get_more_samples();
+
+ new CTimer(100, [&] {
+ if (!next_sample_buffer) {
+ sample_widget->set_buffer(nullptr);
+ return;
+ }
+ bool enqueued = audio_client.try_enqueue(*next_sample_buffer);
+ if (!enqueued)
+ return;
+ sample_widget->set_buffer(next_sample_buffer);
+ next_sample_buffer = loader.get_more_samples(16 * KB);
+ if (!next_sample_buffer) {
+ dbg() << "Exhausted samples :^)";
+ }
+ });
+
+ window->show();
+ return app.exec();
+}