mirror of
https://github.com/RGBCube/serenity
synced 2025-05-18 17:55:07 +00:00
LibAudio: Put all classes in the Audio namespace and remove leading A
This commit is contained in:
parent
0bce5f7403
commit
92f77864de
20 changed files with 127 additions and 103 deletions
|
@ -41,7 +41,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
GUI::Application app(argc, argv);
|
GUI::Application app(argc, argv);
|
||||||
|
|
||||||
auto audio_client = AClientConnection::construct();
|
auto audio_client = Audio::ClientConnection::construct();
|
||||||
audio_client->handshake();
|
audio_client->handshake();
|
||||||
|
|
||||||
AudioEngine audio_engine;
|
AudioEngine audio_engine;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "PlaybackManager.h"
|
#include "PlaybackManager.h"
|
||||||
|
|
||||||
PlaybackManager::PlaybackManager(NonnullRefPtr<AClientConnection> connection)
|
PlaybackManager::PlaybackManager(NonnullRefPtr<Audio::ClientConnection> connection)
|
||||||
: m_connection(connection)
|
: m_connection(connection)
|
||||||
{
|
{
|
||||||
m_timer = Core::Timer::construct(100, [&]() {
|
m_timer = Core::Timer::construct(100, [&]() {
|
||||||
|
@ -41,7 +41,7 @@ PlaybackManager::~PlaybackManager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackManager::set_loader(OwnPtr<AWavLoader>&& loader)
|
void PlaybackManager::set_loader(OwnPtr<Audio::WavLoader>&& loader)
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
m_loader = move(loader);
|
m_loader = move(loader);
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
class PlaybackManager final {
|
class PlaybackManager final {
|
||||||
public:
|
public:
|
||||||
PlaybackManager(NonnullRefPtr<AClientConnection>);
|
PlaybackManager(NonnullRefPtr<Audio::ClientConnection>);
|
||||||
~PlaybackManager();
|
~PlaybackManager();
|
||||||
|
|
||||||
void play();
|
void play();
|
||||||
|
@ -44,14 +44,14 @@ public:
|
||||||
void pause();
|
void pause();
|
||||||
void seek(const int position);
|
void seek(const int position);
|
||||||
bool toggle_pause();
|
bool toggle_pause();
|
||||||
void set_loader(OwnPtr<AWavLoader>&&);
|
void set_loader(OwnPtr<Audio::WavLoader>&&);
|
||||||
|
|
||||||
int last_seek() const { return m_last_seek; }
|
int last_seek() const { return m_last_seek; }
|
||||||
bool is_paused() const { return m_paused; }
|
bool is_paused() const { return m_paused; }
|
||||||
float total_length() const { return m_total_length; }
|
float total_length() const { return m_total_length; }
|
||||||
RefPtr<ABuffer> current_buffer() const { return m_current_buffer; }
|
RefPtr<Audio::Buffer> current_buffer() const { return m_current_buffer; }
|
||||||
|
|
||||||
NonnullRefPtr<AClientConnection> connection() const { return m_connection; }
|
NonnullRefPtr<Audio::ClientConnection> connection() const { return m_connection; }
|
||||||
|
|
||||||
Function<void()> on_update;
|
Function<void()> on_update;
|
||||||
|
|
||||||
|
@ -65,10 +65,10 @@ private:
|
||||||
int m_next_ptr { 0 };
|
int m_next_ptr { 0 };
|
||||||
int m_last_seek { 0 };
|
int m_last_seek { 0 };
|
||||||
float m_total_length { 0 };
|
float m_total_length { 0 };
|
||||||
OwnPtr<AWavLoader> m_loader { nullptr };
|
OwnPtr<Audio::WavLoader> m_loader { nullptr };
|
||||||
NonnullRefPtr<AClientConnection> m_connection;
|
NonnullRefPtr<Audio::ClientConnection> m_connection;
|
||||||
RefPtr<ABuffer> m_next_buffer;
|
RefPtr<Audio::Buffer> m_next_buffer;
|
||||||
RefPtr<ABuffer> m_current_buffer;
|
RefPtr<Audio::Buffer> m_current_buffer;
|
||||||
Vector<RefPtr<ABuffer>> m_buffers;
|
Vector<RefPtr<Audio::Buffer>> m_buffers;
|
||||||
RefPtr<Core::Timer> m_timer;
|
RefPtr<Core::Timer> m_timer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,7 +77,7 @@ void SampleWidget::paint_event(GUI::PaintEvent& event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SampleWidget::set_buffer(ABuffer* buffer)
|
void SampleWidget::set_buffer(Audio::Buffer* buffer)
|
||||||
{
|
{
|
||||||
if (m_buffer == buffer)
|
if (m_buffer == buffer)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -28,17 +28,19 @@
|
||||||
|
|
||||||
#include <LibGUI/GFrame.h>
|
#include <LibGUI/GFrame.h>
|
||||||
|
|
||||||
class ABuffer;
|
namespace Audio {
|
||||||
|
class Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
class SampleWidget final : public GUI::Frame {
|
class SampleWidget final : public GUI::Frame {
|
||||||
C_OBJECT(SampleWidget)
|
C_OBJECT(SampleWidget)
|
||||||
public:
|
public:
|
||||||
virtual ~SampleWidget() override;
|
virtual ~SampleWidget() override;
|
||||||
|
|
||||||
void set_buffer(ABuffer*);
|
void set_buffer(Audio::Buffer*);
|
||||||
private:
|
private:
|
||||||
explicit SampleWidget(GUI::Widget* parent);
|
explicit SampleWidget(GUI::Widget* parent);
|
||||||
virtual void paint_event(GUI::PaintEvent&) override;
|
virtual void paint_event(GUI::PaintEvent&) override;
|
||||||
|
|
||||||
RefPtr<ABuffer> m_buffer;
|
RefPtr<Audio::Buffer> m_buffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <LibGUI/GMessageBox.h>
|
#include <LibGUI/GMessageBox.h>
|
||||||
#include <LibM/math.h>
|
#include <LibM/math.h>
|
||||||
|
|
||||||
SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, NonnullRefPtr<AClientConnection> connection)
|
SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, NonnullRefPtr<Audio::ClientConnection> connection)
|
||||||
: m_window(window)
|
: m_window(window)
|
||||||
, m_connection(connection)
|
, m_connection(connection)
|
||||||
, m_manager(connection)
|
, m_manager(connection)
|
||||||
|
@ -124,7 +124,7 @@ void SoundPlayerWidget::open_file(String path)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnPtr<AWavLoader> loader = make<AWavLoader>(path);
|
OwnPtr<Audio::WavLoader> loader = make<Audio::WavLoader>(path);
|
||||||
if (loader->has_error()) {
|
if (loader->has_error()) {
|
||||||
GUI::MessageBox::show(
|
GUI::MessageBox::show(
|
||||||
String::format(
|
String::format(
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
PlaybackManager& manager() { return m_manager; }
|
PlaybackManager& manager() { return m_manager; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit SoundPlayerWidget(GUI::Window&, NonnullRefPtr<AClientConnection>);
|
explicit SoundPlayerWidget(GUI::Window&, NonnullRefPtr<Audio::ClientConnection>);
|
||||||
|
|
||||||
void update_position(const int position);
|
void update_position(const int position);
|
||||||
void update_ui();
|
void update_ui();
|
||||||
|
@ -77,7 +77,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
GUI::Window& m_window;
|
GUI::Window& m_window;
|
||||||
NonnullRefPtr<AClientConnection> m_connection;
|
NonnullRefPtr<Audio::ClientConnection> m_connection;
|
||||||
PlaybackManager m_manager;
|
PlaybackManager m_manager;
|
||||||
float m_sample_ratio;
|
float m_sample_ratio;
|
||||||
RefPtr<GUI::Label> m_status;
|
RefPtr<GUI::Label> m_status;
|
||||||
|
|
|
@ -50,7 +50,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto audio_client = AClientConnection::construct();
|
auto audio_client = Audio::ClientConnection::construct();
|
||||||
audio_client->handshake();
|
audio_client->handshake();
|
||||||
|
|
||||||
if (pledge("stdio shared_buffer accept rpath", nullptr) < 0) {
|
if (pledge("stdio shared_buffer accept rpath", nullptr) < 0) {
|
||||||
|
|
|
@ -31,24 +31,26 @@
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <AK/SharedBuffer.h>
|
#include <AK/SharedBuffer.h>
|
||||||
|
|
||||||
|
namespace Audio {
|
||||||
|
|
||||||
// A single sample in an audio buffer.
|
// A single sample in an audio buffer.
|
||||||
// Values are floating point, and should range from -1.0 to +1.0
|
// Values are floating point, and should range from -1.0 to +1.0
|
||||||
struct ASample {
|
struct Sample {
|
||||||
ASample()
|
Sample()
|
||||||
: left(0)
|
: left(0)
|
||||||
, right(0)
|
, right(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// For mono
|
// For mono
|
||||||
ASample(float left)
|
Sample(float left)
|
||||||
: left(left)
|
: left(left)
|
||||||
, right(left)
|
, right(left)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// For stereo
|
// For stereo
|
||||||
ASample(float left, float right)
|
Sample(float left, float right)
|
||||||
: left(left)
|
: left(left)
|
||||||
, right(right)
|
, right(right)
|
||||||
{
|
{
|
||||||
|
@ -74,7 +76,7 @@ struct ASample {
|
||||||
right *= pct;
|
right *= pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASample& operator+=(const ASample& other)
|
Sample& operator+=(const Sample& other)
|
||||||
{
|
{
|
||||||
left += other.left;
|
left += other.left;
|
||||||
right += other.right;
|
right += other.right;
|
||||||
|
@ -88,9 +90,9 @@ struct ASample {
|
||||||
// Small helper to resample from one playback rate to another
|
// Small helper to resample from one playback rate to another
|
||||||
// This isn't really "smart", in that we just insert (or drop) samples.
|
// This isn't really "smart", in that we just insert (or drop) samples.
|
||||||
// Should do better...
|
// Should do better...
|
||||||
class AResampleHelper {
|
class ResampleHelper {
|
||||||
public:
|
public:
|
||||||
AResampleHelper(float source, float target);
|
ResampleHelper(float source, float target);
|
||||||
|
|
||||||
void process_sample(float sample_l, float sample_r);
|
void process_sample(float sample_l, float sample_r);
|
||||||
bool read_sample(float& next_l, float& next_r);
|
bool read_sample(float& next_l, float& next_r);
|
||||||
|
@ -103,34 +105,34 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// A buffer of audio samples, normalized to 44100hz.
|
// A buffer of audio samples, normalized to 44100hz.
|
||||||
class ABuffer : public RefCounted<ABuffer> {
|
class Buffer : public RefCounted<Buffer> {
|
||||||
public:
|
public:
|
||||||
static RefPtr<ABuffer> from_pcm_data(ByteBuffer& data, AResampleHelper& resampler, int num_channels, int bits_per_sample);
|
static RefPtr<Buffer> from_pcm_data(ByteBuffer& data, ResampleHelper& resampler, int num_channels, int bits_per_sample);
|
||||||
static NonnullRefPtr<ABuffer> create_with_samples(Vector<ASample>&& samples)
|
static NonnullRefPtr<Buffer> create_with_samples(Vector<Sample>&& samples)
|
||||||
{
|
{
|
||||||
return adopt(*new ABuffer(move(samples)));
|
return adopt(*new Buffer(move(samples)));
|
||||||
}
|
}
|
||||||
static NonnullRefPtr<ABuffer> create_with_shared_buffer(NonnullRefPtr<SharedBuffer>&& buffer, int sample_count)
|
static NonnullRefPtr<Buffer> create_with_shared_buffer(NonnullRefPtr<SharedBuffer>&& buffer, int sample_count)
|
||||||
{
|
{
|
||||||
return adopt(*new ABuffer(move(buffer), sample_count));
|
return adopt(*new Buffer(move(buffer), sample_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ASample* samples() const { return (const ASample*)data(); }
|
const Sample* samples() const { return (const Sample*)data(); }
|
||||||
int sample_count() const { return m_sample_count; }
|
int sample_count() const { return m_sample_count; }
|
||||||
const void* data() const { return m_buffer->data(); }
|
const void* data() const { return m_buffer->data(); }
|
||||||
int size_in_bytes() const { return m_sample_count * (int)sizeof(ASample); }
|
int size_in_bytes() const { return m_sample_count * (int)sizeof(Sample); }
|
||||||
int shared_buffer_id() const { return m_buffer->shared_buffer_id(); }
|
int shared_buffer_id() const { return m_buffer->shared_buffer_id(); }
|
||||||
SharedBuffer& shared_buffer() { return *m_buffer; }
|
SharedBuffer& shared_buffer() { return *m_buffer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ABuffer(Vector<ASample>&& samples)
|
explicit Buffer(Vector<Sample>&& samples)
|
||||||
: m_buffer(*SharedBuffer::create_with_size(samples.size() * sizeof(ASample))),
|
: m_buffer(*SharedBuffer::create_with_size(samples.size() * sizeof(Sample))),
|
||||||
m_sample_count(samples.size())
|
m_sample_count(samples.size())
|
||||||
{
|
{
|
||||||
memcpy(m_buffer->data(), samples.data(), samples.size() * sizeof(ASample));
|
memcpy(m_buffer->data(), samples.data(), samples.size() * sizeof(Sample));
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit ABuffer(NonnullRefPtr<SharedBuffer>&& buffer, int sample_count)
|
explicit Buffer(NonnullRefPtr<SharedBuffer>&& buffer, int sample_count)
|
||||||
: m_buffer(move(buffer)),
|
: m_buffer(move(buffer)),
|
||||||
m_sample_count(sample_count)
|
m_sample_count(sample_count)
|
||||||
{
|
{
|
||||||
|
@ -139,3 +141,5 @@ private:
|
||||||
NonnullRefPtr<SharedBuffer> m_buffer;
|
NonnullRefPtr<SharedBuffer> m_buffer;
|
||||||
const int m_sample_count;
|
const int m_sample_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -28,21 +28,23 @@
|
||||||
#include <LibAudio/ABuffer.h>
|
#include <LibAudio/ABuffer.h>
|
||||||
#include <LibAudio/AClientConnection.h>
|
#include <LibAudio/AClientConnection.h>
|
||||||
|
|
||||||
AClientConnection::AClientConnection()
|
namespace Audio {
|
||||||
|
|
||||||
|
ClientConnection::ClientConnection()
|
||||||
: IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>(*this, "/tmp/portal/audio")
|
: IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>(*this, "/tmp/portal/audio")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::handshake()
|
void ClientConnection::handshake()
|
||||||
{
|
{
|
||||||
auto response = send_sync<AudioServer::Greet>();
|
auto response = send_sync<AudioServer::Greet>();
|
||||||
set_my_client_id(response->client_id());
|
set_my_client_id(response->client_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::enqueue(const ABuffer& buffer)
|
void ClientConnection::enqueue(const Buffer& buffer)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const_cast<ABuffer&>(buffer).shared_buffer().share_with(server_pid());
|
const_cast<Buffer&>(buffer).shared_buffer().share_with(server_pid());
|
||||||
auto response = send_sync<AudioServer::EnqueueBuffer>(buffer.shared_buffer_id(), buffer.sample_count());
|
auto response = send_sync<AudioServer::EnqueueBuffer>(buffer.shared_buffer_id(), buffer.sample_count());
|
||||||
if (response->success())
|
if (response->success())
|
||||||
break;
|
break;
|
||||||
|
@ -50,66 +52,68 @@ void AClientConnection::enqueue(const ABuffer& buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AClientConnection::try_enqueue(const ABuffer& buffer)
|
bool ClientConnection::try_enqueue(const Buffer& buffer)
|
||||||
{
|
{
|
||||||
const_cast<ABuffer&>(buffer).shared_buffer().share_with(server_pid());
|
const_cast<Buffer&>(buffer).shared_buffer().share_with(server_pid());
|
||||||
auto response = send_sync<AudioServer::EnqueueBuffer>(buffer.shared_buffer_id(), buffer.sample_count());
|
auto response = send_sync<AudioServer::EnqueueBuffer>(buffer.shared_buffer_id(), buffer.sample_count());
|
||||||
return response->success();
|
return response->success();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AClientConnection::get_muted()
|
bool ClientConnection::get_muted()
|
||||||
{
|
{
|
||||||
return send_sync<AudioServer::GetMuted>()->muted();
|
return send_sync<AudioServer::GetMuted>()->muted();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::set_muted(bool muted)
|
void ClientConnection::set_muted(bool muted)
|
||||||
{
|
{
|
||||||
send_sync<AudioServer::SetMuted>(muted);
|
send_sync<AudioServer::SetMuted>(muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AClientConnection::get_main_mix_volume()
|
int ClientConnection::get_main_mix_volume()
|
||||||
{
|
{
|
||||||
return send_sync<AudioServer::GetMainMixVolume>()->volume();
|
return send_sync<AudioServer::GetMainMixVolume>()->volume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::set_main_mix_volume(int volume)
|
void ClientConnection::set_main_mix_volume(int volume)
|
||||||
{
|
{
|
||||||
send_sync<AudioServer::SetMainMixVolume>(volume);
|
send_sync<AudioServer::SetMainMixVolume>(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AClientConnection::get_remaining_samples()
|
int ClientConnection::get_remaining_samples()
|
||||||
{
|
{
|
||||||
return send_sync<AudioServer::GetRemainingSamples>()->remaining_samples();
|
return send_sync<AudioServer::GetRemainingSamples>()->remaining_samples();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AClientConnection::get_played_samples()
|
int ClientConnection::get_played_samples()
|
||||||
{
|
{
|
||||||
return send_sync<AudioServer::GetPlayedSamples>()->played_samples();
|
return send_sync<AudioServer::GetPlayedSamples>()->played_samples();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::set_paused(bool paused)
|
void ClientConnection::set_paused(bool paused)
|
||||||
{
|
{
|
||||||
send_sync<AudioServer::SetPaused>(paused);
|
send_sync<AudioServer::SetPaused>(paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::clear_buffer(bool paused)
|
void ClientConnection::clear_buffer(bool paused)
|
||||||
{
|
{
|
||||||
send_sync<AudioServer::ClearBuffer>(paused);
|
send_sync<AudioServer::ClearBuffer>(paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AClientConnection::get_playing_buffer()
|
int ClientConnection::get_playing_buffer()
|
||||||
{
|
{
|
||||||
return send_sync<AudioServer::GetPlayingBuffer>()->buffer_id();
|
return send_sync<AudioServer::GetPlayingBuffer>()->buffer_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::handle(const AudioClient::FinishedPlayingBuffer& message)
|
void ClientConnection::handle(const AudioClient::FinishedPlayingBuffer& message)
|
||||||
{
|
{
|
||||||
if (on_finish_playing_buffer)
|
if (on_finish_playing_buffer)
|
||||||
on_finish_playing_buffer(message.buffer_id());
|
on_finish_playing_buffer(message.buffer_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AClientConnection::handle(const AudioClient::MutedStateChanged& message)
|
void ClientConnection::handle(const AudioClient::MutedStateChanged& message)
|
||||||
{
|
{
|
||||||
if (on_muted_state_change)
|
if (on_muted_state_change)
|
||||||
on_muted_state_change(message.muted());
|
on_muted_state_change(message.muted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -30,17 +30,19 @@
|
||||||
#include <AudioServer/AudioServerEndpoint.h>
|
#include <AudioServer/AudioServerEndpoint.h>
|
||||||
#include <LibIPC/IServerConnection.h>
|
#include <LibIPC/IServerConnection.h>
|
||||||
|
|
||||||
class ABuffer;
|
namespace Audio {
|
||||||
|
|
||||||
class AClientConnection : public IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>
|
class Buffer;
|
||||||
|
|
||||||
|
class ClientConnection : public IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>
|
||||||
, public AudioClientEndpoint {
|
, public AudioClientEndpoint {
|
||||||
C_OBJECT(AClientConnection)
|
C_OBJECT(ClientConnection)
|
||||||
public:
|
public:
|
||||||
AClientConnection();
|
ClientConnection();
|
||||||
|
|
||||||
virtual void handshake() override;
|
virtual void handshake() override;
|
||||||
void enqueue(const ABuffer&);
|
void enqueue(const Buffer&);
|
||||||
bool try_enqueue(const ABuffer&);
|
bool try_enqueue(const Buffer&);
|
||||||
|
|
||||||
bool get_muted();
|
bool get_muted();
|
||||||
void set_muted(bool);
|
void set_muted(bool);
|
||||||
|
@ -62,3 +64,5 @@ private:
|
||||||
virtual void handle(const AudioClient::FinishedPlayingBuffer&) override;
|
virtual void handle(const AudioClient::FinishedPlayingBuffer&) override;
|
||||||
virtual void handle(const AudioClient::MutedStateChanged&) override;
|
virtual void handle(const AudioClient::MutedStateChanged&) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
#include <LibCore/CIODeviceStreamReader.h>
|
#include <LibCore/CIODeviceStreamReader.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
AWavLoader::AWavLoader(const StringView& path)
|
namespace Audio {
|
||||||
|
|
||||||
|
WavLoader::WavLoader(const StringView& path)
|
||||||
: m_file(Core::File::construct(path))
|
: m_file(Core::File::construct(path))
|
||||||
{
|
{
|
||||||
if (!m_file->open(Core::IODevice::ReadOnly)) {
|
if (!m_file->open(Core::IODevice::ReadOnly)) {
|
||||||
|
@ -39,10 +41,10 @@ AWavLoader::AWavLoader(const StringView& path)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_header();
|
parse_header();
|
||||||
m_resampler = make<AResampleHelper>(m_sample_rate, 44100);
|
m_resampler = make<ResampleHelper>(m_sample_rate, 44100);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ABuffer> AWavLoader::get_more_samples(size_t max_bytes_to_read_from_input)
|
RefPtr<Buffer> WavLoader::get_more_samples(size_t max_bytes_to_read_from_input)
|
||||||
{
|
{
|
||||||
#ifdef AWAVLOADER_DEBUG
|
#ifdef AWAVLOADER_DEBUG
|
||||||
dbgprintf("Read WAV of format PCM with num_channels %u sample rate %u, bits per sample %u\n", m_num_channels, m_sample_rate, m_bits_per_sample);
|
dbgprintf("Read WAV of format PCM with num_channels %u sample rate %u, bits per sample %u\n", m_num_channels, m_sample_rate, m_bits_per_sample);
|
||||||
|
@ -52,14 +54,14 @@ RefPtr<ABuffer> AWavLoader::get_more_samples(size_t max_bytes_to_read_from_input
|
||||||
if (raw_samples.is_empty())
|
if (raw_samples.is_empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto buffer = ABuffer::from_pcm_data(raw_samples, *m_resampler, m_num_channels, m_bits_per_sample);
|
auto buffer = Buffer::from_pcm_data(raw_samples, *m_resampler, m_num_channels, m_bits_per_sample);
|
||||||
//Buffer contains normalized samples, but m_loaded_samples should containt the ammount of actually loaded samples
|
//Buffer contains normalized samples, but m_loaded_samples should containt the ammount of actually loaded samples
|
||||||
m_loaded_samples += static_cast<int>(max_bytes_to_read_from_input) / (m_num_channels * (m_bits_per_sample / 8));
|
m_loaded_samples += static_cast<int>(max_bytes_to_read_from_input) / (m_num_channels * (m_bits_per_sample / 8));
|
||||||
m_loaded_samples = min(m_total_samples, m_loaded_samples);
|
m_loaded_samples = min(m_total_samples, m_loaded_samples);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AWavLoader::seek(const int position)
|
void WavLoader::seek(const int position)
|
||||||
{
|
{
|
||||||
if (position < 0 || position > m_total_samples)
|
if (position < 0 || position > m_total_samples)
|
||||||
return;
|
return;
|
||||||
|
@ -68,12 +70,12 @@ void AWavLoader::seek(const int position)
|
||||||
m_file->seek(position * m_num_channels * (m_bits_per_sample / 8));
|
m_file->seek(position * m_num_channels * (m_bits_per_sample / 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AWavLoader::reset()
|
void WavLoader::reset()
|
||||||
{
|
{
|
||||||
seek(0);
|
seek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AWavLoader::parse_header()
|
bool WavLoader::parse_header()
|
||||||
{
|
{
|
||||||
Core::IODeviceStreamReader stream(*m_file);
|
Core::IODeviceStreamReader stream(*m_file);
|
||||||
|
|
||||||
|
@ -179,19 +181,19 @@ bool AWavLoader::parse_header()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AResampleHelper::AResampleHelper(float source, float target)
|
ResampleHelper::ResampleHelper(float source, float target)
|
||||||
: m_ratio(source / target)
|
: m_ratio(source / target)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void AResampleHelper::process_sample(float sample_l, float sample_r)
|
void ResampleHelper::process_sample(float sample_l, float sample_r)
|
||||||
{
|
{
|
||||||
m_last_sample_l = sample_l;
|
m_last_sample_l = sample_l;
|
||||||
m_last_sample_r = sample_r;
|
m_last_sample_r = sample_r;
|
||||||
m_current_ratio += 1;
|
m_current_ratio += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AResampleHelper::read_sample(float& next_l, float& next_r)
|
bool ResampleHelper::read_sample(float& next_l, float& next_r)
|
||||||
{
|
{
|
||||||
if (m_current_ratio > 0) {
|
if (m_current_ratio > 0) {
|
||||||
m_current_ratio -= m_ratio;
|
m_current_ratio -= m_ratio;
|
||||||
|
@ -204,7 +206,7 @@ bool AResampleHelper::read_sample(float& next_l, float& next_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename SampleReader>
|
template<typename SampleReader>
|
||||||
static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector<ASample>& samples, AResampleHelper& resampler, int num_channels)
|
static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector<Sample>& samples, ResampleHelper& resampler, int num_channels)
|
||||||
{
|
{
|
||||||
float norm_l = 0;
|
float norm_l = 0;
|
||||||
float norm_r = 0;
|
float norm_r = 0;
|
||||||
|
@ -213,7 +215,7 @@ static void read_samples_from_stream(BufferStream& stream, SampleReader read_sam
|
||||||
case 1:
|
case 1:
|
||||||
for (;;) {
|
for (;;) {
|
||||||
while (resampler.read_sample(norm_l, norm_r)) {
|
while (resampler.read_sample(norm_l, norm_r)) {
|
||||||
samples.append(ASample(norm_l));
|
samples.append(Sample(norm_l));
|
||||||
}
|
}
|
||||||
norm_l = read_sample(stream);
|
norm_l = read_sample(stream);
|
||||||
|
|
||||||
|
@ -226,7 +228,7 @@ static void read_samples_from_stream(BufferStream& stream, SampleReader read_sam
|
||||||
case 2:
|
case 2:
|
||||||
for (;;) {
|
for (;;) {
|
||||||
while (resampler.read_sample(norm_l, norm_r)) {
|
while (resampler.read_sample(norm_l, norm_r)) {
|
||||||
samples.append(ASample(norm_l, norm_r));
|
samples.append(Sample(norm_l, norm_r));
|
||||||
}
|
}
|
||||||
norm_l = read_sample(stream);
|
norm_l = read_sample(stream);
|
||||||
norm_r = read_sample(stream);
|
norm_r = read_sample(stream);
|
||||||
|
@ -276,10 +278,10 @@ static float read_norm_sample_8(BufferStream& stream)
|
||||||
// ### can't const this because BufferStream is non-const
|
// ### can't const this because BufferStream is non-const
|
||||||
// perhaps we need a reading class separate from the writing one, that can be
|
// perhaps we need a reading class separate from the writing one, that can be
|
||||||
// entirely consted.
|
// entirely consted.
|
||||||
RefPtr<ABuffer> ABuffer::from_pcm_data(ByteBuffer& data, AResampleHelper& resampler, int num_channels, int bits_per_sample)
|
RefPtr<Buffer> Buffer::from_pcm_data(ByteBuffer& data, ResampleHelper& resampler, int num_channels, int bits_per_sample)
|
||||||
{
|
{
|
||||||
BufferStream stream(data);
|
BufferStream stream(data);
|
||||||
Vector<ASample> fdata;
|
Vector<Sample> fdata;
|
||||||
fdata.ensure_capacity(data.size() / (bits_per_sample / 8));
|
fdata.ensure_capacity(data.size() / (bits_per_sample / 8));
|
||||||
#ifdef AWAVLOADER_DEBUG
|
#ifdef AWAVLOADER_DEBUG
|
||||||
dbg() << "Reading " << bits_per_sample << " bits and " << num_channels << " channels, total bytes: " << data.size();
|
dbg() << "Reading " << bits_per_sample << " bits and " << num_channels << " channels, total bytes: " << data.size();
|
||||||
|
@ -304,5 +306,7 @@ RefPtr<ABuffer> ABuffer::from_pcm_data(ByteBuffer& data, AResampleHelper& resamp
|
||||||
// don't belong.
|
// don't belong.
|
||||||
ASSERT(!stream.handle_read_failure());
|
ASSERT(!stream.handle_read_failure());
|
||||||
|
|
||||||
return ABuffer::create_with_samples(move(fdata));
|
return Buffer::create_with_samples(move(fdata));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,27 +26,28 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/String.h>
|
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
|
#include <AK/String.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
#include <LibCore/CFile.h>
|
|
||||||
#include <LibAudio/ABuffer.h>
|
#include <LibAudio/ABuffer.h>
|
||||||
|
#include <LibCore/CFile.h>
|
||||||
class ABuffer;
|
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
class ByteBuffer;
|
class ByteBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses a WAV file and produces an ABuffer instance from it
|
namespace Audio {
|
||||||
class AWavLoader {
|
class Buffer;
|
||||||
|
|
||||||
|
// Parses a WAV file and produces an Audio::Buffer.
|
||||||
|
class WavLoader {
|
||||||
public:
|
public:
|
||||||
explicit AWavLoader(const StringView& path);
|
explicit WavLoader(const StringView& path);
|
||||||
|
|
||||||
bool has_error() const { return !m_error_string.is_null(); }
|
bool has_error() const { return !m_error_string.is_null(); }
|
||||||
const char* error_string() { return m_error_string.characters(); }
|
const char* error_string() { return m_error_string.characters(); }
|
||||||
|
|
||||||
RefPtr<ABuffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KB);
|
RefPtr<Buffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KB);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void seek(const int position);
|
void seek(const int position);
|
||||||
|
@ -62,7 +63,7 @@ private:
|
||||||
bool parse_header();
|
bool parse_header();
|
||||||
RefPtr<Core::File> m_file;
|
RefPtr<Core::File> m_file;
|
||||||
String m_error_string;
|
String m_error_string;
|
||||||
OwnPtr<AResampleHelper> m_resampler;
|
OwnPtr<ResampleHelper> m_resampler;
|
||||||
|
|
||||||
u32 m_sample_rate { 0 };
|
u32 m_sample_rate { 0 };
|
||||||
u16 m_num_channels { 0 };
|
u16 m_num_channels { 0 };
|
||||||
|
@ -71,3 +72,5 @@ private:
|
||||||
int m_loaded_samples { 0 };
|
int m_loaded_samples { 0 };
|
||||||
int m_total_samples { 0 };
|
int m_total_samples { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
AudioWidget()
|
AudioWidget()
|
||||||
: GUI::Widget(nullptr)
|
: GUI::Widget(nullptr)
|
||||||
{
|
{
|
||||||
m_audio_client = make<AClientConnection>();
|
m_audio_client = make<Audio::ClientConnection>();
|
||||||
m_audio_client->on_muted_state_change = [this](bool muted) {
|
m_audio_client->on_muted_state_change = [this](bool muted) {
|
||||||
if (m_audio_muted == muted)
|
if (m_audio_muted == muted)
|
||||||
return;
|
return;
|
||||||
|
@ -67,7 +67,7 @@ private:
|
||||||
painter.blit({}, audio_bitmap, audio_bitmap.rect());
|
painter.blit({}, audio_bitmap, audio_bitmap.rect());
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnPtr<AClientConnection> m_audio_client;
|
OwnPtr<Audio::ClientConnection> m_audio_client;
|
||||||
RefPtr<GraphicsBitmap> m_muted_bitmap;
|
RefPtr<GraphicsBitmap> m_muted_bitmap;
|
||||||
RefPtr<GraphicsBitmap> m_unmuted_bitmap;
|
RefPtr<GraphicsBitmap> m_unmuted_bitmap;
|
||||||
bool m_audio_muted { false };
|
bool m_audio_muted { false };
|
||||||
|
|
|
@ -105,7 +105,7 @@ OwnPtr<AudioServer::EnqueueBufferResponse> ASClientConnection::handle(const Audi
|
||||||
if (m_queue->is_full())
|
if (m_queue->is_full())
|
||||||
return make<AudioServer::EnqueueBufferResponse>(false);
|
return make<AudioServer::EnqueueBufferResponse>(false);
|
||||||
|
|
||||||
m_queue->enqueue(ABuffer::create_with_shared_buffer(*shared_buffer, message.sample_count()));
|
m_queue->enqueue(Audio::Buffer::create_with_shared_buffer(*shared_buffer, message.sample_count()));
|
||||||
return make<AudioServer::EnqueueBufferResponse>(true);
|
return make<AudioServer::EnqueueBufferResponse>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,10 @@
|
||||||
#include <AudioServer/AudioServerEndpoint.h>
|
#include <AudioServer/AudioServerEndpoint.h>
|
||||||
#include <LibIPC/IClientConnection.h>
|
#include <LibIPC/IClientConnection.h>
|
||||||
|
|
||||||
class ABuffer;
|
namespace Audio {
|
||||||
|
class Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
class ASBufferQueue;
|
class ASBufferQueue;
|
||||||
class ASMixer;
|
class ASMixer;
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,8 @@ void ASMixer::mix()
|
||||||
|
|
||||||
active_mix_queues.remove_all_matching([&](auto& entry) { return !entry->client(); });
|
active_mix_queues.remove_all_matching([&](auto& entry) { return !entry->client(); });
|
||||||
|
|
||||||
ASample mixed_buffer[1024];
|
Audio::Sample mixed_buffer[1024];
|
||||||
auto mixed_buffer_length = (int)(sizeof(mixed_buffer) / sizeof(ASample));
|
auto mixed_buffer_length = (int)(sizeof(mixed_buffer) / sizeof(Audio::Sample));
|
||||||
|
|
||||||
// Mix the buffers together into the output
|
// Mix the buffers together into the output
|
||||||
for (auto& queue : active_mix_queues) {
|
for (auto& queue : active_mix_queues) {
|
||||||
|
@ -92,7 +92,7 @@ void ASMixer::mix()
|
||||||
|
|
||||||
for (int i = 0; i < mixed_buffer_length; ++i) {
|
for (int i = 0; i < mixed_buffer_length; ++i) {
|
||||||
auto& mixed_sample = mixed_buffer[i];
|
auto& mixed_sample = mixed_buffer[i];
|
||||||
ASample sample;
|
Audio::Sample sample;
|
||||||
if (!queue->get_next_sample(sample))
|
if (!queue->get_next_sample(sample))
|
||||||
break;
|
break;
|
||||||
mixed_sample += sample;
|
mixed_sample += sample;
|
||||||
|
@ -145,7 +145,7 @@ ASBufferQueue::ASBufferQueue(ASClientConnection& client)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASBufferQueue::enqueue(NonnullRefPtr<ABuffer>&& buffer)
|
void ASBufferQueue::enqueue(NonnullRefPtr<Audio::Buffer>&& buffer)
|
||||||
{
|
{
|
||||||
m_remaining_samples += buffer->sample_count();
|
m_remaining_samples += buffer->sample_count();
|
||||||
m_queue.enqueue(move(buffer));
|
m_queue.enqueue(move(buffer));
|
||||||
|
|
|
@ -45,9 +45,9 @@ public:
|
||||||
~ASBufferQueue() {}
|
~ASBufferQueue() {}
|
||||||
|
|
||||||
bool is_full() const { return m_queue.size() >= 3; }
|
bool is_full() const { return m_queue.size() >= 3; }
|
||||||
void enqueue(NonnullRefPtr<ABuffer>&&);
|
void enqueue(NonnullRefPtr<Audio::Buffer>&&);
|
||||||
|
|
||||||
bool get_next_sample(ASample& sample)
|
bool get_next_sample(Audio::Sample& sample)
|
||||||
{
|
{
|
||||||
if (m_paused)
|
if (m_paused)
|
||||||
return false;
|
return false;
|
||||||
|
@ -97,8 +97,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<ABuffer> m_current;
|
RefPtr<Audio::Buffer> m_current;
|
||||||
Queue<NonnullRefPtr<ABuffer>> m_queue;
|
Queue<NonnullRefPtr<Audio::Buffer>> m_queue;
|
||||||
int m_position { 0 };
|
int m_position { 0 };
|
||||||
int m_remaining_samples { 0 };
|
int m_remaining_samples { 0 };
|
||||||
int m_played_samples { 0 };
|
int m_played_samples { 0 };
|
||||||
|
|
|
@ -38,9 +38,9 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto audio_client = AClientConnection::construct();
|
auto audio_client = Audio::ClientConnection::construct();
|
||||||
audio_client->handshake();
|
audio_client->handshake();
|
||||||
AWavLoader loader(argv[1]);
|
Audio::WavLoader loader(argv[1]);
|
||||||
|
|
||||||
printf("\033[34;1m Playing\033[0m: %s\n", argv[1]);
|
printf("\033[34;1m Playing\033[0m: %s\n", argv[1]);
|
||||||
printf("\033[34;1m Format\033[0m: %u Hz, %u-bit, %s\n",
|
printf("\033[34;1m Format\033[0m: %u Hz, %u-bit, %s\n",
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
Core::EventLoop loop;
|
Core::EventLoop loop;
|
||||||
auto audio_client = AClientConnection::construct();
|
auto audio_client = Audio::ClientConnection::construct();
|
||||||
audio_client->handshake();
|
audio_client->handshake();
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue