apply limiter when input is float

This commit is contained in:
nu774 2014-08-12 23:50:49 +09:00
parent a7e00a4219
commit b54538f79e
7 changed files with 211 additions and 11 deletions

View File

@ -99,6 +99,7 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ </Command>
<ClCompile Include="..\src\caf_reader.c" />
<ClCompile Include="..\src\compat_win32.c" />
<ClCompile Include="..\src\extrapolater.c" />
<ClCompile Include="..\src\limiter.c" />
<ClCompile Include="..\src\lpc.c" />
<ClCompile Include="..\src\m4af.c" />
<ClCompile Include="..\src\main.c" />

View File

@ -27,6 +27,9 @@
<ClCompile Include="..\src\extrapolater.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\limiter.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lpc.c">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -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 \

View File

@ -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;
}

186
src/limiter.c Normal file
View File

@ -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 <stdint.h>
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#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;
}

View File

@ -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,
&params->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;
}

View File

@ -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