comparison foosdk/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #include "foobar2000-sdk-pch.h"
2 #include "audio_chunk.h"
3
4 #ifdef _WIN32
5 #include <ks.h>
6 #include <ksmedia.h>
7
8 #if 0
9 #define SPEAKER_FRONT_LEFT 0x1
10 #define SPEAKER_FRONT_RIGHT 0x2
11 #define SPEAKER_FRONT_CENTER 0x4
12 #define SPEAKER_LOW_FREQUENCY 0x8
13 #define SPEAKER_BACK_LEFT 0x10
14 #define SPEAKER_BACK_RIGHT 0x20
15 #define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
16 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
17 #define SPEAKER_BACK_CENTER 0x100
18 #define SPEAKER_SIDE_LEFT 0x200
19 #define SPEAKER_SIDE_RIGHT 0x400
20 #define SPEAKER_TOP_CENTER 0x800
21 #define SPEAKER_TOP_FRONT_LEFT 0x1000
22 #define SPEAKER_TOP_FRONT_CENTER 0x2000
23 #define SPEAKER_TOP_FRONT_RIGHT 0x4000
24 #define SPEAKER_TOP_BACK_LEFT 0x8000
25 #define SPEAKER_TOP_BACK_CENTER 0x10000
26 #define SPEAKER_TOP_BACK_RIGHT 0x20000
27
28 static struct {DWORD m_wfx; unsigned m_native; } const g_translation_table[] =
29 {
30 {SPEAKER_FRONT_LEFT, audio_chunk::channel_front_left},
31 {SPEAKER_FRONT_RIGHT, audio_chunk::channel_front_right},
32 {SPEAKER_FRONT_CENTER, audio_chunk::channel_front_center},
33 {SPEAKER_LOW_FREQUENCY, audio_chunk::channel_lfe},
34 {SPEAKER_BACK_LEFT, audio_chunk::channel_back_left},
35 {SPEAKER_BACK_RIGHT, audio_chunk::channel_back_right},
36 {SPEAKER_FRONT_LEFT_OF_CENTER, audio_chunk::channel_front_center_left},
37 {SPEAKER_FRONT_RIGHT_OF_CENTER, audio_chunk::channel_front_center_right},
38 {SPEAKER_BACK_CENTER, audio_chunk::channel_back_center},
39 {SPEAKER_SIDE_LEFT, audio_chunk::channel_side_left},
40 {SPEAKER_SIDE_RIGHT, audio_chunk::channel_side_right},
41 {SPEAKER_TOP_CENTER, audio_chunk::channel_top_center},
42 {SPEAKER_TOP_FRONT_LEFT, audio_chunk::channel_top_front_left},
43 {SPEAKER_TOP_FRONT_CENTER, audio_chunk::channel_top_front_center},
44 {SPEAKER_TOP_FRONT_RIGHT, audio_chunk::channel_top_front_right},
45 {SPEAKER_TOP_BACK_LEFT, audio_chunk::channel_top_back_left},
46 {SPEAKER_TOP_BACK_CENTER, audio_chunk::channel_top_back_center},
47 {SPEAKER_TOP_BACK_RIGHT, audio_chunk::channel_top_back_right},
48 };
49
50 #endif
51 #endif
52
53
54
55 static constexpr unsigned g_audio_channel_config_table[] =
56 {
57 0,
58 audio_chunk::channel_config_mono,
59 audio_chunk::channel_config_stereo,
60 audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_lfe,
61 audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right,
62 audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_lfe,
63 audio_chunk::channel_config_5point1,
64 audio_chunk::channel_config_5point1_side | audio_chunk::channel_back_center,
65 audio_chunk::channel_config_7point1,
66 0,
67 audio_chunk::channel_config_7point1 | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left,
68 };
69
70 unsigned audio_chunk::g_guess_channel_config(unsigned count)
71 {
72 if (count == 0) return 0;
73 if (count > 32) throw exception_io_data();
74 unsigned ret = 0;
75 if (count < PFC_TABSIZE(g_audio_channel_config_table)) ret = g_audio_channel_config_table[count];
76 if (ret == 0) {
77 // Warning: 1u<<32u behaves stupidly
78 ret = (unsigned)( (1ull << count) - 1 );
79 }
80 PFC_ASSERT(g_count_channels(ret) == count);
81 return ret;
82 }
83
84 unsigned audio_chunk::g_guess_channel_config_xiph(unsigned count) {
85 switch (count) {
86 case 3:
87 return audio_chunk::channel_front_left | audio_chunk::channel_front_center | audio_chunk::channel_front_right;
88 case 5:
89 return audio_chunk::channel_front_left | audio_chunk::channel_front_center | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right;
90 case 7:
91 return audio_chunk::channel_config_5point1 | audio_chunk::channel_back_center;
92 default:
93 return g_guess_channel_config(count);
94 }
95 }
96
97 unsigned audio_chunk::g_channel_index_from_flag(unsigned p_config,unsigned p_flag) {
98 if (p_config & p_flag) {
99 unsigned index = 0;
100
101 for (unsigned walk = 0; walk < 32; walk++) {
102 unsigned query = 1 << walk;
103 if (p_flag & query) return index;
104 if (p_config & query) index++;
105 }
106 }
107 return (unsigned)(-1);
108 }
109
110 unsigned audio_chunk::g_extract_channel_flag(unsigned p_config,unsigned p_index)
111 {
112 unsigned toskip = p_index;
113 unsigned flag = 1;
114 while(flag)
115 {
116 if (p_config & flag)
117 {
118 if (toskip == 0) break;
119 toskip--;
120 }
121 flag <<= 1;
122 }
123 return flag;
124 }
125
126
127 static const char * const chanNames[] = {
128 "FL", //channel_front_left = 1<<0,
129 "FR", //channel_front_right = 1<<1,
130 "FC", //channel_front_center = 1<<2,
131 "LFE", //channel_lfe = 1<<3,
132 "BL", //channel_back_left = 1<<4,
133 "BR", //channel_back_right = 1<<5,
134 "FCL", //channel_front_center_left = 1<<6,
135 "FCR", //channel_front_center_right = 1<<7,
136 "BC", //channel_back_center = 1<<8,
137 "SL", //channel_side_left = 1<<9,
138 "SR", //channel_side_right = 1<<10,
139 "TC", //channel_top_center = 1<<11,
140 "TFL", //channel_top_front_left = 1<<12,
141 "TFC", //channel_top_front_center = 1<<13,
142 "TFR", //channel_top_front_right = 1<<14,
143 "TBL", //channel_top_back_left = 1<<15,
144 "TBC", //channel_top_back_center = 1<<16,
145 "TBR", //channel_top_back_right = 1<<17,
146 };
147
148 unsigned audio_chunk::g_find_channel_idx(unsigned p_flag) {
149 unsigned rv = 0;
150 if ((p_flag & 0xFFFF) == 0) {
151 rv += 16; p_flag >>= 16;
152 }
153 if ((p_flag & 0xFF) == 0) {
154 rv += 8; p_flag >>= 8;
155 }
156 if ((p_flag & 0xF) == 0) {
157 rv += 4; p_flag >>= 4;
158 }
159 if ((p_flag & 0x3) == 0) {
160 rv += 2; p_flag >>= 2;
161 }
162 if ((p_flag & 0x1) == 0) {
163 rv += 1; p_flag >>= 1;
164 }
165 PFC_ASSERT( p_flag & 1 );
166 return rv;
167 }
168
169 const char * audio_chunk::g_channel_name(unsigned p_flag) {
170 return g_channel_name_byidx(g_find_channel_idx(p_flag));
171 }
172
173 const char * audio_chunk::g_channel_name_byidx(unsigned p_index) {
174 if (p_index < PFC_TABSIZE(chanNames)) return chanNames[p_index];
175 else return "?";
176 }
177
178 pfc::string8 audio_chunk::g_formatChannelMaskDesc(unsigned flags) {
179 pfc::string8 temp; g_formatChannelMaskDesc(flags, temp); return temp;
180 }
181 void audio_chunk::g_formatChannelMaskDesc(unsigned flags, pfc::string_base & out) {
182 out.reset();
183 unsigned idx = 0;
184 while(flags) {
185 if (flags & 1) {
186 if (!out.is_empty()) out << " ";
187 out << g_channel_name_byidx(idx);
188 }
189 flags >>= 1;
190 ++idx;
191 }
192 }
193
194 namespace {
195 struct maskDesc_t {
196 const char* name;
197 unsigned mask;
198 };
199 static constexpr maskDesc_t maskDesc[] = {
200 {"mono", audio_chunk::channel_config_mono},
201 {"stereo", audio_chunk::channel_config_stereo},
202 {"stereo (rear)", audio_chunk::channel_back_left | audio_chunk::channel_back_right},
203 {"stereo (side)", audio_chunk::channel_side_left | audio_chunk::channel_side_right},
204 {"2.1", audio_chunk::channel_config_2point1},
205 {"3.0", audio_chunk::channel_config_3point0},
206 {"4.0", audio_chunk::channel_config_4point0},
207 {"4.1", audio_chunk::channel_config_4point1},
208 {"5.0", audio_chunk::channel_config_5point0},
209 {"5.1", audio_chunk::channel_config_5point1},
210 {"5.1 (side)", audio_chunk::channel_config_5point1_side},
211 {"6.1", audio_chunk::channel_config_5point1 | audio_chunk::channel_back_center},
212 {"6.1 (side)", audio_chunk::channel_config_5point1_side | audio_chunk::channel_back_center},
213 {"7.1", audio_chunk::channel_config_7point1},
214 };
215 }
216
217 const char* audio_chunk::g_channelMaskName(unsigned flags) {
218 for (auto& walk : maskDesc) {
219 if (flags == walk.mask) return walk.name;
220 }
221 return nullptr;
222 }
223
224 static_assert( pfc::countBits32(audio_chunk::channel_config_mono) == 1 );
225 static_assert( pfc::countBits32(audio_chunk::channel_config_stereo) == 2 );
226 static_assert( pfc::countBits32(audio_chunk::channel_config_4point0) == 4 );
227 static_assert( pfc::countBits32(audio_chunk::channel_config_4point0_side) == 4 );
228 static_assert( pfc::countBits32(audio_chunk::channel_config_4point1) == 5 );
229 static_assert( pfc::countBits32(audio_chunk::channel_config_5point0) == 5 );
230 static_assert( pfc::countBits32(audio_chunk::channel_config_5point1) == 6 );
231 static_assert( pfc::countBits32(audio_chunk::channel_config_5point1_side) == 6 );
232 static_assert( pfc::countBits32(audio_chunk::channel_config_6point0) == 6);
233 static_assert( pfc::countBits32(audio_chunk::channel_config_7point1) == 8 );