summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorUwe Klotz <uklotz@mixxx.org>2018-03-04 08:44:28 +0100
committerUwe Klotz <uklotz@mixxx.org>2018-03-11 13:24:10 +0100
commit73001bf863b411df3645029d0f09c9980db598fc (patch)
tree04eaf26311cfd86921abc145f7e8d52b3a9e6f48 /lib
parent7ab6f3fa6f1367c0f3a70df4563257616ee751d8 (diff)
Upgrade libebur128 to version 1.2.4
Diffstat (limited to 'lib')
-rw-r--r--lib/libebur128-1.2.3/test/tests.c241
-rw-r--r--lib/libebur128/.gitignore (renamed from lib/libebur128-1.2.3/.gitignore)0
-rw-r--r--lib/libebur128/CMakeLists.txt (renamed from lib/libebur128-1.2.3/CMakeLists.txt)6
-rw-r--r--lib/libebur128/COPYING (renamed from lib/libebur128-1.2.3/COPYING)0
-rw-r--r--lib/libebur128/README.md (renamed from lib/libebur128-1.2.3/README.md)9
-rw-r--r--lib/libebur128/cmake/utils.cmake (renamed from lib/libebur128-1.2.3/cmake/utils.cmake)0
-rw-r--r--lib/libebur128/doc/license/R128Scan.txt (renamed from lib/libebur128-1.2.3/doc/license/R128Scan.txt)0
-rw-r--r--lib/libebur128/doc/license/queue.txt (renamed from lib/libebur128-1.2.3/doc/license/queue.txt)0
-rw-r--r--lib/libebur128/ebur128/CMakeLists.txt (renamed from lib/libebur128-1.2.3/ebur128/CMakeLists.txt)11
-rw-r--r--lib/libebur128/ebur128/ebur128.c (renamed from lib/libebur128-1.2.3/ebur128/ebur128.c)21
-rw-r--r--lib/libebur128/ebur128/ebur128.def (renamed from lib/libebur128-1.2.3/ebur128/ebur128.def)0
-rw-r--r--lib/libebur128/ebur128/ebur128.h (renamed from lib/libebur128-1.2.3/ebur128/ebur128.h)2
-rw-r--r--lib/libebur128/ebur128/libebur128.pc.cmake (renamed from lib/libebur128-1.2.3/ebur128/libebur128.pc.cmake)0
-rw-r--r--lib/libebur128/ebur128/queue/sys/queue.h (renamed from lib/libebur128-1.2.3/ebur128/queue/sys/queue.h)0
-rw-r--r--lib/libebur128/test/CMakeLists.txt (renamed from lib/libebur128-1.2.3/test/CMakeLists.txt)0
-rw-r--r--lib/libebur128/test/minimal-example.c (renamed from lib/libebur128-1.2.3/test/minimal-example.c)0
-rw-r--r--lib/libebur128/test/tests.c426
17 files changed, 456 insertions, 260 deletions
diff --git a/lib/libebur128-1.2.3/test/tests.c b/lib/libebur128-1.2.3/test/tests.c
deleted file mode 100644
index ace7228db8..0000000000
--- a/lib/libebur128-1.2.3/test/tests.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/* See COPYING file for copyright and license details. */
-
-#include <math.h>
-#include <sndfile.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "ebur128.h"
-
-double test_global_loudness(const char* filename) {
- SF_INFO file_info;
- SNDFILE* file;
- sf_count_t nr_frames_read;
-
- ebur128_state* st = NULL;
- double gated_loudness;
- double* buffer;
-
- memset(&file_info, '\0', sizeof(file_info));
- file = sf_open(filename, SFM_READ, &file_info);
- if (!file) {
- fprintf(stderr, "Could not open file %s!\n", filename);
- return 0.0;
- }
- st = ebur128_init((unsigned) file_info.channels,
- (unsigned) file_info.samplerate,
- EBUR128_MODE_I);
- if (file_info.channels == 5) {
- ebur128_set_channel(st, 0, EBUR128_LEFT);
- ebur128_set_channel(st, 1, EBUR128_RIGHT);
- ebur128_set_channel(st, 2, EBUR128_CENTER);
- ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
- ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
- }
- buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double));
- while ((nr_frames_read = sf_readf_double(file, buffer,
- (sf_count_t) st->samplerate))) {
- ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
- }
-
- ebur128_loudness_global(st, &gated_loudness);
-
- /* clean up */
- ebur128_destroy(&st);
-
- free(buffer);
- buffer = NULL;
- if (sf_close(file)) {
- fprintf(stderr, "Could not close input file!\n");
- }
- return gated_loudness;
-}
-
-double test_loudness_range(const char* filename) {
- SF_INFO file_info;
- SNDFILE* file;
- sf_count_t nr_frames_read;
-
- ebur128_state* st = NULL;
- double loudness_range;
- double* buffer;
-
- memset(&file_info, '\0', sizeof(file_info));
- file = sf_open(filename, SFM_READ, &file_info);
- if (!file) {
- fprintf(stderr, "Could not open file %s!\n", filename);
- return 0.0;
- }
- st = ebur128_init((unsigned) file_info.channels,
- (unsigned) file_info.samplerate,
- EBUR128_MODE_LRA);
- if (file_info.channels == 5) {
- ebur128_set_channel(st, 0, EBUR128_LEFT);
- ebur128_set_channel(st, 1, EBUR128_RIGHT);
- ebur128_set_channel(st, 2, EBUR128_CENTER);
- ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
- ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
- }
- buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double));
- while ((nr_frames_read = sf_readf_double(file, buffer,
- (sf_count_t) st->samplerate))) {
- ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
- }
-
- ebur128_loudness_range(st, &loudness_range);
-
- /* clean up */
- ebur128_destroy(&st);
-
- free(buffer);
- buffer = NULL;
- if (sf_close(file)) {
- fprintf(stderr, "Could not close input file!\n");
- }
- return loudness_range;
-}
-
-double test_true_peak(const char* filename) {
- SF_INFO file_info;
- SNDFILE* file;
- sf_count_t nr_frames_read;
- int i;
-
- ebur128_state* st = NULL;
- double true_peak;
- double max_true_peak = -HUGE_VAL;
- double* buffer;
-
- memset(&file_info, '\0', sizeof(file_info));
- file = sf_open(filename, SFM_READ, &file_info);
- if (!file) {
- fprintf(stderr, "Could not open file %s!\n", filename);
- return 0.0;
- }
- st = ebur128_init((unsigned) file_info.channels,
- (unsigned) file_info.samplerate,
- EBUR128_MODE_TRUE_PEAK);
- if (file_info.channels == 5) {
- ebur128_set_channel(st, 0, EBUR128_LEFT);
- ebur128_set_channel(st, 1, EBUR128_RIGHT);
- ebur128_set_channel(st, 2, EBUR128_CENTER);
- ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
- ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
- }
- buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double));
- while ((nr_frames_read = sf_readf_double(file, buffer,
- (sf_count_t) st->samplerate))) {
- ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
- }
-
- for (i = 0; i < file_info.channels; i++) {
- ebur128_true_peak(st, (unsigned)i, &true_peak);
- if (true_peak > max_true_peak)
- max_true_peak = true_peak;
- }
- /* clean up */
- ebur128_destroy(&st);
-
- free(buffer);
- buffer = NULL;
- if (sf_close(file)) {
- fprintf(stderr, "Could not close input file!\n");
- }
- return 20 * log10(max_true_peak);
-}
-
-double gr[] = {-23.0,
- -33.0,
- -23.0,
- -23.0,
- -23.0,
- -23.0,
- -23.0,
- -23.0,
- -23.0};
-double gre[] = {-2.2953556442089987e+01,
- -3.2959860397340044e+01,
- -2.2995899818255047e+01,
- -2.3035918615414182e+01,
- -2.2949997446096436e+01,
- -2.3017157781104373e+01,
- -2.3017157781104373e+01,
- -2.2980242495081757e+01,
- -2.3009077718930545e+01};
-double lra[] = {10.0,
- 5.0,
- 20.0,
- 15.0,
- 5.0,
- 15.0};
-double lrae[] = {1.0001105488329134e+01,
- 4.9993734051522178e+00,
- 1.9995064067783115e+01,
- 1.4999273937723455e+01,
- 4.9747585878473721e+00,
- 1.4993650849123316e+01};
-
-
-int main() {
- double result;
-
- fprintf(stderr, "Note: the tests do not have to pass with EXACT_PASSED.\n"
- "Passing these tests does not mean that the library is "
- "100%% EBU R 128 compliant!\n\n");
-
-#define TEST_GLOBAL_LOUDNESS(filename, i) \
- result = test_global_loudness(filename); \
- if (result == result) { \
- printf("%s, %s - %s: %1.16e\n", \
- (result <= gr[i] + 0.1 && result >= gr[i] - 0.1) ? "PASSED" : "FAILED", \
- (result == gre[i]) ? "EXACT_PASSED" : "EXACT_FAILED", \
- filename, result); \
- }
-
- TEST_GLOBAL_LOUDNESS("seq-3341-1-16bit.wav", 0)
- TEST_GLOBAL_LOUDNESS("seq-3341-2-16bit.wav", 1)
- TEST_GLOBAL_LOUDNESS("seq-3341-3-16bit-v02.wav", 2)
- TEST_GLOBAL_LOUDNESS("seq-3341-4-16bit-v02.wav", 3)
- TEST_GLOBAL_LOUDNESS("seq-3341-5-16bit-v02.wav", 4)
- TEST_GLOBAL_LOUDNESS("seq-3341-6-5channels-16bit.wav", 5)
- TEST_GLOBAL_LOUDNESS("seq-3341-6-6channels-WAVEEX-16bit.wav", 6)
- TEST_GLOBAL_LOUDNESS("seq-3341-7_seq-3342-5-24bit.wav", 7)
- TEST_GLOBAL_LOUDNESS("seq-3341-2011-8_seq-3342-6-24bit-v02.wav", 8)
-
-
-#define TEST_LRA(filename, i) \
- result = test_loudness_range(filename); \
- if (result == result) { \
- printf("%s, %s - %s: %1.16e\n", \
- (result <= lra[i] + 1 && result >= lra[i] - 1) ? "PASSED" : "FAILED", \
- (result == lrae[i]) ? "EXACT_PASSED" : "EXACT_FAILED", \
- filename, result); \
- }
-
- TEST_LRA("seq-3342-1-16bit.wav", 0)
- TEST_LRA("seq-3342-2-16bit.wav", 1)
- TEST_LRA("seq-3342-3-16bit.wav", 2)
- TEST_LRA("seq-3342-4-16bit.wav", 3)
- TEST_LRA("seq-3341-7_seq-3342-5-24bit.wav", 4)
- TEST_LRA("seq-3341-2011-8_seq-3342-6-24bit-v02.wav", 5)
-
-#define TEST_MAX_TRUE_PEAK(filename, expected) \
- result = test_true_peak(filename); \
- if (result == result) { \
- printf("%s - %s: %1.16e\n", \
- (result <= expected + 0.2 && result >= expected - 0.4) ? "PASSED" : "FAILED", \
- filename, result); \
- }
-
- TEST_MAX_TRUE_PEAK("seq-3341-15-24bit.wav.wav", -6.0)
- TEST_MAX_TRUE_PEAK("seq-3341-16-24bit.wav.wav", -6.0)
- TEST_MAX_TRUE_PEAK("seq-3341-17-24bit.wav.wav", -6.0)
- TEST_MAX_TRUE_PEAK("seq-3341-18-24bit.wav.wav", -6.0)
- TEST_MAX_TRUE_PEAK("seq-3341-19-24bit.wav.wav", 3.0)
- TEST_MAX_TRUE_PEAK("seq-3341-20-24bit.wav.wav", 0.0)
- TEST_MAX_TRUE_PEAK("seq-3341-21-24bit.wav.wav", 0.0)
- TEST_MAX_TRUE_PEAK("seq-3341-22-24bit.wav.wav", 0.0)
- TEST_MAX_TRUE_PEAK("seq-3341-23-24bit.wav.wav", 0.0)
-
- return 0;
-}
diff --git a/lib/libebur128-1.2.3/.gitignore b/lib/libebur128/.gitignore
index 567609b123..567609b123 100644
--- a/lib/libebur128-1.2.3/.gitignore
+++ b/lib/libebur128/.gitignore
diff --git a/lib/libebur128-1.2.3/CMakeLists.txt b/lib/libebur128/CMakeLists.txt
index ff352ebfcb..f741317f50 100644
--- a/lib/libebur128-1.2.3/CMakeLists.txt
+++ b/lib/libebur128/CMakeLists.txt
@@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
project(libebur128 C)
-list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
-set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
-set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR})
+set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR})
include(utils)
include(GNUInstallDirs)
diff --git a/lib/libebur128-1.2.3/COPYING b/lib/libebur128/COPYING
index e3cebca683..e3cebca683 100644
--- a/lib/libebur128-1.2.3/COPYING
+++ b/lib/libebur128/COPYING
diff --git a/lib/libebur128-1.2.3/README.md b/lib/libebur128/README.md
index f44adcb7ab..42e958192e 100644
--- a/lib/libebur128-1.2.3/README.md
+++ b/lib/libebur128/README.md
@@ -12,6 +12,15 @@ See also [loudness-scanner tool](https://github.com/jiixyj/loudness-scanner).
News
----
+v1.2.4 released:
+ * Fix broken `ebur128_loudness_global_multiple()` function. Since v1.1.0 it
+ calculated the relative threshold just from the last state given to it,
+ resulting in wrong values.
+ * More tests
+ * Fix some minor build issues
+ * Fix uninitialized memory in `ebur128_init()`, possibly resulting in wrong
+ values
+
v1.2.3 released:
* Fix uninitialized memory access during true peak scanning (bug #72)
diff --git a/lib/libebur128-1.2.3/cmake/utils.cmake b/lib/libebur128/cmake/utils.cmake
index b27c57bd51..b27c57bd51 100644
--- a/lib/libebur128-1.2.3/cmake/utils.cmake
+++ b/lib/libebur128/cmake/utils.cmake
diff --git a/lib/libebur128-1.2.3/doc/license/R128Scan.txt b/lib/libebur128/doc/license/R128Scan.txt
index 305b5e1d85..305b5e1d85 100644
--- a/lib/libebur128-1.2.3/doc/license/R128Scan.txt
+++ b/lib/libebur128/doc/license/R128Scan.txt
diff --git a/lib/libebur128-1.2.3/doc/license/queue.txt b/lib/libebur128/doc/license/queue.txt
index 87fb4d13ba..87fb4d13ba 100644
--- a/lib/libebur128-1.2.3/doc/license/queue.txt
+++ b/lib/libebur128/doc/license/queue.txt
diff --git a/lib/libebur128-1.2.3/ebur128/CMakeLists.txt b/lib/libebur128/ebur128/CMakeLists.txt
index 2876aabef4..d77385e23f 100644
--- a/lib/libebur128-1.2.3/ebur128/CMakeLists.txt
+++ b/lib/libebur128/ebur128/CMakeLists.txt
@@ -23,12 +23,14 @@ endif()
set(EBUR128_VERSION_MAJOR 1)
-set(EBUR128_VERSION 1.2.3)
+set(EBUR128_VERSION 1.2.4)
#### static
if(BUILD_STATIC_LIBS)
add_library(ebur128_static STATIC ebur128.c)
- set_property(TARGET ebur128_static PROPERTY OUTPUT_NAME ebur128)
+ if(NOT MSVC)
+ set_property(TARGET ebur128_static PROPERTY OUTPUT_NAME ebur128)
+ endif()
endif()
if(WITH_STATIC_PIC)
@@ -47,8 +49,9 @@ set_target_properties(ebur128 PROPERTIES
SOVERSION ${EBUR128_VERSION_MAJOR}
VERSION ${EBUR128_VERSION})
-if(UNIX)
- target_link_libraries(ebur128 m)
+find_library(MATH_LIBRARY m)
+if(MATH_LIBRARY)
+ target_link_libraries(ebur128 ${MATH_LIBRARY})
endif()
set(EBUR128_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
diff --git a/lib/libebur128-1.2.3/ebur128/ebur128.c b/lib/libebur128/ebur128/ebur128.c
index aa20db35df..2e987102cb 100644
--- a/lib/libebur128-1.2.3/ebur128/ebur128.c
+++ b/lib/libebur128/ebur128/ebur128.c
@@ -404,7 +404,7 @@ ebur128_state* ebur128_init(unsigned int 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;
+ st->d->audio_data[j] = 0.0;
}
ebur128_init_filter(st);
@@ -528,7 +528,7 @@ static void ebur128_check_true_peak(ebur128_state* st, size_t frames) {
}
}
-#if defined(__SSE2_MATH__) || defined(__SSE2__)
+#ifdef __SSE2_MATH__
#include <xmmintrin.h>
#define TURN_ON_FTZ \
unsigned int mxcsr = _mm_getcsr(); \
@@ -955,8 +955,6 @@ static int ebur128_calc_relative_threshold(ebur128_state* st,
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) {
@@ -971,11 +969,6 @@ static int ebur128_calc_relative_threshold(ebur128_state* st,
}
}
- if (*above_thresh_counter != 0) {
- *relative_threshold /= (double) *above_thresh_counter;
- *relative_threshold *= relative_gate_factor;
- }
-
return EBUR128_SUCCESS;
}
@@ -1004,6 +997,9 @@ static int ebur128_gated_loudness(ebur128_state** sts, size_t size,
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;
@@ -1042,8 +1038,8 @@ static int ebur128_gated_loudness(ebur128_state** sts, size_t size,
}
int ebur128_relative_threshold(ebur128_state* st, double* out) {
- double relative_threshold;
- size_t above_thresh_counter;
+ double relative_threshold = 0.0;
+ size_t above_thresh_counter = 0;
if ((st->mode & EBUR128_MODE_I) != EBUR128_MODE_I) {
return EBUR128_ERROR_INVALID_MODE;
@@ -1056,6 +1052,9 @@ int ebur128_relative_threshold(ebur128_state* st, double* out) {
return EBUR128_SUCCESS;
}
+ relative_threshold /= (double)above_thresh_counter;
+ relative_threshold *= relative_gate_factor;
+
*out = ebur128_energy_to_loudness(relative_threshold);
return EBUR128_SUCCESS;
}
diff --git a/lib/libebur128-1.2.3/ebur128/ebur128.def b/lib/libebur128/ebur128/ebur128.def
index 81602f74a2..81602f74a2 100644
--- a/lib/libebur128-1.2.3/ebur128/ebur128.def
+++ b/lib/libebur128/ebur128/ebur128.def
diff --git a/lib/libebur128-1.2.3/ebur128/ebur128.h b/lib/libebur128/ebur128/ebur128.h
index 5b95682caf..6a673c7123 100644
--- a/lib/libebur128-1.2.3/ebur128/ebur128.h
+++ b/lib/libebur128/ebur128/ebur128.h
@@ -14,7 +14,7 @@ extern "C" {
#define EBUR128_VERSION_MAJOR 1
#define EBUR128_VERSION_MINOR 2
-#define EBUR128_VERSION_PATCH 3
+#define EBUR128_VERSION_PATCH 4
#include <stddef.h> /* for size_t */
diff --git a/lib/libebur128-1.2.3/ebur128/libebur128.pc.cmake b/lib/libebur128/ebur128/libebur128.pc.cmake
index 017fdebaf3..017fdebaf3 100644
--- a/lib/libebur128-1.2.3/ebur128/libebur128.pc.cmake
+++ b/lib/libebur128/ebur128/libebur128.pc.cmake
diff --git a/lib/libebur128-1.2.3/ebur128/queue/sys/queue.h b/lib/libebur128/ebur128/queue/sys/queue.h
index daf4553d33..daf4553d33 100644
--- a/lib/libebur128-1.2.3/ebur128/queue/sys/queue.h
+++ b/lib/libebur128/ebur128/queue/sys/queue.h
diff --git a/lib/libebur128-1.2.3/test/CMakeLists.txt b/lib/libebur128/test/CMakeLists.txt
index c988bcb189..c988bcb189 100644
--- a/lib/libebur128-1.2.3/test/CMakeLists.txt
+++ b/lib/libebur128/test/CMakeLists.txt
diff --git a/lib/libebur128-1.2.3/test/minimal-example.c b/lib/libebur128/test/minimal-example.c
index 499fe09a95..499fe09a95 100644
--- a/lib/libebur128-1.2.3/test/minimal-example.c
+++ b/lib/libebur128/test/minimal-example.c
diff --git a/lib/libebur128/test/tests.c b/lib/libebur128/test/tests.c
new file mode 100644
index 0000000000..d2bef6f0ea
--- /dev/null
+++ b/lib/libebur128/test/tests.c
@@ -0,0 +1,426 @@
+/* See COPYING file for copyright and license details. */
+
+#include <math.h>
+#include <sndfile.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ebur128.h"
+
+double test_global_loudness(const char* filename, ebur128_state** out_state) {
+ SF_INFO file_info;
+ SNDFILE* file;
+ sf_count_t nr_frames_read;
+
+ ebur128_state* st = NULL;
+ double gated_loudness;
+ double* buffer;
+
+ memset(&file_info, '\0', sizeof(file_info));
+ file = sf_open(filename, SFM_READ, &file_info);
+ if (!file) {
+ fprintf(stderr, "Could not open file %s!\n", filename);
+ return 0.0;
+ }
+ st = ebur128_init((unsigned) file_info.channels,
+ (unsigned) file_info.samplerate,
+ EBUR128_MODE_I);
+ if (file_info.channels == 5) {
+ ebur128_set_channel(st, 0, EBUR128_LEFT);
+ ebur128_set_channel(st, 1, EBUR128_RIGHT);
+ ebur128_set_channel(st, 2, EBUR128_CENTER);
+ ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
+ ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
+ }
+ buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double));
+ while ((nr_frames_read = sf_readf_double(file, buffer,
+ (sf_count_t) st->samplerate))) {
+ ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
+ }
+
+ ebur128_loudness_global(st, &gated_loudness);
+
+ *out_state = st;
+
+ free(buffer);
+ buffer = NULL;
+ if (sf_close(file)) {
+ fprintf(stderr, "Could not close input file!\n");
+ }
+ return gated_loudness;
+}
+
+double test_loudness_range(const char* filename) {
+ SF_INFO file_info;
+ SNDFILE* file;
+ sf_count_t nr_frames_read;
+
+ ebur128_state* st = NULL;
+ double loudness_range;
+ double* buffer;
+
+ memset(&file_info, '\0', sizeof(file_info));
+ file = sf_open(filename, SFM_READ, &file_info);
+ if (!file) {
+ fprintf(stderr, "Could not open file %s!\n", filename);
+ return 0.0;
+ }
+ st = ebur128_init((unsigned) file_info.channels,
+ (unsigned) file_info.samplerate,
+ EBUR128_MODE_LRA);
+ if (file_info.channels == 5) {
+ ebur128_set_channel(st, 0, EBUR128_LEFT);
+ ebur128_set_channel(st, 1, EBUR128_RIGHT);
+ ebur128_set_channel(st, 2, EBUR128_CENTER);
+ ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
+ ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
+ }
+ buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double));
+ while ((nr_frames_read = sf_readf_double(file, buffer,
+ (sf_count_t) st->samplerate))) {
+ ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
+ }
+
+ ebur128_loudness_range(st, &loudness_range);
+
+ /* clean up */
+ ebur128_destroy(&st);
+
+ free(buffer);
+ buffer = NULL;
+ if (sf_close(file)) {
+ fprintf(stderr, "Could not close input file!\n");
+ }
+ return loudness_range;
+}
+
+double test_true_peak(const char* filename) {
+ SF_INFO file_info;
+ SNDFILE* file;
+ sf_count_t nr_frames_read;
+ int i;
+
+ ebur128_state* st = NULL;
+ double true_peak;
+ double max_true_peak = -HUGE_VAL;
+ double* buffer;
+
+ memset(&file_info, '\0', sizeof(file_info));
+ file = sf_open(filename, SFM_READ, &file_info);
+ if (!file) {
+ fprintf(stderr, "Could not open file %s!\n", filename);
+ return 0.0;
+ }
+ st = ebur128_init((unsigned) file_info.channels,
+ (unsigned) file_info.samplerate,
+ EBUR128_MODE_TRUE_PEAK);
+ if (file_info.channels == 5) {
+ ebur128_set_channel(st, 0, EBUR128_LEFT);
+ ebur128_set_channel(st, 1, EBUR128_RIGHT);
+ ebur128_set_channel(st, 2, EBUR128_CENTER);
+ ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
+ ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
+ }
+ buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double));
+ while ((nr_frames_read = sf_readf_double(file, buffer,
+ (sf_count_t) st->samplerate))) {
+ ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
+ }
+
+ for (i = 0; i < file_info.channels; i++) {
+ ebur128_true_peak(st, (unsigned)i, &true_peak);
+ if (true_peak > max_true_peak)
+ max_true_peak = true_peak;
+ }
+ /* clean up */
+ ebur128_destroy(&st);
+
+ free(buffer);
+ buffer = NULL;
+ if (sf_close(file)) {
+ fprintf(stderr, "Could not close input file!\n");
+ }
+ return 20 * log10(max_true_peak);
+}
+
+double test_max_momentary(const char* filename) {
+ SF_INFO file_info;
+ SNDFILE* file;
+ sf_count_t nr_frames_read;
+ sf_count_t total_frames_read;
+ ebur128_state* st = NULL;
+ double momentary;
+ double max_momentary = -HUGE_VAL;
+ double* buffer;
+
+ memset(&file_info, '\0', sizeof(file_info));
+ file = sf_open(filename, SFM_READ, &file_info);
+ if (!file) {
+ fprintf(stderr, "Could not open file %s!\n", filename);
+ return 0.0;
+ }
+ st = ebur128_init((unsigned) file_info.channels,
+ (unsigned) file_info.samplerate,
+ EBUR128_MODE_M);
+ if (file_info.channels == 5) {
+ ebur128_set_channel(st, 0, EBUR128_LEFT);
+ ebur128_set_channel(st, 1, EBUR128_RIGHT);
+ ebur128_set_channel(st, 2, EBUR128_CENTER);
+ ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
+ ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
+ }
+ /* 10 ms buffer/ 100 Hz refresh rate as 10 Hz refresh rate fails on several tests */
+ buffer = (double*) malloc(st->samplerate / 100 * st->channels * sizeof(double));
+ while ((nr_frames_read = sf_readf_double(file, buffer,
+ (sf_count_t) st->samplerate / 100))) {
+ ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
+ total_frames_read += nr_frames_read;
+ /* invalid results before the first 400 ms */
+ if (total_frames_read >= 4 * st->samplerate / 10) {
+ ebur128_loudness_momentary(st, &momentary);
+ if (momentary > max_momentary)
+ max_momentary = momentary;
+ }
+ }
+
+ /* clean up */
+ ebur128_destroy(&st);
+
+ free(buffer);
+ buffer = NULL;
+ if (sf_close(file)) {
+ fprintf(stderr, "Could not close input file!\n");
+ }
+ return max_momentary;
+}
+
+double test_max_shortterm(const char* filename) {
+ SF_INFO file_info;
+ SNDFILE* file;
+ sf_count_t nr_frames_read;
+ sf_count_t total_frames_read;
+ ebur128_state* st = NULL;
+ double shortterm;
+ double max_shortterm = -HUGE_VAL;
+ double* buffer;
+
+ memset(&file_info, '\0', sizeof(file_info));
+ file = sf_open(filename, SFM_READ, &file_info);
+ if (!file) {
+ fprintf(stderr, "Could not open file %s!\n", filename);
+ return 0.0;
+ }
+ st = ebur128_init((unsigned) file_info.channels,
+ (unsigned) file_info.samplerate,
+ EBUR128_MODE_S);
+ if (file_info.channels == 5) {
+ ebur128_set_channel(st, 0, EBUR128_LEFT);
+ ebur128_set_channel(st, 1, EBUR128_RIGHT);
+ ebur128_set_channel(st, 2, EBUR128_CENTER);
+ ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND);
+ ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND);
+ }
+ /* 100 ms buffer / 10 Hz refresh rate */
+ buffer = (double*) malloc(st->samplerate / 10 * st->channels * sizeof(double));
+ while ((nr_frames_read = sf_readf_double(file, buffer,
+ (sf_count_t) st->samplerate / 10))) {
+ ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read);
+ total_frames_read += nr_frames_read;
+ /* invalid results before the first 3 s */
+ if (total_frames_read >= 3 * st->samplerate) {
+ ebur128_loudness_shortterm(st, &shortterm);
+ if (shortterm > max_shortterm)
+ max_shortterm = shortterm;
+ }
+ }
+
+ /* clean up */
+ ebur128_destroy(&st);
+
+ free(buffer);
+ buffer = NULL;
+ if (sf_close(file)) {
+ fprintf(stderr, "Could not close input file!\n");
+ }
+ return max_shortterm;
+}
+
+double gr[] = {-23.0,
+ -33.0,
+ -23.0,
+ -23.0,
+ -23.0,
+ -23.0,
+ -23.0,
+ -23.0,
+ -23.0};
+double gre[] = {-2.2953556442089987e+01,
+ -3.2959860397340044e+01,
+ -2.2995899818255047e+01,
+ -2.3035918615414182e+01,
+ -2.2949997446096436e+01,
+ -2.3017157781104373e+01,
+ -2.3017157781104373e+01,
+ -2.2980242495081757e+01,
+ -2.3009077718930545e+01};
+double lra[] = {10.0,
+ 5.0,
+ 20.0,
+ 15.0,
+ 5.0,
+ 15.0};
+double lrae[] = {1.0001105488329134e+01,
+ 4.9993734051522178e+00,
+ 1.9995064067783115e+01,
+ 1.4999273937723455e+01,
+ 4.9747585878473721e+00,
+ 1.4993650849123316e+01};
+
+
+int main() {
+ double result;
+ ebur128_state* states[9] = {0};
+ int i;
+
+ fprintf(stderr, "Note: the tests do not have to pass with EXACT_PASSED.\n"
+ "Passing these tests does not mean that the library is "
+ "100%% EBU R 128 compliant!\n\n");
+
+#define TEST_GLOBAL_LOUDNESS(filename, i, state_array) \
+ result = test_global_loudness(filename, &state_array[i]); \
+ if (result == result) { \
+ printf("%s, %s - %s: %1.16e\n", \
+ (result <= gr[i] + 0.1 && result >= gr[i] - 0.1) ? "PASSED" : "FAILED", \
+ (result == gre[i]) ? "EXACT_PASSED" : "EXACT_FAILED", \
+ filename, result); \
+ }
+
+ TEST_GLOBAL_LOUDNESS("seq-3341-1-16bit.wav", 0, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-2-16bit.wav", 1, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-3-16bit-v02.wav", 2, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-4-16bit-v02.wav", 3, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-5-16bit-v02.wav", 4, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-6-5channels-16bit.wav", 5, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-6-6channels-WAVEEX-16bit.wav", 6, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-7_seq-3342-5-24bit.wav", 7, states)
+ TEST_GLOBAL_LOUDNESS("seq-3341-2011-8_seq-3342-6-24bit-v02.wav", 8, states)
+
+ /* Move some states around, to make the bug where
+ * ebur128_loudness_global_multiple() calculated the relative threshold just
+ * from the last state easier to reproduce. Don't care for leaks, etc. */
+ states[5] = states[0];
+ states[0] = states[8];
+
+ for (i = 0; i < 6; ++i) {
+ if (states[i] == NULL) {
+ printf("FAILED, ebur128_loudness_global_multiple needs all states of seq-3341-1 until seq-3341-5 (inclusive) and seq-3341-2011-8_seq-3342-6-24bit\n");
+ goto after_multiple_test;
+ }
+ }
+
+ result = 0;
+ ebur128_loudness_global_multiple(states, 6, &result);
+ fprintf(stderr, "multiple output: %f\n", result);
+ if (result >= -23.18758 - 0.05 && result <= -23.18758 + 0.05) {
+ printf("PASSED, ebur128_loudness_global_multiple\n");
+ } else {
+ printf("FAILED, ebur128_loudness_global_multiple\n");
+ }
+
+after_multiple_test:
+ ;
+
+#define TEST_LRA(filename, i) \
+ result = test_loudness_range(filename); \
+ if (result == result) { \
+ printf("%s, %s - %s: %1.16e\n", \
+ (result <= lra[i] + 1 && result >= lra[i] - 1) ? "PASSED" : "FAILED", \
+ (result == lrae[i]) ? "EXACT_PASSED" : "EXACT_FAILED", \
+ filename, result); \
+ }
+
+ TEST_LRA("seq-3342-1-16bit.wav", 0)
+ TEST_LRA("seq-3342-2-16bit.wav", 1)
+ TEST_LRA("seq-3342-3-16bit.wav", 2)
+ TEST_LRA("seq-3342-4-16bit.wav", 3)
+ TEST_LRA("seq-3341-7_seq-3342-5-24bit.wav", 4)
+ TEST_LRA("seq-3341-2011-8_seq-3342-6-24bit-v02.wav", 5)
+
+#define TEST_MAX_TRUE_PEAK(filename, expected) \
+ result = test_true_peak(filename); \
+ if (result == result) { \
+ printf("%s - %s: %1.16e\n", \
+ (result <= expected + 0.2 && result >= expected - 0.4) ? "PASSED" : "FAILED", \
+ filename, result); \
+ }
+
+ TEST_MAX_TRUE_PEAK("seq-3341-15-24bit.wav.wav", -6.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-16-24bit.wav.wav", -6.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-17-24bit.wav.wav", -6.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-18-24bit.wav.wav", -6.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-19-24bit.wav.wav", 3.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-20-24bit.wav.wav", 0.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-21-24bit.wav.wav", 0.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-22-24bit.wav.wav", 0.0)
+ TEST_MAX_TRUE_PEAK("seq-3341-23-24bit.wav.wav", 0.0)
+
+#define TEST_MAX_MOMENTARY(filename, expected) \
+ result = test_max_momentary(filename); \
+ if (result == result) { \
+ printf("%s - %s: %1.16e\n", \
+ (result <= expected + 0.1 && result >= expected - 0.1) ? "PASSED" : "FAILED", \
+ filename, result); \