JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
ChannelConversion.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 "JPLSpatial/Core.h"
26//#include "JPLSpatial/Panning/ChannelConversionMaps.h"
27
28#include <array>
29#include <bit>
30#include <vector>
31#include <utility>
32
33namespace JPL
34{
36
38 // Plane LEFT 0
39 // Plane RIGHT 1
40 // Plane FRONT 2
41 // Plane BACK 3
42 // Plane BOTTOM 4
43 // Plane TOP 5
44 constexpr std::array<std::array<float, 6>, 22> cChannelPlaneRatios =
45 {
46 std::to_array({ 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f}), // FrontLeft
47 std::to_array({ 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f}), // FrontRight
48 std::to_array({ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}), // FrontCentre
49 std::to_array({ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}), // LFE
50
51 std::to_array({ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}), // SideLeft
52 std::to_array({ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}), // SideRight
53
54 std::to_array({ 0.25f, 0.0f, 0.75f, 0.0f, 0.0f, 0.0f}), // FrontLeftCentre
55 std::to_array({ 0.0f, 0.25f, 0.75f, 0.0f, 0.0f, 0.0f}), // FrontRightCenter
56
57 std::to_array({ 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}), // BackLeft
58 std::to_array({ 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f}), // BackRight
59 std::to_array({ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}), // BackCentre
60
61 // We put our wide channels to side planes
62 std::to_array({ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}), // WideLeft
63 std::to_array({ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}), // WideRigh
64
65 std::to_array({ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}), // TopCentre
66 std::to_array({ 0.33f, 0.0f, 0.33f, 0.0f, 0.0f, 0.34f}), // TopFrontLeft
67 std::to_array({ 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f}), // TopFrontCentre
68 std::to_array({ 0.0f, 0.33f, 0.33f, 0.0f, 0.0f, 0.34f}), // TopFrontRight
69
70 std::to_array({ 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f}), // TopSideLeft
71 std::to_array({ 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f}), // TopSideRight
72
73 std::to_array({ 0.33f, 0.0f, 0.0f, 0.33f, 0.0f, 0.34f}), // TopBackLeft
74 std::to_array({ 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f}), // TopBackCentre
75 std::to_array({ 0.0f, 0.33f, 0.0f, 0.33f, 0.0f, 0.34f}) // TopBakcRight
76 };
77
78 // Paramerers have to be valid indices of cChannelPlaneRatios
91
92 [[nodiscard]] JPL_INLINE constexpr int ToChannelPos(EChannel channel) noexcept
93 {
94 return std::bit_width(static_cast<uint32>(channel) - 1);
95 };
96
97
100 {
101 public:
107
112
114 {
115 mWeights.resize(numOutputs, std::pmr::vector<float>(numInputs, 0.0f, GetDefaultMemoryResource()));
116 }
117
118 JPL_INLINE void Clear() noexcept { mWeights.clear(); }
119
120 JPL_INLINE bool IsEmpty() const noexcept { return mWeights.empty(); }
121
123 {
124 size_t size = 0;
125 for (const auto& outWeights : mWeights)
126 size += outWeights.size();
127 return size;
128 }
129
130 JPL_INLINE std::pair<uint32, uint32> GetDimensions() const
131 {
132 if (IsEmpty())
133 return { 0u, 0u };
134
135 return {
136 static_cast<uint32>(mWeights.size()),
137 static_cast<uint32>(mWeights[0].size())
138 };
139 }
140
141 JPL_INLINE std::pmr::vector<float>& operator[](int i) { return mWeights[i]; }
142 JPL_INLINE const std::pmr::vector<float>& operator[](int i) const { return mWeights[i]; }
143
144 private:
145 std::pmr::vector<std::pmr::vector<float>> mWeights{ GetDefaultMemoryResource() };
146 };
147
148
150 //template<class ChannelConversionWeightsType>
151 static void ComputeChannelConversionRectangularWeights(
152 ChannelMap channelMapIn,
153 ChannelMap channelMapOut,
154 ChannelConversionWeights& outWeights)
155 {
156 // Unmapped input channels.
157 const uint32 numChannelsIn = channelMapIn.GetNumChannels();
158 const uint32 numChannelsOut = channelMapOut.GetNumChannels();
159
161
162 //std::fill(outWeights.begin(), outWeights.end(), 0.0f);
163
164 static auto isSpatialChannel = [](EChannel channel)
165 {
167 };
168
169 // We need to make sure all channels that are present in both channel maps have a 1:1 mapping.
171 {
173 {
174 if (channelIn == channelOut)
176 });
177 });
178
179
180 channelMapIn.ForEachChannel([channelMapOut, /*numChannelsIn, */&outWeights](EChannel channelIn, uint32 iChannelIn)
181 {
183 return;
184
185 if (channelMapOut.Has(channelIn))
186 return;
187
189 {
191 return;
192
194 //const uint32 offset = iChannelOut * numChannelsIn + iChannelIn;
195
196 if (outWeights[iChannelOut][iChannelIn] == 0.0f)
198
199 // Only apply the weight if we haven't already got some contribution from the respective channels.
200 /*if (outWeights[offset] == 0.0f)
201 outWeights[offset] = weight;*/
202 });
203 });
204
205 // Unmapped output channels.
207 {
209 return;
210
211 if (channelMapIn.Has(channelOut))
212 return;
213
214 channelMapIn.ForEachChannel([iChannelOut, channelOut, /*numChannelsIn,*/ &outWeights](EChannel channelIn, uint32 iChannelIn)
215 {
217 return;
218
220 //const uint32 offset = iChannelOut * numChannelsIn + iChannelIn;
221
222 if (outWeights[iChannelOut][iChannelIn] == 0.0f)
224
225 // Only apply the weight if we haven't already got some contribution from the respective channels.
226 /*if (outWeights[offset] == 0)
227 outWeights[offset] = weight;*/
228 });
229 });
230
231 // TODO: handle LFE
232 }
233
234
235#if 0
236 inline void ApplyChannelConversion(const ChannelConversionWeights<Array>& weights, std::span<const float> inValues, std::span<float> outValues)
237 {
238 //JPL_ASSERT(weights.size() >= inValues.size() + outValues.size());
239
241 {
242 float accumulation = 0;
243
246
248 }
249 }
250#endif
251
252#if 0
253 // Hypothetical audio block on mixing thread
256 {
258 {
259 const float* channelInData = inSamples[iChannelIn];
260
262 {
264
265 // channelOutData += channelInData * VBAP
266 const float g = VBAP[iChannelIn][iChannelOut];
267
268 for (uint32 sample = 0; samples < numSamples; ++samples)
270 }
271 }
272 }
273#endif
274} // namespace JPL
#define JPL_ASSERT(inExpression,...)
Main assert macro, usage: JPL_ASSERT(condition, message) or JPL_ASSERT(condition)
Definition ErrorReporting.h:76
Utility helper to access 2D array kind of weights.
Definition ChannelConversion.h:100
ChannelConversionWeights(uint32 numOutputs, uint32 numInputs)
Definition ChannelConversion.h:103
ChannelConversionWeights & operator=(ChannelConversionWeights &&)=default
JPL_INLINE bool IsEmpty() const noexcept
Definition ChannelConversion.h:120
JPL_INLINE const std::pmr::vector< float > & operator[](int i) const
Definition ChannelConversion.h:142
ChannelConversionWeights & operator=(const ChannelConversionWeights &)=default
JPL_INLINE void Clear() noexcept
Definition ChannelConversion.h:118
JPL_INLINE std::pair< uint32, uint32 > GetDimensions() const
Definition ChannelConversion.h:130
JPL_INLINE std::pmr::vector< float > & operator[](int i)
Definition ChannelConversion.h:141
ChannelConversionWeights(ChannelConversionWeights &&)=default
JPL_INLINE size_t size() const noexcept
Definition ChannelConversion.h:122
JPL_INLINE void Resize(uint32 numOutputs, uint32 numInputs)
Definition ChannelConversion.h:113
ChannelConversionWeights(const ChannelConversionWeights &)=default
Definition AcousticMaterial.h:36
JPL_INLINE constexpr int ToChannelPos(EChannel channel) noexcept
Definition ChannelConversion.h:92
constexpr std::array< std::array< float, 6 >, 22 > cChannelPlaneRatios
Implementation adapted from David Reid's https://github.com/mackron/miniaudio.
Definition ChannelConversion.h:44
std::uint32_t uint32
Definition Core.h:311
std::pmr::memory_resource * GetDefaultMemoryResource() noexcept
Definition Memory.h:42
EChannel
Definition ChannelMap.h:39
@ Invalid
Definition ChannelMap.h:78
@ FrontCenter
Definition ChannelMap.h:42
@ LFE
Definition ChannelMap.h:43
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
JPL_INLINE constexpr float CalculateChannelPositionRectangularWeight(uint32 channelPositionA, uint32 channelPositionB)
Definition ChannelConversion.h:79
static constexpr std::size_t size() noexcept
Get number of element of the vector.
Definition SIMD.h:97