Loading...
Searching...
No Matches
ChannelLayout.hpp
1#pragma once
2#include <QString>
3
4#include <algorithm>
5#include <array>
6#include <cmath>
7#include <span>
8#include <string_view>
9
14namespace Ui::Monitor
15{
16enum class ChannelLayout
17{
18 Auto,
19 Numbered,
20 Stereo,
21 Surround51,
22 Surround71,
23 Surround714,
24 Ambisonic
25};
26
27inline constexpr std::string_view channel_layout_names[]{
28 "Auto", "Numbered", "Stereo", "5.1", "7.1", "7.1.4", "Ambisonic"};
29
30struct Speaker
31{
32 std::string_view name;
34 double azimuth{};
36 double elevation{};
37 bool lfe{};
38};
39
40namespace detail
41{
42inline constexpr Speaker stereo[]{{"L", -30}, {"R", 30}};
43inline constexpr Speaker s51[]{
44 {"L", -30}, {"R", 30}, {"C", 0}, {"LFE", 0, 0, true}, {"Ls", -110}, {"Rs", 110}};
45inline constexpr Speaker s71[]{
46 {"L", -30}, {"R", 30}, {"C", 0}, {"LFE", 0, 0, true},
47 {"Lss", -90}, {"Rss", 90}, {"Lrs", -150}, {"Rrs", 150}};
48inline constexpr Speaker s714[]{
49 {"L", -30}, {"R", 30}, {"C", 0}, {"LFE", 0, 0, true},
50 {"Lss", -90}, {"Rss", 90}, {"Lrs", -150}, {"Rrs", 150},
51 {"Ltf", -45, 45}, {"Rtf", 45, 45}, {"Ltr", -135, 45}, {"Rtr", 135, 45}};
52}
53
56inline ChannelLayout resolve(ChannelLayout l, int channels) noexcept
57{
58 if(l != ChannelLayout::Auto)
59 return l;
60 switch(channels)
61 {
62 case 2:
63 return ChannelLayout::Stereo;
64 case 6:
65 return ChannelLayout::Surround51;
66 case 8:
67 return ChannelLayout::Surround71;
68 case 12:
69 return ChannelLayout::Surround714;
70 default:
71 return ChannelLayout::Numbered;
72 }
73}
74
76inline std::span<const Speaker> speakers(ChannelLayout l, int channels) noexcept
77{
78 switch(resolve(l, channels))
79 {
80 case ChannelLayout::Stereo:
81 return detail::stereo;
82 case ChannelLayout::Surround51:
83 return detail::s51;
84 case ChannelLayout::Surround71:
85 return detail::s71;
86 case ChannelLayout::Surround714:
87 return detail::s714;
88 default:
89 return {};
90 }
91}
92
93inline QString channelLabel(ChannelLayout l, int channels, int c)
94{
95 const auto sp = speakers(l, channels);
96 if(c < int(sp.size()))
97 return QString::fromLatin1(sp[c].name.data(), sp[c].name.size());
98 if(resolve(l, channels) == ChannelLayout::Ambisonic)
99 {
100 // ACN order: degree n holds channels n^2 .. (n+1)^2 - 1
101 const int n = int(std::sqrt(double(c)));
102 return QStringLiteral("%1.%2").arg(n).arg(c - n * n - n);
103 }
104 return QString::number(c + 1);
105}
106
113inline double loudnessWeight(ChannelLayout l, int channels, int c) noexcept
114{
115 if(resolve(l, channels) == ChannelLayout::Ambisonic)
116 return c == 0 ? 1. : 0.;
117 const auto sp = speakers(l, channels);
118 if(c >= int(sp.size()))
119 return 1.;
120 if(sp[c].lfe)
121 return 0.;
122 const double a = std::abs(sp[c].azimuth);
123 return (a >= 60. && a <= 120. && std::abs(sp[c].elevation) < 30.) ? 1.41 : 1.;
124}
125
131struct Ring
132{
133 std::array<int, 64> channel{};
134 std::array<double, 64> azimuth{};
135 int size{};
136};
137
138inline Ring ring(ChannelLayout l, int channels) noexcept
139{
140 Ring r;
141 const auto sp = speakers(l, channels);
142 if(!sp.empty())
143 {
144 for(int c = 0; c < int(sp.size()) && c < channels; c++)
145 {
146 if(sp[c].lfe || sp[c].elevation > 0)
147 continue;
148 r.channel[r.size] = c;
149 r.azimuth[r.size] = sp[c].azimuth;
150 r.size++;
151 }
152 // Insertion sort by azimuth: at most a dozen entries
153 for(int i = 1; i < r.size; i++)
154 for(int j = i; j > 0 && r.azimuth[j - 1] > r.azimuth[j]; j--)
155 {
156 std::swap(r.azimuth[j - 1], r.azimuth[j]);
157 std::swap(r.channel[j - 1], r.channel[j]);
158 }
159 return r;
160 }
161 r.size = std::min(channels, 64);
162 for(int c = 0; c < r.size; c++)
163 {
164 r.channel[c] = c;
165 r.azimuth[c] = -180. + 360. * (c + 0.5) / r.size;
166 }
167 return r;
168}
169}
Definition BufferDecode.hpp:16
double loudnessWeight(ChannelLayout l, int channels, int c) noexcept
Definition ChannelLayout.hpp:113
ChannelLayout resolve(ChannelLayout l, int channels) noexcept
Definition ChannelLayout.hpp:56
std::span< const Speaker > speakers(ChannelLayout l, int channels) noexcept
The speakers of a layout, empty when it has no fixed positions.
Definition ChannelLayout.hpp:76
Definition ChannelLayout.hpp:132
Definition ChannelLayout.hpp:31
double elevation
Degrees above the listener.
Definition ChannelLayout.hpp:36
double azimuth
Degrees, 0 in front, positive to the right.
Definition ChannelLayout.hpp:34