diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-09-04 20:18:41 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-09-04 20:18:41 +0200 |
commit | 1188a036e9b5e7a28a563ffbadae9b24ea8c4c67 (patch) | |
tree | ff5ab804ffe8fad23510ca1afb4aebeb0ae2d95c /Applications | |
parent | 6693e56603888fcfe29a669acc24bd21079f33d2 (diff) | |
download | serenity-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/Makefile | 9 | ||||
-rw-r--r-- | Applications/SoundPlayer/SampleWidget.cpp | 45 | ||||
-rw-r--r-- | Applications/SoundPlayer/SampleWidget.h | 19 | ||||
-rw-r--r-- | Applications/SoundPlayer/main.cpp | 72 |
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(); +} |