diff --git a/README.md b/README.md index e9116d4..5015ec9 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ See also [loudness-scanner tool](https://github.com/jiixyj/loudness-scanner). News ---- +v1.1 Released: + + * Add `ebur128_relative_threshold()` v1.0.3 Released: diff --git a/ebur128/CMakeLists.txt b/ebur128/CMakeLists.txt index bcd8956..f84febc 100644 --- a/ebur128/CMakeLists.txt +++ b/ebur128/CMakeLists.txt @@ -22,7 +22,7 @@ endif() set(EBUR128_VERSION_MAJOR 1) -set(EBUR128_VERSION 1.0.3) +set(EBUR128_VERSION 1.1.0) #### static if(BUILD_STATIC_LIBS) diff --git a/ebur128/ebur128.c b/ebur128/ebur128.c index ad15e64..019fcf1 100644 --- a/ebur128/ebur128.c +++ b/ebur128/ebur128.c @@ -706,12 +706,41 @@ EBUR128_ADD_FRAMES(int) EBUR128_ADD_FRAMES(float) EBUR128_ADD_FRAMES(double) +static int ebur128_calc_relative_threshold(ebur128_state* st, + size_t* above_thresh_counter, + double* relative_threshold) { + struct ebur128_dq_entry* it; + size_t i; + *relative_threshold = 0.0; + *above_thresh_counter = 0; + + if (st->d->use_histogram) { + for (i = 0; i < 1000; ++i) { + *relative_threshold += st->d->block_energy_histogram[i] * + histogram_energies[i]; + *above_thresh_counter += st->d->block_energy_histogram[i]; + } + } else { + SLIST_FOREACH(it, &st->d->block_list, entries) { + ++*above_thresh_counter; + *relative_threshold += it->z; + } + } + + if (*above_thresh_counter != 0) { + *relative_threshold /= (double) *above_thresh_counter; + *relative_threshold *= relative_gate_factor; + } + + return EBUR128_SUCCESS; +} + static int ebur128_gated_loudness(ebur128_state** sts, size_t size, double* out) { struct ebur128_dq_entry* it; - double relative_threshold = 0.0; double gated_loudness = 0.0; - size_t above_thresh_counter = 0; + double relative_threshold; + size_t above_thresh_counter; size_t i, j, start_index; for (i = 0; i < size; i++) { @@ -722,25 +751,13 @@ static int ebur128_gated_loudness(ebur128_state** sts, size_t size, for (i = 0; i < size; i++) { if (!sts[i]) continue; - if (sts[i]->d->use_histogram) { - for (j = 0; j < 1000; ++j) { - relative_threshold += sts[i]->d->block_energy_histogram[j] * - histogram_energies[j]; - above_thresh_counter += sts[i]->d->block_energy_histogram[j]; - } - } else { - SLIST_FOREACH(it, &sts[i]->d->block_list, entries) { - ++above_thresh_counter; - relative_threshold += it->z; - } - } + ebur128_calc_relative_threshold(sts[i], &above_thresh_counter, &relative_threshold); } if (!above_thresh_counter) { *out = -HUGE_VAL; return EBUR128_SUCCESS; } - relative_threshold /= (double) above_thresh_counter; - relative_threshold *= relative_gate_factor; + above_thresh_counter = 0; if (relative_threshold < histogram_energy_boundaries[0]) { start_index = 0; @@ -776,6 +793,24 @@ static int ebur128_gated_loudness(ebur128_state** sts, size_t size, return EBUR128_SUCCESS; } +int ebur128_relative_threshold(ebur128_state* st, double* out) { + double relative_threshold; + size_t above_thresh_counter; + + if (st && (st->mode & EBUR128_MODE_I) != EBUR128_MODE_I) + return EBUR128_ERROR_INVALID_MODE; + + ebur128_calc_relative_threshold(st, &above_thresh_counter, &relative_threshold); + + if (!above_thresh_counter) { + *out = -70.0; + return EBUR128_SUCCESS; + } + + *out = ebur128_energy_to_loudness(relative_threshold); + return EBUR128_SUCCESS; +} + int ebur128_loudness_global(ebur128_state* st, double* out) { return ebur128_gated_loudness(&st, 1, out); } diff --git a/ebur128/ebur128.h b/ebur128/ebur128.h index 33594d3..b589844 100644 --- a/ebur128/ebur128.h +++ b/ebur128/ebur128.h @@ -13,8 +13,8 @@ extern "C" { #endif #define EBUR128_VERSION_MAJOR 1 -#define EBUR128_VERSION_MINOR 0 -#define EBUR128_VERSION_PATCH 3 +#define EBUR128_VERSION_MINOR 1 +#define EBUR128_VERSION_PATCH 0 #include /* for size_t */ @@ -82,7 +82,7 @@ enum mode { EBUR128_MODE_M = (1 << 0), /** can call ebur128_loudness_shortterm */ EBUR128_MODE_S = (1 << 1) | EBUR128_MODE_M, - /** can call ebur128_loudness_global_* */ + /** can call ebur128_loudness_global_* and ebur128_relative_threshold */ EBUR128_MODE_I = (1 << 2) | EBUR128_MODE_M, /** can call ebur128_loudness_range */ EBUR128_MODE_LRA = (1 << 3) | EBUR128_MODE_S, @@ -312,6 +312,17 @@ int ebur128_true_peak(ebur128_state* st, unsigned int channel_number, double* out); +/** \brief Get relative threshold in LUFS. + * + * @param st library state + * @param out relative threshold in LUFS. + * @return + * - EBUR128_SUCCESS on success. + * - EBUR128_ERROR_INVALID_MODE if mode "EBUR128_MODE_I" has not + * been set. + */ +int ebur128_relative_threshold(ebur128_state* st, double* out); + #ifdef __cplusplus } #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9bc67d4..c988bcb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,10 +4,11 @@ set(ENABLE_TESTS OFF CACHE BOOL "Build test binaries, needs libsndfile") if(ENABLE_TESTS) find_package(PkgConfig REQUIRED) - pkg_check_modules(SNDFILE REQUIRED sndfile) + find_pkg_config(SNDFILE sndfile REQUIRED) include_directories(${EBUR128_INCLUDE_DIR}) include_directories(SYSTEM ${SNDFILE_INCLUDE_DIRS}) + add_executable(r128-test-library tests) add_executable(minimal-example minimal-example) set_property(TARGET r128-test-library APPEND_STRING PROPERTY