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 constexpr std::string_view ToString(EChannel channel);
82 constexpr std::string_view ToStringShort(EChannel channel);
83
84
85 //==========================================================================
87 namespace ChannelMask
88 {
89 // TODO: channel order matters and some formats differ only by it, so our simple bit mask may not be functional for everything
90
91 // TODO: Extended setups WIP. Integrate, test, etc...
92
93 inline constexpr uint32 Invalid = uint32(0);
94
95 //======================================================================
96 inline constexpr uint32 Mono = FrontCenter;
97 inline constexpr uint32 Stereo = FrontLeft | FrontRight;
98 inline constexpr uint32 LCR = FrontLeft | FrontRight | FrontCenter;
99 inline constexpr uint32 LRS = FrontLeft | FrontRight | BackCenter;
102
103 // TODO: this clashes with Surround 5.0, we should just remove it, or refactor ChannelMask to be a more than just an integer bitmask
105
106 //? Couldn't arrange in a way to preserve channel order across different setups
107 //?inline constexpr uint32 Hexagonal = FrontLeft | FrontRight | FrontCenter | BackCenter | BackLeft | BackRight;
108
110
111 //======================================================================
117
118 //======================================================================
119 // DTS surround setups
122
123 //======================================================================
128
129 //======================================================================
130 // Dolby Atmos surround setups
135
138
139 //======================================================================
140 // Atmos surround setups
145
146 JPL_INLINE std::string_view ToString(uint32 channelMask);
147 }
148
149
150 //==========================================================================
153 class [[nodiscard]] ChannelMap
154 {
155 constexpr explicit ChannelMap(uint32 value) : mChannelMask(value) {}
156 public:
157 constexpr ChannelMap() = default;
158
159 static constexpr uint32 InvalidChannelIndex = ~uint32(0);
160
161 [[nodiscard]] constexpr bool Has(EChannel channel) const noexcept { return (mChannelMask & static_cast<uint32_t>(channel)) == channel; }
162 [[nodiscard]] constexpr bool HasLFE() const noexcept { return (mChannelMask & static_cast<uint32_t>(EChannel::LFE)) == EChannel::LFE; }
163 [[nodiscard]] constexpr bool HasTopChannels() const noexcept { return mChannelMask >= EChannel::TOP_Channels; }
164 [[nodiscard]] constexpr bool IsValid() const noexcept { return mChannelMask != ChannelMask::Invalid; }
165
166 [[nodiscard]] constexpr uint32 GetNumChannels() const noexcept { return std::popcount(mChannelMask); }
167 [[nodiscard]] constexpr uint32 GetChannelIndex(EChannel channel) const
168 {
169 if (!Has(channel))
170 return InvalidChannelIndex;
171
172 uint32 channelIndex = 0;
173 int value = static_cast<int>(mChannelMask);
174 while (value != 0)
175 {
176 if (channel == static_cast<EChannel>(value & -value))
177 return channelIndex;
178
179 value &= (value - 1);
180 ++channelIndex;
181 }
182 return InvalidChannelIndex;
183 }
184
185 [[nodiscard]] constexpr EChannel GetChannelAtIndex(uint32 index) const
186 {
187 EChannel foundChannel = EChannel::Invalid;
188
189 ForEachChannel([index, &foundChannel](EChannel channel, uint32 channelIndex)
190 {
191 if (channelIndex == index)
192 foundChannel = channel;
193 });
194
195 return foundChannel;
196 }
197
198 [[nodiscard]] constexpr uint32 GetChannelMask() const { return mChannelMask; }
199
200 //[[nodiscard]] static constexpr uint32 MaxSupportedChannels() noexcept { return 8u; }
201
202 [[nodiscard]] static constexpr ChannelMap FromChannelMask(uint32 channelMask) { return ChannelMap(channelMask); }
203 [[nodiscard]] static constexpr ChannelMap FromNumChannels(uint32 numChannels)
204 {
205 switch (numChannels)
206 {
207 case 1: return ChannelMap(ChannelMask::Mono);
208 case 2: return ChannelMap(ChannelMask::Stereo);
209 case 3: return ChannelMap(ChannelMask::LCR);
210 case 4: return ChannelMap(ChannelMask::Quad);
211 case 5: return ChannelMap(ChannelMask::Surround_4_1);
212 case 6: return ChannelMap(ChannelMask::Surround_5_1);
213 case 7: return ChannelMap(ChannelMask::Surround_6_1);
214 case 8: return ChannelMap(ChannelMask::Surround_7_1);
215 default:
216 JPL_ASSERT("ChannelMap can be created from channel count up to 8 channels.");
217 return ChannelMap(ChannelMask::Invalid);
218 }
219 }
220
221 template<class Predicate>
222 constexpr void ForEachChannel(Predicate predicate) const
223 {
224 uint32 channelIndex = 0;
225 int value = static_cast<int>(mChannelMask);
226 while (value != 0)
227 {
228 static_assert(std::invocable<Predicate, EChannel, uint32> ||
229 std::invocable<Predicate, EChannel>, "Invalid predicate signature.");
230
231 const auto channel = static_cast<EChannel>(value & -value);
232 if constexpr (std::invocable<Predicate, EChannel, uint32>)
233 predicate(channel, channelIndex);
234 else
235 predicate(channel);
236
237 // Clear the lowest set bit
238 value &= (value - 1);
239 ++channelIndex;
240 }
241 }
242
243 [[nodiscard]] constexpr bool operator==(const ChannelMap& other) const noexcept { return mChannelMask == other.mChannelMask; }
244 [[nodiscard]] constexpr bool operator!=(const ChannelMap& other) const noexcept { return mChannelMask != other.mChannelMask; }
245
246 private:
247 friend struct std::hash<JPL::ChannelMap>;
248 uint32 mChannelMask = ChannelMask::Invalid;
249 };
250
251 //==========================================================================
254 {
255 std::string_view Name;
257
259 : Name(ChannelMask::ToString(channelMask))
260 , Layout(ChannelMap::FromChannelMask(channelMask))
261 {
262 }
263
264 NamedChannelMask() noexcept = default;
265
266 JPL_INLINE bool operator==(const NamedChannelMask& other) const noexcept { return other.Layout == Layout; }
267 };
268} // namespace JPL
269
270//==============================================================================
271namespace std
272{
273 template <>
274 struct [[nodiscard]] hash<JPL::ChannelMap>
275 {
276 constexpr std::size_t operator()(const JPL::ChannelMap& channelMap) const
277 {
278 return channelMap.mChannelMask;
279 }
280 };
281}
282
283namespace JPL
284{
285 JPL_INLINE std::string_view ChannelMask::ToString(uint32 channelMask)
286 {
287 switch (channelMask)
288 {
289 case ChannelMask::Invalid: return "INVALID";
290 case ChannelMask::Mono: return "Mono";
291 case ChannelMask::Stereo: return "Stereo";
292 case ChannelMask::LCR: return "LCR";
293 case ChannelMask::LRS: return "LRS";
294 case ChannelMask::LCRS: return "LCRS";
295 case ChannelMask::Quad: return "Quad";
296 //case ChannelMask::Pentagonal: return "Pentagonal"; //? clashes with Surround 5.0
297 case ChannelMask::Octagonal: return "Octagonal";
298 case ChannelMask::Surround_4_1: return "Surround 4.1";
299 case ChannelMask::Surround_5_0: return "Surround 5.0";
300 case ChannelMask::Surround_5_1: return "Surround 5.1";
301 case ChannelMask::Surround_6_0: return "Surround 6.0";
302 case ChannelMask::Surround_6_1: return "Surround 6.1";
303 case ChannelMask::Surround_7_0: return "Surround 7.0";
304 case ChannelMask::Surround_7_1: return "Surround 7.1";
305 case ChannelMask::Surround_5_0_2: return "Surround 5.0.2";
306 case ChannelMask::Surround_5_1_2: return "Surround 5.1.2";
307 case ChannelMask::Surround_5_0_4: return "Surround 5.0.4";
308 case ChannelMask::Surround_5_1_4: return "Surround 5.1.4";
309 case ChannelMask::Surround_7_0_2: return "Surround 7.0.2";
310 case ChannelMask::Surround_7_1_2: return "Surround 7.1.2";
311 case ChannelMask::Surround_7_0_4: return "Surround 7.0.4";
312 case ChannelMask::Surround_7_1_4: return "Surround 7.1.4";
313 case ChannelMask::Surround_7_0_6: return "Surround 7.0.6";
314 case ChannelMask::Surround_7_1_6: return "Surround 7.1.6";
315 case ChannelMask::Surround_9_0_4: return "Surround 9.0.4";
316 case ChannelMask::Surround_9_1_4: return "Surround 9.1.4";
317 case ChannelMask::Surround_9_0_6: return "Surround 9.0.6";
318 case ChannelMask::Surround_9_1_6: return "Surround 9.1.6";
319 default:
320 JPL_ASSERT(false, "Unknown channel mask.");
321 return "< UKNOWN >";
322 }
323 }
324
325 constexpr std::string_view ToString(EChannel channel)
326 {
327 switch (channel)
328 {
329 case EChannel::FrontLeft: return "FrontLeft";
330 case EChannel::FrontRight: return "FrontRight";
331 case EChannel::FrontCenter: return "FrontCenter";
332 case EChannel::LFE: return "LFE";
333 case EChannel::SideLeft: return "SideLeft";
334 case EChannel::SideRight: return "SideRight";
335 case EChannel::FrontLeftCenter: return "FrontLeftCenter";
336 case EChannel::FrontRightCenter: return "FrontRightCenter";
337 case EChannel::BackLeft: return "BackLeft";
338 case EChannel::BackRight: return "BackRight";
339 case EChannel::BackCenter: return "BackCenter";
340 case EChannel::WideLeft: return "WideLeft";
341 case EChannel::WideRight: return "WideRight";
342 case EChannel::TopCenter: return "TopCenter";
343 case EChannel::TopFrontLeft: return "TopFrontLeft";
344 case EChannel::TopFrontCenter: return "TopFrontCenter";
345 case EChannel::TopFrontRight: return "TopFrontRight";
346 case EChannel::TopSideLeft: return "TopSideLeft";
347 case EChannel::TopSideRight: return "TopSideRight";
348 case EChannel::TopBackLeft: return "TopBackLeft";
349 case EChannel::TopBackCenter: return "TopBackCenter";
350 case EChannel::TopBackRight: return "TopBackRight";
351 default:
352 case EChannel::Invalid: return "Invalid";
353 }
354 }
355
356 constexpr std::string_view ToStringShort(EChannel channel)
357 {
358 switch (channel)
359 {
360 case EChannel::FrontLeft: return "FL";
361 case EChannel::FrontRight: return "FR";
362 case EChannel::FrontCenter: return "FC";
363 case EChannel::LFE: return "LFE";
364 case EChannel::SideLeft: return "SL";
365 case EChannel::SideRight: return "SR";
366 case EChannel::FrontLeftCenter: return "FLC";
367 case EChannel::FrontRightCenter: return "FRC";
368 case EChannel::BackLeft: return "BL";
369 case EChannel::BackRight: return "BR";
370 case EChannel::BackCenter: return "BC";
371 case EChannel::WideLeft: return "WL";
372 case EChannel::WideRight: return "WR";
373 case EChannel::TopCenter: return "TC";
374 case EChannel::TopFrontLeft: return "TFL";
375 case EChannel::TopFrontCenter: return "TFC";
376 case EChannel::TopFrontRight: return "TFR";
377 case EChannel::TopSideLeft: return "TSL";
378 case EChannel::TopSideRight: return "TSR";
379 case EChannel::TopBackLeft: return "TBL";
380 case EChannel::TopBackCenter: return "TBC";
381 case EChannel::TopBackRight: return "TBR";
382 default:
383 case EChannel::Invalid: return "-";
384 }
385 }
386} // 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:80
Definition ChannelMap.h:154
constexpr uint32 GetNumChannels() const noexcept
Definition ChannelMap.h:166
constexpr bool IsValid() const noexcept
Definition ChannelMap.h:164
constexpr bool operator==(const ChannelMap &other) const noexcept
Definition ChannelMap.h:243
static constexpr ChannelMap FromNumChannels(uint32 numChannels)
Definition ChannelMap.h:203
static constexpr ChannelMap FromChannelMask(uint32 channelMask)
Definition ChannelMap.h:202
constexpr bool operator!=(const ChannelMap &other) const noexcept
Definition ChannelMap.h:244
constexpr ChannelMap()=default
constexpr uint32 GetChannelMask() const
Definition ChannelMap.h:198
constexpr bool HasTopChannels() const noexcept
Definition ChannelMap.h:163
constexpr EChannel GetChannelAtIndex(uint32 index) const
Definition ChannelMap.h:185
constexpr uint32 GetChannelIndex(EChannel channel) const
Definition ChannelMap.h:167
constexpr bool HasLFE() const noexcept
Definition ChannelMap.h:162
constexpr bool Has(EChannel channel) const noexcept
Definition ChannelMap.h:161
constexpr void ForEachChannel(Predicate predicate) const
Definition ChannelMap.h:222
constexpr uint32 Surround_7_1
Definition ChannelMap.h:121
constexpr uint32 LCR
Definition ChannelMap.h:98
constexpr uint32 Surround_5_1
Definition ChannelMap.h:114
constexpr uint32 Pentagonal
Definition ChannelMap.h:104
constexpr uint32 Surround_9_0_6
Definition ChannelMap.h:143
constexpr uint32 Surround_7_0_2
Definition ChannelMap.h:131
constexpr uint32 Surround_7_0
Definition ChannelMap.h:120
constexpr uint32 Surround_7_1_4
Definition ChannelMap.h:134
constexpr uint32 Surround_6_1
Definition ChannelMap.h:116
constexpr uint32 Stereo
Definition ChannelMap.h:97
constexpr uint32 Surround_9_0_4
Definition ChannelMap.h:141
constexpr uint32 Surround_5_1_4
Definition ChannelMap.h:127
constexpr uint32 LRS
Definition ChannelMap.h:99
constexpr uint32 Octagonal
Definition ChannelMap.h:109
constexpr uint32 Surround_4_1
Definition ChannelMap.h:112
constexpr uint32 Surround_7_0_4
Definition ChannelMap.h:133
constexpr uint32 Invalid
Definition ChannelMap.h:93
constexpr uint32 Surround_6_0
Definition ChannelMap.h:115
constexpr uint32 LCRS
Definition ChannelMap.h:100
constexpr uint32 Surround_5_0
Definition ChannelMap.h:113
constexpr uint32 Surround_7_0_6
Definition ChannelMap.h:136
JPL_INLINE std::string_view ToString(uint32 channelMask)
Definition ChannelMap.h:285
constexpr uint32 Surround_9_1_6
Definition ChannelMap.h:144
constexpr uint32 Surround_9_1_4
Definition ChannelMap.h:142
constexpr uint32 Surround_5_0_4
Definition ChannelMap.h:126
constexpr uint32 Quad
Definition ChannelMap.h:101
constexpr uint32 Surround_7_1_6
Definition ChannelMap.h:137
constexpr uint32 Surround_7_1_2
Definition ChannelMap.h:132
constexpr uint32 Surround_5_0_2
Definition ChannelMap.h:124
constexpr uint32 Mono
Definition ChannelMap.h:96
constexpr uint32 Surround_5_1_2
Definition ChannelMap.h:125
Definition AcousticMaterial.h:36
std::uint32_t uint32
Definition Core.h:311
constexpr std::string_view ToString(EChannel channel)
Definition ChannelMap.h:325
constexpr std::string_view ToStringShort(EChannel channel)
Definition ChannelMap.h:356
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
Definition ChannelMap.h:272
Utility to hold some channel mask with a name.
Definition ChannelMap.h:254
NamedChannelMask(uint32 channelMask)
Definition ChannelMap.h:258
std::string_view Name
Definition ChannelMap.h:255
ChannelMap Layout
Definition ChannelMap.h:256
NamedChannelMask() noexcept=default
constexpr std::size_t operator()(const JPL::ChannelMap &channelMap) const
Definition ChannelMap.h:276