Simple Directmedia Layer
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

audio: Allow channel maps to specify -1 to mute a channel.

Fixes #11373.

+62 -23
+15 -7
include/SDL3/SDL_audio.h
··· 1189 1189 * channel that it should be remapped to. To reverse a stereo signal's left 1190 1190 * and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap 1191 1191 * multiple channels to the same thing, so `{ 1, 1 }` would duplicate the 1192 - * right channel to both channels of a stereo signal. You cannot change the 1193 - * number of channels through a channel map, just reorder them. 1192 + * right channel to both channels of a stereo signal. An element in the 1193 + * channel map set to -1 instead of a valid channel will mute that channel, 1194 + * setting it to a silence value. 1195 + * 1196 + * You cannot change the number of channels through a channel map, just 1197 + * reorder/mute them. 1194 1198 * 1195 1199 * Data that was previously queued in the stream will still be operated on in 1196 1200 * the order that was current when it was added, which is to say you can put ··· 1206 1210 * 1207 1211 * If `count` is not equal to the current number of channels in the audio 1208 1212 * stream's format, this will fail. This is a safety measure to make sure a a 1209 - * race condition hasn't changed the format while you this call is setting the 1213 + * race condition hasn't changed the format while this call is setting the 1210 1214 * channel map. 1211 1215 * 1212 1216 * \param stream the SDL_AudioStream to change. ··· 1235 1239 * The output channel map reorders data that leaving a stream via 1236 1240 * SDL_GetAudioStreamData. 1237 1241 * 1238 - * Each item in the array represents an output channel, and its value is the 1242 + * Each item in the array represents an input channel, and its value is the 1239 1243 * channel that it should be remapped to. To reverse a stereo signal's left 1240 1244 * and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap 1241 1245 * multiple channels to the same thing, so `{ 1, 1 }` would duplicate the 1242 - * right channel to both channels of a stereo signal. You cannot change the 1243 - * number of channels through a channel map, just reorder them. 1246 + * right channel to both channels of a stereo signal. An element in the 1247 + * channel map set to -1 instead of a valid channel will mute that channel, 1248 + * setting it to a silence value. 1249 + * 1250 + * You cannot change the number of channels through a channel map, just 1251 + * reorder/mute them. 1244 1252 * 1245 1253 * The output channel map can be changed at any time, as output remapping is 1246 1254 * applied during SDL_GetAudioStreamData. ··· 1253 1261 * 1254 1262 * If `count` is not equal to the current number of channels in the audio 1255 1263 * stream's format, this will fail. This is a safety measure to make sure a a 1256 - * race condition hasn't changed the format while you this call is setting the 1264 + * race condition hasn't changed the format while this call is setting the 1257 1265 * channel map. 1258 1266 * 1259 1267 * \param stream the SDL_AudioStream to change.
+47 -16
src/audio/SDL_audiocvt.c
··· 129 129 if (chmap) { 130 130 for (int i = 0; i < channels; i++) { 131 131 const int mapping = chmap[i]; 132 - if ((mapping < 0) || (mapping >= channels)) { 132 + if ((mapping < -1) || (mapping >= channels)) { 133 133 return true; 134 134 } 135 135 } ··· 150 150 } 151 151 152 152 // Swizzle audio channels. src and dst can be the same pointer. It does not change the buffer size. 153 - static void SwizzleAudio(const int num_frames, void *dst, const void *src, int channels, const int *map, int bitsize) 153 + static void SwizzleAudio(const int num_frames, void *dst, const void *src, int channels, const int *map, SDL_AudioFormat fmt) 154 154 { 155 + const int bitsize = (int) SDL_AUDIO_BITSIZE(fmt); 156 + 157 + bool has_null_mappings = false; 158 + for (int i = 0; i < channels; i++) { 159 + if (map[i] == -1) { 160 + has_null_mappings = true; 161 + break; 162 + } 163 + } 164 + 155 165 #define CHANNEL_SWIZZLE(bits) { \ 156 166 Uint##bits *tdst = (Uint##bits *) dst; /* treat as UintX; we only care about moving bits and not the type here. */ \ 157 167 const Uint##bits *tsrc = (const Uint##bits *) src; \ 158 168 if (src != dst) { /* don't need to copy to a temporary frame first. */ \ 159 - for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \ 160 - for (int ch = 0; ch < channels; ch++) { \ 161 - tdst[ch] = tsrc[map[ch]]; \ 169 + if (has_null_mappings) { \ 170 + const Uint##bits silence = (Uint##bits) SDL_GetSilenceValueForFormat(fmt); \ 171 + for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \ 172 + for (int ch = 0; ch < channels; ch++) { \ 173 + const int m = map[ch]; \ 174 + tdst[ch] = (m == -1) ? silence : tsrc[m]; \ 175 + } \ 176 + } \ 177 + } else { \ 178 + for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \ 179 + for (int ch = 0; ch < channels; ch++) { \ 180 + tdst[ch] = tsrc[map[ch]]; \ 181 + } \ 162 182 } \ 163 183 } \ 164 184 } else { \ 165 185 bool isstack; \ 166 186 Uint##bits *tmp = (Uint##bits *) SDL_small_alloc(int, channels, &isstack); /* !!! FIXME: allocate this when setting the channel map instead. */ \ 167 187 if (tmp) { \ 168 - for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \ 169 - for (int ch = 0; ch < channels; ch++) { \ 170 - tmp[ch] = tsrc[map[ch]]; \ 188 + if (has_null_mappings) { \ 189 + const Uint##bits silence = (Uint##bits) SDL_GetSilenceValueForFormat(fmt); \ 190 + for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \ 191 + for (int ch = 0; ch < channels; ch++) { \ 192 + const int m = map[ch]; \ 193 + tmp[ch] = (m == -1) ? silence : tsrc[m]; \ 194 + } \ 195 + for (int ch = 0; ch < channels; ch++) { \ 196 + tdst[ch] = tmp[ch]; \ 197 + } \ 171 198 } \ 172 - for (int ch = 0; ch < channels; ch++) { \ 173 - tdst[ch] = tmp[ch]; \ 199 + } else { \ 200 + for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \ 201 + for (int ch = 0; ch < channels; ch++) { \ 202 + tmp[ch] = tsrc[map[ch]]; \ 203 + } \ 204 + for (int ch = 0; ch < channels; ch++) { \ 205 + tdst[ch] = tmp[ch]; \ 206 + } \ 174 207 } \ 175 208 } \ 176 209 SDL_small_free(tmp, isstack); \ ··· 221 254 SDL_Log("SDL_AUDIO_CONVERT: Convert format %04x->%04x, channels %u->%u", src_format, dst_format, src_channels, dst_channels); 222 255 #endif 223 256 224 - const int src_bitsize = (int) SDL_AUDIO_BITSIZE(src_format); 225 257 const int dst_bitsize = (int) SDL_AUDIO_BITSIZE(dst_format); 226 - 227 258 const int dst_sample_frame_size = (dst_bitsize / 8) * dst_channels; 228 259 229 260 /* Type conversion goes like this now: ··· 245 276 // swizzle input to "standard" format if necessary. 246 277 if (src_map) { 247 278 void* buf = scratch ? scratch : dst; // use scratch if available, since it has to be big enough to hold src, unless it's NULL, then dst has to be. 248 - SwizzleAudio(num_frames, buf, src, src_channels, src_map, src_bitsize); 279 + SwizzleAudio(num_frames, buf, src, src_channels, src_map, src_format); 249 280 src = buf; 250 281 } 251 282 ··· 254 285 if (src_format == dst_format) { 255 286 // nothing to do, we're already in the right format, just copy it over if necessary. 256 287 if (dst_map) { 257 - SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize); 288 + SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format); 258 289 } else if (src != dst) { 259 290 SDL_memcpy(dst, src, num_frames * dst_sample_frame_size); 260 291 } ··· 264 295 // just a byteswap needed? 265 296 if ((src_format ^ dst_format) == SDL_AUDIO_MASK_BIG_ENDIAN) { 266 297 if (dst_map) { // do this first, in case we duplicate channels, we can avoid an extra copy if src != dst. 267 - SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize); 298 + SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format); 268 299 src = dst; 269 300 } 270 301 ConvertAudioSwapEndian(dst, src, num_frames * dst_channels, dst_bitsize); ··· 348 379 SDL_assert(src == dst); // if we got here, we _had_ to have done _something_. Otherwise, we should have memcpy'd! 349 380 350 381 if (dst_map) { 351 - SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize); 382 + SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format); 352 383 } 353 384 } 354 385