From: nu774 Date: Tue, 12 Aug 2014 14:43:19 +0000 (+0900) Subject: refactor pcm reader framework X-Git-Tag: v0.6.0~2 X-Git-Url: http://git.ieval.ro/?a=commitdiff_plain;h=a7e00a42195bd01fad75e5800fcbadeb1a5d3efd;p=fdkaac.git refactor pcm reader framework --- diff --git a/MSVC/fdkaac.vcxproj b/MSVC/fdkaac.vcxproj index fc9a7ef..1ef36fb 100644 --- a/MSVC/fdkaac.vcxproj +++ b/MSVC/fdkaac.vcxproj @@ -100,11 +100,12 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ - + + @@ -113,7 +114,6 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ - @@ -124,7 +124,6 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ - diff --git a/MSVC/fdkaac.vcxproj.filters b/MSVC/fdkaac.vcxproj.filters index 3ad1065..7d1749c 100644 --- a/MSVC/fdkaac.vcxproj.filters +++ b/MSVC/fdkaac.vcxproj.filters @@ -30,15 +30,18 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + + + Source Files + Source Files @@ -59,9 +62,6 @@ Header Files - - Header Files - Header Files @@ -86,9 +86,6 @@ Header Files - - Header Files - Header Files diff --git a/Makefile.am b/Makefile.am index cfceda4..1b896a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,11 +8,12 @@ fdkaac_SOURCES = \ src/caf_reader.c \ src/extrapolater.c \ src/lpc.c \ - src/lpcm.c \ src/m4af.c \ src/main.c \ src/metadata.c \ src/parson.c \ + src/pcm_float_converter.c \ + src/pcm_native_converter.c \ src/pcm_readhelper.c \ src/pcm_sint16_converter.c \ src/progress.c \ diff --git a/src/caf_reader.c b/src/caf_reader.c index 89a66c5..71d21c9 100644 --- a/src/caf_reader.c +++ b/src/caf_reader.c @@ -14,7 +14,7 @@ #include #include #include -#include "caf_reader.h" +#include "pcm_reader.h" #include "m4af.h" typedef struct caf_reader_t { diff --git a/src/caf_reader.h b/src/caf_reader.h deleted file mode 100644 index d341531..0000000 --- a/src/caf_reader.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2013 nu774 - * For conditions of distribution and use, see copyright notice in COPYING - */ -#ifndef CAF_READER_H -#define CAF_READER_H - -#include "lpcm.h" -#include "pcm_reader.h" -#include "metadata.h" - -pcm_reader_t *caf_open(pcm_io_context_t *io, - aacenc_tag_callback_t tag_callback, void *tag_ctx); - -#endif diff --git a/src/extrapolater.c b/src/extrapolater.c index c976be5..e80d305 100644 --- a/src/extrapolater.c +++ b/src/extrapolater.c @@ -86,11 +86,11 @@ static int fetch(extrapolater_t *self, unsigned nframes) if (realloc_buffer(bp, nframes * sfmt->bytes_per_frame) == 0) { rc = pcm_read_frames(self->src, bp->data, nframes); - bp->count = rc > 0 ? rc : 0; + if (rc > 0) bp->count = rc; } if (rc > 0) self->nbuffer ^= 1; - return bp->count; + return rc <= 0 ? 0 : bp->count; } static int extrapolate(extrapolater_t *self, const buffer_t *bp, @@ -137,8 +137,27 @@ static int process1(extrapolater_t *self, void *buffer, unsigned nframes) assert(bp->count <= nframes); memcpy(buffer, bp->data, bp->count * sfmt->bytes_per_frame); - if (!fetch(self, nframes)) + if (!fetch(self, nframes)) { + buffer_t *bbp = &self->buffer[self->nbuffer]; + if (bp->count < 2 * LPC_ORDER) { + size_t total = bp->count + bbp->count; + if (bbp->count && + realloc_buffer(bbp, total * sfmt->bytes_per_frame) == 0 && + realloc_buffer(bp, total * sfmt->bytes_per_frame) == 0) + { + memcpy(bbp->data + bbp->count * sfmt->channels_per_frame, + bp->data, bp->count * sfmt->bytes_per_frame); + memcpy(bp->data, bbp->data, total * sfmt->bytes_per_frame); + bp->count = total; + } + } + if (bp->count >= 2 * LPC_ORDER) + extrapolate(self, bp, bbp->data, nframes); + else + memset(bbp->data, 0, nframes * sfmt->bytes_per_frame); + bbp->count = nframes; self->process = process2; + } return bp->count; } @@ -146,27 +165,15 @@ static int process2(extrapolater_t *self, void *buffer, unsigned nframes) { const pcm_sample_description_t *sfmt = pcm_get_format(self->src); buffer_t *bp = &self->buffer[self->nbuffer]; - buffer_t *bbp = &self->buffer[self->nbuffer ^ 1]; - - if (bp->count < 2 * LPC_ORDER) { - size_t total = bp->count + bbp->count; - if (bbp->count && - realloc_buffer(bbp, total * sfmt->bytes_per_frame) == 0) - { - memcpy(bbp->data + bbp->count * sfmt->channels_per_frame, - bp->data, bp->count * sfmt->bytes_per_frame); - bbp->count = total; - bp->count = 0; - bp = bbp; - self->nbuffer ^= 1; - } - } - self->process = process3; - - if (bp->count >= 2 * LPC_ORDER) - extrapolate(self, bp, buffer, nframes); - else - memset(buffer, 0, nframes * sfmt->bytes_per_frame); + if (bp->count < nframes) + nframes = bp->count; + memcpy(buffer, bp->data, nframes * sfmt->bytes_per_frame); + if (bp->count > nframes) + memmove(bp->data, bp->data + nframes * sfmt->channels_per_frame, + (bp->count - nframes) * sfmt->bytes_per_frame); + bp->count -= nframes; + if (bp->count == 0) + self->process = process3; return nframes; } diff --git a/src/lpcm.c b/src/lpcm.c deleted file mode 100644 index a54f83d..0000000 --- a/src/lpcm.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2013 nu774 - * For conditions of distribution and use, see copyright notice in COPYING - */ -#if HAVE_CONFIG_H -# include "config.h" -#endif -#if HAVE_STDINT_H -# include -#endif -#include -#include -#include "lpcm.h" -#include "m4af_endian.h" - -static -inline float pcm_i2f(int32_t n) -{ - union { - int32_t ivalue; - float fvalue; - } u; - u.ivalue = n; - return u.fvalue; -} -static -inline double pcm_i2d(int64_t n) -{ - union { - int64_t ivalue; - double fvalue; - } u; - u.ivalue = n; - return u.fvalue; -} -static -inline int16_t pcm_quantize_s32(int32_t n) -{ - n = ((n >> 15) + 1) >> 1; - return (n == 0x8000) ? 0x7fff : n; -} -static -inline int16_t pcm_quantize_f64(double v) -{ - return (int16_t)lrint(pcm_clip(v * 32768.0, -32768.0, 32767.0)); -} -static -inline int16_t pcm_s8_to_s16(int8_t n) -{ - return n << 8; -} -static -inline int16_t pcm_u8_to_s16(uint8_t n) -{ - return (n << 8) ^ 0x8000; -} -static -inline int16_t pcm_s16le_to_s16(int16_t n) -{ - return m4af_ltoh16(n); -} -static -inline int16_t pcm_s16be_to_s16(int16_t n) -{ - return m4af_btoh16(n); -} -static -inline int16_t pcm_u16le_to_s16(uint16_t n) -{ - return m4af_ltoh16(n) ^ 0x8000; -} -static -inline int16_t pcm_u16be_to_s16(uint16_t n) -{ - return m4af_btoh16(n) ^ 0x8000; -} -static -inline int32_t pcm_s24le_to_s32(uint8_t *p) -{ - return p[0]<<8 | p[1]<<16 | p[2]<<24; -} -static -inline int32_t pcm_s24be_to_s32(uint8_t *p) -{ - return p[0]<<24 | p[1]<<16 | p[2]<<8; -} -static -inline int32_t pcm_u24le_to_s32(uint8_t *p) -{ - return pcm_s24le_to_s32(p) ^ 0x80000000; -} -static -inline int32_t pcm_u24be_to_s32(uint8_t *p) -{ - return pcm_s24be_to_s32(p) ^ 0x80000000; -} -static -inline int16_t pcm_s24le_to_s16(uint8_t *p) -{ - return pcm_quantize_s32(pcm_s24le_to_s32(p)); -} -static -inline int16_t pcm_s24be_to_s16(uint8_t *p) -{ - return pcm_quantize_s32(pcm_s24be_to_s32(p)); -} -static -inline int16_t pcm_u24le_to_s16(uint8_t *p) -{ - return pcm_quantize_s32(pcm_u24le_to_s32(p)); -} -static -inline int16_t pcm_u24be_to_s16(uint8_t *p) -{ - return pcm_quantize_s32(pcm_u24be_to_s32(p)); -} -static -inline int16_t pcm_s32le_to_s16(int32_t n) -{ - return pcm_quantize_s32(m4af_ltoh32(n)); -} -static -inline int16_t pcm_s32be_to_s16(int32_t n) -{ - return pcm_quantize_s32(m4af_btoh32(n)); -} -static -inline int16_t pcm_u32le_to_s16(int32_t n) -{ - return pcm_quantize_s32(m4af_ltoh32(n) ^ 0x80000000); -} -static -inline int16_t pcm_u32be_to_s16(int32_t n) -{ - return pcm_quantize_s32(m4af_btoh32(n) ^ 0x80000000); -} -static -inline int16_t pcm_f32le_to_s16(int32_t n) -{ - return pcm_quantize_f64(pcm_i2f(m4af_ltoh32(n))); -} -static -inline int16_t pcm_f32be_to_s16(int32_t n) -{ - return pcm_quantize_f64(pcm_i2f(m4af_btoh32(n))); -} -static -inline int16_t pcm_f64le_to_s16(int64_t n) -{ - return pcm_quantize_f64(pcm_i2d(m4af_ltoh64(n))); -} -static -inline int16_t pcm_f64be_to_s16(int64_t n) -{ - return pcm_quantize_f64(pcm_i2d(m4af_btoh64(n))); -} - -int pcm_convert_to_native_sint16(const pcm_sample_description_t *format, - const void *input, uint32_t nframes, - int16_t *result) -{ -#define CONVERT(type, conv) \ - do { \ - unsigned i; \ - type *ip = (type *)input; \ - for (i = 0; i < count; ++i) { \ - result[i] = conv(ip[i]); \ - } \ - } while(0) - -#define CONVERT_BYTES(conv) \ - do { \ - unsigned i, bytes_per_channel; \ - uint8_t *ip = (uint8_t *)input; \ - bytes_per_channel = PCM_BYTES_PER_CHANNEL(format); \ - for (i = 0; i < count; ++i) { \ - result[i] = conv(ip); \ - ip += bytes_per_channel; \ - } \ - } while(0) - - uint32_t count = nframes * format->channels_per_frame; - if (!count) - return 0; - switch (PCM_BYTES_PER_CHANNEL(format) | format->sample_type<<4) { - case 1 | PCM_TYPE_SINT<<4: - CONVERT(int8_t, pcm_s8_to_s16); break; - case 1 | PCM_TYPE_UINT<<4: - CONVERT(uint8_t, pcm_u8_to_s16); break; - case 2 | PCM_TYPE_SINT<<4: - CONVERT(int16_t, pcm_s16le_to_s16); break; - case 2 | PCM_TYPE_UINT<<4: - CONVERT(uint16_t, pcm_u16le_to_s16); break; - case 2 | PCM_TYPE_SINT_BE<<4: - CONVERT(int16_t, pcm_s16be_to_s16); break; - case 2 | PCM_TYPE_UINT_BE<<4: - CONVERT(int16_t, pcm_u16be_to_s16); break; - case 3 | PCM_TYPE_SINT<<4: - CONVERT_BYTES(pcm_s24le_to_s16); break; - case 3 | PCM_TYPE_UINT<<4: - CONVERT_BYTES(pcm_u24le_to_s16); break; - case 3 | PCM_TYPE_SINT_BE<<4: - CONVERT_BYTES(pcm_s24be_to_s16); break; - case 3 | PCM_TYPE_UINT_BE<<4: - CONVERT_BYTES(pcm_u24be_to_s16); break; - case 4 | PCM_TYPE_SINT<<4: - CONVERT(int32_t, pcm_s32le_to_s16); break; - case 4 | PCM_TYPE_UINT<<4: - CONVERT(uint32_t, pcm_u32le_to_s16); break; - case 4 | PCM_TYPE_FLOAT<<4: - CONVERT(int32_t, pcm_f32le_to_s16); break; - case 4 | PCM_TYPE_SINT_BE<<4: - CONVERT(int32_t, pcm_s32be_to_s16); break; - case 4 | PCM_TYPE_UINT_BE<<4: - CONVERT(uint32_t, pcm_u32be_to_s16); break; - case 4 | PCM_TYPE_FLOAT_BE<<4: - CONVERT(int32_t, pcm_f32be_to_s16); break; - case 8 | PCM_TYPE_FLOAT<<4: - CONVERT(int64_t, pcm_f64le_to_s16); break; - case 8 | PCM_TYPE_FLOAT_BE<<4: - CONVERT(int64_t, pcm_f64be_to_s16); break; - default: - return -1; - } - return 0; -} diff --git a/src/lpcm.h b/src/lpcm.h index 2ac93ab..b6598c9 100644 --- a/src/lpcm.h +++ b/src/lpcm.h @@ -61,7 +61,4 @@ inline double pcm_clip(double n, double min_value, double max_value) return n; } -int pcm_convert_to_native_sint16(const pcm_sample_description_t *format, - const void *input, uint32_t nframes, - int16_t *result); #endif diff --git a/src/main.c b/src/main.c index ef2fa87..89af78e 100644 --- a/src/main.c +++ b/src/main.c @@ -33,8 +33,7 @@ #include #endif #include "compat.h" -#include "wav_reader.h" -#include "caf_reader.h" +#include "pcm_reader.h" #include "aacenc.h" #include "m4af.h" #include "progress.h" @@ -749,8 +748,9 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) goto END; } } - if ((reader = pcm_open_sint16_converter(reader)) != 0) - reader = extrapolater_open(reader); + if ((reader = pcm_open_native_converter(reader)) != 0) + if ((reader = pcm_open_sint16_converter(reader)) != 0) + reader = extrapolater_open(reader); return reader; END: return 0; @@ -824,8 +824,7 @@ int main(int argc, char **argv) goto END; m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf, aacinfo.confSize); - m4af_set_fixed_frame_duration(m4af, 0, - framelen >> scale_shift); + m4af_set_fixed_frame_duration(m4af, 0, framelen >> scale_shift); m4af_set_vbr_mode(m4af, 0, params.bitrate_mode); m4af_set_priming_mode(m4af, params.gapless_mode + 1); m4af_begin_write(m4af); diff --git a/src/pcm_float_converter.c b/src/pcm_float_converter.c new file mode 100644 index 0000000..594879f --- /dev/null +++ b/src/pcm_float_converter.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2013 nu774 + * For conditions of distribution and use, see copyright notice in COPYING + */ +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#if HAVE_STDINT_H +# include +#endif +#include "pcm_reader.h" + +typedef struct pcm_float_converter_t { + pcm_reader_vtbl_t *vtbl; + pcm_reader_t *src; + pcm_sample_description_t format; +} pcm_float_converter_t; + +static inline pcm_reader_t *get_source(pcm_reader_t *reader) +{ + return ((pcm_float_converter_t *)reader)->src; +} + +static const +pcm_sample_description_t *get_format(pcm_reader_t *reader) +{ + return &((pcm_float_converter_t *)reader)->format; +} + +static int64_t get_length(pcm_reader_t *reader) +{ + return pcm_get_length(get_source(reader)); +} + +static int64_t get_position(pcm_reader_t *reader) +{ + return pcm_get_position(get_source(reader)); +} + +static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) +{ + unsigned i; + pcm_float_converter_t *self = (pcm_float_converter_t *)reader; + const pcm_sample_description_t *sfmt = pcm_get_format(self->src); + nframes = pcm_read_frames(self->src, buffer, nframes); + if (!(sfmt->sample_type & PCM_TYPE_FLOAT)) { + int32_t *ip = buffer; + float *op = buffer; + unsigned i, count = nframes * sfmt->channels_per_frame; + for (i = 0; i < count; ++i) + op[i] = ip[i] / 2147483648.0f; + } + return nframes; +} + +static void teardown(pcm_reader_t **reader) +{ + pcm_float_converter_t *self = (pcm_float_converter_t *)*reader; + pcm_teardown(&self->src); + free(self); + *reader = 0; +} + +static pcm_reader_vtbl_t my_vtable = { + get_format, get_length, get_position, read_frames, teardown +}; + +pcm_reader_t *pcm_open_float_converter(pcm_reader_t *reader) +{ + pcm_float_converter_t *self = 0; + pcm_sample_description_t *fmt; + + if ((self = calloc(1, sizeof(pcm_float_converter_t))) == 0) + return 0; + self->src = reader; + self->vtbl = &my_vtable; + memcpy(&self->format, pcm_get_format(reader), sizeof(self->format)); + fmt = &self->format; + fmt->bits_per_channel = 32; + fmt->sample_type = PCM_TYPE_FLOAT; + fmt->bytes_per_frame = 4 * fmt->channels_per_frame; + return (pcm_reader_t *)self; +} diff --git a/src/pcm_native_converter.c b/src/pcm_native_converter.c new file mode 100644 index 0000000..edba84e --- /dev/null +++ b/src/pcm_native_converter.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2013 nu774 + * For conditions of distribution and use, see copyright notice in COPYING + */ +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#if HAVE_STDINT_H +# include +#endif +#include "m4af_endian.h" +#include "pcm_reader.h" + +static +inline float pcm_i2f(int32_t n) +{ + union { + int32_t ivalue; + float fvalue; + } u; + u.ivalue = n; + return u.fvalue; +} +static +inline double pcm_i2d(int64_t n) +{ + union { + int64_t ivalue; + double fvalue; + } u; + u.ivalue = n; + return u.fvalue; +} +static +inline int32_t pcm_s8_to_s32(int8_t n) +{ + return n << 24; +} +static +inline int32_t pcm_u8_to_s32(uint8_t n) +{ + return (n << 24) ^ 0x80000000; +} +static +inline int32_t pcm_s16le_to_s32(int16_t n) +{ + return m4af_ltoh16(n) << 16; +} +static +inline int32_t pcm_s16be_to_s32(int16_t n) +{ + return m4af_btoh16(n) << 16; +} +static +inline int32_t pcm_u16le_to_s32(uint16_t n) +{ + return (m4af_ltoh16(n) << 16) ^ 0x80000000; +} +static +inline int32_t pcm_u16be_to_s32(uint16_t n) +{ + return (m4af_btoh16(n) << 16) ^ 0x80000000; +} +static +inline int32_t pcm_s24le_to_s32(uint8_t *p) +{ + return p[0]<<8 | p[1]<<16 | p[2]<<24; +} +static +inline int32_t pcm_s24be_to_s32(uint8_t *p) +{ + return p[0]<<24 | p[1]<<16 | p[2]<<8; +} +static +inline int32_t pcm_u24le_to_s32(uint8_t *p) +{ + return pcm_s24le_to_s32(p) ^ 0x80000000; +} +static +inline int32_t pcm_u24be_to_s32(uint8_t *p) +{ + return pcm_s24be_to_s32(p) ^ 0x80000000; +} +static +inline int32_t pcm_s32le_to_s32(int32_t n) +{ + return m4af_ltoh32(n); +} +static +inline int32_t pcm_s32be_to_s32(int32_t n) +{ + return m4af_btoh32(n); +} +static +inline int32_t pcm_u32le_to_s32(int32_t n) +{ + return m4af_ltoh32(n) ^ 0x80000000; +} +static +inline int32_t pcm_u32be_to_s32(int32_t n) +{ + return m4af_btoh32(n) ^ 0x80000000; +} +static +inline float pcm_f32le_to_f32(int32_t n) +{ + return pcm_i2f(m4af_ltoh32(n)); +} +static +inline float pcm_f32be_to_f32(int32_t n) +{ + return pcm_i2f(m4af_btoh32(n)); +} +static +inline float pcm_f64le_to_f32(int64_t n) +{ + return pcm_i2d(m4af_ltoh64(n)); +} +static +inline float pcm_f64be_to_f32(int64_t n) +{ + return pcm_i2d(m4af_btoh64(n)); +} + +static +int pcm_convert_to_native(const pcm_sample_description_t *format, + const void *input, uint32_t nframes, + void *result) +{ +#define CONVERT(type, rtype, conv) \ + do { \ + unsigned i; \ + type *ip = (type *)input; \ + for (i = 0; i < count; ++i) { \ + ((rtype *)result)[i] = conv(ip[i]); \ + } \ + } while(0) + +#define CONVERT_BYTES(rtype, conv) \ + do { \ + unsigned i, bytes_per_channel; \ + uint8_t *ip = (uint8_t *)input; \ + bytes_per_channel = PCM_BYTES_PER_CHANNEL(format); \ + for (i = 0; i < count; ++i) { \ + ((rtype *)result)[i] = conv(ip); \ + ip += bytes_per_channel; \ + } \ + } while(0) + + uint32_t count = nframes * format->channels_per_frame; + if (!count) + return 0; + switch (PCM_BYTES_PER_CHANNEL(format) | format->sample_type<<4) { + case 1 | PCM_TYPE_SINT<<4: + CONVERT(int8_t, int32_t, pcm_s8_to_s32); break; + case 1 | PCM_TYPE_UINT<<4: + CONVERT(uint8_t, int32_t, pcm_u8_to_s32); break; + case 2 | PCM_TYPE_SINT<<4: + CONVERT(int16_t, int32_t, pcm_s16le_to_s32); break; + case 2 | PCM_TYPE_UINT<<4: + CONVERT(uint16_t, int32_t, pcm_u16le_to_s32); break; + case 2 | PCM_TYPE_SINT_BE<<4: + CONVERT(int16_t, int32_t, pcm_s16be_to_s32); break; + case 2 | PCM_TYPE_UINT_BE<<4: + CONVERT(int16_t, int32_t, pcm_u16be_to_s32); break; + case 3 | PCM_TYPE_SINT<<4: + CONVERT_BYTES(int32_t, pcm_s24le_to_s32); break; + case 3 | PCM_TYPE_UINT<<4: + CONVERT_BYTES(int32_t, pcm_u24le_to_s32); break; + case 3 | PCM_TYPE_SINT_BE<<4: + CONVERT_BYTES(int32_t, pcm_s24be_to_s32); break; + case 3 | PCM_TYPE_UINT_BE<<4: + CONVERT_BYTES(int32_t, pcm_u24be_to_s32); break; + case 4 | PCM_TYPE_SINT<<4: + CONVERT(int32_t, int32_t, pcm_s32le_to_s32); break; + case 4 | PCM_TYPE_UINT<<4: + CONVERT(uint32_t, int32_t, pcm_u32le_to_s32); break; + case 4 | PCM_TYPE_FLOAT<<4: + CONVERT(int32_t, float, pcm_f32le_to_f32); break; + case 4 | PCM_TYPE_SINT_BE<<4: + CONVERT(int32_t, int32_t, pcm_s32be_to_s32); break; + case 4 | PCM_TYPE_UINT_BE<<4: + CONVERT(uint32_t, int32_t, pcm_u32be_to_s32); break; + case 4 | PCM_TYPE_FLOAT_BE<<4: + CONVERT(int32_t, float, pcm_f32be_to_f32); break; + case 8 | PCM_TYPE_FLOAT<<4: + CONVERT(int64_t, float, pcm_f64le_to_f32); break; + case 8 | PCM_TYPE_FLOAT_BE<<4: + CONVERT(int64_t, float, pcm_f64be_to_f32); break; + default: + return -1; + } + return 0; +} + +typedef struct pcm_native_converter_t { + pcm_reader_vtbl_t *vtbl; + pcm_reader_t *src; + pcm_sample_description_t format; + void *pivot; + unsigned capacity; +} pcm_native_converter_t; + +static inline pcm_reader_t *get_source(pcm_reader_t *reader) +{ + return ((pcm_native_converter_t *)reader)->src; +} + +static const +pcm_sample_description_t *get_format(pcm_reader_t *reader) +{ + return &((pcm_native_converter_t *)reader)->format; +} + +static int64_t get_length(pcm_reader_t *reader) +{ + return pcm_get_length(get_source(reader)); +} + +static int64_t get_position(pcm_reader_t *reader) +{ + return pcm_get_position(get_source(reader)); +} + +static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) +{ + pcm_native_converter_t *self = (pcm_native_converter_t *)reader; + const pcm_sample_description_t *sfmt = pcm_get_format(self->src); + unsigned bytes = nframes * sfmt->bytes_per_frame; + + if (self->capacity < bytes) { + void *p = realloc(self->pivot, bytes); + if (!p) return -1; + self->pivot = p; + self->capacity = bytes; + } + nframes = pcm_read_frames(self->src, self->pivot, nframes); + if (pcm_convert_to_native(sfmt, self->pivot, nframes, buffer) < 0) + return -1; + return nframes; +} + +static void teardown(pcm_reader_t **reader) +{ + pcm_native_converter_t *self = (pcm_native_converter_t *)*reader; + pcm_teardown(&self->src); + free(self->pivot); + free(self); + *reader = 0; +} + +static pcm_reader_vtbl_t my_vtable = { + get_format, get_length, get_position, read_frames, teardown +}; + +pcm_reader_t *pcm_open_native_converter(pcm_reader_t *reader) +{ + pcm_native_converter_t *self = 0; + pcm_sample_description_t *fmt; + + if ((self = calloc(1, sizeof(pcm_native_converter_t))) == 0) + return 0; + self->src = reader; + self->vtbl = &my_vtable; + memcpy(&self->format, pcm_get_format(reader), sizeof(self->format)); + fmt = &self->format; + fmt->sample_type = PCM_IS_FLOAT(fmt) ? PCM_TYPE_FLOAT : PCM_TYPE_SINT; + fmt->bytes_per_frame = 4 * fmt->channels_per_frame; + return (pcm_reader_t *)self; +} diff --git a/src/pcm_reader.h b/src/pcm_reader.h index 1dfef34..c115002 100644 --- a/src/pcm_reader.h +++ b/src/pcm_reader.h @@ -6,6 +6,7 @@ #define PCM_READER_H #include "lpcm.h" +#include "metadata.h" typedef struct pcm_reader_t pcm_reader_t; @@ -54,11 +55,7 @@ int64_t pcm_get_position(pcm_reader_t *r) return r->vtbl->get_position(r); } -static inline -int64_t pcm_read_frames(pcm_reader_t *r, void *data, unsigned nframes) -{ - return r->vtbl->read_frames(r, data, nframes); -} +int pcm_read_frames(pcm_reader_t *r, void *data, unsigned nframes); static inline void pcm_teardown(pcm_reader_t **r) @@ -111,6 +108,14 @@ int pcm_scanb(pcm_io_context_t *io, const char *fmt, ...); int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size, pcm_sample_description_t *fmt, uint8_t *mapping); +pcm_reader_t *wav_open(pcm_io_context_t *io, int ignore_length); +pcm_reader_t *raw_open(pcm_io_context_t *io, + const pcm_sample_description_t *desc); +pcm_reader_t *caf_open(pcm_io_context_t *io, + aacenc_tag_callback_t tag_callback, void *tag_ctx); + +pcm_reader_t *pcm_open_native_converter(pcm_reader_t *reader); +pcm_reader_t *pcm_open_float_converter(pcm_reader_t *reader); pcm_reader_t *pcm_open_sint16_converter(pcm_reader_t *reader); pcm_reader_t *extrapolater_open(pcm_reader_t *reader); diff --git a/src/pcm_readhelper.c b/src/pcm_readhelper.c index 9087721..dad92ee 100644 --- a/src/pcm_readhelper.c +++ b/src/pcm_readhelper.c @@ -19,15 +19,35 @@ #include "m4af_endian.h" #include "catypes.h" +int pcm_read_frames(pcm_reader_t *r, void *data, unsigned nframes) +{ + int n; + unsigned count = 0; + uint8_t *bp = data; + unsigned bpf = pcm_get_format(r)->bytes_per_frame; + + do { + n = r->vtbl->read_frames(r, bp, nframes - count); + if (n > 0) { + count += n; + bp += n * bpf; + } + } while (n > 0 && count < nframes); + return count; +} + int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size) { int rc; uint32_t count = 0; + uint8_t *bp = buffer; do { - rc = io->vtbl->read(io->cookie, buffer, size - count); - if (rc > 0) + rc = io->vtbl->read(io->cookie, bp, size - count); + if (rc > 0) { count += rc; + bp += rc; + } } while (rc > 0 && count < size); return count > 0 ? count : rc; } diff --git a/src/pcm_sint16_converter.c b/src/pcm_sint16_converter.c index f4a7ad6..052efc8 100644 --- a/src/pcm_sint16_converter.c +++ b/src/pcm_sint16_converter.c @@ -43,10 +43,10 @@ static int64_t get_position(pcm_reader_t *reader) static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) { + unsigned i, count; pcm_sint16_converter_t *self = (pcm_sint16_converter_t *)reader; const pcm_sample_description_t *sfmt = pcm_get_format(self->src); unsigned bytes = nframes * sfmt->bytes_per_frame; - if (self->capacity < bytes) { void *p = realloc(self->pivot, bytes); if (!p) return -1; @@ -54,8 +54,25 @@ static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) self->capacity = bytes; } nframes = pcm_read_frames(self->src, self->pivot, nframes); - if (pcm_convert_to_native_sint16(sfmt, self->pivot, nframes, buffer) < 0) - return -1; + count = nframes * sfmt->channels_per_frame; + if (PCM_IS_FLOAT(sfmt)) { + float *ip = self->pivot; + int16_t *op = buffer; + for (i = 0; i < count; ++i) + op[i] = pcm_clip(ip[i] * 32768.0, -32768.0, 32767.0); + } else { + int32_t *ip = self->pivot; + int16_t *op = buffer; + if (sfmt->bits_per_channel <= 16) { + for (i = 0; i < count; ++i) + op[i] = ip[i] >> 16; + } else { + for (i = 0; i < count; ++i) { + int n = ((ip[i] >> 15) + 1) >> 1; + op[i] = (n == 0x8000) ? 0x7fff : n; + } + } + } return nframes; } @@ -83,12 +100,8 @@ pcm_reader_t *pcm_open_sint16_converter(pcm_reader_t *reader) self->vtbl = &my_vtable; memcpy(&self->format, pcm_get_format(reader), sizeof(self->format)); fmt = &self->format; -#if WORDS_BIGENDIAN - fmt->sample_type = PCM_TYPE_SINT_BE; -#else - fmt->sample_type = PCM_TYPE_SINT; -#endif fmt->bits_per_channel = 16; + fmt->sample_type = PCM_TYPE_SINT; fmt->bytes_per_frame = 2 * fmt->channels_per_frame; return (pcm_reader_t *)self; } diff --git a/src/wav_reader.c b/src/wav_reader.c index bb0e93e..2690d24 100644 --- a/src/wav_reader.c +++ b/src/wav_reader.c @@ -14,7 +14,7 @@ #include #include #include -#include "wav_reader.h" +#include "pcm_reader.h" #define RIFF_FOURCC(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24)) diff --git a/src/wav_reader.h b/src/wav_reader.h deleted file mode 100644 index 2a69df1..0000000 --- a/src/wav_reader.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2013 nu774 - * For conditions of distribution and use, see copyright notice in COPYING - */ -#ifndef WAV_READER_H -#define WAV_READER_H - -#include "lpcm.h" -#include "pcm_reader.h" - -pcm_reader_t *wav_open(pcm_io_context_t *io, int ignore_length); -pcm_reader_t *raw_open(pcm_io_context_t *io, - const pcm_sample_description_t *desc); - -#endif