From b54538f79e8180499baa7d88325733102e061bc5 Mon Sep 17 00:00:00 2001 From: nu774 Date: Tue, 12 Aug 2014 23:50:49 +0900 Subject: [PATCH] apply limiter when input is float --- MSVC/fdkaac.vcxproj | 1 + MSVC/fdkaac.vcxproj.filters | 3 + Makefile.am | 1 + src/extrapolater.c | 8 +- src/limiter.c | 186 ++++++++++++++++++++++++++++++++++++ src/main.c | 22 +++-- src/pcm_reader.h | 1 + 7 files changed, 211 insertions(+), 11 deletions(-) create mode 100644 src/limiter.c diff --git a/MSVC/fdkaac.vcxproj b/MSVC/fdkaac.vcxproj index 1ef36fb..229e8ad 100644 --- a/MSVC/fdkaac.vcxproj +++ b/MSVC/fdkaac.vcxproj @@ -99,6 +99,7 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ + diff --git a/MSVC/fdkaac.vcxproj.filters b/MSVC/fdkaac.vcxproj.filters index 7d1749c..4dd9d00 100644 --- a/MSVC/fdkaac.vcxproj.filters +++ b/MSVC/fdkaac.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + Source Files diff --git a/Makefile.am b/Makefile.am index 1b896a7..17b74ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,7 @@ fdkaac_SOURCES = \ src/aacenc.c \ src/caf_reader.c \ src/extrapolater.c \ + src/limiter.c \ src/lpc.c \ src/m4af.c \ src/main.c \ diff --git a/src/extrapolater.c b/src/extrapolater.c index e80d305..b093478 100644 --- a/src/extrapolater.c +++ b/src/extrapolater.c @@ -126,7 +126,13 @@ static int process0(extrapolater_t *self, void *buffer, unsigned nframes) reverse_buffer(buffer, nframes, nchannels); reverse_buffer(bp->data, bp->count, nchannels); } - self->process = bp->count ? process1 : process2; + if (bp->count) + self->process = process1; + else { + memset(bp->data, 0, nframes * sfmt->bytes_per_frame); + bp->count = nframes; + self->process = process2; + } return nframes; } diff --git a/src/limiter.c b/src/limiter.c new file mode 100644 index 0000000..75eb855 --- /dev/null +++ b/src/limiter.c @@ -0,0 +1,186 @@ +/* + * 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 +#include +#include +#include "pcm_reader.h" +#include "lpc.h" + +typedef struct buffer_t { + void *data; + unsigned count; + unsigned capacity; + unsigned head; +} buffer_t; + +typedef struct limiter_t { + pcm_reader_vtbl_t *vtbl; + pcm_reader_t *src; + pcm_sample_description_t format; + int64_t position; + buffer_t buffers[1]; +} limiter_t; + +static inline pcm_reader_t *get_source(pcm_reader_t *reader) +{ + return ((limiter_t *)reader)->src; +} + +static const +pcm_sample_description_t *get_format(pcm_reader_t *reader) +{ + return pcm_get_format(get_source(reader)); +} + +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 ((limiter_t *)reader)->position; +} + +static int reserve_buffer(buffer_t *bp, size_t required, unsigned unit) +{ + if (bp->capacity < required) { + unsigned newsize = 1; + void *p; + while (newsize < required) + newsize <<= 1; + p = realloc(bp->data, newsize * unit); + if (!p) return -1; + bp->data = p; + bp->capacity = newsize; + } + return 0; +} + +static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) +{ + limiter_t *self = (limiter_t *)reader; + unsigned i, n, res, nch = self->format.channels_per_frame; + size_t bytes = nframes * pcm_get_format(self->src)->bytes_per_frame; + buffer_t *ibp = &self->buffers[nch]; + float *obp = buffer; + + do { + if (reserve_buffer(ibp, bytes, 1) < 0) + return -1; + res = pcm_read_frames(self->src, ibp->data, nframes); + for (n = 0; n < nch; ++n) { + float *ip = (float *)ibp->data, *x; + buffer_t *bp = &self->buffers[n]; + unsigned end, limit; + if (reserve_buffer(bp, bp->count + res, sizeof(float)) < 0) + return -1; + x = bp->data; + for (i = 0; i < res; ++i) + x[bp->count++] = pcm_clip(ip[i * nch + n], -3.0, 3.0); + limit = bp->count; + if (limit > 0 && res > 0) { + float last = x[limit - 1]; + for (; limit > 0 && x[limit-1] * last > 0; --limit) + ; + } + end = bp->head; + while (end < limit) { + unsigned start, peak_pos; + float peak; + for (peak_pos = end; peak_pos < limit; ++peak_pos) + if (x[peak_pos] > 1.0f || x[peak_pos] < -1.0f) + break; + if (peak_pos == limit) + break; + start = peak_pos; + peak = fabs(x[peak_pos]); + while (start > bp->head && x[peak_pos] * x[start] >= 0.0f) + --start; + ++start; + for (end = peak_pos + 1; end < limit; ++end) { + float y; + if (x[peak_pos] * x[end] < 0.0f) + break; + y = fabs(x[end]); + if (y > peak) { + peak = y; + peak_pos = end; + } + } + if (peak < 2.0f) { + float a = (peak - 1.0f) / (peak * peak); + if (x[peak_pos] > 0.0f) a = -a; + for (i = start; i < end; ++i) + x[i] = x[i] + a * x[i] * x[i]; + } else { + float u = peak, v = 1.0f; + float a = (u - 2.0f * v) / (u * u * u); + float b = (3.0f * v - 2.0f * u) / (u * u); + if (x[peak_pos] < 0.0f) b = -b; + for (i = start; i < end; ++i) + x[i] = x[i] + b * x[i] * x[i] + a * x[i] * x[i] * x[i]; + } + } + bp->head = limit; + } + res = nframes; + for (n = 0; n < nch; ++n) + if (self->buffers[n].head < res) + res = self->buffers[n].head; + for (i = 0; i < res; ++i) + for (n = 0; n < nch; ++n) + *obp++ = ((float *)self->buffers[n].data)[i]; + if (res) { + for (n = 0; n < nch; ++n) { + buffer_t *bp = &self->buffers[n]; + float *p = bp->data; + memmove(p, p + res, (bp->count - res) * sizeof(float)); + bp->count -= res; + bp->head -= res; + } + } + } while (res == 0 && self->buffers[0].count); + self->position += res; + return res; +} + +static void teardown(pcm_reader_t **reader) +{ + int i; + limiter_t *self = (limiter_t *)*reader; + pcm_teardown(&self->src); + for (i = 0; i < self->format.channels_per_frame + 1; ++i) + free(self->buffers[i].data); + free(self); + *reader = 0; +} + +static pcm_reader_vtbl_t my_vtable = { + get_format, get_length, get_position, read_frames, teardown +}; + +pcm_reader_t *limiter_open(pcm_reader_t *reader) +{ + limiter_t *self; + int n = pcm_get_format(reader)->channels_per_frame; + size_t size = sizeof(limiter_t) + offsetof(limiter_t, buffers[n + 1]); + + if ((self = calloc(1, size)) == 0) + return 0; + self->src = reader; + self->vtbl = &my_vtable; + self->format = *pcm_get_format(reader); + self->format.bits_per_channel = 32; + return (pcm_reader_t *)self; +} diff --git a/src/main.c b/src/main.c index 89af78e..9e104a4 100644 --- a/src/main.c +++ b/src/main.c @@ -698,7 +698,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) if ((params->input_fp = aacenc_fopen(params->input_filename, "rb")) == 0) { aacenc_fprintf(stderr, "ERROR: %s: %s\n", params->input_filename, strerror(errno)); - goto END; + goto FAIL; } io.cookie = params->input_fp; if (fstat(fileno(params->input_fp), &stb) == 0 @@ -712,7 +712,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) pcm_sample_description_t desc = { 0 }; if (parse_raw_spec(params->raw_format, &desc) < 0) { fprintf(stderr, "ERROR: invalid raw-format spec\n"); - goto END; + goto FAIL; } desc.sample_rate = params->raw_rate; desc.channels_per_frame = params->raw_channels; @@ -720,7 +720,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) desc.bytes_per_frame = params->raw_channels * bytes_per_channel; if ((reader = raw_open(&io, &desc)) == 0) { fprintf(stderr, "ERROR: failed to open raw input\n"); - goto END; + goto FAIL; } } else { int c; @@ -730,7 +730,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) case 'R': if ((reader = wav_open(&io, params->ignore_length)) == 0) { fprintf(stderr, "ERROR: broken / unsupported input file\n"); - goto END; + goto FAIL; } break; case 'c': @@ -740,19 +740,21 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) aacenc_translate_generic_text_tag, ¶ms->source_tag_ctx)) == 0) { fprintf(stderr, "ERROR: broken / unsupported input file\n"); - goto END; + goto FAIL; } break; default: fprintf(stderr, "ERROR: unsupported input file\n"); - goto END; + goto FAIL; } } - if ((reader = pcm_open_native_converter(reader)) != 0) - if ((reader = pcm_open_sint16_converter(reader)) != 0) - reader = extrapolater_open(reader); + reader = pcm_open_native_converter(reader); + if (reader && PCM_IS_FLOAT(pcm_get_format(reader))) + reader = limiter_open(reader); + if (reader && (reader = pcm_open_sint16_converter(reader)) != 0) + reader = extrapolater_open(reader); return reader; -END: +FAIL: return 0; } diff --git a/src/pcm_reader.h b/src/pcm_reader.h index c115002..68c3c55 100644 --- a/src/pcm_reader.h +++ b/src/pcm_reader.h @@ -119,5 +119,6 @@ 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); +pcm_reader_t *limiter_open(pcm_reader_t *reader); #endif -- 2.39.2