pcm_channels: support floating point samples
This commit is contained in:
parent
31e1be7570
commit
e166ddf46f
@ -244,3 +244,74 @@ pcm_convert_channels_32(struct pcm_buffer *buffer,
|
|||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pcm_convert_channels_float_1_to_2(float *dest, const float *src,
|
||||||
|
const float *src_end)
|
||||||
|
{
|
||||||
|
pcm_convert_channels_24_1_to_2((int32_t *)dest,
|
||||||
|
(const int32_t *)src,
|
||||||
|
(const int32_t *)src_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pcm_convert_channels_float_2_to_1(float *restrict dest,
|
||||||
|
const float *restrict src,
|
||||||
|
const float *restrict src_end)
|
||||||
|
{
|
||||||
|
while (src < src_end) {
|
||||||
|
double a = *src++, b = *src++;
|
||||||
|
|
||||||
|
*dest++ = (a + b) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pcm_convert_channels_float_n_to_2(float *dest,
|
||||||
|
unsigned src_channels, const float *src,
|
||||||
|
const float *src_end)
|
||||||
|
{
|
||||||
|
unsigned c;
|
||||||
|
|
||||||
|
assert(src_channels > 0);
|
||||||
|
|
||||||
|
while (src < src_end) {
|
||||||
|
double sum = 0;
|
||||||
|
float value;
|
||||||
|
|
||||||
|
for (c = 0; c < src_channels; ++c)
|
||||||
|
sum += *src++;
|
||||||
|
value = sum / (double)src_channels;
|
||||||
|
|
||||||
|
/* XXX this is actually only mono ... */
|
||||||
|
*dest++ = value;
|
||||||
|
*dest++ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float *
|
||||||
|
pcm_convert_channels_float(struct pcm_buffer *buffer,
|
||||||
|
unsigned dest_channels,
|
||||||
|
unsigned src_channels, const float *src,
|
||||||
|
size_t src_size, size_t *dest_size_r)
|
||||||
|
{
|
||||||
|
assert(src_size % (sizeof(*src) * src_channels) == 0);
|
||||||
|
|
||||||
|
size_t dest_size = src_size / src_channels * dest_channels;
|
||||||
|
*dest_size_r = dest_size;
|
||||||
|
|
||||||
|
float *dest = pcm_buffer_get(buffer, dest_size);
|
||||||
|
const float *src_end = pcm_end_pointer(src, src_size);
|
||||||
|
|
||||||
|
if (src_channels == 1 && dest_channels == 2)
|
||||||
|
pcm_convert_channels_float_1_to_2(dest, src, src_end);
|
||||||
|
else if (src_channels == 2 && dest_channels == 1)
|
||||||
|
pcm_convert_channels_float_2_to_1(dest, src, src_end);
|
||||||
|
else if (dest_channels == 2)
|
||||||
|
pcm_convert_channels_float_n_to_2(dest, src_channels, src,
|
||||||
|
src_end);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
@ -77,4 +77,21 @@ pcm_convert_channels_32(struct pcm_buffer *buffer,
|
|||||||
unsigned src_channels, const int32_t *src,
|
unsigned src_channels, const int32_t *src,
|
||||||
size_t src_size, size_t *dest_size_r);
|
size_t src_size, size_t *dest_size_r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the number of channels in 32 bit float PCM data.
|
||||||
|
*
|
||||||
|
* @param buffer the destination pcm_buffer object
|
||||||
|
* @param dest_channels the number of channels requested
|
||||||
|
* @param src_channels the number of channels in the source buffer
|
||||||
|
* @param src the source PCM buffer
|
||||||
|
* @param src_size the number of bytes in #src
|
||||||
|
* @param dest_size_r returns the number of bytes of the destination buffer
|
||||||
|
* @return the destination buffer
|
||||||
|
*/
|
||||||
|
const float *
|
||||||
|
pcm_convert_channels_float(struct pcm_buffer *buffer,
|
||||||
|
unsigned dest_channels,
|
||||||
|
unsigned src_channels, const float *src,
|
||||||
|
size_t src_size, size_t *dest_size_r);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,55 +61,6 @@ pcm_convert_reset(struct pcm_convert_state *state)
|
|||||||
pcm_resample_reset(&state->resample);
|
pcm_resample_reset(&state->resample);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *
|
|
||||||
pcm_convert_channels(struct pcm_buffer *buffer, enum sample_format format,
|
|
||||||
uint8_t dest_channels,
|
|
||||||
uint8_t src_channels, const void *src,
|
|
||||||
size_t src_size, size_t *dest_size_r,
|
|
||||||
GError **error_r)
|
|
||||||
{
|
|
||||||
const void *dest = NULL;
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
|
||||||
case SAMPLE_FORMAT_S8:
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
|
||||||
case SAMPLE_FORMAT_DSD:
|
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
|
||||||
"Channel conversion not implemented for format '%s'",
|
|
||||||
sample_format_to_string(format));
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
|
||||||
dest = pcm_convert_channels_16(buffer, dest_channels,
|
|
||||||
src_channels, src,
|
|
||||||
src_size, dest_size_r);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
|
||||||
dest = pcm_convert_channels_24(buffer, dest_channels,
|
|
||||||
src_channels, src,
|
|
||||||
src_size, dest_size_r);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
|
||||||
dest = pcm_convert_channels_32(buffer, dest_channels,
|
|
||||||
src_channels, src,
|
|
||||||
src_size, dest_size_r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest == NULL) {
|
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
|
||||||
"Conversion from %u to %u channels "
|
|
||||||
"is not implemented",
|
|
||||||
src_channels, dest_channels);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int16_t *
|
static const int16_t *
|
||||||
pcm_convert_16(struct pcm_convert_state *state,
|
pcm_convert_16(struct pcm_convert_state *state,
|
||||||
const struct audio_format *src_format,
|
const struct audio_format *src_format,
|
||||||
@ -273,19 +224,6 @@ pcm_convert_float(struct pcm_convert_state *state,
|
|||||||
|
|
||||||
assert(dest_format->format == SAMPLE_FORMAT_FLOAT);
|
assert(dest_format->format == SAMPLE_FORMAT_FLOAT);
|
||||||
|
|
||||||
/* convert channels first, hoping the source format is
|
|
||||||
supported (float is not) */
|
|
||||||
|
|
||||||
if (dest_format->channels != src_format->channels) {
|
|
||||||
buffer = pcm_convert_channels(&state->channels_buffer,
|
|
||||||
src_format->format,
|
|
||||||
dest_format->channels,
|
|
||||||
src_format->channels,
|
|
||||||
buffer, size, &size, error_r);
|
|
||||||
if (buffer == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert to float now */
|
/* convert to float now */
|
||||||
|
|
||||||
buffer = pcm_convert_to_float(&state->format_buffer,
|
buffer = pcm_convert_to_float(&state->format_buffer,
|
||||||
@ -298,6 +236,23 @@ pcm_convert_float(struct pcm_convert_state *state,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* convert channels */
|
||||||
|
|
||||||
|
if (src_format->channels != dest_format->channels) {
|
||||||
|
buffer = pcm_convert_channels_float(&state->channels_buffer,
|
||||||
|
dest_format->channels,
|
||||||
|
src_format->channels,
|
||||||
|
buffer, size, &size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
|
"Conversion from %u to %u channels "
|
||||||
|
"is not implemented",
|
||||||
|
src_format->channels,
|
||||||
|
dest_format->channels);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* resample with float, because this is the best format for
|
/* resample with float, because this is the best format for
|
||||||
libsamplerate */
|
libsamplerate */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user