mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-06 03:18:13 +00:00
audio: Allow channel maps to specify -1 to mute a channel.
Fixes #11373.
This commit is contained in:
@@ -1189,8 +1189,12 @@ extern SDL_DECLSPEC int * SDLCALL SDL_GetAudioStreamOutputChannelMap(SDL_AudioSt
|
|||||||
* channel that it should be remapped to. To reverse a stereo signal's left
|
* channel that it should be remapped to. To reverse a stereo signal's left
|
||||||
* and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap
|
* and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap
|
||||||
* multiple channels to the same thing, so `{ 1, 1 }` would duplicate the
|
* multiple channels to the same thing, so `{ 1, 1 }` would duplicate the
|
||||||
* right channel to both channels of a stereo signal. You cannot change the
|
* right channel to both channels of a stereo signal. An element in the
|
||||||
* number of channels through a channel map, just reorder them.
|
* channel map set to -1 instead of a valid channel will mute that channel,
|
||||||
|
* setting it to a silence value.
|
||||||
|
*
|
||||||
|
* You cannot change the number of channels through a channel map, just
|
||||||
|
* reorder/mute them.
|
||||||
*
|
*
|
||||||
* Data that was previously queued in the stream will still be operated on in
|
* Data that was previously queued in the stream will still be operated on in
|
||||||
* the order that was current when it was added, which is to say you can put
|
* the order that was current when it was added, which is to say you can put
|
||||||
@@ -1206,7 +1210,7 @@ extern SDL_DECLSPEC int * SDLCALL SDL_GetAudioStreamOutputChannelMap(SDL_AudioSt
|
|||||||
*
|
*
|
||||||
* If `count` is not equal to the current number of channels in the audio
|
* If `count` is not equal to the current number of channels in the audio
|
||||||
* stream's format, this will fail. This is a safety measure to make sure a a
|
* stream's format, this will fail. This is a safety measure to make sure a a
|
||||||
* race condition hasn't changed the format while you this call is setting the
|
* race condition hasn't changed the format while this call is setting the
|
||||||
* channel map.
|
* channel map.
|
||||||
*
|
*
|
||||||
* \param stream the SDL_AudioStream to change.
|
* \param stream the SDL_AudioStream to change.
|
||||||
@@ -1235,12 +1239,16 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamInputChannelMap(SDL_AudioStre
|
|||||||
* The output channel map reorders data that leaving a stream via
|
* The output channel map reorders data that leaving a stream via
|
||||||
* SDL_GetAudioStreamData.
|
* SDL_GetAudioStreamData.
|
||||||
*
|
*
|
||||||
* Each item in the array represents an output channel, and its value is the
|
* Each item in the array represents an input channel, and its value is the
|
||||||
* channel that it should be remapped to. To reverse a stereo signal's left
|
* channel that it should be remapped to. To reverse a stereo signal's left
|
||||||
* and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap
|
* and right values, you'd have an array of `{ 1, 0 }`. It is legal to remap
|
||||||
* multiple channels to the same thing, so `{ 1, 1 }` would duplicate the
|
* multiple channels to the same thing, so `{ 1, 1 }` would duplicate the
|
||||||
* right channel to both channels of a stereo signal. You cannot change the
|
* right channel to both channels of a stereo signal. An element in the
|
||||||
* number of channels through a channel map, just reorder them.
|
* channel map set to -1 instead of a valid channel will mute that channel,
|
||||||
|
* setting it to a silence value.
|
||||||
|
*
|
||||||
|
* You cannot change the number of channels through a channel map, just
|
||||||
|
* reorder/mute them.
|
||||||
*
|
*
|
||||||
* The output channel map can be changed at any time, as output remapping is
|
* The output channel map can be changed at any time, as output remapping is
|
||||||
* applied during SDL_GetAudioStreamData.
|
* applied during SDL_GetAudioStreamData.
|
||||||
@@ -1253,7 +1261,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamInputChannelMap(SDL_AudioStre
|
|||||||
*
|
*
|
||||||
* If `count` is not equal to the current number of channels in the audio
|
* If `count` is not equal to the current number of channels in the audio
|
||||||
* stream's format, this will fail. This is a safety measure to make sure a a
|
* stream's format, this will fail. This is a safety measure to make sure a a
|
||||||
* race condition hasn't changed the format while you this call is setting the
|
* race condition hasn't changed the format while this call is setting the
|
||||||
* channel map.
|
* channel map.
|
||||||
*
|
*
|
||||||
* \param stream the SDL_AudioStream to change.
|
* \param stream the SDL_AudioStream to change.
|
||||||
|
@@ -129,7 +129,7 @@ bool SDL_ChannelMapIsBogus(const int *chmap, int channels)
|
|||||||
if (chmap) {
|
if (chmap) {
|
||||||
for (int i = 0; i < channels; i++) {
|
for (int i = 0; i < channels; i++) {
|
||||||
const int mapping = chmap[i];
|
const int mapping = chmap[i];
|
||||||
if ((mapping < 0) || (mapping >= channels)) {
|
if ((mapping < -1) || (mapping >= channels)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,21 +150,53 @@ bool SDL_ChannelMapIsDefault(const int *chmap, int channels)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Swizzle audio channels. src and dst can be the same pointer. It does not change the buffer size.
|
// Swizzle audio channels. src and dst can be the same pointer. It does not change the buffer size.
|
||||||
static void SwizzleAudio(const int num_frames, void *dst, const void *src, int channels, const int *map, int bitsize)
|
static void SwizzleAudio(const int num_frames, void *dst, const void *src, int channels, const int *map, SDL_AudioFormat fmt)
|
||||||
{
|
{
|
||||||
|
const int bitsize = (int) SDL_AUDIO_BITSIZE(fmt);
|
||||||
|
|
||||||
|
bool has_null_mappings = false;
|
||||||
|
for (int i = 0; i < channels; i++) {
|
||||||
|
if (map[i] == -1) {
|
||||||
|
has_null_mappings = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define CHANNEL_SWIZZLE(bits) { \
|
#define CHANNEL_SWIZZLE(bits) { \
|
||||||
Uint##bits *tdst = (Uint##bits *) dst; /* treat as UintX; we only care about moving bits and not the type here. */ \
|
Uint##bits *tdst = (Uint##bits *) dst; /* treat as UintX; we only care about moving bits and not the type here. */ \
|
||||||
const Uint##bits *tsrc = (const Uint##bits *) src; \
|
const Uint##bits *tsrc = (const Uint##bits *) src; \
|
||||||
if (src != dst) { /* don't need to copy to a temporary frame first. */ \
|
if (src != dst) { /* don't need to copy to a temporary frame first. */ \
|
||||||
|
if (has_null_mappings) { \
|
||||||
|
const Uint##bits silence = (Uint##bits) SDL_GetSilenceValueForFormat(fmt); \
|
||||||
|
for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
|
||||||
|
for (int ch = 0; ch < channels; ch++) { \
|
||||||
|
const int m = map[ch]; \
|
||||||
|
tdst[ch] = (m == -1) ? silence : tsrc[m]; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
|
for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
|
||||||
for (int ch = 0; ch < channels; ch++) { \
|
for (int ch = 0; ch < channels; ch++) { \
|
||||||
tdst[ch] = tsrc[map[ch]]; \
|
tdst[ch] = tsrc[map[ch]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
} \
|
||||||
} else { \
|
} else { \
|
||||||
bool isstack; \
|
bool isstack; \
|
||||||
Uint##bits *tmp = (Uint##bits *) SDL_small_alloc(int, channels, &isstack); /* !!! FIXME: allocate this when setting the channel map instead. */ \
|
Uint##bits *tmp = (Uint##bits *) SDL_small_alloc(int, channels, &isstack); /* !!! FIXME: allocate this when setting the channel map instead. */ \
|
||||||
if (tmp) { \
|
if (tmp) { \
|
||||||
|
if (has_null_mappings) { \
|
||||||
|
const Uint##bits silence = (Uint##bits) SDL_GetSilenceValueForFormat(fmt); \
|
||||||
|
for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
|
||||||
|
for (int ch = 0; ch < channels; ch++) { \
|
||||||
|
const int m = map[ch]; \
|
||||||
|
tmp[ch] = (m == -1) ? silence : tsrc[m]; \
|
||||||
|
} \
|
||||||
|
for (int ch = 0; ch < channels; ch++) { \
|
||||||
|
tdst[ch] = tmp[ch]; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
|
for (int i = 0; i < num_frames; i++, tsrc += channels, tdst += channels) { \
|
||||||
for (int ch = 0; ch < channels; ch++) { \
|
for (int ch = 0; ch < channels; ch++) { \
|
||||||
tmp[ch] = tsrc[map[ch]]; \
|
tmp[ch] = tsrc[map[ch]]; \
|
||||||
@@ -173,6 +205,7 @@ static void SwizzleAudio(const int num_frames, void *dst, const void *src, int c
|
|||||||
tdst[ch] = tmp[ch]; \
|
tdst[ch] = tmp[ch]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
} \
|
||||||
SDL_small_free(tmp, isstack); \
|
SDL_small_free(tmp, isstack); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@@ -221,9 +254,7 @@ void ConvertAudio(int num_frames,
|
|||||||
SDL_Log("SDL_AUDIO_CONVERT: Convert format %04x->%04x, channels %u->%u", src_format, dst_format, src_channels, dst_channels);
|
SDL_Log("SDL_AUDIO_CONVERT: Convert format %04x->%04x, channels %u->%u", src_format, dst_format, src_channels, dst_channels);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const int src_bitsize = (int) SDL_AUDIO_BITSIZE(src_format);
|
|
||||||
const int dst_bitsize = (int) SDL_AUDIO_BITSIZE(dst_format);
|
const int dst_bitsize = (int) SDL_AUDIO_BITSIZE(dst_format);
|
||||||
|
|
||||||
const int dst_sample_frame_size = (dst_bitsize / 8) * dst_channels;
|
const int dst_sample_frame_size = (dst_bitsize / 8) * dst_channels;
|
||||||
|
|
||||||
/* Type conversion goes like this now:
|
/* Type conversion goes like this now:
|
||||||
@@ -245,7 +276,7 @@ void ConvertAudio(int num_frames,
|
|||||||
// swizzle input to "standard" format if necessary.
|
// swizzle input to "standard" format if necessary.
|
||||||
if (src_map) {
|
if (src_map) {
|
||||||
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.
|
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.
|
||||||
SwizzleAudio(num_frames, buf, src, src_channels, src_map, src_bitsize);
|
SwizzleAudio(num_frames, buf, src, src_channels, src_map, src_format);
|
||||||
src = buf;
|
src = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +285,7 @@ void ConvertAudio(int num_frames,
|
|||||||
if (src_format == dst_format) {
|
if (src_format == dst_format) {
|
||||||
// nothing to do, we're already in the right format, just copy it over if necessary.
|
// nothing to do, we're already in the right format, just copy it over if necessary.
|
||||||
if (dst_map) {
|
if (dst_map) {
|
||||||
SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize);
|
SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format);
|
||||||
} else if (src != dst) {
|
} else if (src != dst) {
|
||||||
SDL_memcpy(dst, src, num_frames * dst_sample_frame_size);
|
SDL_memcpy(dst, src, num_frames * dst_sample_frame_size);
|
||||||
}
|
}
|
||||||
@@ -264,7 +295,7 @@ void ConvertAudio(int num_frames,
|
|||||||
// just a byteswap needed?
|
// just a byteswap needed?
|
||||||
if ((src_format ^ dst_format) == SDL_AUDIO_MASK_BIG_ENDIAN) {
|
if ((src_format ^ dst_format) == SDL_AUDIO_MASK_BIG_ENDIAN) {
|
||||||
if (dst_map) { // do this first, in case we duplicate channels, we can avoid an extra copy if src != dst.
|
if (dst_map) { // do this first, in case we duplicate channels, we can avoid an extra copy if src != dst.
|
||||||
SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize);
|
SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format);
|
||||||
src = dst;
|
src = dst;
|
||||||
}
|
}
|
||||||
ConvertAudioSwapEndian(dst, src, num_frames * dst_channels, dst_bitsize);
|
ConvertAudioSwapEndian(dst, src, num_frames * dst_channels, dst_bitsize);
|
||||||
@@ -348,7 +379,7 @@ void ConvertAudio(int num_frames,
|
|||||||
SDL_assert(src == dst); // if we got here, we _had_ to have done _something_. Otherwise, we should have memcpy'd!
|
SDL_assert(src == dst); // if we got here, we _had_ to have done _something_. Otherwise, we should have memcpy'd!
|
||||||
|
|
||||||
if (dst_map) {
|
if (dst_map) {
|
||||||
SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_bitsize);
|
SwizzleAudio(num_frames, dst, src, dst_channels, dst_map, dst_format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user