Mercurial > foo_out_sdl
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 ); |
