···11891189 * channel that it should be remapped to. To reverse a stereo signal's left
11901190 * and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap
11911191 * multiple channels to the same thing, so `{ 1, 1 }` would duplicate the
11921192- * right channel to both channels of a stereo signal. You cannot change the
11931193- * number of channels through a channel map, just reorder them.
11921192+ * right channel to both channels of a stereo signal. An element in the
11931193+ * channel map set to -1 instead of a valid channel will mute that channel,
11941194+ * setting it to a silence value.
11951195+ *
11961196+ * You cannot change the number of channels through a channel map, just
11971197+ * reorder/mute them.
11941198 *
11951199 * Data that was previously queued in the stream will still be operated on in
11961200 * the order that was current when it was added, which is to say you can put
···12061210 *
12071211 * If `count` is not equal to the current number of channels in the audio
12081212 * stream's format, this will fail. This is a safety measure to make sure a a
12091209- * race condition hasn't changed the format while you this call is setting the
12131213+ * race condition hasn't changed the format while this call is setting the
12101214 * channel map.
12111215 *
12121216 * \param stream the SDL_AudioStream to change.
···12351239 * The output channel map reorders data that leaving a stream via
12361240 * SDL_GetAudioStreamData.
12371241 *
12381238- * Each item in the array represents an output channel, and its value is the
12421242+ * Each item in the array represents an input channel, and its value is the
12391243 * channel that it should be remapped to. To reverse a stereo signal's left
12401244 * and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap
12411245 * multiple channels to the same thing, so `{ 1, 1 }` would duplicate the
12421242- * right channel to both channels of a stereo signal. You cannot change the
12431243- * number of channels through a channel map, just reorder them.
12461246+ * right channel to both channels of a stereo signal. An element in the
12471247+ * channel map set to -1 instead of a valid channel will mute that channel,
12481248+ * setting it to a silence value.
12491249+ *
12501250+ * You cannot change the number of channels through a channel map, just
12511251+ * reorder/mute them.
12441252 *
12451253 * The output channel map can be changed at any time, as output remapping is
12461254 * applied during SDL_GetAudioStreamData.
···12531261 *
12541262 * If `count` is not equal to the current number of channels in the audio
12551263 * stream's format, this will fail. This is a safety measure to make sure a a
12561256- * race condition hasn't changed the format while you this call is setting the
12641264+ * race condition hasn't changed the format while this call is setting the
12571265 * channel map.
12581266 *
12591267 * \param stream the SDL_AudioStream to change.
+47-16
src/audio/SDL_audiocvt.c
···129129 if (chmap) {
130130 for (int i = 0; i < channels; i++) {
131131 const int mapping = chmap[i];
132132- if ((mapping < 0) || (mapping >= channels)) {
132132+ if ((mapping < -1) || (mapping >= channels)) {
133133 return true;
134134 }
135135 }
···150150}
151151152152// Swizzle audio channels. src and dst can be the same pointer. It does not change the buffer size.
153153-static void SwizzleAudio(const int num_frames, void *dst, const void *src, int channels, const int *map, int bitsize)
153153+static void SwizzleAudio(const int num_frames, void *dst, const void *src, int channels, const int *map, SDL_AudioFormat fmt)
154154{
155155+ const int bitsize = (int) SDL_AUDIO_BITSIZE(fmt);
156156+157157+ bool has_null_mappings = false;
158158+ for (int i = 0; i < channels; i++) {
159159+ if (map[i] == -1) {
160160+ has_null_mappings = true;
161161+ break;
162162+ }
163163+ }
164164+155165 #define CHANNEL_SWIZZLE(bits) { \
156166 Uint##bits *tdst = (Uint##bits *) dst; /* treat as UintX; we only care about moving bits and not the type here. */ \
157167 const Uint##bits *tsrc = (const Uint##bits *) src; \
158168 if (src != dst) { /* don't need to copy to a temporary frame first. */ \
159159- for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
160160- for (int ch = 0; ch < channels; ch++) { \
161161- tdst[ch] = tsrc[map[ch]]; \
169169+ if (has_null_mappings) { \
170170+ const Uint##bits silence = (Uint##bits) SDL_GetSilenceValueForFormat(fmt); \
171171+ for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
172172+ for (int ch = 0; ch < channels; ch++) { \
173173+ const int m = map[ch]; \
174174+ tdst[ch] = (m == -1) ? silence : tsrc[m]; \
175175+ } \
176176+ } \
177177+ } else { \
178178+ for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
179179+ for (int ch = 0; ch < channels; ch++) { \
180180+ tdst[ch] = tsrc[map[ch]]; \
181181+ } \
162182 } \
163183 } \
164184 } else { \
165185 bool isstack; \
166186 Uint##bits *tmp = (Uint##bits *) SDL_small_alloc(int, channels, &isstack); /* !!! FIXME: allocate this when setting the channel map instead. */ \
167187 if (tmp) { \
168168- for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
169169- for (int ch = 0; ch < channels; ch++) { \
170170- tmp[ch] = tsrc[map[ch]]; \
188188+ if (has_null_mappings) { \
189189+ const Uint##bits silence = (Uint##bits) SDL_GetSilenceValueForFormat(fmt); \
190190+ for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
191191+ for (int ch = 0; ch < channels; ch++) { \
192192+ const int m = map[ch]; \
193193+ tmp[ch] = (m == -1) ? silence : tsrc[m]; \
194194+ } \
195195+ for (int ch = 0; ch < channels; ch++) { \
196196+ tdst[ch] = tmp[ch]; \
197197+ } \
171198 } \
172172- for (int ch = 0; ch < channels; ch++) { \
173173- tdst[ch] = tmp[ch]; \
199199+ } else { \
200200+ for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
201201+ for (int ch = 0; ch < channels; ch++) { \
202202+ tmp[ch] = tsrc[map[ch]]; \
203203+ } \
204204+ for (int ch = 0; ch < channels; ch++) { \
205205+ tdst[ch] = tmp[ch]; \
206206+ } \
174207 } \
175208 } \
176209 SDL_small_free(tmp, isstack); \
···221254 SDL_Log("SDL_AUDIO_CONVERT: Convert format %04x->%04x, channels %u->%u", src_format, dst_format, src_channels, dst_channels);
222255#endif
223256224224- const int src_bitsize = (int) SDL_AUDIO_BITSIZE(src_format);
225257 const int dst_bitsize = (int) SDL_AUDIO_BITSIZE(dst_format);
226226-227258 const int dst_sample_frame_size = (dst_bitsize / 8) * dst_channels;
228259229260 /* Type conversion goes like this now:
···245276 // swizzle input to "standard" format if necessary.
246277 if (src_map) {
247278 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.
248248- SwizzleAudio(num_frames, buf, src, src_channels, src_map, src_bitsize);
279279+ SwizzleAudio(num_frames, buf, src, src_channels, src_map, src_format);
249280 src = buf;
250281 }
251282···254285 if (src_format == dst_format) {
255286 // nothing to do, we're already in the right format, just copy it over if necessary.
256287 if (dst_map) {
257257- SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize);
288288+ SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format);
258289 } else if (src != dst) {
259290 SDL_memcpy(dst, src, num_frames * dst_sample_frame_size);
260291 }
···264295 // just a byteswap needed?
265296 if ((src_format ^ dst_format) == SDL_AUDIO_MASK_BIG_ENDIAN) {
266297 if (dst_map) { // do this first, in case we duplicate channels, we can avoid an extra copy if src != dst.
267267- SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize);
298298+ SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format);
268299 src = dst;
269300 }
270301 ConvertAudioSwapEndian(dst, src, num_frames * dst_channels, dst_bitsize);
···348379 SDL_assert(src == dst); // if we got here, we _had_ to have done _something_. Otherwise, we should have memcpy'd!
349380350381 if (dst_map) {
351351- SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize);
382382+ SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format);
352383 }
353384}
354385