mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-19 17:27:51 +03:00
238 lines
7.3 KiB
Diff
238 lines
7.3 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Julian=20Offenh=C3=A4user?= <offenhaeuser@protonmail.com>
|
|
Date: Fri, 23 Feb 2024 21:17:23 +0100
|
|
Subject: [PATCH] Add support for Serenity LibAudio
|
|
|
|
---
|
|
src/Makefile.am | 5 +-
|
|
src/sound.c | 1 +
|
|
src/sound.h | 1 +
|
|
src/sound_serenity.cpp | 157 +++++++++++++++++++++++++++++++++++++++++
|
|
src/xmp.conf | 2 +-
|
|
5 files changed, 164 insertions(+), 2 deletions(-)
|
|
create mode 100644 src/sound_serenity.cpp
|
|
|
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
index b65eb85244acec722b2f240976f184f06db11a27..840845dc1f5d7459bfbb339071b817adc2507c6a 100644
|
|
--- a/src/Makefile.am
|
|
+++ b/src/Makefile.am
|
|
@@ -1,7 +1,7 @@
|
|
# -*- Makefile -*-
|
|
|
|
AM_CPPFLAGS = -DSYSCONFDIR=\"${sysconfdir}/${PACKAGE_NAME}\" ${LIBXMP_CFLAGS} \
|
|
- ${alsa_CFLAGS} ${pulseaudio_CFLAGS}
|
|
+ ${alsa_CFLAGS} ${pulseaudio_CFLAGS} -std=c++2a
|
|
AM_CFLAGS = -Wall
|
|
|
|
bin_PROGRAMS = xmp
|
|
@@ -93,6 +93,9 @@ xmp_SOURCES += sound_dart.c
|
|
xmp_LDADD += -lmmpm2
|
|
endif
|
|
|
|
+xmp_SOURCES += sound_serenity.cpp
|
|
+xmp_LDADD += -lcore -lipc -laudio -lstdc++
|
|
+
|
|
man_MANS = xmp.1
|
|
|
|
pkgsysconfdir = ${sysconfdir}/${PACKAGE_NAME}
|
|
diff --git a/src/sound.c b/src/sound.c
|
|
index b6d0c971876a555e27a628b0517a8dd653f24dff..04935412baf8a17558dcc62914d4a5cc1a72c49d 100644
|
|
--- a/src/sound.c
|
|
+++ b/src/sound.c
|
|
@@ -73,6 +73,7 @@ void init_sound_drivers(void)
|
|
#ifdef SOUND_SB
|
|
register_sound_driver(&sound_sb);
|
|
#endif
|
|
+ register_sound_driver(&sound_serenity);
|
|
register_sound_driver(&sound_wav);
|
|
register_sound_driver(&sound_aiff);
|
|
register_sound_driver(&sound_file);
|
|
diff --git a/src/sound.h b/src/sound.h
|
|
index 153a6c7cb6f6f1431e00b5a10a8a36d3fe7ab7db..beebb83fa3cccdb53bdd2f6893307e476460373f 100644
|
|
--- a/src/sound.h
|
|
+++ b/src/sound.h
|
|
@@ -41,6 +41,7 @@ extern struct sound_driver sound_beos;
|
|
extern struct sound_driver sound_aix;
|
|
extern struct sound_driver sound_ahi;
|
|
extern struct sound_driver sound_sb;
|
|
+extern struct sound_driver sound_serenity;
|
|
|
|
#define parm_init(p) { char *token; for (; *(p); (p)++) { \
|
|
char s[80]; strncpy(s, *(p), 79); s[79] = 0; \
|
|
diff --git a/src/sound_serenity.cpp b/src/sound_serenity.cpp
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..172996990b7807e3eecf119557274febcc4f5d54
|
|
--- /dev/null
|
|
+++ b/src/sound_serenity.cpp
|
|
@@ -0,0 +1,157 @@
|
|
+#include "sound.h"
|
|
+
|
|
+#include <AK/OwnPtr.h>
|
|
+#include <AK/RefPtr.h>
|
|
+#include <LibAudio/ConnectionToServer.h>
|
|
+#include <LibAudio/Sample.h>
|
|
+#include <LibAudio/SampleFormats.h>
|
|
+
|
|
+static RefPtr<Audio::ConnectionToServer> client;
|
|
+static OwnPtr<Core::EventLoop> event_loop;
|
|
+
|
|
+static Array<Audio::Sample, Audio::AUDIO_BUFFER_SIZE> output_buffer {};
|
|
+static size_t output_buffer_samples_remaining { 0 };
|
|
+
|
|
+static int format;
|
|
+static int channels;
|
|
+static int bytes_per_sample;
|
|
+
|
|
+static int init(struct options* options)
|
|
+{
|
|
+ event_loop = make<Core::EventLoop>();
|
|
+ client = MUST(Audio::ConnectionToServer::try_create());
|
|
+
|
|
+ format = options->format;
|
|
+ channels = format & XMP_FORMAT_MONO ? 1 : 2;
|
|
+ bytes_per_sample = format & XMP_FORMAT_8BIT ? 1 : 2;
|
|
+
|
|
+ u32 sample_rate = options->rate;
|
|
+ client->set_self_sample_rate(sample_rate);
|
|
+
|
|
+ client->async_start_playback();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void deinit(void)
|
|
+{
|
|
+ client->die();
|
|
+}
|
|
+
|
|
+template<typename T>
|
|
+static double read_sample(void*& b)
|
|
+{
|
|
+ T sample = *(T*)b;
|
|
+ b += sizeof(T);
|
|
+
|
|
+ // Remap integer samples to normalized floating-point range of -1 to 1.
|
|
+ if constexpr (IsIntegral<T>) {
|
|
+ if constexpr (NumericLimits<T>::is_signed()) {
|
|
+ // Signed integer samples are centered around zero, so this division is enough.
|
|
+ return static_cast<double>(AK::convert_between_host_and_little_endian(sample)) / static_cast<double>(NumericLimits<T>::max());
|
|
+ } else {
|
|
+ // Unsigned integer samples, on the other hand, need to be shifted to center them around zero.
|
|
+ // The first division therefore remaps to the range 0 to 2.
|
|
+ return static_cast<double>(AK::convert_between_host_and_little_endian(sample)) / (static_cast<double>(NumericLimits<T>::max()) / 2.0) - 1.0;
|
|
+ }
|
|
+ } else {
|
|
+ return static_cast<double>(AK::convert_between_host_and_little_endian(sample));
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Build and write one tick (one PAL frame or 1/50 s in standard vblank
|
|
+ * timed mods) of audio data to the output device.
|
|
+ */
|
|
+static void play(void* b, int i)
|
|
+{
|
|
+ int samples_per_channel = i / (channels * bytes_per_sample);
|
|
+ int unsigned_samples = format & XMP_FORMAT_UNSIGNED;
|
|
+
|
|
+ auto const sleep_spec = Duration::from_nanoseconds(100).to_timespec();
|
|
+
|
|
+ while (samples_per_channel > 0) {
|
|
+ // Fill up the output buffer
|
|
+ auto const samples_to_process = min(samples_per_channel, Audio::AUDIO_BUFFER_SIZE - output_buffer_samples_remaining);
|
|
+
|
|
+ for (int i = 0; i < samples_to_process; ++i) {
|
|
+ float left, right;
|
|
+
|
|
+ auto convert_sample = [&]() -> float {
|
|
+ if (unsigned_samples) {
|
|
+ if (format & XMP_FORMAT_8BIT)
|
|
+ return read_sample<u8>(b);
|
|
+ else
|
|
+ return read_sample<u16>(b);
|
|
+ } else {
|
|
+ if (format & XMP_FORMAT_8BIT)
|
|
+ return read_sample<i8>(b);
|
|
+ else
|
|
+ return read_sample<i16>(b);
|
|
+ }
|
|
+ return 0.0f;
|
|
+ };
|
|
+
|
|
+ left = convert_sample();
|
|
+ if (format & XMP_FORMAT_MONO) {
|
|
+ right = left;
|
|
+ } else {
|
|
+ right = convert_sample();
|
|
+ }
|
|
+
|
|
+ output_buffer[output_buffer_samples_remaining + i] = Audio::Sample { left, right };
|
|
+ }
|
|
+ output_buffer_samples_remaining += samples_to_process;
|
|
+ samples_per_channel -= samples_to_process;
|
|
+
|
|
+ // Stop if we don't have enough samples to fill a buffer
|
|
+ if (output_buffer_samples_remaining < Audio::AUDIO_BUFFER_SIZE)
|
|
+ break;
|
|
+
|
|
+ // Try to enqueue our output buffer
|
|
+ for (;;) {
|
|
+ auto enqueue_result = client->realtime_enqueue(output_buffer);
|
|
+ if (!enqueue_result.is_error())
|
|
+ break;
|
|
+ if (enqueue_result.error() != Audio::AudioQueue::QueueStatus::Full)
|
|
+ return;
|
|
+
|
|
+ nanosleep(&sleep_spec, nullptr);
|
|
+ }
|
|
+ output_buffer_samples_remaining = 0;
|
|
+ }
|
|
+
|
|
+ // Pump our event loop - should just be the IPC call to start playback
|
|
+ for (;;) {
|
|
+ auto number_of_events_pumped = event_loop->pump(Core::EventLoop::WaitMode::PollForEvents);
|
|
+ if (number_of_events_pumped == 0)
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void flush(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static void onpause(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static void onresume(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static char const* const help[] = {
|
|
+ NULL
|
|
+};
|
|
+
|
|
+struct sound_driver sound_serenity = {
|
|
+ "serenity",
|
|
+ "Serenity AudioServer",
|
|
+ help,
|
|
+ init,
|
|
+ deinit,
|
|
+ play,
|
|
+ flush,
|
|
+ onpause,
|
|
+ onresume
|
|
+};
|
|
diff --git a/src/xmp.conf b/src/xmp.conf
|
|
index 08166a0e7e5f2cefa69fc1c843ca27c5388cbdf1..fa9ace68299cb0c503276629b809b83edad5cf31 100644
|
|
--- a/src/xmp.conf
|
|
+++ b/src/xmp.conf
|
|
@@ -19,7 +19,7 @@
|
|
# driver = <name>
|
|
# Output device to be used
|
|
#
|
|
-#driver = alsa
|
|
+driver = serenity
|
|
|
|
|
|
# ALSA driver
|