mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-28 18:47:15 +02:00
By doing this, we can default-initialize it and not have to rely on Optional with its extra size.
214 lines
5.4 KiB
C++
214 lines
5.4 KiB
C++
/*
|
|
* Copyright (c) 2025, Gregory Bertilson <gregory@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Format.h>
|
|
#include <AK/StdLibExtras.h>
|
|
#include <AK/String.h>
|
|
#include <AK/StringBuilder.h>
|
|
#include <AK/TypedTransfer.h>
|
|
#include <AK/Types.h>
|
|
|
|
namespace Audio {
|
|
|
|
enum class Channel : u8 {
|
|
Unknown,
|
|
FrontLeft,
|
|
FrontRight,
|
|
FrontCenter,
|
|
LowFrequency,
|
|
BackLeft,
|
|
BackRight,
|
|
FrontLeftOfCenter,
|
|
FrontRightOfCenter,
|
|
BackCenter,
|
|
SideLeft,
|
|
SideRight,
|
|
TopCenter,
|
|
TopFrontLeft,
|
|
TopFrontCenter,
|
|
TopFrontRight,
|
|
TopBackLeft,
|
|
TopBackCenter,
|
|
TopBackRight,
|
|
Count,
|
|
};
|
|
|
|
class ChannelMap {
|
|
public:
|
|
static constexpr ChannelMap invalid()
|
|
{
|
|
return ChannelMap();
|
|
}
|
|
|
|
static constexpr ChannelMap mono()
|
|
{
|
|
return ChannelMap(Channel::FrontCenter);
|
|
}
|
|
|
|
static constexpr ChannelMap stereo()
|
|
{
|
|
return ChannelMap(Channel::FrontLeft, Channel::FrontRight);
|
|
}
|
|
|
|
static constexpr ChannelMap quadrophonic()
|
|
{
|
|
return ChannelMap(
|
|
Channel::FrontLeft,
|
|
Channel::FrontRight,
|
|
Channel::BackLeft,
|
|
Channel::BackRight);
|
|
}
|
|
|
|
static constexpr ChannelMap surround_5_1()
|
|
{
|
|
return ChannelMap(
|
|
Channel::FrontLeft,
|
|
Channel::FrontRight,
|
|
Channel::FrontCenter,
|
|
Channel::LowFrequency,
|
|
Channel::BackLeft,
|
|
Channel::BackRight);
|
|
}
|
|
|
|
static constexpr ChannelMap surround_7_1()
|
|
{
|
|
return ChannelMap(
|
|
Channel::FrontLeft,
|
|
Channel::FrontRight,
|
|
Channel::FrontCenter,
|
|
Channel::LowFrequency,
|
|
Channel::BackLeft,
|
|
Channel::BackRight,
|
|
Channel::SideLeft,
|
|
Channel::SideRight);
|
|
}
|
|
|
|
template<typename... Channels>
|
|
requires(IsSame<Channels, Channel> && ...)
|
|
constexpr ChannelMap(Channels... channels)
|
|
: m_channel_count(sizeof...(channels) / sizeof(Channel))
|
|
, m_channels(channels...)
|
|
{
|
|
}
|
|
|
|
template<size_t VecCapacity>
|
|
ChannelMap(Vector<Channel, VecCapacity> const& channels)
|
|
: ChannelMap(channels.span())
|
|
{
|
|
}
|
|
|
|
ChannelMap(ReadonlySpan<Channel> channels)
|
|
: m_channel_count(channels.size())
|
|
{
|
|
VERIFY(channels.size() <= capacity());
|
|
AK::TypedTransfer<Channel>::copy(m_channels, channels.data(), channels.size());
|
|
}
|
|
|
|
bool is_valid() const { return m_channel_count > 0; }
|
|
|
|
u8 channel_count() const { return m_channel_count; }
|
|
Channel channel_at(u8 index) const
|
|
{
|
|
VERIFY(index < channel_count());
|
|
return m_channels[index];
|
|
}
|
|
|
|
static constexpr size_t capacity() { return sizeof(m_channels) / sizeof(*m_channels); }
|
|
|
|
[[nodiscard]] constexpr bool operator==(ChannelMap const& other) const
|
|
{
|
|
if (channel_count() != other.channel_count())
|
|
return false;
|
|
for (u8 i = 0; i < channel_count(); i++) {
|
|
if (channel_at(i) != other.channel_at(i))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
u8 m_channel_count { 0 };
|
|
Channel m_channels[to_underlying(Channel::Count)];
|
|
};
|
|
|
|
constexpr StringView audio_channel_to_string(Channel channel)
|
|
{
|
|
switch (channel) {
|
|
case Audio::Channel::Unknown:
|
|
return "None"sv;
|
|
case Audio::Channel::FrontLeft:
|
|
return "FrontLeft"sv;
|
|
case Audio::Channel::FrontRight:
|
|
return "FrontRight"sv;
|
|
case Audio::Channel::FrontCenter:
|
|
return "FrontCenter"sv;
|
|
case Audio::Channel::LowFrequency:
|
|
return "LowFrequency"sv;
|
|
case Audio::Channel::BackLeft:
|
|
return "BackLeft"sv;
|
|
case Audio::Channel::BackRight:
|
|
return "BackRight"sv;
|
|
case Audio::Channel::FrontLeftOfCenter:
|
|
return "FrontLeftOfCenter"sv;
|
|
case Audio::Channel::FrontRightOfCenter:
|
|
return "FrontRightOfCenter"sv;
|
|
case Audio::Channel::BackCenter:
|
|
return "BackCenter"sv;
|
|
case Audio::Channel::SideLeft:
|
|
return "SideLeft"sv;
|
|
case Audio::Channel::SideRight:
|
|
return "SideRight"sv;
|
|
case Audio::Channel::TopCenter:
|
|
return "TopCenter"sv;
|
|
case Audio::Channel::TopFrontLeft:
|
|
return "TopFrontLeft"sv;
|
|
case Audio::Channel::TopFrontCenter:
|
|
return "TopFrontCenter"sv;
|
|
case Audio::Channel::TopFrontRight:
|
|
return "TopFrontRight"sv;
|
|
case Audio::Channel::TopBackLeft:
|
|
return "TopBackLeft"sv;
|
|
case Audio::Channel::TopBackCenter:
|
|
return "TopBackCenter"sv;
|
|
case Audio::Channel::TopBackRight:
|
|
return "TopBackRight"sv;
|
|
case Audio::Channel::Count:
|
|
break;
|
|
}
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
}
|
|
|
|
namespace AK {
|
|
|
|
template<>
|
|
struct Formatter<Audio::Channel> : Formatter<StringView> {
|
|
ErrorOr<void> format(FormatBuilder& builder, Audio::Channel channel)
|
|
{
|
|
return Formatter<StringView>::format(builder, Audio::audio_channel_to_string(channel));
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Formatter<Audio::ChannelMap> : StandardFormatter {
|
|
static ErrorOr<void> format(FormatBuilder& builder, Audio::ChannelMap channel_map)
|
|
{
|
|
TRY(builder.builder().try_append("[ "sv));
|
|
auto count = channel_map.channel_count();
|
|
for (u8 i = 0; i < count; i++)
|
|
TRY(builder.builder().try_appendff("{}, ", channel_map.channel_at(i)));
|
|
if (count > 0)
|
|
builder.builder().trim(2);
|
|
TRY(builder.builder().try_append(" ]"sv));
|
|
return {};
|
|
}
|
|
};
|
|
|
|
}
|