JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
ChannelMap.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright 2024 Jaroslav Pevno, JPLSpatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21
22#include "Core.h"
23#include "ErrorReporting.h"
24
25#include <bit>
26#include <string_view>
27
28namespace JPL
29{
30 //==========================================================================
34 // This no longer conforms to WAVEFORMATEXTENSIBLE, but supposidely conforms
35 // to common speaker arrangements.
39 {
44
45 SideLeft = JPL_BIT(4), // also "left surround side", "left centre"
46 SideRight = JPL_BIT(5), // also "right surround side", "right centre"
47
50
51 BackLeft = JPL_BIT(8), // also "left surround", "left surround read"
52 BackRight = JPL_BIT(9), // also "right surround", "right surround rear"
53 BackCenter = JPL_BIT(10), // also "surround" or "centre surround"
54
57
62
63 // These used by Dolby Atmos 7.0.2 and 7.1.2
66
67 TopBackLeft = JPL_BIT(19), // also "top rear left"
69 TopBackRight = JPL_BIT(21), // also "top rear right"
70
71 // ..other speakers can be added here
72
73 NUM_GroundChannels = std::bit_width((uint32)WideRight), // Number of ground channels
74
75 TOP_Channels = TopCenter, // Top channels have value >= than TOP_Channels
76 NUM_TopChannels = std::bit_width((uint32)TopBackRight) - NUM_GroundChannels, // Number of ground channels
77
78 Invalid = 0
79 };
80
81 //==========================================================================
83 namespace ChannelMask
84 {
85 // TODO: channel order matters and some formats differ only by it, so our simple bit mask may not be functional for everything
86
87 // TODO: Extended setups WIP. Integrate, test, etc...
88
89 static constexpr uint32 Invalid = uint32(0);
90
91 //======================================================================
92 static constexpr uint32 Mono = FrontCenter;
93 static constexpr uint32 Stereo = FrontLeft | FrontRight;
94 static constexpr uint32 LCR = FrontLeft | FrontRight | FrontCenter;
95 static constexpr uint32 LRS = FrontLeft | FrontRight | BackCenter;
96 static constexpr uint32 LCRS = FrontLeft | FrontRight | FrontCenter | BackCenter;
97 static constexpr uint32 Quad = FrontLeft | FrontRight | BackLeft | BackRight;
98
99 // TODO: this clashes with Surround 5.0, we should just remove it, or refactor ChannelMask to be a more than just an integer bitmask
100 static constexpr uint32 Pentagonal = FrontLeft | FrontRight | FrontCenter | BackLeft | BackRight;
101
102 //? Couldn't arrange in a way to preserve channel order across different setups
103 //?static constexpr uint32 Hexagonal = FrontLeft | FrontRight | FrontCenter | BackCenter | BackLeft | BackRight;
104
105 static constexpr uint32 Octagonal = FrontLeft | FrontRight | FrontCenter | BackLeft | BackRight | BackCenter | WideLeft | WideRight;
106
107 //======================================================================
108 static constexpr uint32 Surround_4_1 = FrontLeft | FrontRight | LFE | BackLeft | BackRight;
109 static constexpr uint32 Surround_5_0 = FrontLeft | FrontRight | FrontCenter | BackLeft | BackRight;
110 static constexpr uint32 Surround_5_1 = FrontLeft | FrontRight | FrontCenter | LFE | BackLeft | BackRight;
111 static constexpr uint32 Surround_6_0 = FrontLeft | FrontRight | FrontCenter | BackLeft | BackRight | BackCenter;
112 static constexpr uint32 Surround_6_1 = FrontLeft | FrontRight | FrontCenter | LFE | BackLeft | BackRight | BackCenter;
113
114 //======================================================================
115 // DTS surround setups
116 static constexpr uint32 Surround_7_0 = FrontLeft | FrontRight | FrontCenter | SideLeft | SideRight | BackLeft | BackRight;
117 static constexpr uint32 Surround_7_1 = FrontLeft | FrontRight | FrontCenter | LFE | SideLeft | SideRight | BackLeft | BackRight;
118
119 //======================================================================
120 static constexpr uint32 Surround_5_0_2 = FrontLeft | FrontRight | FrontCenter | BackLeft | BackRight | TopSideLeft | TopSideRight;
121 static constexpr uint32 Surround_5_1_2 = FrontLeft | FrontRight | FrontCenter | LFE | BackLeft | BackRight | TopSideLeft | TopSideRight;
124
125 //======================================================================
126 // Dolby Atmos surround setups
127 static constexpr uint32 Surround_7_0_2 = FrontLeft | FrontRight | FrontCenter | SideLeft | SideRight | BackLeft | BackRight | TopSideLeft | TopSideRight;
128 static constexpr uint32 Surround_7_1_2 = FrontLeft | FrontRight | FrontCenter | LFE | SideLeft | SideRight | BackLeft | BackRight | TopSideLeft | TopSideRight;
131
134
135 //======================================================================
136 // Atmos surround setups
141
142 JPL_INLINE std::string_view ToString(uint32 channelMask);
143 }
144
145
146 //==========================================================================
150 {
151 constexpr explicit ChannelMap(uint32 value) : mChannelMask(value) {}
152 public:
153 constexpr ChannelMap() = default;
154
155 static constexpr uint32 InvalidChannelIndex = ~uint32(0);
156
157 [[nodiscard]] constexpr bool Has(EChannel channel) const noexcept { return (mChannelMask & static_cast<uint32_t>(channel)) == channel; }
158 [[nodiscard]] constexpr bool HasLFE() const noexcept { return (mChannelMask & static_cast<uint32_t>(EChannel::LFE)) == EChannel::LFE; }
159 [[nodiscard]] constexpr bool HasTopChannels() const noexcept { return mChannelMask >= EChannel::TOP_Channels; }
160 [[nodiscard]] constexpr bool IsValid() const noexcept { return mChannelMask != ChannelMask::Invalid; }
161
162 [[nodiscard]] constexpr uint32 GetNumChannels() const noexcept { return std::popcount(mChannelMask); }
164 {
165 if (!Has(channel))
166 return InvalidChannelIndex;
167
169 int value = static_cast<int>(mChannelMask);
170 while (value != 0)
171 {
172 if (channel == static_cast<EChannel>(value & -value))
173 return channelIndex;
174
175 value &= (value - 1);
176 ++channelIndex;
177 }
178 return InvalidChannelIndex;
179 }
180
181 [[nodiscard]] constexpr EChannel GetChannelAtIndex(uint32 index) const
182 {
184
185 ForEachChannel([index, &foundChannel](EChannel channel, uint32 channelIndex)
186 {
187 if (channelIndex == index)
189 });
190
191 return foundChannel;
192 }
193
194 [[nodiscard]] constexpr uint32 GetChannelMask() const { return mChannelMask; }
195
196 //[[nodiscard]] static constexpr uint32 MaxSupportedChannels() noexcept { return 8u; }
197
200 {
201 switch (numChannels)
202 {
203 case 1: return ChannelMap(ChannelMask::Mono);
204 case 2: return ChannelMap(ChannelMask::Stereo);
205 case 3: return ChannelMap(ChannelMask::LCR);
206 case 4: return ChannelMap(ChannelMask::Quad);
207 case 5: return ChannelMap(ChannelMask::Surround_4_1);
208 case 6: return ChannelMap(ChannelMask::Surround_5_1);
209 case 7: return ChannelMap(ChannelMask::Surround_6_1);
210 case 8: return ChannelMap(ChannelMask::Surround_7_1);
211 default:
212 JPL_ASSERT("ChannelMap can be created from channel count up to 8 channels.");
213 return ChannelMap(ChannelMask::Invalid);
214 }
215 }
216
217 template<class Predicate>
218 constexpr void ForEachChannel(Predicate predicate) const
219 {
221 int value = static_cast<int>(mChannelMask);
222 while (value != 0)
223 {
224 static_assert(std::invocable<Predicate, EChannel, uint32> ||
225 std::invocable<Predicate, EChannel>, "Invalid predicate signature.");
226
227 const auto channel = static_cast<EChannel>(value & -value);
228 if constexpr (std::invocable<Predicate, EChannel, uint32>)
230 else
232
233 // Clear the lowest set bit
234 value &= (value - 1);
235 ++channelIndex;
236 }
237 }
238
239 [[nodiscard]] constexpr bool operator==(const ChannelMap& other) const noexcept { return mChannelMask == other.mChannelMask; }
240 [[nodiscard]] constexpr bool operator!=(const ChannelMap& other) const noexcept { return mChannelMask != other.mChannelMask; }
241
242 private:
243 friend struct std::hash<JPL::ChannelMap>;
244 uint32 mChannelMask = ChannelMask::Invalid;
245 };
246
247 //==========================================================================
250 {
251 std::string_view Name;
253
255 : Name(ChannelMask::ToString(channelMask))
256 , Layout(ChannelMap::FromChannelMask(channelMask))
257 {
258 }
259
260 NamedChannelMask() noexcept = default;
261
262 JPL_INLINE bool operator==(const NamedChannelMask& other) const noexcept { return other.Layout == Layout; }
263 };
264} // namespace JPL
265
266//==============================================================================
267namespace std
268{
269 template <>
270 struct [[nodiscard]] hash<JPL::ChannelMap>
271 {
272 constexpr std::size_t operator()(const JPL::ChannelMap& channelMap) const
273 {
274 return channelMap.mChannelMask;
275 }
276 };
277}
278
279namespace JPL
280{
282 {
283 switch (channelMask)
284 {
285 case ChannelMask::Invalid: return "INVALID";
286 case ChannelMask::Mono: return "Mono";
287 case ChannelMask::Stereo: return "Stereo";
288 case ChannelMask::LCR: return "LCR";
289 case ChannelMask::LRS: return "LRS";
290 case ChannelMask::LCRS: return "LCRS";
291 case ChannelMask::Quad: return "Quad";
292 //case ChannelMask::Pentagonal: return "Pentagonal"; //? clashes with Surround 5.0
293 case ChannelMask::Octagonal: return "Octagonal";
294 case ChannelMask::Surround_4_1: return "Surround 4.1";
295 case ChannelMask::Surround_5_0: return "Surround 5.0";
296 case ChannelMask::Surround_5_1: return "Surround 5.1";
297 case ChannelMask::Surround_6_0: return "Surround 6.0";
298 case ChannelMask::Surround_6_1: return "Surround 6.1";
299 case ChannelMask::Surround_7_0: return "Surround 7.0";
300 case ChannelMask::Surround_7_1: return "Surround 7.1";
301 case ChannelMask::Surround_5_0_2: return "Surround 5.0.2";
302 case ChannelMask::Surround_5_1_2: return "Surround 5.1.2";
303 case ChannelMask::Surround_5_0_4: return "Surround 5.0.4";
304 case ChannelMask::Surround_5_1_4: return "Surround 5.1.4";
305 case ChannelMask::Surround_7_0_2: return "Surround 7.0.2";
306 case ChannelMask::Surround_7_1_2: return "Surround 7.1.2";
307 case ChannelMask::Surround_7_0_4: return "Surround 7.0.4";
308 case ChannelMask::Surround_7_1_4: return "Surround 7.1.4";
309 case ChannelMask::Surround_7_0_6: return "Surround 7.0.6";
310 case ChannelMask::Surround_7_1_6: return "Surround 7.1.6";
311 case ChannelMask::Surround_9_0_4: return "Surround 9.0.4";
312 case ChannelMask::Surround_9_1_4: return "Surround 9.1.4";
313 case ChannelMask::Surround_9_0_6: return "Surround 9.0.6";
314 case ChannelMask::Surround_9_1_6: return "Surround 9.1.6";
315 default:
316 JPL_ASSERT(false, "Unknown channel mask.");
317 return "< UKNOWN >";
318 }
319 }
320} // namespace JPL
#define JPL_BIT(x)
Definition Core.h:359
#define JPL_ASSERT(inExpression,...)
Main assert macro, usage: JPL_ASSERT(condition, message) or JPL_ASSERT(condition)
Definition ErrorReporting.h:76
Definition ChannelMap.h:150
constexpr uint32 GetNumChannels() const noexcept
Definition ChannelMap.h:162
constexpr bool IsValid() const noexcept
Definition ChannelMap.h:160
constexpr bool operator==(const ChannelMap &other) const noexcept
Definition ChannelMap.h:239
static constexpr ChannelMap FromNumChannels(uint32 numChannels)
Definition ChannelMap.h:199
static constexpr ChannelMap FromChannelMask(uint32 channelMask)
Definition ChannelMap.h:198
constexpr bool operator!=(const ChannelMap &other) const noexcept
Definition ChannelMap.h:240
constexpr ChannelMap()=default
constexpr uint32 GetChannelMask() const
Definition ChannelMap.h:194
constexpr bool HasTopChannels() const noexcept
Definition ChannelMap.h:159
constexpr EChannel GetChannelAtIndex(uint32 index) const
Definition ChannelMap.h:181
constexpr uint32 GetChannelIndex(EChannel channel) const
Definition ChannelMap.h:163
constexpr bool HasLFE() const noexcept
Definition ChannelMap.h:158
constexpr bool Has(EChannel channel) const noexcept
Definition ChannelMap.h:157
constexpr void ForEachChannel(Predicate predicate) const
Definition ChannelMap.h:218
JPL_INLINE std::string_view ToString(uint32 channelMask)
Definition ChannelMap.h:281
Definition AcousticMaterial.h:36
std::uint32_t uint32
Definition Core.h:311
EChannel
Definition ChannelMap.h:39
@ TOP_Channels
Definition ChannelMap.h:75
@ TopBackLeft
Definition ChannelMap.h:67
@ TopFrontRight
Definition ChannelMap.h:61
@ BackCenter
Definition ChannelMap.h:53
@ TopSideRight
Definition ChannelMap.h:65
@ Invalid
Definition ChannelMap.h:78
@ TopFrontCenter
Definition ChannelMap.h:60
@ TopSideLeft
Definition ChannelMap.h:64
@ FrontLeftCenter
Definition ChannelMap.h:48
@ TopBackCenter
Definition ChannelMap.h:68
@ SideRight
Definition ChannelMap.h:46
@ SideLeft
Definition ChannelMap.h:45
@ FrontCenter
Definition ChannelMap.h:42
@ WideRight
Definition ChannelMap.h:56
@ BackRight
Definition ChannelMap.h:52
@ NUM_GroundChannels
Definition ChannelMap.h:73
@ NUM_TopChannels
Definition ChannelMap.h:76
@ TopBackRight
Definition ChannelMap.h:69
@ BackLeft
Definition ChannelMap.h:51
@ FrontRightCenter
Definition ChannelMap.h:49
@ TopCenter
Definition ChannelMap.h:58
@ LFE
Definition ChannelMap.h:43
@ FrontLeft
Definition ChannelMap.h:40
@ WideLeft
Definition ChannelMap.h:55
@ TopFrontLeft
Definition ChannelMap.h:59
@ FrontRight
Definition ChannelMap.h:41
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
Definition ChannelMap.h:268
Utility to hold some channel mask with a name.
Definition ChannelMap.h:250
NamedChannelMask(uint32 channelMask)
Definition ChannelMap.h:254
std::string_view Name
Definition ChannelMap.h:251
ChannelMap Layout
Definition ChannelMap.h:252
NamedChannelMask() noexcept=default
constexpr std::size_t operator()(const JPL::ChannelMap &channelMap) const
Definition ChannelMap.h:272