summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDaniel Schürmann <daschuer@mixxx.org>2017-11-27 21:21:54 +0100
committerGitHub <noreply@github.com>2017-11-27 21:21:54 +0100
commitcad470257688b574c383f0542d502c0a6cfd73d5 (patch)
treee478a467f9f48791fedf6ae4328d10736c760eb0 /lib
parent95bda91a01c4d34ba80d017342d2dc53835072ed (diff)
parent02babe62c3ec85721a2d6da40025f34a5926dca9 (diff)
Merge pull request #1395 from uklotzde/libebur128-1.2.3
Upgrade libebur128 from version 1.1.0 to 1.2.3
Diffstat (limited to 'lib')
-rw-r--r--lib/libebur128-1.2.3/.gitignore (renamed from lib/libebur128-1.1.0/.gitignore)0
-rw-r--r--lib/libebur128-1.2.3/CMakeLists.txt (renamed from lib/libebur128-1.1.0/CMakeLists.txt)8
-rw-r--r--lib/libebur128-1.2.3/COPYING (renamed from lib/libebur128-1.1.0/COPYING)0
-rw-r--r--lib/libebur128-1.2.3/README.md (renamed from lib/libebur128-1.1.0/README.md)23
-rw-r--r--lib/libebur128-1.2.3/cmake/utils.cmake (renamed from lib/libebur128-1.1.0/cmake/utils.cmake)0
-rw-r--r--lib/libebur128-1.2.3/doc/license/R128Scan.txt (renamed from lib/libebur128-1.1.0/doc/license/R128Scan.txt)0
-rw-r--r--lib/libebur128-1.2.3/doc/license/queue.txt (renamed from lib/libebur128-1.1.0/doc/license/queue.txt)0
-rw-r--r--lib/libebur128-1.2.3/ebur128/CMakeLists.txt (renamed from lib/libebur128-1.1.0/ebur128/CMakeLists.txt)40
-rw-r--r--lib/libebur128-1.2.3/ebur128/ebur128.c (renamed from lib/libebur128-1.1.0/ebur128/ebur128.c)552
-rw-r--r--lib/libebur128-1.2.3/ebur128/ebur128.def26
-rw-r--r--lib/libebur128-1.2.3/ebur128/ebur128.h (renamed from lib/libebur128-1.1.0/ebur128/ebur128.h)130
-rw-r--r--lib/libebur128-1.2.3/ebur128/libebur128.pc.cmake11
-rw-r--r--lib/libebur128-1.2.3/ebur128/queue/sys/queue.h (renamed from lib/libebur128-1.1.0/ebur128/queue/sys/queue.h)0
-rw-r--r--lib/libebur128-1.2.3/test/CMakeLists.txt (renamed from lib/libebur128-1.1.0/test/CMakeLists.txt)0
-rw-r--r--lib/libebur128-1.2.3/test/minimal-example.c (renamed from lib/libebur128-1.1.0/test/minimal-example.c)0
-rw-r--r--lib/libebur128-1.2.3/test/tests.c (renamed from lib/libebur128-1.1.0/test/tests.c)43
16 files changed, 645 insertions, 188 deletions
diff --git a/lib/libebur128-1.1.0/.gitignore b/lib/libebur128-1.2.3/.gitignore
index 567609b123..567609b123 100644
--- a/lib/libebur128-1.1.0/.gitignore
+++ b/lib/libebur128-1.2.3/.gitignore
diff --git a/lib/libebur128-1.1.0/CMakeLists.txt b/lib/libebur128-1.2.3/CMakeLists.txt
index e2816f299b..ff352ebfcb 100644
--- a/lib/libebur128-1.1.0/CMakeLists.txt
+++ b/lib/libebur128-1.2.3/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
project(libebur128 C)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
@@ -11,8 +11,7 @@ include(GNUInstallDirs)
add_subdirectory(ebur128)
add_subdirectory(test)
-to_yes_no(SUMMARY_HAS_QUEUE SUMMARY_SPEEXDSP_FOUND)
-to_yes_no(DISABLE_SPEEXDSP)
+to_yes_no(SUMMARY_HAS_QUEUE)
if(ENABLE_INTERNAL_QUEUE_H)
set(USE_QUEUE "using own copy of queue.h")
@@ -23,7 +22,6 @@ endif()
##### Print status
message(STATUS "Status found / disabled --")
message(STATUS "queue.h: ${SUMMARY_HAS_QUEUE}" " ${USE_QUEUE}")
-message(STATUS "speexdsp: ${SUMMARY_SPEEXDSP_FOUND}" " ${DISABLE_SPEEXDSP}")
if(BUILD_STATIC_LIBS)
message(STATUS "build static library and shared library!")
@@ -31,7 +29,7 @@ else()
message(STATUS "not building static library, set BUILD_STATIC_LIBS to ON to enable")
endif()
-if(NOT SUMMARY_HAS_QUEUE AND NOT ENABLE_INTERNAL_QUEUE_H)
+if(NOT ${SUMMARY_HAS_QUEUE} AND NOT ${ENABLE_INTERNAL_QUEUE_H})
message(FATAL_ERROR "queue.h not found, please set ENABLE_INTERNAL_QUEUE_H to ON")
endif()
diff --git a/lib/libebur128-1.1.0/COPYING b/lib/libebur128-1.2.3/COPYING
index e3cebca683..e3cebca683 100644
--- a/lib/libebur128-1.1.0/COPYING
+++ b/lib/libebur128-1.2.3/COPYING
diff --git a/lib/libebur128-1.1.0/README.md b/lib/libebur128-1.2.3/README.md
index 7dfd6aa883..f44adcb7ab 100644
--- a/lib/libebur128-1.1.0/README.md
+++ b/lib/libebur128-1.2.3/README.md
@@ -12,6 +12,24 @@ See also [loudness-scanner tool](https://github.com/jiixyj/loudness-scanner).
News
----
+v1.2.3 released:
+ * Fix uninitialized memory access during true peak scanning (bug #72)
+
+v1.2.2 released (v1.2.1 was mistagged):
+ * Fix a null pointer dereference when doing true peak scanning of 192kHz data
+
+v1.2.0 released:
+
+ * New functions for real time loudness/peak monitoring:
+ * `ebur128_loudness_window()`
+ * `ebur128_set_max_window()`
+ * `ebur128_set_max_history()`
+ * `ebur128_prev_sample_peak()`
+ * `ebur128_prev_true_peak()`
+ * New FIR resampler for true peak calculation, removing Speex dependency
+ * Add true peak conformance tests
+ * Bug fixes
+
v1.1.0 released:
* Add `ebur128_relative_threshold()`
@@ -34,11 +52,6 @@ Features
* True peak scanning
* Supports all samplerates by recalculation of the filter coefficients
-Requirements
-------------
-
-* [libspeexdsp](http://www.speex.org/) - Needed for `ebur128_true_peak`.
-
Installation
------------
diff --git a/lib/libebur128-1.1.0/cmake/utils.cmake b/lib/libebur128-1.2.3/cmake/utils.cmake
index b27c57bd51..b27c57bd51 100644
--- a/lib/libebur128-1.1.0/cmake/utils.cmake
+++ b/lib/libebur128-1.2.3/cmake/utils.cmake
diff --git a/lib/libebur128-1.1.0/doc/license/R128Scan.txt b/lib/libebur128-1.2.3/doc/license/R128Scan.txt
index 305b5e1d85..305b5e1d85 100644
--- a/lib/libebur128-1.1.0/doc/license/R128Scan.txt
+++ b/lib/libebur128-1.2.3/doc/license/R128Scan.txt
diff --git a/lib/libebur128-1.1.0/doc/license/queue.txt b/lib/libebur128-1.2.3/doc/license/queue.txt
index 87fb4d13ba..87fb4d13ba 100644
--- a/lib/libebur128-1.1.0/doc/license/queue.txt
+++ b/lib/libebur128-1.2.3/doc/license/queue.txt
diff --git a/lib/libebur128-1.1.0/ebur128/CMakeLists.txt b/lib/libebur128-1.2.3/ebur128/CMakeLists.txt
index f84febc025..2876aabef4 100644
--- a/lib/libebur128-1.1.0/ebur128/CMakeLists.txt
+++ b/lib/libebur128-1.2.3/ebur128/CMakeLists.txt
@@ -1,7 +1,6 @@
set(BUILD_STATIC_LIBS ON CACHE BOOL "Build static library")
set(WITH_STATIC_PIC OFF CACHE BOOL "Compile static library with -fPIC flag")
set(ENABLE_INTERNAL_QUEUE_H OFF CACHE BOOL "Use own queue.h")
-set(DISABLE_SPEEXDSP OFF CACHE BOOL "Don't build with speexdsp")
#### queue.h
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/queuetest.c
@@ -18,11 +17,13 @@ endif()
if(MSVC)
add_definitions(-D_USE_MATH_DEFINES)
+ add_definitions(/arch:SSE2)
+ add_definitions(-D __SSE2_MATH__)
endif()
set(EBUR128_VERSION_MAJOR 1)
-set(EBUR128_VERSION 1.1.0)
+set(EBUR128_VERSION 1.2.3)
#### static
if(BUILD_STATIC_LIBS)
@@ -35,36 +36,21 @@ if(WITH_STATIC_PIC)
endif()
#### shared
-add_library(ebur128 SHARED ebur128.c)
+# set source file for library, which includes def file if using MSVC
+set(EBUR128_SHARED_SOURCE ebur128.c)
+if(MSVC)
+ set(EBUR128_SHARED_SOURCE ${EBUR128_SHARED_SOURCE} ebur128.def)
+endif()
+
+add_library(ebur128 SHARED ${EBUR128_SHARED_SOURCE})
set_target_properties(ebur128 PROPERTIES
SOVERSION ${EBUR128_VERSION_MAJOR}
VERSION ${EBUR128_VERSION})
-#### speexdsp
-if(NOT DISABLE_SPEEXDSP)
- find_pkg_config(SPEEXDSP speexdsp)
- if(SPEEXDSP_FOUND)
- target_include_directories(ebur128 PRIVATE
- ${SPEEXDSP_INCLUDE_DIRS})
- target_compile_definitions(ebur128 PRIVATE
- -DUSE_SPEEX_RESAMPLER
- -DHAVE_STDINT_H)
- endif()
-endif()
-
if(UNIX)
target_link_libraries(ebur128 m)
endif()
-if(SPEEXDSP_FOUND AND NOT DISABLE_SPEEXDSP)
- if(BUILD_STATIC_LIBS)
- target_compile_options(ebur128_static PRIVATE ${SPEEXDSP_CFLAGS})
- endif()
- target_compile_options(ebur128 PRIVATE ${SPEEXDSP_CFLAGS})
- target_link_libraries(ebur128 ${SPEEXDSP_LIBRARIES})
-endif()
-
-set(SUMMARY_SPEEXDSP_FOUND ${SPEEXDSP_FOUND} CACHE INTERNAL "")
set(EBUR128_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
install(FILES ebur128.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
@@ -73,3 +59,9 @@ if(BUILD_STATIC_LIBS)
else()
install(TARGETS ebur128 DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
+
+#### pkg-config
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libebur128.pc.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/libebur128.pc @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libebur128.pc"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
diff --git a/lib/libebur128-1.1.0/ebur128/ebur128.c b/lib/libebur128-1.2.3/ebur128/ebur128.c
index 3b88662ae1..aa20db35df 100644
--- a/lib/libebur128-1.1.0/ebur128/ebur128.c
+++ b/lib/libebur128-1.2.3/ebur128/ebur128.c
@@ -11,22 +11,34 @@
/* This can be replaced by any BSD-like queue implementation. */
#include <sys/queue.h>
-#ifdef USE_SPEEX_RESAMPLER
- #include <speex/speex_resampler.h>
-#endif
-
#define CHECK_ERROR(condition, errorcode, goto_point) \
if ((condition)) { \
errcode = (errorcode); \
goto goto_point; \
}
-SLIST_HEAD(ebur128_double_queue, ebur128_dq_entry);
+STAILQ_HEAD(ebur128_double_queue, ebur128_dq_entry);
struct ebur128_dq_entry {
double z;
- SLIST_ENTRY(ebur128_dq_entry) entries;
+ STAILQ_ENTRY(ebur128_dq_entry) entries;
};
+#define ALMOST_ZERO 0.000001
+
+typedef struct { /* Data structure for polyphase FIR interpolator */
+ unsigned int factor; /* Interpolation factor of the interpolator */
+ unsigned int taps; /* Taps (prefer odd to increase zero coeffs) */
+ unsigned int channels; /* Number of channels */
+ unsigned int delay; /* Size of delay buffer */
+ struct {
+ unsigned int count; /* Number of coefficients in this subfilter */
+ unsigned int* index; /* Delay index of corresponding filter coeff */
+ double* coeff; /* List of subfilter coefficients */
+ }* filter; /* List of subfilters (one for each factor) */
+ float** z; /* List of delay buffers (one for each channel) */
+ unsigned int zi; /* Current delay buffer index */
+} interpolator;
+
struct ebur128_state_internal {
/** Filtered audio data (used as ring buffer). */
double* audio_data;
@@ -50,8 +62,12 @@ struct ebur128_state_internal {
double v[5][5];
/** Linked list of block energies. */
struct ebur128_double_queue block_list;
+ unsigned long block_list_max;
+ unsigned long block_list_size;
/** Linked list of 3s-block energies, used to calculate LRA. */
struct ebur128_double_queue short_term_block_list;
+ unsigned long st_block_list_max;
+ unsigned long st_block_list_size;
int use_histogram;
unsigned long *block_energy_histogram;
unsigned long *short_term_block_energy_histogram;
@@ -59,16 +75,18 @@ struct ebur128_state_internal {
size_t short_term_frame_counter;
/** Maximum sample peak, one per channel */
double* sample_peak;
+ double* prev_sample_peak;
/** Maximum true peak, one per channel */
double* true_peak;
-#ifdef USE_SPEEX_RESAMPLER
- SpeexResamplerState* resampler;
-#endif
- size_t oversample_factor;
+ double* prev_true_peak;
+ interpolator* interp;
float* resampler_buffer_input;
size_t resampler_buffer_input_frames;
float* resampler_buffer_output;
size_t resampler_buffer_output_frames;
+ /** The maximum window duration in ms. */
+ unsigned long window;
+ unsigned long history;
};
static double relative_gate = -10.0;
@@ -79,6 +97,107 @@ static double minus_twenty_decibels;
static double histogram_energies[1000];
static double histogram_energy_boundaries[1001];
+static interpolator* interp_create(unsigned int taps, unsigned int factor, unsigned int channels) {
+ interpolator* interp = calloc(1, sizeof(interpolator));
+ unsigned int j = 0;
+
+ interp->taps = taps;
+ interp->factor = factor;
+ interp->channels = channels;
+ interp->delay = (interp->taps + interp->factor - 1) / interp->factor;
+
+ /* Initialize the filter memory
+ * One subfilter per interpolation factor. */
+ interp->filter = calloc(interp->factor, sizeof(*interp->filter));
+ for (j = 0; j < interp->factor; j++) {
+ interp->filter[j].index = calloc(interp->delay, sizeof(unsigned int));
+ interp->filter[j].coeff = calloc(interp->delay, sizeof(double));
+ }
+ /* One delay buffer per channel. */
+ interp->z = calloc(interp->channels, sizeof(float*));
+ for (j = 0; j < interp->channels; j++) {
+ interp->z[j] = calloc( interp->delay, sizeof(float) );
+ }
+
+ /* Calculate the filter coefficients */
+ for (j = 0; j < interp->taps; j++) {
+ /* Calculate sinc */
+ double m = (double)j - (double)(interp->taps - 1) / 2.0;
+ double c = 1.0;
+ if (fabs(m) > ALMOST_ZERO) {
+ c = sin(m * M_PI / interp->factor) / (m * M_PI / interp->factor);
+ }
+ /* Apply Hanning window */
+ c *= 0.5 * (1 - cos(2 * M_PI * j / (interp->taps - 1)));
+
+ if (fabs(c) > ALMOST_ZERO) { /* Ignore any zero coeffs. */
+ /* Put the coefficient into the correct subfilter */
+ unsigned int f = j % interp->factor;
+ unsigned int t = interp->filter[f].count++;
+ interp->filter[f].coeff[t] = c;
+ interp->filter[f].index[t] = j / interp->factor;
+ }
+ }
+ return interp;
+}
+
+static void interp_destroy(interpolator* interp) {
+ unsigned int j = 0;
+ if (!interp) {
+ return;
+ }
+ for (j = 0; j < interp->factor; j++) {
+ free(interp->filter[j].index);
+ free(interp->filter[j].coeff);
+ }
+ free(interp->filter);
+ for (j = 0; j < interp->channels; j++) {
+ free(interp->z[j]);
+ }
+ free(interp->z);
+ free(interp);
+}
+
+static size_t interp_process(interpolator* interp, size_t frames, float* in, float* out) {
+ size_t frame = 0;
+ unsigned int chan = 0;
+ unsigned int f = 0;
+ unsigned int t = 0;
+ unsigned int out_stride = interp->channels * interp->factor;
+ float* outp = 0;
+ double acc = 0;
+ double c = 0;
+
+ for (frame = 0; frame < frames; frame++) {
+ for (chan = 0; chan < interp->channels; chan++) {
+ /* Add sample to delay buffer */
+ interp->z[chan][interp->zi] = *in++;
+ /* Apply coefficients */
+ outp = out + chan;
+ for (f = 0; f < interp->factor; f++) {
+ acc = 0.0;
+ for (t = 0; t < interp->filter[f].count; t++) {
+ int i = (int)interp->zi - (int)interp->filter[f].index[t];
+ if (i < 0) {
+ i += interp->delay;
+ }
+ c = interp->filter[f].coeff[t];
+ acc += interp->z[chan][i] * c;
+ }
+ *outp = (float)acc;
+ outp += interp->channels;
+ }
+ }
+ out += out_stride;
+ interp->zi++;
+ if (interp->zi == interp->delay) {
+ interp->zi = 0;
+ }
+ }
+
+ return frames * interp->factor;
+}
+
static void ebur128_init_filter(ebur128_state* st) {
int i, j;
@@ -136,7 +255,9 @@ static void ebur128_init_filter(ebur128_state* st) {
static int ebur128_init_channel_map(ebur128_state* st) {
size_t i;
st->d->channel_map = (int*) malloc(st->channels * sizeof(int));
- if (!st->d->channel_map) return EBUR128_ERROR_NOMEM;
+ if (!st->d->channel_map) {
+ return EBUR128_ERROR_NOMEM;
+ }
if (st->channels == 4) {
st->d->channel_map[0] = EBUR128_LEFT;
st->d->channel_map[1] = EBUR128_RIGHT;
@@ -164,48 +285,42 @@ static int ebur128_init_channel_map(ebur128_state* st) {
return EBUR128_SUCCESS;
}
-#ifdef USE_SPEEX_RESAMPLER
static int ebur128_init_resampler(ebur128_state* st) {
int errcode = EBUR128_SUCCESS;
if (st->samplerate < 96000) {
- st->d->oversample_factor = 4;
+ st->d->interp = interp_create(49, 4, st->channels);
+ CHECK_ERROR(!st->d->interp, EBUR128_ERROR_NOMEM, exit)
} else if (st->samplerate < 192000) {
- st->d->oversample_factor = 2;
+ st->d->interp = interp_create(49, 2, st->channels);
+ CHECK_ERROR(!st->d->interp, EBUR128_ERROR_NOMEM, exit)
} else {
- st->d->oversample_factor = 1;
st->d->resampler_buffer_input = NULL;
st->d->resampler_buffer_output = NULL;
- st->d->resampler = NULL;
+ st->d->interp = NULL;
+ goto exit;
}
st->d->resampler_buffer_input_frames = st->d->samples_in_100ms * 4;
st->d->resampler_buffer_input = malloc(st->d->resampler_buffer_input_frames *
st->channels *
sizeof(float));
- CHECK_ERROR(!st->d->resampler_buffer_input, EBUR128_ERROR_NOMEM, exit)
+ CHECK_ERROR(!st->d->resampler_buffer_input, EBUR128_ERROR_NOMEM, free_interp)
st->d->resampler_buffer_output_frames =
st->d->resampler_buffer_input_frames *
- st->d->oversample_factor;
+ st->d->interp->factor;
st->d->resampler_buffer_output = malloc
(st->d->resampler_buffer_output_frames *
st->channels *
sizeof(float));
CHECK_ERROR(!st->d->resampler_buffer_output, EBUR128_ERROR_NOMEM, free_input)
- st->d->resampler = speex_resampler_init
- ((spx_uint32_t) st->channels,
- (spx_uint32_t) st->samplerate,
- (spx_uint32_t) (st->samplerate * st->d->oversample_factor),
- 8, NULL);
- CHECK_ERROR(!st->d->resampler, EBUR128_ERROR_NOMEM, free_output)
-
return errcode;
-free_output:
- free(st->d->resampler_buffer_output);
- st->d->resampler_buffer_output = NULL;
+free_interp:
+ interp_destroy(st->d->interp);
+ st->d->interp = NULL;
free_input:
free(st->d->resampler_buffer_input);
st->d->resampler_buffer_input = NULL;
@@ -218,10 +333,9 @@ static void ebur128_destroy_resampler(ebur128_state* st) {
st->d->resampler_buffer_input = NULL;
free(st->d->resampler_buffer_output);
st->d->resampler_buffer_output = NULL;
- speex_resampler_destroy(st->d->resampler);
- st->d->resampler = NULL;
+ interp_destroy(st->d->interp);
+ st->d->interp = NULL;
}
-#endif
void ebur128_get_version(int* major, int* minor, int* patch) {
*major = EBUR128_VERSION_MAJOR;
@@ -232,9 +346,15 @@ void ebur128_get_version(int* major, int* minor, int* patch) {
ebur128_state* ebur128_init(unsigned int channels,
unsigned long samplerate,
int mode) {
- int errcode, result;
+ int result;
+ int errcode;
ebur128_state* st;
unsigned int i;
+ size_t j;
+
+ if (channels == 0 || samplerate < 5) {
+ return NULL;
+ }
st = (ebur128_state*) malloc(sizeof(ebur128_state));
CHECK_ERROR(!st, 0, exit)
@@ -247,29 +367,46 @@ ebur128_state* ebur128_init(unsigned int channels,
st->d->sample_peak = (double*) malloc(channels * sizeof(double));
CHECK_ERROR(!st->d->sample_peak, 0, free_channel_map)
+ st->d->prev_sample_peak = (double*) malloc(channels * sizeof(double));
+ CHECK_ERROR(!st->d->prev_sample_peak, 0, free_sample_peak)
st->d->true_peak = (double*) malloc(channels * sizeof(double));
- CHECK_ERROR(!st->d->true_peak, 0, free_sample_peak)
+ CHECK_ERROR(!st->d->true_peak, 0, free_prev_sample_peak)
+ st->d->prev_true_peak = (double*) malloc(channels * sizeof(double));
+ CHECK_ERROR(!st->d->prev_true_peak, 0, free_true_peak)
for (i = 0; i < channels; ++i) {
st->d->sample_peak[i] = 0.0;
+ st->d->prev_sample_peak[i] = 0.0;
st->d->true_peak[i] = 0.0;
+ st->d->prev_true_peak[i] = 0.0;
}
st->d->use_histogram = mode & EBUR128_MODE_HISTOGRAM ? 1 : 0;
-
+ st->d->history = ULONG_MAX;
st->samplerate = samplerate;
st->d->samples_in_100ms = (st->samplerate + 5) / 10;
st->mode = mode;
if ((mode & EBUR128_MODE_S) == EBUR128_MODE_S) {
- st->d->audio_data_frames = st->d->samples_in_100ms * 30;
+ st->d->window = 3000;
} else if ((mode & EBUR128_MODE_M) == EBUR128_MODE_M) {
- st->d->audio_data_frames = st->d->samples_in_100ms * 4;
+ st->d->window = 400;
} else {
- goto free_true_peak;
+ goto free_prev_true_peak;
+ }
+ st->d->audio_data_frames = st->samplerate * st->d->window / 1000;
+ if (st->d->audio_data_frames % st->d->samples_in_100ms) {
+ /* round up to multiple of samples_in_100ms */
+ st->d->audio_data_frames = st->d->audio_data_frames
+ + st->d->samples_in_100ms
+ - (st->d->audio_data_frames % st->d->samples_in_100ms);
}
st->d->audio_data = (double*) malloc(st->d->audio_data_frames *
st->channels *
sizeof(double));
CHECK_ERROR(!st->d->audio_data, 0, free_true_peak)
+ for (j = 0; j < st->d->audio_data_frames * st->channels; ++j) {
+ st->d->audio_data[i] = 0.0;
+ }
+
ebur128_init_filter(st);
if (st->d->use_histogram) {
@@ -290,14 +427,16 @@ ebur128_state* ebur128_init(unsigned int channels,
} else {
st->d->short_term_block_energy_histogram = NULL;
}
- SLIST_INIT(&st->d->block_list);
- SLIST_INIT(&st->d->short_term_block_list);
+ STAILQ_INIT(&st->d->block_list);
+ st->d->block_list_size = 0;
+ st->d->block_list_max = st->d->history / 100;
+ STAILQ_INIT(&st->d->short_term_block_list);
+ st->d->st_block_list_size = 0;
+ st->d->st_block_list_max = st->d->history / 3000;
st->d->short_term_frame_counter = 0;
-#ifdef USE_SPEEX_RESAMPLER
result = ebur128_init_resampler(st);
CHECK_ERROR(result, 0, free_short_term_block_energy_histogram)
-#endif
/* the first block needs 400ms of audio data */
st->d->needed_frames = st->d->samples_in_100ms * 4;
@@ -325,8 +464,12 @@ free_block_energy_histogram:
free(st->d->block_energy_histogram);
free_audio_data:
free(st->d->audio_data);
+free_prev_true_peak:
+ free(st->d->prev_true_peak);
free_true_peak:
free(st->d->true_peak);
+free_prev_sample_peak:
+ free(st->d->prev_sample_peak);
free_sample_peak:
free(st->d->sample_peak);
free_channel_map:
@@ -346,63 +489,46 @@ void ebur128_destroy(ebur128_state** st) {
free((*st)->d->audio_data);
free((*st)->d->channel_map);
free((*st)->d->sample_peak);
+ free((*st)->d->prev_sample_peak);
free((*st)->d->true_peak);
- while (!SLIST_EMPTY(&(*st)->d->block_list)) {
- entry = SLIST_FIRST(&(*st)->d->block_list);
- SLIST_REMOVE_HEAD(&(*st)->d->block_list, entries);
+ free((*st)->d->prev_true_peak);
+ while (!STAILQ_EMPTY(&(*st)->d->block_list)) {
+ entry = STAILQ_FIRST(&(*st)->d->block_list);
+ STAILQ_REMOVE_HEAD(&(*st)->d->block_list, entries);
free(entry);
}
- while (!SLIST_EMPTY(&(*st)->d->short_term_block_list)) {
- entry = SLIST_FIRST(&(*st)->d->short_term_block_list);
- SLIST_REMOVE_HEAD(&(*st)->d->short_term_block_list, entries);
+ while (!STAILQ_EMPTY(&(*st)->d->short_term_block_list)) {
+ entry = STAILQ_FIRST(&(*st)->d->short_term_block_list);
+ STAILQ_REMOVE_HEAD(&(*st)->d->short_term_block_list, entries);
free(entry);
}
-#ifdef USE_SPEEX_RESAMPLER
ebur128_destroy_resampler(*st);
-#endif
-
free((*st)->d);
free(*st);
*st = NULL;
}
-static int ebur128_use_speex_resampler(ebur128_state* st) {
-#ifdef USE_SPEEX_RESAMPLER
- return ((st->mode & EBUR128_MODE_TRUE_PEAK) == EBUR128_MODE_TRUE_PEAK);
-#else
- (void) st;
- return 0;
-#endif
-}
-
static void ebur128_check_true_peak(ebur128_state* st, size_t frames) {
-#ifdef USE_SPEEX_RESAMPLER
- size_t c, i;
- spx_uint32_t in_len = (spx_uint32_t) frames;
- spx_uint32_t out_len = (spx_uint32_t) st->d->resampler_buffer_output_frames;
- speex_resampler_process_interleaved_float(
- st->d->resampler,
- st->d->resampler_buffer_input, &in_len,
- st->d->resampler_buffer_output, &out_len);
- for (c = 0; c < st->channels; ++c) {
- for (i = 0; i < out_len; ++i) {
- if (st->d->resampler_buffer_output[i * st->channels + c] >
- st->d->true_peak[c]) {
- st->d->true_peak[c] =
- st->d->resampler_buffer_output[i * st->channels + c];
- } else if (-st->d->resampler_buffer_output[i * st->channels + c] >
- st->d->true_peak[c]) {
- st->d->true_peak[c] =
- -st->d->resampler_buffer_output[i * st->channels + c];
+ size_t c, i, frames_out;
+
+ frames_out = interp_process(st->d->interp, frames,
+ st->d->resampler_buffer_input,
+ st->d->resampler_buffer_output);
+
+ for (i = 0; i < frames_out; ++i) {
+ for (c = 0; c < st->channels; ++c) {
+ float val = st->d->resampler_buffer_output[i * st->channels + c];
+
+ if (val > st->d->prev_true_peak[c]) {
+ st->d->prev_true_peak[c] = val;
+ } else if (-val > st->d->prev_true_peak[c]) {
+ st->d->prev_true_peak[c] = -val;
}
}
}
-#else
- (void) st; (void) frames;
-#endif
}
-#ifdef __SSE2_MATH__
+#if defined(__SSE2_MATH__) || defined(__SSE2__)
#include <xmmintrin.h>
#define TURN_ON_FTZ \
unsigned int mxcsr = _mm_getcsr(); \
@@ -410,7 +536,7 @@ static void ebur128_check_true_peak(ebur128_state* st, size_t frames) {
#define TURN_OFF_FTZ _mm_setcsr(mxcsr);
#define FLUSH_MANUALLY
#else
-#pragma message ( "warning: manual FTZ is being used, please enable SSE2 (-msse2 -mfpmath=sse)" )
+#warning "manual FTZ is being used, please enable SSE2 (-msse2 -mfpmath=sse)"
#define TURN_ON_FTZ
#define TURN_OFF_FTZ
#define FLUSH_MANUALLY \
@@ -423,8 +549,9 @@ static void ebur128_check_true_peak(ebur128_state* st, size_t frames) {
#define EBUR128_FILTER(type, min_scale, max_scale) \
static void ebur128_filter_##type(ebur128_state* st, const type* src, \
size_t frames) { \
- static double scaling_factor = -((double) min_scale) > (double) max_scale ? \
- -((double) min_scale) : (double) max_scale; \
+ static double scaling_factor = \
+ -((double) (min_scale)) > (double) (max_scale) ? \
+ -((double) (min_scale)) : (double) (max_scale); \
double* audio_data = st->d->audio_data + st->d->audio_data_index; \
size_t i, c; \
\
@@ -441,10 +568,11 @@ static void ebur128_filter_##type(ebur128_state* st, const type* src, \
} \
} \
max /= scaling_factor; \
- if (max > st->d->sample_peak[c]) st->d->sample_peak[c] = max; \
+ if (max > st->d->prev_sample_peak[c]) st->d->prev_sample_peak[c] = max; \
} \
} \
- if (ebur128_use_speex_resampler(st)) { \
+ if ((st->mode & EBUR128_MODE_TRUE_PEAK) == EBUR128_MODE_TRUE_PEAK && \
+ st->d->interp) { \
for (c = 0; c < st->channels; ++c) { \
for (i = 0; i < frames; ++i) { \
st->d->resampler_buffer_input[i * st->channels + c] = \
@@ -510,7 +638,9 @@ static int ebur128_calc_gating_block(ebur128_state* st, size_t frames_per_block,
double sum = 0.0;
double channel_sum;
for (c = 0; c < st->channels; ++c) {
- if (st->d->channel_map[c] == EBUR128_UNUSED) continue;
+ if (st->d->channel_map[c] == EBUR128_UNUSED) {
+ continue;
+ }
channel_sum = 0.0;
if (st->d->audio_data_index < frames_per_block * st->channels) {
for (i = 0; i < st->d->audio_data_index / st->channels; ++i) {
@@ -553,10 +683,18 @@ static int ebur128_calc_gating_block(ebur128_state* st, size_t frames_per_block,
++st->d->block_energy_histogram[find_histogram_index(sum)];
} else {
struct ebur128_dq_entry* block;
- block = (struct ebur128_dq_entry*) malloc(sizeof(struct ebur128_dq_entry));
- if (!block) return EBUR128_ERROR_NOMEM;
+ if (st->d->block_list_size == st->d->block_list_max) {
+ block = STAILQ_FIRST(&st->d->block_list);
+ STAILQ_REMOVE_HEAD(&st->d->block_list, entries);
+ } else {
+ block = (struct ebur128_dq_entry*) malloc(sizeof(struct ebur128_dq_entry));
+ if (!block) {
+ return EBUR128_ERROR_NOMEM;
+ }
+ st->d->block_list_size++;
+ }
block->z = sum;
- SLIST_INSERT_HEAD(&st->d->block_list, block, entries);
+ STAILQ_INSERT_TAIL(&st->d->block_list, block, entries);
}
return EBUR128_SUCCESS;
} else {
@@ -582,11 +720,18 @@ int ebur128_set_channel(ebur128_state* st,
int ebur128_change_parameters(ebur128_state* st,
unsigned int channels,
unsigned long samplerate) {
- int errcode;
+ int errcode = EBUR128_SUCCESS;
+ size_t j;
+
+ if (channels == 0 || samplerate < 5) {
+ return EBUR128_ERROR_NOMEM;
+ }
+
if (channels == st->channels &&
samplerate == st->samplerate) {
- return 2;
+ return EBUR128_ERROR_NO_CHANGE;
}
+
free(st->d->audio_data);
st->d->audio_data = NULL;
@@ -595,41 +740,52 @@ int ebur128_change_parameters(ebur128_state* st,
free(st->d->channel_map); st->d->channel_map = NULL;
free(st->d->sample_peak); st->d->sample_peak = NULL;
+ free(st->d->prev_sample_peak); st->d->prev_sample_peak = NULL;
free(st->d->true_peak); st->d->true_peak = NULL;
+ free(st->d->prev_true_peak); st->d->prev_true_peak = NULL;
st->channels = channels;
-#ifdef USE_SPEEX_RESAMPLER
- ebur128_destroy_resampler(st);
- ebur128_init_resampler(st);
-#endif
-
errcode = ebur128_init_channel_map(st);
CHECK_ERROR(errcode, EBUR128_ERROR_NOMEM, exit)
st->d->sample_peak = (double*) malloc(channels * sizeof(double));
CHECK_ERROR(!st->d->sample_peak, EBUR128_ERROR_NOMEM, exit)
+ st->d->prev_sample_peak = (double*) malloc(channels * sizeof(double));
+ CHECK_ERROR(!st->d->prev_sample_peak, EBUR128_ERROR_NOMEM, exit)
st->d->true_peak = (double*) malloc(channels * sizeof(double));
CHECK_ERROR(!st->d->true_peak, EBUR128_ERROR_NOMEM, exit)
+ st->d->prev_true_peak = (double*) malloc(channels * sizeof(double));
+ CHECK_ERROR(!st->d->prev_true_peak, EBUR128_ERROR_NOMEM, exit)
for (i = 0; i < channels; ++i) {
st->d->sample_peak[i] = 0.0;
+ st->d->prev_sample_peak[i] = 0.0;
st->d->true_peak[i] = 0.0;
+ st->d->prev_true_peak[i] = 0.0;
}
}
if (samplerate != st->samplerate) {
st->samplerate = samplerate;
+ st->d->samples_in_100ms = (st->samplerate + 5) / 10;
ebur128_init_filter(st);
}
- if ((st->mode & EBUR128_MODE_S) == EBUR128_MODE_S) {
- st->d->audio_data_frames = st->d->samples_in_100ms * 30;
- } else if ((st->mode & EBUR128_MODE_M) == EBUR128_MODE_M) {
- st->d->audio_data_frames = st->d->samples_in_100ms * 4;
- } else {
- return 1;
+ st->d->audio_data_frames = st->samplerate * st->d->window / 1000;
+ if (st->d->audio_data_frames % st->d->samples_in_100ms) {
+ /* round up to multiple of samples_in_100ms */
+ st->d->audio_data_frames = st->d->audio_data_frames
+ + st->d->samples_in_100ms
+ - (st->d->audio_data_frames % st->d->samples_in_100ms);
}
st->d->audio_data = (double*) malloc(st->d->audio_data_frames *
st->channels *
sizeof(double));
CHECK_ERROR(!st->d->audio_data, EBUR128_ERROR_NOMEM, exit)
+ for (j = 0; j < st->d->audio_data_frames * st->channels; ++j) {
+ st->d->audio_data[j] = 0.0;
+ }
+
+ ebur128_destroy_resamp