forked from SerenityOS/serenity
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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. :^)
- Loading branch information
1 parent
6693e56
commit 1188a03
Showing
6 changed files
with
148 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
include ../../Makefile.common | ||
|
||
OBJS = \ | ||
SampleWidget.o \ | ||
main.o | ||
|
||
APP = SoundPlayer | ||
|
||
include ../Makefile.common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters