mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:48:10 +00:00
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. :^)
This commit is contained in:
parent
6693e56603
commit
1188a036e9
6 changed files with 148 additions and 0 deletions
9
Applications/SoundPlayer/Makefile
Normal file
9
Applications/SoundPlayer/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
include ../../Makefile.common
|
||||
|
||||
OBJS = \
|
||||
SampleWidget.o \
|
||||
main.o
|
||||
|
||||
APP = SoundPlayer
|
||||
|
||||
include ../Makefile.common
|
45
Applications/SoundPlayer/SampleWidget.cpp
Normal file
45
Applications/SoundPlayer/SampleWidget.cpp
Normal file
|
@ -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();
|
||||
}
|
19
Applications/SoundPlayer/SampleWidget.h
Normal file
19
Applications/SoundPlayer/SampleWidget.h
Normal file
|
@ -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;
|
||||
};
|
72
Applications/SoundPlayer/main.cpp
Normal file
72
Applications/SoundPlayer/main.cpp
Normal file
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue