From 1188a036e9b5e7a28a563ffbadae9b24ea8c4c67 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 4 Sep 2019 20:18:41 +0200 Subject: [PATCH] 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. :^) --- Applications/SoundPlayer/Makefile | 9 +++ Applications/SoundPlayer/SampleWidget.cpp | 45 ++++++++++++++ Applications/SoundPlayer/SampleWidget.h | 19 ++++++ Applications/SoundPlayer/main.cpp | 72 +++++++++++++++++++++++ Kernel/build-root-filesystem.sh | 2 + Kernel/makeall.sh | 1 + 6 files changed, 148 insertions(+) create mode 100644 Applications/SoundPlayer/Makefile create mode 100644 Applications/SoundPlayer/SampleWidget.cpp create mode 100644 Applications/SoundPlayer/SampleWidget.h create mode 100644 Applications/SoundPlayer/main.cpp 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 +#include + +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 + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + printf("usage: %s \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(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(); +} diff --git a/Kernel/build-root-filesystem.sh b/Kernel/build-root-filesystem.sh index ce4affa089..8979c047e5 100755 --- a/Kernel/build-root-filesystem.sh +++ b/Kernel/build-root-filesystem.sh @@ -85,6 +85,7 @@ cp ../Applications/Piano/Piano mnt/bin/Piano cp ../Applications/SystemDialog/SystemDialog mnt/bin/SystemDialog cp ../Applications/ChanViewer/ChanViewer mnt/bin/ChanViewer cp ../Applications/Calculator/Calculator mnt/bin/Calculator +cp ../Applications/SoundPlayer/SoundPlayer mnt/bin/SoundPlayer cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld cp ../Demos/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2 cp ../Demos/RetroFetch/RetroFetch mnt/bin/RetroFetch @@ -123,6 +124,7 @@ ln -s SystemDialog mnt/bin/sd ln -s ChanViewer mnt/bin/cv ln -s Calculator mnt/bin/calc ln -s Inspector mnt/bin/ins +ln -s SoundPlayer mnt/bin/sp echo "done" # Run local sync script, if it exists diff --git a/Kernel/makeall.sh b/Kernel/makeall.sh index b21ee80acf..e87cd3db11 100755 --- a/Kernel/makeall.sh +++ b/Kernel/makeall.sh @@ -55,6 +55,7 @@ build_targets="$build_targets ../Applications/SystemMonitor" build_targets="$build_targets ../Applications/Taskbar" build_targets="$build_targets ../Applications/Terminal" build_targets="$build_targets ../Applications/TextEditor" +build_targets="$build_targets ../Applications/SoundPlayer" build_targets="$build_targets ../Demos/Fire" build_targets="$build_targets ../Demos/HelloWorld"