diff options
author | Daniel Schürmann <daschuer@mixxx.org> | 2017-11-27 21:21:54 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-27 21:21:54 +0100 |
commit | cad470257688b574c383f0542d502c0a6cfd73d5 (patch) | |
tree | e478a467f9f48791fedf6ae4328d10736c760eb0 /lib | |
parent | 95bda91a01c4d34ba80d017342d2dc53835072ed (diff) | |
parent | 02babe62c3ec85721a2d6da40025f34a5926dca9 (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.def | 26 | ||||
-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.cmake | 11 | ||||
-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 |