mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:12:45 +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/SystemDialog/SystemDialog mnt/bin/SystemDialog | ||||||
| cp ../Applications/ChanViewer/ChanViewer mnt/bin/ChanViewer | cp ../Applications/ChanViewer/ChanViewer mnt/bin/ChanViewer | ||||||
| cp ../Applications/Calculator/Calculator mnt/bin/Calculator | cp ../Applications/Calculator/Calculator mnt/bin/Calculator | ||||||
|  | cp ../Applications/SoundPlayer/SoundPlayer mnt/bin/SoundPlayer | ||||||
| cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld | cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld | ||||||
| cp ../Demos/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2 | cp ../Demos/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2 | ||||||
| cp ../Demos/RetroFetch/RetroFetch mnt/bin/RetroFetch | 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 ChanViewer mnt/bin/cv | ||||||
| ln -s Calculator mnt/bin/calc | ln -s Calculator mnt/bin/calc | ||||||
| ln -s Inspector mnt/bin/ins | ln -s Inspector mnt/bin/ins | ||||||
|  | ln -s SoundPlayer mnt/bin/sp | ||||||
| echo "done" | echo "done" | ||||||
| 
 | 
 | ||||||
| # Run local sync script, if it exists | # 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/Taskbar" | ||||||
| build_targets="$build_targets ../Applications/Terminal" | build_targets="$build_targets ../Applications/Terminal" | ||||||
| build_targets="$build_targets ../Applications/TextEditor" | build_targets="$build_targets ../Applications/TextEditor" | ||||||
|  | build_targets="$build_targets ../Applications/SoundPlayer" | ||||||
| 
 | 
 | ||||||
| build_targets="$build_targets ../Demos/Fire" | build_targets="$build_targets ../Demos/Fire" | ||||||
| build_targets="$build_targets ../Demos/HelloWorld" | build_targets="$build_targets ../Demos/HelloWorld" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling