static const float * pcm_convert_float(struct pcm_convert_state *state, const struct audio_format *src_format, const void *src_buffer, size_t src_size, const struct audio_format *dest_format, size_t *dest_size_r, GError **error_r) { const float *buffer = src_buffer; size_t size = src_size; assert(dest_format->format == SAMPLE_FORMAT_FLOAT); if (src_format->reverse_endian || dest_format->reverse_endian) { g_set_error_literal(error_r, pcm_convert_quark(), 0, "Reverse endian not supported"); return NULL; } /* 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, src_format->format, buffer, size, &size); if (buffer == NULL) { g_set_error(error_r, pcm_convert_quark(), 0, "Conversion from %s to float is not implemented", sample_format_to_string(src_format->format)); return NULL; } /* resample with float, because this is the best format for libsamplerate */ if (src_format->sample_rate != dest_format->sample_rate) { buffer = pcm_resample_float(&state->resample, dest_format->channels, src_format->sample_rate, buffer, size, dest_format->sample_rate, &size, error_r); if (buffer == NULL) return NULL; } *dest_size_r = size; return buffer; }
static const int16_t * pcm_convert_16(struct pcm_convert_state *state, const struct audio_format *src_format, const void *src_buffer, size_t src_size, const struct audio_format *dest_format, size_t *dest_size_r, GError **error_r) { const int16_t *buf; size_t len; assert(dest_format->format == SAMPLE_FORMAT_S16); buf = pcm_convert_to_16(&state->format_buffer, &state->dither, src_format->format, src_buffer, src_size, &len); if (buf == NULL) { g_set_error(error_r, pcm_convert_quark(), 0, "Conversion from %s to 16 bit is not implemented", sample_format_to_string(src_format->format)); return NULL; } if (src_format->channels != dest_format->channels) { buf = pcm_convert_channels_16(&state->channels_buffer, dest_format->channels, src_format->channels, buf, len, &len); if (buf == 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; } } if (src_format->sample_rate != dest_format->sample_rate) { buf = pcm_resample_16(&state->resample, dest_format->channels, src_format->sample_rate, buf, len, dest_format->sample_rate, &len, error_r); if (buf == NULL) return NULL; } if (dest_format->reverse_endian) { buf = pcm_byteswap_16(&state->byteswap_buffer, buf, len); assert(buf != NULL); } *dest_size_r = len; return buf; }
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_S24: case SAMPLE_FORMAT_FLOAT: case SAMPLE_FORMAT_DSD: case SAMPLE_FORMAT_DSD_LSBFIRST: 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; }
const void * pcm_convert(G_GNUC_UNUSED struct pcm_convert_state *state, G_GNUC_UNUSED const struct audio_format *src_format, G_GNUC_UNUSED const void *src, G_GNUC_UNUSED size_t src_size, G_GNUC_UNUSED const struct audio_format *dest_format, G_GNUC_UNUSED size_t *dest_size_r, GError **error_r) { g_set_error(error_r, pcm_convert_quark(), 0, "Not implemented"); return NULL; }
const void * pcm_convert(struct pcm_convert_state *state, const struct audio_format *src_format, const void *src, size_t src_size, const struct audio_format *dest_format, size_t *dest_size_r, GError **error_r) { switch (dest_format->format) { case SAMPLE_FORMAT_S16: return pcm_convert_16(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_S24: return pcm_convert_24_packed(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_S24_P32: return pcm_convert_24(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_S32: return pcm_convert_32(state, src_format, src, src_size, dest_format, dest_size_r, error_r); default: g_set_error(error_r, pcm_convert_quark(), 0, "PCM conversion to %s is not implemented", sample_format_to_string(dest_format->format)); return NULL; } }
const void * pcm_convert(struct pcm_convert_state *state, const struct audio_format *src_format, const void *src, size_t src_size, const struct audio_format *dest_format, size_t *dest_size_r, GError **error_r) { if (src_format->reverse_endian) { /* convert to host byte order, because all of our conversion libraries assume host byte order */ src = pcm_byteswap(&state->byteswap_buffer, src_format->format, src, src_size); if (src == NULL) { g_set_error(error_r, pcm_convert_quark(), 0, "PCM byte order change of format '%s' is not implemented", sample_format_to_string(src_format->format)); return NULL; } } struct audio_format float_format; if (src_format->format == SAMPLE_FORMAT_DSD || src_format->format == SAMPLE_FORMAT_DSD_LSBFIRST) { size_t f_size; const bool lsbfirst = src_format->format == SAMPLE_FORMAT_DSD_LSBFIRST; const float *f = pcm_dsd_to_float(&state->dsd, src_format->channels, lsbfirst, src, src_size, &f_size); if (f == NULL) { g_set_error_literal(error_r, pcm_convert_quark(), 0, "DSD to PCM conversion failed"); return NULL; } float_format = *src_format; float_format.format = SAMPLE_FORMAT_FLOAT; src_format = &float_format; src = f; src_size = f_size; } switch (dest_format->format) { case SAMPLE_FORMAT_S16: return pcm_convert_16(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_S24: return pcm_convert_24_packed(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_S24_P32: return pcm_convert_24(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_S32: return pcm_convert_32(state, src_format, src, src_size, dest_format, dest_size_r, error_r); case SAMPLE_FORMAT_FLOAT: return pcm_convert_float(state, src_format, src, src_size, dest_format, dest_size_r, error_r); default: g_set_error(error_r, pcm_convert_quark(), 0, "PCM conversion to %s is not implemented", sample_format_to_string(dest_format->format)); return NULL; } }