mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:07:44 +00:00
SoundPlayer: Update the SoundPlayer interface
Also fix rebase conflict
This commit is contained in:
parent
45e928bfb2
commit
7aa5297835
5 changed files with 395 additions and 59 deletions
|
@ -25,19 +25,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SoundPlayerWidget.h"
|
#include "SoundPlayerWidget.h"
|
||||||
|
#include "Common.h"
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibCore/MimeData.h>
|
#include <LibCore/MimeData.h>
|
||||||
#include <LibGUI/BoxLayout.h>
|
#include <LibGUI/BoxLayout.h>
|
||||||
#include <LibGUI/Button.h>
|
#include <LibGUI/Button.h>
|
||||||
#include <LibGUI/Label.h>
|
#include <LibGUI/Label.h>
|
||||||
#include <LibGUI/MessageBox.h>
|
#include <LibGUI/MessageBox.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, NonnullRefPtr<Audio::ClientConnection> connection)
|
SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager)
|
||||||
: m_window(window)
|
: m_window(window)
|
||||||
, m_connection(connection)
|
, m_connection(connection)
|
||||||
, m_manager(connection)
|
, m_manager(manager)
|
||||||
{
|
{
|
||||||
|
window.set_resizable(false);
|
||||||
|
window.resize(350, 140);
|
||||||
|
|
||||||
set_fill_with_background_color(true);
|
set_fill_with_background_color(true);
|
||||||
set_layout<GUI::VerticalBoxLayout>();
|
set_layout<GUI::VerticalBoxLayout>();
|
||||||
layout()->set_margins({ 2, 2, 2, 2 });
|
layout()->set_margins({ 2, 2, 2, 2 });
|
||||||
|
@ -104,16 +107,7 @@ SoundPlayerWidget::~SoundPlayerWidget()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundPlayerWidget::Slider::~Slider()
|
void SoundPlayerWidget::open_file(StringView path)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayerWidget::hide_scope(bool hide)
|
|
||||||
{
|
|
||||||
m_sample_widget->set_visible(!hide);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayerWidget::open_file(String path)
|
|
||||||
{
|
{
|
||||||
NonnullRefPtr<Audio::Loader> loader = Audio::Loader::create(path);
|
NonnullRefPtr<Audio::Loader> loader = Audio::Loader::create(path);
|
||||||
if (loader->has_error() || !loader->sample_rate()) {
|
if (loader->has_error() || !loader->sample_rate()) {
|
||||||
|
@ -192,3 +186,8 @@ void SoundPlayerWidget::update_position(const int position)
|
||||||
|
|
||||||
m_slider->set_value(total_norm_samples);
|
m_slider->set_value(total_norm_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundPlayerWidget::hide_scope(bool hide)
|
||||||
|
{
|
||||||
|
m_sample_widget->set_visible(!hide);
|
||||||
|
}
|
||||||
|
|
|
@ -26,24 +26,28 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
#include "PlaybackManager.h"
|
#include "PlaybackManager.h"
|
||||||
|
#include "Player.h"
|
||||||
#include "SampleWidget.h"
|
#include "SampleWidget.h"
|
||||||
|
#include <AK/NonnullRefPtr.h>
|
||||||
#include <LibGUI/Button.h>
|
#include <LibGUI/Button.h>
|
||||||
#include <LibGUI/Label.h>
|
#include <LibGUI/Label.h>
|
||||||
#include <LibGUI/Slider.h>
|
|
||||||
#include <LibGUI/Widget.h>
|
#include <LibGUI/Widget.h>
|
||||||
#include <LibGUI/Window.h>
|
#include <LibGUI/Window.h>
|
||||||
|
|
||||||
class SoundPlayerWidget final : public GUI::Widget {
|
class SoundPlayerWidget final : public GUI::Widget
|
||||||
|
, public Player {
|
||||||
C_OBJECT(SoundPlayerWidget)
|
C_OBJECT(SoundPlayerWidget)
|
||||||
public:
|
public:
|
||||||
virtual ~SoundPlayerWidget() override;
|
virtual ~SoundPlayerWidget() override;
|
||||||
void open_file(String path);
|
void open_file(StringView path) override;
|
||||||
void hide_scope(bool);
|
void hide_scope(bool);
|
||||||
PlaybackManager& manager() { return m_manager; }
|
Audio::ClientConnection& client_connection() override { return m_connection; }
|
||||||
|
PlaybackManager& playback_manager() override { return m_manager; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit SoundPlayerWidget(GUI::Window&, NonnullRefPtr<Audio::ClientConnection>);
|
explicit SoundPlayerWidget(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager);
|
||||||
|
|
||||||
virtual void drop_event(GUI::DropEvent&) override;
|
virtual void drop_event(GUI::DropEvent&) override;
|
||||||
|
|
||||||
|
@ -52,35 +56,10 @@ private:
|
||||||
int normalize_rate(int) const;
|
int normalize_rate(int) const;
|
||||||
int denormalize_rate(int) const;
|
int denormalize_rate(int) const;
|
||||||
|
|
||||||
class Slider final : public GUI::Slider {
|
|
||||||
C_OBJECT(Slider)
|
|
||||||
public:
|
|
||||||
virtual ~Slider() override;
|
|
||||||
Function<void(int)> on_knob_released;
|
|
||||||
void set_value(int value)
|
|
||||||
{
|
|
||||||
if (!knob_dragging())
|
|
||||||
GUI::Slider::set_value(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Slider(Orientation orientation)
|
|
||||||
: GUI::Slider(orientation)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void mouseup_event(GUI::MouseEvent& event) override
|
|
||||||
{
|
|
||||||
if (on_knob_released && is_enabled())
|
|
||||||
on_knob_released(value());
|
|
||||||
|
|
||||||
GUI::Slider::mouseup_event(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GUI::Window& m_window;
|
GUI::Window& m_window;
|
||||||
NonnullRefPtr<Audio::ClientConnection> m_connection;
|
Audio::ClientConnection& m_connection;
|
||||||
PlaybackManager m_manager;
|
PlaybackManager& m_manager;
|
||||||
|
|
||||||
float m_sample_ratio { 1.0 };
|
float m_sample_ratio { 1.0 };
|
||||||
RefPtr<GUI::Label> m_status;
|
RefPtr<GUI::Label> m_status;
|
||||||
RefPtr<GUI::Label> m_elapsed;
|
RefPtr<GUI::Label> m_elapsed;
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Cesar Torres <shortanemoia@protonmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SoundPlayerWidgetAdvancedView.h"
|
||||||
|
#include "BarsVisualizationWidget.h"
|
||||||
|
#include "PlaybackManager.h"
|
||||||
|
#include "SoundPlayerWidget.h"
|
||||||
|
#include <AK/SIMD.h>
|
||||||
|
#include <LibGUI/Action.h>
|
||||||
|
#include <LibGUI/BoxLayout.h>
|
||||||
|
#include <LibGUI/Button.h>
|
||||||
|
#include <LibGUI/DragOperation.h>
|
||||||
|
#include <LibGUI/Label.h>
|
||||||
|
#include <LibGUI/MessageBox.h>
|
||||||
|
#include <LibGUI/Slider.h>
|
||||||
|
#include <LibGUI/ToolBar.h>
|
||||||
|
#include <LibGUI/ToolBarContainer.h>
|
||||||
|
#include <LibGUI/Window.h>
|
||||||
|
#include <LibGfx/Bitmap.h>
|
||||||
|
|
||||||
|
SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager)
|
||||||
|
: m_window(window)
|
||||||
|
, m_connection(connection)
|
||||||
|
, m_manager(manager)
|
||||||
|
{
|
||||||
|
|
||||||
|
window.resize(455, 350);
|
||||||
|
window.set_minimum_size(440, 130);
|
||||||
|
window.set_resizable(true);
|
||||||
|
|
||||||
|
set_fill_with_background_color(true);
|
||||||
|
set_layout<GUI::VerticalBoxLayout>();
|
||||||
|
|
||||||
|
m_play_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/play.png");
|
||||||
|
m_pause_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/pause.png");
|
||||||
|
m_stop_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/stop.png");
|
||||||
|
m_back_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/go-back.png");
|
||||||
|
m_next_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png");
|
||||||
|
|
||||||
|
m_visualization = add<BarsVisualizationWidget>();
|
||||||
|
|
||||||
|
m_playback_progress_slider = add<Slider>(Orientation::Horizontal);
|
||||||
|
m_playback_progress_slider->set_fixed_height(20);
|
||||||
|
m_playback_progress_slider->set_min(0);
|
||||||
|
m_playback_progress_slider->set_max(m_manager.total_length() * 44100); //this value should be set when we load a new file
|
||||||
|
m_playback_progress_slider->on_knob_released = [&](int value) {
|
||||||
|
m_manager.seek(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto& toolbar_container = add<GUI::ToolBarContainer>();
|
||||||
|
|
||||||
|
auto& menubar = toolbar_container.add<GUI::ToolBar>();
|
||||||
|
|
||||||
|
m_play_button = menubar.add<GUI::Button>();
|
||||||
|
m_play_button->set_icon(*m_play_icon);
|
||||||
|
m_play_button->set_fixed_width(50);
|
||||||
|
|
||||||
|
m_play_button->on_click = [&](unsigned) {
|
||||||
|
bool paused = m_manager.toggle_pause();
|
||||||
|
m_play_button->set_icon(paused ? *m_play_icon : *m_pause_icon);
|
||||||
|
m_stop_button->set_enabled(!paused);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_stop_button = menubar.add<GUI::Button>();
|
||||||
|
m_stop_button->set_icon(*m_stop_icon);
|
||||||
|
m_stop_button->set_fixed_width(50);
|
||||||
|
m_stop_button->on_click = [&](unsigned) {
|
||||||
|
m_manager.stop();
|
||||||
|
m_play_button->set_icon(*m_play_icon);
|
||||||
|
m_stop_button->set_enabled(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto& timestamp_label = menubar.add<GUI::Label>();
|
||||||
|
timestamp_label.set_fixed_width(110);
|
||||||
|
timestamp_label.set_text("Elapsed: 00:00:00");
|
||||||
|
|
||||||
|
// filler_label
|
||||||
|
menubar.add<GUI::Label>();
|
||||||
|
|
||||||
|
auto& back_button = menubar.add<GUI::Button>();
|
||||||
|
back_button.set_fixed_width(50);
|
||||||
|
back_button.set_icon(*m_back_icon);
|
||||||
|
|
||||||
|
auto& next_button = menubar.add<GUI::Button>();
|
||||||
|
next_button.set_fixed_width(50);
|
||||||
|
next_button.set_icon(*m_next_icon);
|
||||||
|
|
||||||
|
m_volume_label = &menubar.add<GUI::Label>();
|
||||||
|
m_volume_label->set_fixed_width(30);
|
||||||
|
m_volume_label->set_text("100%");
|
||||||
|
|
||||||
|
auto& volume_slider = menubar.add<GUI::HorizontalSlider>();
|
||||||
|
volume_slider.set_fixed_width(95);
|
||||||
|
volume_slider.set_min(0);
|
||||||
|
volume_slider.set_max(150);
|
||||||
|
volume_slider.set_value(100);
|
||||||
|
|
||||||
|
volume_slider.on_change = [&](int value) {
|
||||||
|
double volume = m_nonlinear_volume_slider ? (double)(value * value) / (100 * 100) : value / 100.;
|
||||||
|
m_volume_label->set_text(String::formatted("{}%", (int)(volume * 100)));
|
||||||
|
set_volume(volume);
|
||||||
|
};
|
||||||
|
|
||||||
|
set_volume(1.);
|
||||||
|
set_nonlinear_volume_slider(false);
|
||||||
|
|
||||||
|
m_manager.on_update = [&]() {
|
||||||
|
//TODO: make this program support other sample rates
|
||||||
|
int samples_played = m_connection.get_played_samples() + m_manager.last_seek();
|
||||||
|
int current_second = samples_played / 44100;
|
||||||
|
timestamp_label.set_text(String::formatted("Elapsed: {:02}:{:02}:{:02}", current_second / 3600, current_second / 60, current_second % 60));
|
||||||
|
m_playback_progress_slider->set_value(samples_played);
|
||||||
|
|
||||||
|
dynamic_cast<Visualization*>(m_visualization.ptr())->set_buffer(m_manager.current_buffer());
|
||||||
|
};
|
||||||
|
|
||||||
|
m_manager.on_load_sample_buffer = [&](Audio::Buffer& buffer) {
|
||||||
|
if (m_volume == 1.)
|
||||||
|
return;
|
||||||
|
auto sample_count = buffer.sample_count();
|
||||||
|
if (sample_count % 4 == 0) {
|
||||||
|
const int total_iter = sample_count / (sizeof(AK::SIMD::f64x4) / sizeof(double) / 2);
|
||||||
|
AK::SIMD::f64x4* sample_ptr = const_cast<AK::SIMD::f64x4*>(reinterpret_cast<const AK::SIMD::f64x4*>((buffer.data())));
|
||||||
|
for (int i = 0; i < total_iter; ++i) {
|
||||||
|
sample_ptr[i] = sample_ptr[i] * m_volume;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const int total_iter = sample_count / (sizeof(AK::SIMD::f64x2) / sizeof(double) / 2);
|
||||||
|
AK::SIMD::f64x2* sample_ptr = const_cast<AK::SIMD::f64x2*>(reinterpret_cast<const AK::SIMD::f64x2*>((buffer.data())));
|
||||||
|
for (int i = 0; i < total_iter; ++i) {
|
||||||
|
sample_ptr[i] = sample_ptr[i] * m_volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayerWidgetAdvancedView::set_volume(double value)
|
||||||
|
{
|
||||||
|
m_volume = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayerWidgetAdvancedView::open_file(StringView path)
|
||||||
|
{
|
||||||
|
NonnullRefPtr<Audio::Loader> loader = Audio::Loader::create(path);
|
||||||
|
if (loader->has_error() || !loader->sample_rate()) {
|
||||||
|
const String error_string = loader->error_string();
|
||||||
|
GUI::MessageBox::show(&m_window, String::formatted("Failed to load audio file: {} ({})", path, error_string.is_null() ? "Unknown error" : error_string),
|
||||||
|
"Filetype error", GUI::MessageBox::Type::Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_window.set_title(String::formatted("{} - SoundPlayer", loader->file()->filename()));
|
||||||
|
m_playback_progress_slider->set_max(loader->total_samples());
|
||||||
|
m_manager.set_loader(move(loader));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayerWidgetAdvancedView::set_nonlinear_volume_slider(bool nonlinear)
|
||||||
|
{
|
||||||
|
m_nonlinear_volume_slider = nonlinear;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayerWidgetAdvancedView::drop_event(GUI::DropEvent& event)
|
||||||
|
{
|
||||||
|
event.accept();
|
||||||
|
window()->move_to_front();
|
||||||
|
|
||||||
|
if (event.mime_data().has_urls()) {
|
||||||
|
auto urls = event.mime_data().urls();
|
||||||
|
if (urls.is_empty())
|
||||||
|
return;
|
||||||
|
open_file(urls.first().path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundPlayerWidgetAdvancedView::~SoundPlayerWidgetAdvancedView()
|
||||||
|
{
|
||||||
|
m_manager.on_load_sample_buffer = nullptr;
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Cesar Torres <shortanemoia@protonmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BarsVisualizationWidget.h"
|
||||||
|
#include "PlaybackManager.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "SoundPlayerWidget.h"
|
||||||
|
#include <AK/NonnullRefPtr.h>
|
||||||
|
#include <LibAudio/ClientConnection.h>
|
||||||
|
#include <LibGUI/Widget.h>
|
||||||
|
|
||||||
|
class SoundPlayerWidgetAdvancedView final : public GUI::Widget
|
||||||
|
, public Player {
|
||||||
|
C_OBJECT(SoundPlayerWidgetAdvancedView)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SoundPlayerWidgetAdvancedView(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager);
|
||||||
|
~SoundPlayerWidgetAdvancedView() override;
|
||||||
|
|
||||||
|
void open_file(StringView path) override;
|
||||||
|
Audio::ClientConnection& client_connection() override { return m_connection; }
|
||||||
|
PlaybackManager& playback_manager() override { return m_manager; }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void set_visualization()
|
||||||
|
{
|
||||||
|
m_visualization->remove_from_parent();
|
||||||
|
update();
|
||||||
|
auto new_visualization = T::construct();
|
||||||
|
insert_child_before(new_visualization, *static_cast<Core::Object*>(m_playback_progress_slider.ptr()));
|
||||||
|
m_visualization = new_visualization;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_nonlinear_volume_slider(bool nonlinear);
|
||||||
|
|
||||||
|
void set_volume(double value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drop_event(GUI::DropEvent& event) override;
|
||||||
|
|
||||||
|
GUI::Window& m_window;
|
||||||
|
Audio::ClientConnection& m_connection;
|
||||||
|
PlaybackManager& m_manager;
|
||||||
|
|
||||||
|
RefPtr<GUI::Widget> m_visualization;
|
||||||
|
|
||||||
|
RefPtr<Gfx::Bitmap> m_play_icon;
|
||||||
|
RefPtr<Gfx::Bitmap> m_pause_icon;
|
||||||
|
RefPtr<Gfx::Bitmap> m_stop_icon;
|
||||||
|
RefPtr<Gfx::Bitmap> m_back_icon;
|
||||||
|
RefPtr<Gfx::Bitmap> m_next_icon;
|
||||||
|
|
||||||
|
RefPtr<GUI::Button> m_play_button;
|
||||||
|
RefPtr<GUI::Button> m_stop_button;
|
||||||
|
RefPtr<Slider> m_playback_progress_slider;
|
||||||
|
RefPtr<GUI::Label> m_volume_label;
|
||||||
|
|
||||||
|
double m_volume;
|
||||||
|
bool m_nonlinear_volume_slider;
|
||||||
|
};
|
|
@ -24,7 +24,10 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "NoVisualizationWidget.h"
|
||||||
|
#include "Player.h"
|
||||||
#include "SoundPlayerWidget.h"
|
#include "SoundPlayerWidget.h"
|
||||||
|
#include "SoundPlayerWidgetAdvancedView.h"
|
||||||
#include <LibAudio/ClientConnection.h>
|
#include <LibAudio/ClientConnection.h>
|
||||||
#include <LibGUI/Action.h>
|
#include <LibGUI/Action.h>
|
||||||
#include <LibGUI/Application.h>
|
#include <LibGUI/Application.h>
|
||||||
|
@ -52,6 +55,8 @@ int main(int argc, char** argv)
|
||||||
auto audio_client = Audio::ClientConnection::construct();
|
auto audio_client = Audio::ClientConnection::construct();
|
||||||
audio_client->handshake();
|
audio_client->handshake();
|
||||||
|
|
||||||
|
PlaybackManager playback_manager(audio_client);
|
||||||
|
|
||||||
if (pledge("stdio recvfd sendfd accept rpath thread", nullptr) < 0) {
|
if (pledge("stdio recvfd sendfd accept rpath thread", nullptr) < 0) {
|
||||||
perror("pledge");
|
perror("pledge");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -61,31 +66,55 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
auto window = GUI::Window::construct();
|
auto window = GUI::Window::construct();
|
||||||
window->set_title("Sound Player");
|
window->set_title("Sound Player");
|
||||||
window->set_resizable(false);
|
|
||||||
window->resize(350, 140);
|
|
||||||
window->set_icon(app_icon.bitmap_for_size(16));
|
window->set_icon(app_icon.bitmap_for_size(16));
|
||||||
|
|
||||||
auto menubar = GUI::MenuBar::construct();
|
auto menubar = GUI::MenuBar::construct();
|
||||||
auto& app_menu = menubar->add_menu("File");
|
|
||||||
auto& player = window->set_main_widget<SoundPlayerWidget>(window, audio_client);
|
|
||||||
|
|
||||||
|
auto& app_menu = menubar->add_menu("File");
|
||||||
|
// start in simple view by default
|
||||||
|
Player* player = &window->set_main_widget<SoundPlayerWidget>(window, audio_client, playback_manager);
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
String path = argv[1];
|
String path = argv[1];
|
||||||
player.open_file(path);
|
player->open_file(path);
|
||||||
player.manager().play();
|
player->playback_manager().play();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hide_scope = GUI::Action::create_checkable("Hide scope", { Mod_Ctrl, Key_H }, [&](auto& action) {
|
|
||||||
player.hide_scope(action.is_checked());
|
|
||||||
});
|
|
||||||
|
|
||||||
app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
|
app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
|
||||||
Optional<String> path = GUI::FilePicker::get_open_filepath(window, "Open sound file...");
|
Optional<String> path = GUI::FilePicker::get_open_filepath(window, "Open sound file...");
|
||||||
if (path.has_value()) {
|
if (path.has_value()) {
|
||||||
player.open_file(path.value());
|
player->open_file(path.value());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
app_menu.add_action(move(hide_scope));
|
|
||||||
|
RefPtr<GUI::Action> hide_scope;
|
||||||
|
|
||||||
|
auto advanced_view_check = GUI::Action::create_checkable("Advanced view", { Mod_Ctrl, Key_A }, [&](auto& action) {
|
||||||
|
window->close();
|
||||||
|
if (action.is_checked()) {
|
||||||
|
player = &window->set_main_widget<SoundPlayerWidgetAdvancedView>(window, audio_client, playback_manager);
|
||||||
|
hide_scope->set_checkable(false);
|
||||||
|
} else {
|
||||||
|
player = &window->set_main_widget<SoundPlayerWidget>(window, audio_client, playback_manager);
|
||||||
|
hide_scope->set_checkable(true);
|
||||||
|
}
|
||||||
|
window->show();
|
||||||
|
});
|
||||||
|
app_menu.add_action(advanced_view_check);
|
||||||
|
|
||||||
|
hide_scope = GUI::Action::create_checkable("Hide visualization (legacy view)", { Mod_Ctrl, Key_H }, [&](auto& action) {
|
||||||
|
if (!advanced_view_check->is_checked())
|
||||||
|
static_cast<SoundPlayerWidget*>(player)->hide_scope(action.is_checked());
|
||||||
|
});
|
||||||
|
|
||||||
|
auto linear_volume_slider = GUI::Action::create_checkable("Nonlinear volume slider", [&](auto& action) {
|
||||||
|
if (advanced_view_check->is_checked())
|
||||||
|
static_cast<SoundPlayerWidgetAdvancedView*>(player)->set_nonlinear_volume_slider(action.is_checked());
|
||||||
|
});
|
||||||
|
app_menu.add_action(linear_volume_slider);
|
||||||
|
|
||||||
|
auto ptr_copy = hide_scope;
|
||||||
|
|
||||||
|
app_menu.add_action(ptr_copy.release_nonnull());
|
||||||
app_menu.add_separator();
|
app_menu.add_separator();
|
||||||
app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
|
app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
|
||||||
app->quit();
|
app->quit();
|
||||||
|
@ -94,11 +123,55 @@ int main(int argc, char** argv)
|
||||||
auto& playback_menu = menubar->add_menu("Playback");
|
auto& playback_menu = menubar->add_menu("Playback");
|
||||||
|
|
||||||
auto loop = GUI::Action::create_checkable("Loop", { Mod_Ctrl, Key_R }, [&](auto& action) {
|
auto loop = GUI::Action::create_checkable("Loop", { Mod_Ctrl, Key_R }, [&](auto& action) {
|
||||||
player.manager().loop(action.is_checked());
|
player->playback_manager().loop(action.is_checked());
|
||||||
});
|
});
|
||||||
|
|
||||||
playback_menu.add_action(move(loop));
|
playback_menu.add_action(move(loop));
|
||||||
|
|
||||||
|
auto& visualization_menu = menubar->add_menu("Visualization");
|
||||||
|
Vector<NonnullRefPtr<GUI::Action>> visualization_checkmarks;
|
||||||
|
GUI::Action* checked_vis = nullptr;
|
||||||
|
auto uncheck_all_but = [&](GUI::Action& one) {for (auto& a : visualization_checkmarks) if (a != &one) a->set_checked(false); };
|
||||||
|
|
||||||
|
auto bars = GUI::Action::create_checkable("Bars", [&](auto& action) {
|
||||||
|
uncheck_all_but(action);
|
||||||
|
if (checked_vis == &action) {
|
||||||
|
action.set_checked(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checked_vis = &action;
|
||||||
|
static_cast<SoundPlayerWidgetAdvancedView*>(player)->set_visualization<BarsVisualizationWidget>();
|
||||||
|
});
|
||||||
|
bars->set_checked(true);
|
||||||
|
|
||||||
|
visualization_menu.add_action(bars);
|
||||||
|
visualization_checkmarks.append(bars);
|
||||||
|
|
||||||
|
auto samples = GUI::Action::create_checkable("Samples", [&](auto& action) {
|
||||||
|
uncheck_all_but(action);
|
||||||
|
if (checked_vis == &action) {
|
||||||
|
action.set_checked(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checked_vis = &action;
|
||||||
|
static_cast<SoundPlayerWidgetAdvancedView*>(player)->set_visualization<SampleWidget>();
|
||||||
|
});
|
||||||
|
|
||||||
|
visualization_menu.add_action(samples);
|
||||||
|
visualization_checkmarks.append(samples);
|
||||||
|
|
||||||
|
auto none = GUI::Action::create_checkable("None", [&](auto& action) {
|
||||||
|
uncheck_all_but(action);
|
||||||
|
if (checked_vis == &action) {
|
||||||
|
action.set_checked(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static_cast<SoundPlayerWidgetAdvancedView*>(player)->set_visualization<NoVisualizationWidget>();
|
||||||
|
});
|
||||||
|
|
||||||
|
visualization_menu.add_action(none);
|
||||||
|
visualization_checkmarks.append(none);
|
||||||
|
|
||||||
auto& help_menu = menubar->add_menu("Help");
|
auto& help_menu = menubar->add_menu("Help");
|
||||||
help_menu.add_action(GUI::CommonActions::make_about_action("Sound Player", app_icon, window));
|
help_menu.add_action(GUI::CommonActions::make_about_action("Sound Player", app_icon, window));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue