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;
|
||||
}
|
||||
|
||||
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,
|
||||
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
|
||||
|
|
|
@ -61,55 +61,6 @@ pcm_convert_reset(struct pcm_convert_state *state)
|
|||
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 *
|
||||
pcm_convert_16(struct pcm_convert_state *state,
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
|
||||
buffer = pcm_convert_to_float(&state->format_buffer,
|
||||
|
@ -298,6 +236,23 @@ pcm_convert_float(struct pcm_convert_state *state,
|
|||
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
|
||||
libsamplerate */
|
||||
|
||||
|
|
Loading…
Reference in New Issue