diff options
author | Harish Mahendrakar <harish.mahendrakar@ittiam.com> | 2020-10-04 19:14:15 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-10-04 19:14:15 +0000 |
commit | ad4bd1a10fbdf609c337becbfd7585453f428b11 (patch) | |
tree | 086b8caee09ec165e8b7a1700e63427b54d79e39 | |
parent | 6f3060bc0fd66912b6f467b1bbaa51d11422e5dc (diff) | |
parent | 7015979258a4b4eefb522ad072b03ee9b5ab3602 (diff) | |
download | libopus-ad4bd1a10fbdf609c337becbfd7585453f428b11.tar.gz |
Merge branch 'upstream-master' am: e2bcf2c247 am: 7a87b356ef am: 0dc8a539d8 am: 57e7bcb6ae am: 7015979258
Original change: https://android-review.googlesource.com/c/platform/external/libopus/+/1443636
Change-Id: I4b55fd4b9c5338df3701793595e93da428810902
71 files changed, 1851 insertions, 254 deletions
@@ -38,6 +38,7 @@ opus_demo repacketizer_demo stamp-h1 test-driver +trivial_example *.sw* *.o *.lo @@ -83,3 +84,7 @@ silk/tests/test_unit_LPC_inv_pred_gain src/Debug src/Release src/x64 +/*[Bb]uild*/ +.vs/ +.vscode/ +CMakeSettings.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..88a1342c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,42 @@ +default: + tags: + - docker + # Image from https://hub.docker.com/_/gcc/ based on Debian + image: gcc:9 + +whitespace: + stage: test + only: + - merge_requests + script: + - git diff-tree --check origin/master HEAD + +autoconf: + stage: build + before_script: + - apt-get update && + apt-get install -y zip doxygen + script: + - ./autogen.sh + - ./configure + - make + - make distcheck + cache: + paths: + - "src/*.o" + - "src/.libs/*.o" + - "silk/*.o" + - "silk/.libs/*.o" + - "celt/*.o" + - "celt/.libs/*.o" + +cmake: + stage: build + before_script: + - apt-get update && + apt-get install -y cmake ninja-build + script: + - mkdir build + - cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DOPUS_BUILD_TESTING=ON -DOPUS_BUILD_PROGRAMS=ON + - cmake --build build + - cd build && ctest --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..244ad139 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,574 @@ +cmake_minimum_required(VERSION 3.1) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(OpusPackageVersion) +get_package_version(PACKAGE_VERSION PROJECT_VERSION) + +project(Opus LANGUAGES C VERSION ${PROJECT_VERSION}) + +include(OpusFunctions) +include(OpusBuildtype) +include(OpusConfig) +include(OpusSources) +include(GNUInstallDirs) +include(CMakeDependentOption) +include(FeatureSummary) + +set(OPUS_BUILD_SHARED_LIBRARY_HELP_STR "build shared library.") +option(OPUS_BUILD_SHARED_LIBRARY ${OPUS_BUILD_SHARED_LIBRARY_HELP_STR} OFF) +if(OPUS_BUILD_SHARED_LIBRARY OR BUILD_SHARED_LIBS OR OPUS_BUILD_FRAMEWORK) + # Global flag to cause add_library() to create shared libraries if on. + set(BUILD_SHARED_LIBS ON) + set(OPUS_BUILD_SHARED_LIBRARY ON) +endif() +add_feature_info(OPUS_BUILD_SHARED_LIBRARY OPUS_BUILD_SHARED_LIBRARY ${OPUS_BUILD_SHARED_LIBRARY_HELP_STR}) + +set(OPUS_BUILD_TESTING_HELP_STR "build tests.") +option(OPUS_BUILD_TESTING ${OPUS_BUILD_TESTING_HELP_STR} OFF) +if(OPUS_BUILD_TESTING OR BUILD_TESTING) + set(OPUS_BUILD_TESTING ON) + set(BUILD_TESTING ON) +endif() +add_feature_info(OPUS_BUILD_TESTING OPUS_BUILD_TESTING ${OPUS_BUILD_TESTING_HELP_STR}) + +set(OPUS_CUSTOM_MODES_HELP_STR "enable non-Opus modes, e.g. 44.1 kHz & 2^n frames.") +option(OPUS_CUSTOM_MODES ${OPUS_CUSTOM_MODES_HELP_STR} OFF) +add_feature_info(OPUS_CUSTOM_MODES OPUS_CUSTOM_MODES ${OPUS_CUSTOM_MODES_HELP_STR}) + +set(OPUS_BUILD_PROGRAMS_HELP_STR "build programs.") +option(OPUS_BUILD_PROGRAMS ${OPUS_BUILD_PROGRAMS_HELP_STR} OFF) +add_feature_info(OPUS_BUILD_PROGRAMS OPUS_BUILD_PROGRAMS ${OPUS_BUILD_PROGRAMS_HELP_STR}) + +set(OPUS_DISABLE_INTRINSICS_HELP_STR "disable all intrinsics optimizations.") +option(OPUS_DISABLE_INTRINSICS ${OPUS_DISABLE_INTRINSICS_HELP_STR} OFF) +add_feature_info(OPUS_DISABLE_INTRINSICS OPUS_DISABLE_INTRINSICS ${OPUS_DISABLE_INTRINSICS_HELP_STR}) + +set(OPUS_FIXED_POINT_HELP_STR "compile as fixed-point (for machines without a fast enough FPU).") +option(OPUS_FIXED_POINT ${OPUS_FIXED_POINT_HELP_STR} OFF) +add_feature_info(OPUS_FIXED_POINT OPUS_FIXED_POINT ${OPUS_FIXED_POINT_HELP_STR}) + +set(OPUS_ENABLE_FLOAT_API_HELP_STR "compile with the floating point API (for machines with float library).") +option(OPUS_ENABLE_FLOAT_API ${OPUS_ENABLE_FLOAT_API_HELP_STR} ON) +add_feature_info(OPUS_ENABLE_FLOAT_API OPUS_ENABLE_FLOAT_API ${OPUS_ENABLE_FLOAT_API_HELP_STR}) + +set(OPUS_FLOAT_APPROX_HELP_STR "enable floating point approximations (Ensure your platform supports IEEE 754 before enabling).") +option(OPUS_FLOAT_APPROX ${OPUS_FLOAT_APPROX_HELP_STR} OFF) +add_feature_info(OPUS_FLOAT_APPROX OPUS_FLOAT_APPROX ${OPUS_FLOAT_APPROX_HELP_STR}) + +set(OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR "install pkg-config module.") +option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ON) +add_feature_info(OPUS_INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR}) + +set(OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR "install CMake package config module.") +option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ON) +add_feature_info(OPUS_INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR}) + +if(APPLE) + set(OPUS_BUILD_FRAMEWORK_HELP_STR "build Framework bundle for Apple systems.") + option(OPUS_BUILD_FRAMEWORK ${OPUS_BUILD_FRAMEWORK_HELP_STR} OFF) + add_feature_info(OPUS_BUILD_FRAMEWORK OPUS_BUILD_FRAMEWORK ${OPUS_BUILD_FRAMEWORK_HELP_STR}) +endif() + +set(OPUS_VAR_ARRAYS_HELP_STR "use variable length arrays for stack arrays.") +cmake_dependent_option(OPUS_VAR_ARRAYS + ${OPUS_VAR_ARRAYS_HELP_STR} + ON + "VLA_SUPPORTED; NOT OPUS_USE_ALLOCA; NOT OPUS_NONTHREADSAFE_PSEUDOSTACK" + OFF) +add_feature_info(OPUS_VAR_ARRAYS OPUS_VAR_ARRAYS ${OPUS_VAR_ARRAYS_HELP_STR}) + +set(OPUS_USE_ALLOCA_HELP_STR "use alloca for stack arrays (on non-C99 compilers).") +cmake_dependent_option(OPUS_USE_ALLOCA + ${OPUS_USE_ALLOCA_HELP_STR} + ON + "USE_ALLOCA_SUPPORTED; NOT OPUS_VAR_ARRAYS; NOT OPUS_NONTHREADSAFE_PSEUDOSTACK" + OFF) +add_feature_info(OPUS_USE_ALLOCA OPUS_USE_ALLOCA ${OPUS_USE_ALLOCA_HELP_STR}) + +set(OPUS_NONTHREADSAFE_PSEUDOSTACK_HELP_STR "use a non threadsafe pseudostack when neither variable length arrays or alloca is supported.") +cmake_dependent_option(OPUS_NONTHREADSAFE_PSEUDOSTACK + ${OPUS_NONTHREADSAFE_PSEUDOSTACK_HELP_STR} + ON + "NOT OPUS_VAR_ARRAYS; NOT OPUS_USE_ALLOCA" + OFF) +add_feature_info(OPUS_NONTHREADSAFE_PSEUDOSTACK OPUS_NONTHREADSAFE_PSEUDOSTACK ${OPUS_NONTHREADSAFE_PSEUDOSTACK_HELP_STR}) + +set(OPUS_FAST_MATH_HELP_STR "enable fast math (unsupported and discouraged use, as code is not well tested with this build option).") +cmake_dependent_option(OPUS_FAST_MATH + ${OPUS_FAST_MATH_HELP_STR} + ON + "OPUS_FLOAT_APPROX; OPUS_FAST_MATH; FAST_MATH_SUPPORTED" + OFF) +add_feature_info(OPUS_FAST_MATH OPUS_FAST_MATH ${OPUS_FAST_MATH_HELP_STR}) + +set(OPUS_STACK_PROTECTOR_HELP_STR "use stack protection.") +cmake_dependent_option(OPUS_STACK_PROTECTOR + ${OPUS_STACK_PROTECTOR_HELP_STR} + ON + "STACK_PROTECTOR_SUPPORTED" + OFF) +add_feature_info(OPUS_STACK_PROTECTOR OPUS_STACK_PROTECTOR ${OPUS_STACK_PROTECTOR_HELP_STR}) + +if(NOT MSVC) + set(OPUS_FORTIFY_SOURCE_HELP_STR "add protection against buffer overflows.") + cmake_dependent_option(OPUS_FORTIFY_SOURCE + ${OPUS_FORTIFY_SOURCE_HELP_STR} + ON + "FORTIFY_SOURCE_SUPPORTED" + OFF) + add_feature_info(OPUS_FORTIFY_SOURCE OPUS_FORTIFY_SOURCE ${OPUS_FORTIFY_SOURCE_HELP_STR}) +endif() + +if(MINGW AND (OPUS_FORTIFY_SOURCE OR OPUS_STACK_PROTECTOR)) + # ssp lib is needed for security features for MINGW + list(APPEND OPUS_REQUIRED_LIBRARIES ssp) +endif() + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + set(OPUS_X86_MAY_HAVE_SSE_HELP_STR "does runtime check for SSE1 support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE + ${OPUS_X86_MAY_HAVE_SSE_HELP_STR} + ON + "SSE1_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_SSE OPUS_X86_MAY_HAVE_SSE ${OPUS_X86_MAY_HAVE_SSE_HELP_STR}) + + set(OPUS_X86_MAY_HAVE_SSE2_HELP_STR "does runtime check for SSE2 support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE2 + ${OPUS_X86_MAY_HAVE_SSE2_HELP_STR} + ON + "SSE2_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_SSE2 OPUS_X86_MAY_HAVE_SSE2 ${OPUS_X86_MAY_HAVE_SSE2_HELP_STR}) + + set(OPUS_X86_MAY_HAVE_SSE4_1_HELP_STR "does runtime check for SSE4.1 support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE4_1 + ${OPUS_X86_MAY_HAVE_SSE4_1_HELP_STR} + ON + "SSE4_1_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_SSE4_1 OPUS_X86_MAY_HAVE_SSE4_1 ${OPUS_X86_MAY_HAVE_SSE4_1_HELP_STR}) + + set(OPUS_X86_MAY_HAVE_AVX_HELP_STR "does runtime check for AVX support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_AVX + ${OPUS_X86_MAY_HAVE_AVX_HELP_STR} + ON + "AVX_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_AVX OPUS_X86_MAY_HAVE_AVX ${OPUS_X86_MAY_HAVE_AVX_HELP_STR}) + + # PRESUME depends on MAY HAVE, but PRESUME will override runtime detection + set(OPUS_X86_PRESUME_SSE_HELP_STR "assume target CPU has SSE1 support (override runtime check).") + set(OPUS_X86_PRESUME_SSE2_HELP_STR "assume target CPU has SSE2 support (override runtime check).") + if(OPUS_CPU_X64) # Assume x86_64 has up to SSE2 support + cmake_dependent_option(OPUS_X86_PRESUME_SSE + ${OPUS_X86_PRESUME_SSE_HELP_STR} + ON + "OPUS_X86_MAY_HAVE_SSE; NOT OPUS_DISABLE_INTRINSICS" + OFF) + + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + ${OPUS_X86_PRESUME_SSE2_HELP_STR} + ON + "OPUS_X86_MAY_HAVE_SSE2; NOT OPUS_DISABLE_INTRINSICS" + OFF) + else() + cmake_dependent_option(OPUS_X86_PRESUME_SSE + ${OPUS_X86_PRESUME_SSE_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_SSE; NOT OPUS_DISABLE_INTRINSICS" + OFF) + + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + ${OPUS_X86_PRESUME_SSE2_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_SSE2; NOT OPUS_DISABLE_INTRINSICS" + OFF) + endif() + add_feature_info(OPUS_X86_PRESUME_SSE OPUS_X86_PRESUME_SSE ${OPUS_X86_PRESUME_SSE_HELP_STR}) + add_feature_info(OPUS_X86_PRESUME_SSE2 OPUS_X86_PRESUME_SSE2 ${OPUS_X86_PRESUME_SSE2_HELP_STR}) + + set(OPUS_X86_PRESUME_SSE4_1_HELP_STR "assume target CPU has SSE4.1 support (override runtime check).") + cmake_dependent_option(OPUS_X86_PRESUME_SSE4_1 + ${OPUS_X86_PRESUME_SSE4_1_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_SSE4_1; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_PRESUME_SSE4_1 OPUS_X86_PRESUME_SSE4_1 ${OPUS_X86_PRESUME_SSE4_1_HELP_STR}) + + set(OPUS_X86_PRESUME_AVX_HELP_STR "assume target CPU has AVX support (override runtime check).") + cmake_dependent_option(OPUS_X86_PRESUME_AVX + ${OPUS_X86_PRESUME_AVX_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_AVX; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_PRESUME_AVX OPUS_X86_PRESUME_AVX ${OPUS_X86_PRESUME_AVX_HELP_STR}) +endif() + +feature_summary(WHAT ALL) + +set_package_properties(Git + PROPERTIES + TYPE + REQUIRED + DESCRIPTION + "fast, scalable, distributed revision control system" + URL + "https://git-scm.com/" + PURPOSE + "required to set up package version") + +set(Opus_PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_defines.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_multistream.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_projection.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_types.h) + +if(OPUS_CUSTOM_MODES) + list(APPEND Opus_PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_custom.h) +endif() + +add_library(opus ${opus_headers} ${opus_sources} ${opus_sources_float} ${Opus_PUBLIC_HEADER}) +add_library(Opus::opus ALIAS opus) + +get_library_version(OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) +message(STATUS "Opus library version: ${OPUS_LIBRARY_VERSION}") + +set_target_properties(opus + PROPERTIES SOVERSION + ${OPUS_LIBRARY_VERSION_MAJOR} + VERSION + ${OPUS_LIBRARY_VERSION} + PUBLIC_HEADER + "${Opus_PUBLIC_HEADER}") + +target_include_directories( + opus + PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/opus> + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + celt + silk) + +target_link_libraries(opus PRIVATE ${OPUS_REQUIRED_LIBRARIES}) +target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING) + +if(OPUS_FORTIFY_SOURCE AND NOT MSVC) + target_compile_definitions(opus PRIVATE + $<$<NOT:$<CONFIG:debug>>:_FORTIFY_SOURCE=2>) +endif() + +if(OPUS_FLOAT_APPROX) + target_compile_definitions(opus PRIVATE FLOAT_APPROX) +endif() + +if(OPUS_VAR_ARRAYS) + target_compile_definitions(opus PRIVATE VAR_ARRAYS) +elseif(OPUS_USE_ALLOCA) + target_compile_definitions(opus PRIVATE USE_ALLOCA) +elseif(OPUS_NONTHREADSAFE_PSEUDOSTACK) + target_compile_definitions(opus PRIVATE NONTHREADSAFE_PSEUDOSTACK) +else() + message(ERROR "Need to set a define for stack allocation") +endif() + +if(OPUS_CUSTOM_MODES) + target_compile_definitions(opus PRIVATE CUSTOM_MODES) +endif() + +if(OPUS_FAST_MATH) + if(MSVC) + target_compile_options(opus PRIVATE /fp:fast) + else() + target_compile_options(opus PRIVATE -ffast-math) + endif() +endif() + +if(OPUS_STACK_PROTECTOR) + if(MSVC) + target_compile_options(opus PRIVATE /GS) + else() + target_compile_options(opus PRIVATE -fstack-protector-strong) + endif() +elseif(STACK_PROTECTOR_DISABLED_SUPPORTED) + target_compile_options(opus PRIVATE /GS-) +endif() + +if(BUILD_SHARED_LIBS) + if(WIN32) + target_compile_definitions(opus PRIVATE DLL_EXPORT) + elseif(HIDDEN_VISIBILITY_SUPPORTED) + set_target_properties(opus PROPERTIES C_VISIBILITY_PRESET hidden) + endif() +endif() + +add_sources_group(opus silk ${silk_headers} ${silk_sources}) +add_sources_group(opus celt ${celt_headers} ${celt_sources}) + +if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed}) + target_include_directories(opus PRIVATE silk/fixed) + target_compile_definitions(opus PRIVATE FIXED_POINT=1) +else() + add_sources_group(opus silk ${silk_sources_float}) + target_include_directories(opus PRIVATE silk/float) +endif() + +if(NOT OPUS_ENABLE_FLOAT_API) + target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API) +endif() + +if(NOT OPUS_DISABLE_INTRINSICS) + if((OPUS_X86_MAY_HAVE_SSE AND NOT OPUS_X86_PRESUME_SSE) OR + (OPUS_X86_MAY_HAVE_SSE2 AND NOT OPUS_X86_PRESUME_SSE2) OR + (OPUS_X86_MAY_HAVE_SSE4_1 AND NOT OPUS_X86_PRESUME_SSE4_1) OR + (OPUS_X86_MAY_HAVE_AVX AND NOT OPUS_X86_PRESUME_AVX)) + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) + endif() + + if(SSE1_SUPPORTED) + if(OPUS_X86_MAY_HAVE_SSE) + add_sources_group(opus celt ${celt_sources_sse}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE) + if(NOT MSVC) + set_source_files_properties(${celt_sources_sse} PROPERTIES COMPILE_FLAGS -msse) + endif() + endif() + if(OPUS_X86_PRESUME_SSE) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE) + if(NOT MSVC) + target_compile_options(opus PRIVATE -msse) + endif() + endif() + endif() + + if(SSE2_SUPPORTED) + if(OPUS_X86_MAY_HAVE_SSE2) + add_sources_group(opus celt ${celt_sources_sse2}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE2) + if(NOT MSVC) + set_source_files_properties(${celt_sources_sse2} PROPERTIES COMPILE_FLAGS -msse2) + endif() + endif() + if(OPUS_X86_PRESUME_SSE2) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE2) + if(NOT MSVC) + target_compile_options(opus PRIVATE -msse2) + endif() + endif() + endif() + + if(SSE4_1_SUPPORTED) + if(OPUS_X86_MAY_HAVE_SSE4_1) + add_sources_group(opus celt ${celt_sources_sse4_1}) + add_sources_group(opus silk ${silk_sources_sse4_1}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE4_1) + if(NOT MSVC) + set_source_files_properties(${celt_sources_sse4_1} ${silk_sources_sse4_1} PROPERTIES COMPILE_FLAGS -msse4.1) + endif() + + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_sse4_1}) + if(NOT MSVC) + set_source_files_properties(${silk_sources_fixed_sse4_1} PROPERTIES COMPILE_FLAGS -msse4.1) + endif() + endif() + endif() + if(OPUS_X86_PRESUME_SSE4_1) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE4_1) + if(NOT MSVC) + target_compile_options(opus PRIVATE -msse4.1) + endif() + endif() + endif() + + if(AVX_SUPPORTED) + # mostly placeholder in case of avx intrinsics is added + if(OPUS_X86_MAY_HAVE_AVX) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_AVX) + endif() + if(OPUS_X86_PRESUME_AVX) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_AVX) + if(NOT MSVC) + target_compile_options(opus PRIVATE -mavx) + endif() + endif() + endif() + + if(MSVC) + if(AVX_SUPPORTED AND OPUS_X86_PRESUME_AVX) # on 64 bit and 32 bits + add_definitions(/arch:AVX) + elseif(OPUS_CPU_X86) # if AVX not supported then set SSE flag + if((SSE4_1_SUPPORTED AND OPUS_X86_PRESUME_SSE4_1) + OR (SSE2_SUPPORTED AND OPUS_X86_PRESUME_SSE2)) + target_compile_definitions(opus PRIVATE /arch:SSE2) + elseif(SSE1_SUPPORTED AND OPUS_X86_PRESUME_SSE) + target_compile_definitions(opus PRIVATE /arch:SSE) + endif() + endif() + endif() + + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + add_sources_group(opus celt ${celt_sources_arm}) + endif() + + if(COMPILER_SUPPORT_NEON) + if(OPUS_MAY_HAVE_NEON) + if(RUNTIME_CPU_CAPABILITY_DETECTION) + message(STATUS "OPUS_MAY_HAVE_NEON enabling runtime detection") + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) + else() + message(ERROR "Runtime cpu capability detection needed for MAY_HAVE_NEON") + endif() + # Do runtime check for NEON + target_compile_definitions(opus + PRIVATE + OPUS_ARM_MAY_HAVE_NEON + OPUS_ARM_MAY_HAVE_NEON_INTR) + endif() + + add_sources_group(opus celt ${celt_sources_arm_neon_intr}) + add_sources_group(opus silk ${silk_sources_arm_neon_intr}) + + # silk arm neon depends on main_Fix.h + target_include_directories(opus PRIVATE silk/fixed) + + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_arm_neon_intr}) + endif() + + if(OPUS_PRESUME_NEON) + target_compile_definitions(opus + PRIVATE + OPUS_ARM_PRESUME_NEON + OPUS_ARM_PRESUME_NEON_INTR) + endif() + endif() +endif() + +target_compile_definitions(opus + PRIVATE + $<$<BOOL:${HAVE_LRINT}>:HAVE_LRINT> + $<$<BOOL:${HAVE_LRINTF}>:HAVE_LRINTF>) + +if(OPUS_BUILD_FRAMEWORK) + set_target_properties(opus PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER org.xiph.opus + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" + OUTPUT_NAME Opus) +endif() + +install(TARGETS opus + EXPORT OpusTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus) + +if(OPUS_INSTALL_PKG_CONFIG_MODULE) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_PREFIX}) + set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) + set(VERSION ${PACKAGE_VERSION}) + if(HAVE_LIBM) + set(LIBM "-lm") + endif() + configure_file(opus.pc.in opus.pc) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() + +if(OPUS_INSTALL_CMAKE_CONFIG_MODULE) + set(CPACK_GENERATOR TGZ) + include(CPack) + set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + install(EXPORT OpusTargets + NAMESPACE Opus:: + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + + include(CMakePackageConfigHelpers) + + set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in + OpusConfig.cmake + INSTALL_DESTINATION + ${CMAKE_INSTALL_PACKAGEDIR} + PATH_VARS + INCLUDE_INSTALL_DIR + INSTALL_PREFIX + ${CMAKE_INSTALL_PREFIX}) + write_basic_package_version_file(OpusConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) +endif() + +if(OPUS_BUILD_PROGRAMS) + # demo + if(OPUS_CUSTOM_MODES) + add_executable(opus_custom_demo ${opus_custom_demo_sources}) + target_include_directories(opus_custom_demo + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_custom_demo PRIVATE opus) + endif() + + add_executable(opus_demo ${opus_demo_sources}) + target_include_directories(opus_demo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories(opus_demo PRIVATE silk) # debug.h + target_include_directories(opus_demo PRIVATE celt) # arch.h + target_link_libraries(opus_demo PRIVATE opus ${OPUS_REQUIRED_LIBRARIES}) + + # compare + add_executable(opus_compare ${opus_compare_sources}) + target_include_directories(opus_compare PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_compare PRIVATE opus ${OPUS_REQUIRED_LIBRARIES}) +endif() + +if(BUILD_TESTING) + enable_testing() + + # tests + add_executable(test_opus_decode ${test_opus_decode_sources}) + target_include_directories(test_opus_decode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_decode PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_decode PRIVATE DISABLE_FLOAT_API) + endif() + add_test(test_opus_decode test_opus_decode) + + add_executable(test_opus_padding ${test_opus_padding_sources}) + target_include_directories(test_opus_padding + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_padding PRIVATE opus) + add_test(test_opus_padding test_opus_padding) + + if(NOT BUILD_SHARED_LIBS) + # disable tests that depends on private API when building shared lib + add_executable(test_opus_api ${test_opus_api_sources}) + target_include_directories(test_opus_api + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_api PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_api PRIVATE DISABLE_FLOAT_API) + endif() + add_test(test_opus_api test_opus_api) + + add_executable(test_opus_encode ${test_opus_encode_sources}) + target_include_directories(test_opus_encode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_encode PRIVATE opus) + add_test(test_opus_encode test_opus_encode) + endif() +endif() @@ -1,3 +1,15 @@ +name: "libopus" +description: "Android fork of the opus library." third_party { + url { + type: GIT + value: "https://gitlab.xiph.org/xiph/opus.git" + } + version: "b83dd52868326a401c8578041e3dbea439d53f11" license_type: NOTICE + last_upgrade_date { + year: 2020 + month: 9 + day: 30 + } } diff --git a/Makefile.am b/Makefile.am index 9c09decd..e5213739 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,7 +103,8 @@ noinst_PROGRAMS = celt/tests/test_unit_cwrs32 \ tests/test_opus_decode \ tests/test_opus_encode \ tests/test_opus_padding \ - tests/test_opus_projection + tests/test_opus_projection \ + trivial_example TESTS = celt/tests/test_unit_cwrs32 \ celt/tests/test_unit_dft \ @@ -131,6 +132,9 @@ repacketizer_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) opus_compare_SOURCES = src/opus_compare.c opus_compare_LDADD = $(LIBM) +trivial_example_SOURCES = doc/trivial_example.c +trivial_example_LDADD = libopus.la $(LIBM) + tests_test_opus_api_SOURCES = tests/test_opus_api.c tests/test_opus_common.h tests_test_opus_api_LDADD = libopus.la $(NE10_LIBS) $(LIBM) @@ -210,6 +214,16 @@ EXTRA_DIST = opus.pc.in \ opus.m4 \ Makefile.mips \ Makefile.unix \ + CMakeLists.txt \ + cmake/CFeatureCheck.cmake \ + cmake/OpusBuildtype.cmake \ + cmake/OpusConfig.cmake \ + cmake/OpusConfig.cmake.in \ + cmake/OpusFunctions.cmake \ + cmake/OpusPackageVersion.cmake \ + cmake/OpusSources.cmake \ + cmake/config.h.cmake.in \ + cmake/vla.c \ tests/run_vectors.sh \ celt/arm/arm2gnu.pl \ celt/arm/celt_pitch_xcorr_arm.s \ diff --git a/Makefile.mips b/Makefile.mips index d25af8cb..e9bfc22e 100644 --- a/Makefile.mips +++ b/Makefile.mips @@ -12,7 +12,7 @@ CFLAGS := -DUSE_ALLOCA $(CFLAGS) # These options affect performance # HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion -#CFLAGS := -DHAVE_LRINTF $(CFLAGS) +CFLAGS := -DHAVE_LRINTF $(CFLAGS) ###################### END OF OPTIONS ###################### @@ -35,7 +35,7 @@ An opus-tools package is available which provides encoding and decoding of Ogg encapsulated Opus files and includes a number of useful features. Opus-tools can be found at: - https://git.xiph.org/?p=opus-tools.git + https://gitlab.xiph.org/xiph/opus-tools.git or on the main Opus website: https://opus-codec.org/ @@ -68,7 +68,7 @@ On Apple macOS, install Xcode and brew.sh, then in the Terminal enter: 1) Clone the repository: - % git clone https://git.xiph.org/opus.git + % git clone https://gitlab.xiph.org/xiph/opus.git % cd opus 2) Compiling the source diff --git a/README.draft b/README.draft index 8d8e24df..9c31bd02 100644 --- a/README.draft +++ b/README.draft @@ -7,7 +7,7 @@ If this does not work, or if you want to change the default configuration in the Makefile. An up-to-date implementation conforming to this standard is available in a -Git repository at https://git.xiph.org/opus.git or on a website at: +Git repository at https://gitlab.xiph.org/xiph/opus.git or on a website at: https://opus-codec.org/ However, although that implementation is expected to remain conformant with the standard, it is the code in this RFC that shall remain normative. @@ -17,7 +17,7 @@ steps: 1) Clone the repository (latest implementation of this standard at the time of publication) -% git clone https://git.xiph.org/opus.git +% git clone https://gitlab.xiph.org/xiph/opus.git % cd opus 2) Compile diff --git a/README.version b/README.version index 77ed7aa4..515fea88 100644 --- a/README.version +++ b/README.version @@ -1,3 +1,7 @@ -URL: https://git.xiph.org/?p=opus.git;a=snapshot;h=83d5155f151ca47c9d6274ded1a7481f746b9a43;sf=tgz -Version: 1.3 -BugComponent: 25690 +This commit is upto-date with following the commit in upstream-master +Branch: upstream-master +commit: b83dd52868326a401c8578041e3dbea439d53f11 + +upstream-master is in sync with upstream project at +URL: https://gitlab.xiph.org/xiph/opus.git + diff --git a/celt/arch.h b/celt/arch.h index c627a744..3845c3a0 100644 --- a/celt/arch.h +++ b/celt/arch.h @@ -73,6 +73,9 @@ __attribute__((noreturn)) void celt_fatal(const char *str, const char *file, int line) { fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); +#if defined(_MSC_VER) + _set_abort_behavior( 0, _WRITE_ABORT_MSG); +#endif abort(); } #endif @@ -160,7 +163,7 @@ static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { #ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR #include "arm/fixed_arm64.h" -#elif OPUS_ARM_INLINE_EDSP +#elif defined (OPUS_ARM_INLINE_EDSP) #include "arm/fixed_armv5e.h" #elif defined (OPUS_ARM_INLINE_ASM) #include "arm/fixed_armv4.h" diff --git a/celt/arm/armcpu.c b/celt/arm/armcpu.c index 694a63b7..cce3ae3a 100644 --- a/celt/arm/armcpu.c +++ b/celt/arm/armcpu.c @@ -93,6 +93,8 @@ static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ #elif defined(__linux__) /* Linux based */ +#include <stdio.h> + opus_uint32 opus_cpu_capabilities(void) { opus_uint32 flags = 0; diff --git a/celt/bands.c b/celt/bands.c index f7bb66a9..2702963c 100644 --- a/celt/bands.c +++ b/celt/bands.c @@ -371,14 +371,14 @@ void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_mas static void compute_channel_weights(celt_ener Ex, celt_ener Ey, opus_val16 w[2]) { celt_ener minE; -#if FIXED_POINT +#ifdef FIXED_POINT int shift; #endif minE = MIN32(Ex, Ey); /* Adjustment to make the weights a bit more conservative. */ Ex = ADD32(Ex, minE/3); Ey = ADD32(Ey, minE/3); -#if FIXED_POINT +#ifdef FIXED_POINT shift = celt_ilog2(EPSILON+MAX32(Ex, Ey))-14; #endif w[0] = VSHR32(Ex, shift); diff --git a/celt/celt_decoder.c b/celt/celt_decoder.c index e6efce93..74ca3b74 100644 --- a/celt/celt_decoder.c +++ b/celt/celt_decoder.c @@ -117,13 +117,19 @@ void validate_celt_decoder(CELTDecoder *st) #ifndef CUSTOM_MODES celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL)); celt_assert(st->overlap == 120); + celt_assert(st->end <= 21); +#else +/* From Section 4.3 in the spec: "The normal CELT layer uses 21 of those bands, + though Opus Custom (see Section 6.2) may use a different number of bands" + + Check if it's within the maximum number of Bark frequency bands instead */ + celt_assert(st->end <= 25); #endif celt_assert(st->channels == 1 || st->channels == 2); celt_assert(st->stream_channels == 1 || st->stream_channels == 2); celt_assert(st->downsample > 0); celt_assert(st->start == 0 || st->start == 17); celt_assert(st->start < st->end); - celt_assert(st->end <= 21); #ifdef OPUS_ARCHMASK celt_assert(st->arch >= 0); celt_assert(st->arch <= OPUS_ARCHMASK); diff --git a/celt/celt_encoder.c b/celt/celt_encoder.c index 44cb0850..d6f8afc2 100644 --- a/celt/celt_encoder.c +++ b/celt/celt_encoder.c @@ -1571,7 +1571,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); effectiveBytes = nbCompressedBytes - nbFilledBytes; } - equiv_rate = ((opus_int32)nbCompressedBytes*8*50 >> (3-LM)) - (40*C+20)*((400>>LM) - 50); + equiv_rate = ((opus_int32)nbCompressedBytes*8*50 << (3-LM)) - (40*C+20)*((400>>LM) - 50); if (st->bitrate != OPUS_BITRATE_MAX) equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50)); diff --git a/celt/ecintrin.h b/celt/ecintrin.h index 2263cff6..66a4c36e 100644 --- a/celt/ecintrin.h +++ b/celt/ecintrin.h @@ -49,7 +49,11 @@ This macro should only be used for implementing ec_ilog(), if it is defined. All other code should use EC_ILOG() instead.*/ #if defined(_MSC_VER) && (_MSC_VER >= 1400) +#if defined(_MSC_VER) && (_MSC_VER >= 1910) +# include <intrin0.h> /* Improve compiler throughput. */ +#else # include <intrin.h> +#endif /*In _DEBUG mode this is not an intrinsic by default.*/ # pragma intrinsic(_BitScanReverse) diff --git a/celt/float_cast.h b/celt/float_cast.h index f218e864..9d34976e 100644 --- a/celt/float_cast.h +++ b/celt/float_cast.h @@ -67,6 +67,38 @@ #include <xmmintrin.h> static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));} +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) + + #include <xmmintrin.h> + static OPUS_INLINE opus_int32 float2int(float value) + { + /* _mm_load_ss will generate same code as _mm_set_ss + ** in _MSC_VER >= 1914 /02 so keep __mm_load__ss + ** for backward compatibility. + */ + return _mm_cvtss_si32(_mm_load_ss(&value)); + } + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86) + + #include <math.h> + + /* Win32 doesn't seem to have these functions. + ** Therefore implement OPUS_INLINE versions of these functions here. + */ + + static OPUS_INLINE opus_int32 + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + #elif defined(HAVE_LRINTF) /* These defines enable functionality introduced with the 1999 ISO C @@ -96,32 +128,6 @@ static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_s #include <math.h> #define float2int(x) lrint(x) -#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) - #include <xmmintrin.h> - - __inline long int float2int(float value) - { - return _mm_cvtss_si32(_mm_load_ss(&value)); - } -#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86) - #include <math.h> - - /* Win32 doesn't seem to have these functions. - ** Therefore implement OPUS_INLINE versions of these functions here. - */ - - __inline long int - float2int (float flt) - { int intgr; - - _asm - { fld flt - fistp intgr - } ; - - return intgr ; - } - #else #if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) diff --git a/celt/mips/celt_mipsr1.h b/celt/mips/celt_mipsr1.h index e85661a6..c332fe04 100644 --- a/celt/mips/celt_mipsr1.h +++ b/celt/mips/celt_mipsr1.h @@ -53,6 +53,7 @@ #include "celt_lpc.h" #include "vq.h" +#define OVERRIDE_COMB_FILTER_CONST #define OVERRIDE_comb_filter void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, diff --git a/celt/mips/vq_mipsr1.h b/celt/mips/vq_mipsr1.h index fd18eab7..f26a33e7 100644 --- a/celt/mips/vq_mipsr1.h +++ b/celt/mips/vq_mipsr1.h @@ -36,8 +36,6 @@ #include "mathops.h" #include "arch.h" -static void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch); - #define OVERRIDE_vq_exp_rotation1 static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) { @@ -66,11 +64,7 @@ static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_ } #define OVERRIDE_renormalise_vector - -#define renormalise_vector(X, N, gain, arch) \ - (renormalise_vector_mips(X, N, gain, arch)) - -void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch) +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) { int i; #ifdef FIXED_POINT diff --git a/celt/os_support.h b/celt/os_support.h index a2171971..009bf861 100644 --- a/celt/os_support.h +++ b/celt/os_support.h @@ -39,7 +39,6 @@ #include "opus_defines.h" #include <string.h> -#include <stdio.h> #include <stdlib.h> /** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ diff --git a/celt/rate.h b/celt/rate.h index 852b9d6f..fad5e412 100644 --- a/celt/rate.h +++ b/celt/rate.h @@ -95,7 +95,7 @@ static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int puls @param pulses Number of pulses per band (returned) @return Total number of bits allocated */ -int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero, +int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo, opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth); #endif @@ -39,6 +39,10 @@ #include "rate.h" #include "pitch.h" +#if defined(MIPSr1_ASM) +#include "mips/vq_mipsr1.h" +#endif + #ifndef OVERRIDE_vq_exp_rotation1 static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) { @@ -41,10 +41,6 @@ #include "x86/vq_sse.h" #endif -#if defined(MIPSr1_ASM) -#include "mips/vq_mipsr1.h" -#endif - void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread); opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch); diff --git a/celt_sources.mk b/celt_sources.mk index b619dae3..c9dab06e 100644 --- a/celt_sources.mk +++ b/celt_sources.mk @@ -1,4 +1,5 @@ -CELT_SOURCES = celt/bands.c \ +CELT_SOURCES = \ +celt/bands.c \ celt/celt.c \ celt/celt_encoder.c \ celt/celt_decoder.c \ diff --git a/cmake/CFeatureCheck.cmake b/cmake/CFeatureCheck.cmake new file mode 100644 index 00000000..08828f58 --- /dev/null +++ b/cmake/CFeatureCheck.cmake @@ -0,0 +1,39 @@ +# - Compile and run code to check for C features +# +# This functions compiles a source file under the `cmake` folder +# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake +# environment +# +# c_feature_check(<FLAG> [<VARIANT>]) +# +# - Example +# +# include(CFeatureCheck) +# c_feature_check(VLA) + +if(__c_feature_check) + return() +endif() +set(__c_feature_check INCLUDED) + +function(c_feature_check FILE) + string(TOLOWER ${FILE} FILE) + string(TOUPPER ${FILE} VAR) + string(TOUPPER "${VAR}_SUPPORTED" FEATURE) + if (DEFINED ${VAR}_SUPPORTED) + set(${VAR}_SUPPORTED 1 PARENT_SCOPE) + return() + endif() + + if (NOT DEFINED COMPILE_${FEATURE}) + message(STATUS "Performing Test ${FEATURE}") + try_compile(COMPILE_${FEATURE} ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/${FILE}.c) + endif() + + if(COMPILE_${FEATURE}) + message(STATUS "Performing Test ${FEATURE} -- success") + set(${VAR}_SUPPORTED 1 PARENT_SCOPE) + else() + message(STATUS "Performing Test ${FEATURE} -- failed to compile") + endif() +endfunction() diff --git a/cmake/OpusBuildtype.cmake b/cmake/OpusBuildtype.cmake new file mode 100644 index 00000000..557cc89b --- /dev/null +++ b/cmake/OpusBuildtype.cmake @@ -0,0 +1,27 @@ +# Set a default build type if none was specified +if(__opus_buildtype) + return() +endif() +set(__opus_buildtype INCLUDED) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if(CMAKE_C_FLAGS) + message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) + else() + set(default_build_type "Release") + message( + STATUS + "Setting build type to '${default_build_type}' as none was specified and no CFLAGS was exported." + ) + set(CMAKE_BUILD_TYPE "${default_build_type}" + CACHE STRING "Choose the type of build." + FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo") + endif() +endif() diff --git a/cmake/OpusConfig.cmake b/cmake/OpusConfig.cmake new file mode 100644 index 00000000..8d19a535 --- /dev/null +++ b/cmake/OpusConfig.cmake @@ -0,0 +1,104 @@ +if(__opus_config) + return() +endif() +set(__opus_config INCLUDED) + +include(OpusFunctions) + +configure_file(cmake/config.h.cmake.in config.h @ONLY) +add_definitions(-DHAVE_CONFIG_H) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY C_STANDARD 99) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +include(CheckLibraryExists) +check_library_exists(m floor "" HAVE_LIBM) +if(HAVE_LIBM) + list(APPEND OPUS_REQUIRED_LIBRARIES m) +endif() + +include(CFeatureCheck) +c_feature_check(VLA) + +include(CheckIncludeFile) +check_include_file(alloca.h HAVE_ALLOCA_H) + +include(CheckSymbolExists) +if(HAVE_ALLOCA_H) + add_definitions(-DHAVE_ALLOCA_H) + check_symbol_exists(alloca "alloca.h" USE_ALLOCA_SUPPORTED) +else() + check_symbol_exists(alloca "stdlib.h;malloc.h" USE_ALLOCA_SUPPORTED) +endif() + +include(CheckFunctionExists) +check_function_exists(lrintf HAVE_LRINTF) +check_function_exists(lrint HAVE_LRINT) + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(i[0-9]86|x86|X86|amd64|AMD64|x86_64)") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(OPUS_CPU_X64 1) + else() + set(OPUS_CPU_X86 1) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + set(OPUS_CPU_ARM 1) +endif() + +if(NOT OPUS_DISABLE_INTRINSICS) + opus_supports_cpu_detection(RUNTIME_CPU_CAPABILITY_DETECTION) +endif() + +if(OPUS_CPU_X86 OR OPUS_CPU_X64 AND NOT OPUS_DISABLE_INTRINSICS) + opus_detect_sse(COMPILER_SUPPORT_SIMD) +elseif(OPUS_CPU_ARM AND NOT OPUS_DISABLE_INTRINSICS) + opus_detect_neon(COMPILER_SUPPORT_NEON) + if(COMPILER_SUPPORT_NEON) + option(OPUS_USE_NEON "Option to enable NEON" ON) + option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ON) + option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(OPUS_PRESUME_NEON ON) + elseif(CMAKE_SYSTEM_NAME MATCHES "iOS") + set(OPUS_PRESUME_NEON ON) + endif() + endif() +endif() + +if(MSVC) + check_flag(FAST_MATH /fp:fast) + check_flag(STACK_PROTECTOR /GS) + check_flag(STACK_PROTECTOR_DISABLED /GS-) +else() + check_flag(FAST_MATH -ffast-math) + check_flag(STACK_PROTECTOR -fstack-protector-strong) + check_flag(HIDDEN_VISIBILITY -fvisibility=hidden) + set(FORTIFY_SOURCE_SUPPORTED 1) +endif() + +if(MINGW) + # For MINGW we need to link ssp lib for security features such as + # stack protector and fortify_sources + check_library_exists(ssp __stack_chk_fail "" HAVE_LIBSSP) + if(NOT HAVE_LIBSSP) + message(WARNING "Could not find libssp in MinGW, disabling STACK_PROTECTOR and FORTIFY_SOURCE") + set(STACK_PROTECTOR_SUPPORTED 0) + set(FORTIFY_SOURCE_SUPPORTED 0) + endif() +endif() + +if(NOT MSVC) + set(WARNING_LIST -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow) + include(CheckCCompilerFlag) + foreach(WARNING_FLAG ${WARNING_LIST}) + string(REPLACE - "" WARNING_VAR ${WARNING_FLAG}) + check_c_compiler_flag(${WARNING_FLAG} ${WARNING_VAR}_SUPPORTED) + if(${WARNING_VAR}_SUPPORTED) + add_compile_options(${WARNING_FLAG}) + endif() + endforeach() +endif() diff --git a/cmake/OpusConfig.cmake.in b/cmake/OpusConfig.cmake.in new file mode 100644 index 00000000..0b21231d --- /dev/null +++ b/cmake/OpusConfig.cmake.in @@ -0,0 +1,20 @@ +set(OPUS_VERSION @PROJECT_VERSION@) +set(OPUS_VERSION_STRING @PROJECT_VERSION@) +set(OPUS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(OPUS_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(OPUS_VERSION_PATCH @PROJECT_VERSION_PATCH@) + +@PACKAGE_INIT@ + +set_and_check(OPUS_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set(OPUS_INCLUDE_DIR ${OPUS_INCLUDE_DIR};${OPUS_INCLUDE_DIR}/opus) +set(OPUS_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@;@PACKAGE_INCLUDE_INSTALL_DIR@/opus") + +include(${CMAKE_CURRENT_LIST_DIR}/OpusTargets.cmake) + +set(OPUS_LIBRARY Opus::opus) +set(OPUS_LIBRARIES Opus::opus) + +check_required_components(Opus) + +set(OPUS_FOUND 1) diff --git a/cmake/OpusFunctions.cmake b/cmake/OpusFunctions.cmake new file mode 100644 index 00000000..fcf3351f --- /dev/null +++ b/cmake/OpusFunctions.cmake @@ -0,0 +1,215 @@ +if(__opus_functions) + return() +endif() +set(__opus_functions INCLUDED) + +function(get_library_version OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) + file(STRINGS configure.ac opus_lt_current_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_CURRENT=") + string(REGEX MATCH + "OPUS_LT_CURRENT=([0-9]*)" + _ + ${opus_lt_current_string}) + set(OPUS_LT_CURRENT ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_revision_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_REVISION=") + string(REGEX MATCH + "OPUS_LT_REVISION=([0-9]*)" + _ + ${opus_lt_revision_string}) + set(OPUS_LT_REVISION ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_age_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_AGE=") + string(REGEX MATCH + "OPUS_LT_AGE=([0-9]*)" + _ + ${opus_lt_age_string}) + set(OPUS_LT_AGE ${CMAKE_MATCH_1}) + + math(EXPR OPUS_LIBRARY_VERSION_MAJOR "${OPUS_LT_CURRENT} - ${OPUS_LT_AGE}") + set(OPUS_LIBRARY_VERSION_MINOR ${OPUS_LT_AGE}) + set(OPUS_LIBRARY_VERSION_PATCH ${OPUS_LT_REVISION}) + set( + OPUS_LIBRARY_VERSION + "${OPUS_LIBRARY_VERSION_MAJOR}.${OPUS_LIBRARY_VERSION_MINOR}.${OPUS_LIBRARY_VERSION_PATCH}" + PARENT_SCOPE) + set(OPUS_LIBRARY_VERSION_MAJOR ${OPUS_LIBRARY_VERSION_MAJOR} PARENT_SCOPE) +endfunction() + +function(check_flag NAME FLAG) + include(CheckCCompilerFlag) + check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED) +endfunction() + +include(CheckIncludeFile) +# function to check if compiler supports SSE, SSE2, SSE4.1 and AVX if target +# systems may not have SSE support then use OPUS_MAY_HAVE_SSE option if target +# system is guaranteed to have SSE support then OPUS_PRESUME_SSE can be used to +# skip SSE runtime check +function(opus_detect_sse COMPILER_SUPPORT_SIMD) + message(STATUS "Check SIMD support by compiler") + check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) # SSE1 + if(HAVE_XMMINTRIN_H) + if(MSVC) + # different arch options for 32 and 64 bit target for MSVC + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE1 /arch:SSE) + else() + set(SSE1_SUPPORTED + 1 + PARENT_SCOPE) + endif() + else() + check_flag(SSE1 -msse) + endif() + else() + set(SSE1_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + check_include_file(emmintrin.h HAVE_EMMINTRIN_H) # SSE2 + if(HAVE_EMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE2 /arch:SSE2) + else() + set(SSE2_SUPPORTED + 1 + PARENT_SCOPE) + endif() + else() + check_flag(SSE2 -msse2) + endif() + else() + set(SSE2_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + check_include_file(smmintrin.h HAVE_SMMINTRIN_H) # SSE4.1 + if(HAVE_SMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE4_1 /arch:SSE2) # SSE2 and above + else() + set(SSE4_1_SUPPORTED + 1 + PARENT_SCOPE) + endif() + else() + check_flag(SSE4_1 -msse4.1) + endif() + else() + set(SSE4_1_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + check_include_file(immintrin.h HAVE_IMMINTRIN_H) # AVX + if(HAVE_IMMINTRIN_H) + if(MSVC) + check_flag(AVX /arch:AVX) + else() + check_flag(AVX -mavx) + endif() + else() + set(AVX_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + if(SSE1_SUPPORTED OR SSE2_SUPPORTED OR SSE4_1_SUPPORTED OR AVX_SUPPORTED) + set(COMPILER_SUPPORT_SIMD 1 PARENT_SCOPE) + else() + message(STATUS "No SIMD support in compiler") + endif() +endfunction() + +function(opus_detect_neon COMPILER_SUPPORT_NEON) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + message(STATUS "Check NEON support by compiler") + check_include_file(arm_neon.h HAVE_ARM_NEON_H) + if(HAVE_ARM_NEON_H) + set(COMPILER_SUPPORT_NEON ${HAVE_ARM_NEON_H} PARENT_SCOPE) + endif() + endif() +endfunction() + +function(opus_supports_cpu_detection RUNTIME_CPU_CAPABILITY_DETECTION) + if(MSVC) + check_include_file(intrin.h HAVE_INTRIN_H) + else() + check_include_file(cpuid.h HAVE_CPUID_H) + endif() + if(HAVE_INTRIN_H OR HAVE_CPUID_H) + set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + # ARM cpu detection is implemented for Windows and anything + # using a Linux kernel (such as Android). + if (CMAKE_SYSTEM_NAME MATCHES "(Windows|Linux|Android)") + set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE) + endif () + else() + set(RUNTIME_CPU_CAPABILITY_DETECTION 0 PARENT_SCOPE) + endif() +endfunction() + +function(add_sources_group target group) + target_sources(${target} PRIVATE ${ARGN}) + source_group(${group} FILES ${ARGN}) +endfunction() + +function(get_opus_sources SOURCE_GROUP MAKE_FILE SOURCES) + # read file, each item in list is one group + file(STRINGS ${MAKE_FILE} opus_sources) + + # add wildcard for regex match + string(CONCAT SOURCE_GROUP ${SOURCE_GROUP} ".*$") + + # find group + foreach(val IN LISTS opus_sources) + if(val MATCHES ${SOURCE_GROUP}) + list(LENGTH val list_length) + if(${list_length} EQUAL 1) + # for tests split by '=' and clean up the rest into a list + string(FIND ${val} "=" index) + math(EXPR index "${index} + 1") + string(SUBSTRING ${val} + ${index} + -1 + sources) + string(REPLACE " " + ";" + sources + ${sources}) + else() + # discard the group + list(REMOVE_AT val 0) + set(sources ${val}) + endif() + break() + endif() + endforeach() + + list(LENGTH sources list_length) + if(${list_length} LESS 1) + message( + FATAL_ERROR + "No files parsed succesfully from ${SOURCE_GROUP} in ${MAKE_FILE}") + endif() + + # remove trailing whitespaces + set(list_var "") + foreach(source ${sources}) + string(STRIP "${source}" source) + list(APPEND list_var "${source}") + endforeach() + + set(${SOURCES} ${list_var} PARENT_SCOPE) +endfunction() diff --git a/cmake/OpusPackageVersion.cmake b/cmake/OpusPackageVersion.cmake new file mode 100644 index 00000000..447ce3b1 --- /dev/null +++ b/cmake/OpusPackageVersion.cmake @@ -0,0 +1,70 @@ +if(__opus_version) + return() +endif() +set(__opus_version INCLUDED) + +function(get_package_version PACKAGE_VERSION PROJECT_VERSION) + + find_package(Git) + if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/.git") + execute_process(COMMAND ${GIT_EXECUTABLE} + --git-dir=${CMAKE_CURRENT_LIST_DIR}/.git describe + --tags --match "v*" OUTPUT_VARIABLE OPUS_PACKAGE_VERSION) + if(OPUS_PACKAGE_VERSION) + string(STRIP ${OPUS_PACKAGE_VERSION}, OPUS_PACKAGE_VERSION) + string(REPLACE \n + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + string(REPLACE , + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + + string(SUBSTRING ${OPUS_PACKAGE_VERSION} + 1 + -1 + OPUS_PACKAGE_VERSION) + message(STATUS "Opus package version from git repo: ${OPUS_PACKAGE_VERSION}") + endif() + + elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/package_version" + AND NOT OPUS_PACKAGE_VERSION) + # Not a git repo, lets' try to parse it from package_version file if exists + file(STRINGS package_version OPUS_PACKAGE_VERSION + LIMIT_COUNT 1 + REGEX "PACKAGE_VERSION=") + string(REPLACE "PACKAGE_VERSION=" + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + string(REPLACE "\"" + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + # In case we have a unknown dist here we just replace it with 0 + string(REPLACE "unknown" + "0" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + message(STATUS "Opus package version from package_version file: ${OPUS_PACKAGE_VERSION}") + endif() + + if(OPUS_PACKAGE_VERSION) + string(REGEX + REPLACE "^([0-9]+.[0-9]+\\.?([0-9]+)?).*" + "\\1" + OPUS_PROJECT_VERSION + ${OPUS_PACKAGE_VERSION}) + else() + # fail to parse version from git and package version + message(WARNING "Could not get package version.") + set(OPUS_PACKAGE_VERSION 0) + set(OPUS_PROJECT_VERSION 0) + endif() + + message(STATUS "Opus project version: ${OPUS_PROJECT_VERSION}") + + set(PACKAGE_VERSION ${OPUS_PACKAGE_VERSION} PARENT_SCOPE) + set(PROJECT_VERSION ${OPUS_PROJECT_VERSION} PARENT_SCOPE) +endfunction() diff --git a/cmake/OpusSources.cmake b/cmake/OpusSources.cmake new file mode 100644 index 00000000..01e75d1a --- /dev/null +++ b/cmake/OpusSources.cmake @@ -0,0 +1,46 @@ +if(__opus_sources) + return() +endif() +set(__opus_sources INCLUDED) + +include(OpusFunctions) + +get_opus_sources(SILK_HEAD silk_headers.mk silk_headers) +get_opus_sources(SILK_SOURCES silk_sources.mk silk_sources) +get_opus_sources(SILK_SOURCES_FLOAT silk_sources.mk silk_sources_float) +get_opus_sources(SILK_SOURCES_FIXED silk_sources.mk silk_sources_fixed) +get_opus_sources(SILK_SOURCES_SSE4_1 silk_sources.mk silk_sources_sse4_1) +get_opus_sources(SILK_SOURCES_FIXED_SSE4_1 silk_sources.mk + silk_sources_fixed_sse4_1) +get_opus_sources(SILK_SOURCES_ARM_NEON_INTR silk_sources.mk + silk_sources_arm_neon_intr) +get_opus_sources(SILK_SOURCES_FIXED_ARM_NEON_INTR silk_sources.mk + silk_sources_fixed_arm_neon_intr) + +get_opus_sources(OPUS_HEAD opus_headers.mk opus_headers) +get_opus_sources(OPUS_SOURCES opus_sources.mk opus_sources) +get_opus_sources(OPUS_SOURCES_FLOAT opus_sources.mk opus_sources_float) + +get_opus_sources(CELT_HEAD celt_headers.mk celt_headers) +get_opus_sources(CELT_SOURCES celt_sources.mk celt_sources) +get_opus_sources(CELT_SOURCES_SSE celt_sources.mk celt_sources_sse) +get_opus_sources(CELT_SOURCES_SSE2 celt_sources.mk celt_sources_sse2) +get_opus_sources(CELT_SOURCES_SSE4_1 celt_sources.mk celt_sources_sse4_1) +get_opus_sources(CELT_SOURCES_ARM celt_sources.mk celt_sources_arm) +get_opus_sources(CELT_SOURCES_ARM_ASM celt_sources.mk celt_sources_arm_asm) +get_opus_sources(CELT_AM_SOURCES_ARM_ASM celt_sources.mk + celt_am_sources_arm_asm) +get_opus_sources(CELT_SOURCES_ARM_NEON_INTR celt_sources.mk + celt_sources_arm_neon_intr) +get_opus_sources(CELT_SOURCES_ARM_NE10 celt_sources.mk celt_sources_arm_ne10) + +get_opus_sources(opus_demo_SOURCES Makefile.am opus_demo_sources) +get_opus_sources(opus_custom_demo_SOURCES Makefile.am opus_custom_demo_sources) +get_opus_sources(opus_compare_SOURCES Makefile.am opus_compare_sources) +get_opus_sources(tests_test_opus_api_SOURCES Makefile.am test_opus_api_sources) +get_opus_sources(tests_test_opus_encode_SOURCES Makefile.am + test_opus_encode_sources) +get_opus_sources(tests_test_opus_decode_SOURCES Makefile.am + test_opus_decode_sources) +get_opus_sources(tests_test_opus_padding_SOURCES Makefile.am + test_opus_padding_sources) diff --git a/cmake/config.h.cmake.in b/cmake/config.h.cmake.in new file mode 100644 index 00000000..5550842c --- /dev/null +++ b/cmake/config.h.cmake.in @@ -0,0 +1 @@ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
\ No newline at end of file diff --git a/cmake/vla.c b/cmake/vla.c new file mode 100644 index 00000000..05b21197 --- /dev/null +++ b/cmake/vla.c @@ -0,0 +1,7 @@ +int main() { + static int x; + char a[++x]; + a[sizeof a - 1] = 0; + int N; + return a[0]; +}
\ No newline at end of file diff --git a/configure.ac b/configure.ac index e2921fa2..f12f0aa9 100644 --- a/configure.ac +++ b/configure.ac @@ -22,9 +22,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) # For libtool. dnl Please update these for releases. -OPUS_LT_CURRENT=7 +OPUS_LT_CURRENT=8 OPUS_LT_REVISION=0 -OPUS_LT_AGE=7 +OPUS_LT_AGE=8 AC_SUBST(OPUS_LT_CURRENT) AC_SUBST(OPUS_LT_REVISION) @@ -691,6 +691,18 @@ AS_IF([test x"$enable_intrinsics" = x"yes"],[ unsigned int CPUInfo2; unsigned int CPUInfo3; unsigned int InfoType; + #if defined(__i386__) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n": + "=a" (CPUInfo0), + "=r" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + #else __asm__ __volatile__ ( "cpuid": "=a" (CPUInfo0), @@ -699,6 +711,7 @@ AS_IF([test x"$enable_intrinsics" = x"yes"],[ "=d" (CPUInfo3) : "a" (InfoType), "c" (0) ); + #endif ]])], [get_cpuid_by_asm="yes" AC_MSG_RESULT([Inline Assembly]) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 36eee0b5..6d25f1fb 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.10 +# Doxyfile 1.8.18 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -101,7 +101,7 @@ EXTRACT_PRIVATE = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES @@ -248,8 +248,8 @@ HTML_TIMESTAMP = YES # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://www.mathjax.org/mathjax @@ -326,10 +326,12 @@ PREDEFINED = OPUS_EXPORT= \ # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: # http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent -# Bell Labs. +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. # Debian defaults to YES here, while Fedora and Homebrew default to NO. # So we set this based on whether the graphviz package is available at # configure time. # -HAVE_DOT = @HAVE_DOT@ +HAVE_DOT = @HAVE_DOT@ diff --git a/doc/build_draft.sh b/doc/build_draft.sh index d15b22a7..14ae51dd 100755 --- a/doc/build_draft.sh +++ b/doc/build_draft.sh @@ -48,7 +48,16 @@ mkdir "${destdir}/src" mkdir "${destdir}/silk" mkdir "${destdir}/silk/float" mkdir "${destdir}/silk/fixed" +mkdir "${destdir}/silk/fixed/x86" +mkdir "${destdir}/silk/fixed/arm" +mkdir "${destdir}/silk/fixed/mips" +mkdir "${destdir}/silk/x86" +mkdir "${destdir}/silk/arm" +mkdir "${destdir}/silk/mips" mkdir "${destdir}/celt" +mkdir "${destdir}/celt/x86" +mkdir "${destdir}/celt/arm" +mkdir "${destdir}/celt/mips" mkdir "${destdir}/include" for f in `cat "${toplevel}"/opus_sources.mk "${toplevel}"/celt_sources.mk \ "${toplevel}"/silk_sources.mk "${toplevel}"/opus_headers.mk \ @@ -82,7 +91,7 @@ cat opus_source.tar.gz| base64 | tr -d '\n' | fold -w 64 | \ #echo '</artwork>' >> opus_compare_escaped.c #echo '</figure>' >> opus_compare_escaped.c -if [[ ! -d ../opus_testvectors ]] ; then +if [ ! -d ../opus_testvectors ] ; then echo "Downloading test vectors..." wget 'http://opus-codec.org/testvectors/opus_testvectors.tar.gz' tar -C .. -xvzf opus_testvectors.tar.gz diff --git a/doc/footer.html b/doc/footer.html index ad4a9259..346c40ab 100644 --- a/doc/footer.html +++ b/doc/footer.html @@ -1,6 +1,10 @@ +<!-- HTML footer for doxygen 1.8.18--> +<!-- start footer part --> <!--BEGIN GENERATE_TREEVIEW--> +<div id="nav-path" class="navpath"><!-- id is needed for treeview function! --> + <ul> <li class="footer">Generated by - <a href="https://www.stack.nl/~dimitri/doxygen/"> + <a href="http://www.doxygen.org/index.html"> <img class="footer" src="doxygen.png" alt="doxygen"/></a> $doxygenversion </li> </ul> </div> @@ -16,7 +20,7 @@ For more information visit the <a href="https://opus-codec.org">Opus Website</a> <td> <address class="footer"><small> Generated by - <a href="https://www.stack.nl/~dimitri/doxygen/">doxygen</a> + <a href="http://www.doxygen.org/index.html">doxygen</a> $doxygenversion </small></address> </td> diff --git a/doc/header.html b/doc/header.html index b2c906be..babdcf6d 100644 --- a/doc/header.html +++ b/doc/header.html @@ -1,18 +1,24 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<!-- HTML header for doxygen 1.8.18--> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/> <meta http-equiv="X-UA-Compatible" content="IE=9"/> +<meta name="generator" content="Doxygen $doxygenversion"/> +<meta name="viewport" content="width=device-width, initial-scale=1"/> <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME--> <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME--> -<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/> -<link href="$relpath$customdoxygen.css" rel="stylesheet" type="text/css" /> +<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/> +<script type="text/javascript" src="$relpath^jquery.js"></script> +<script type="text/javascript" src="$relpath^dynsections.js"></script> $treeview $search $mathjax +<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> +$extrastylesheet </head> <body> -<div id="top"><!-- do not remove this div! --> +<div id="top"><!-- do not remove this div, it is closed by doxygen! --> <!--BEGIN TITLEAREA--> <div id="titlearea"> @@ -20,7 +26,7 @@ $mathjax <tbody> <tr style="height: 64px;"> <!--BEGIN PROJECT_LOGO--> - <td id="projectlogo"><img alt="Logo" src="$relpath$$projectlogo"/></td> + <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td> <!--END PROJECT_LOGO--> <!--BEGIN PROJECT_NAME--> <td style="padding-left: 0.5em;"> @@ -52,3 +58,4 @@ $mathjax </table> </div> <!--END TITLEAREA--> +<!-- end header part --> diff --git a/doc/release.txt b/doc/release.txt index 6d3ffa23..411ab7f4 100644 --- a/doc/release.txt +++ b/doc/release.txt @@ -15,7 +15,7 @@ - svn commit - Copy to archive.mozilla.org/pub/opus/ - Update checksum files there as well. -- Add release notes to https://git.xiph.org/opus-website.git +- Add release notes to https://gitlab.xiph.org/xiph/opus-website.git - Update links and checksums on the downloads page. - Add a copy of the documentation to <https://www.opus-codec.org/docs/> and update the links. @@ -25,7 +25,7 @@ Releases are commited to https://svn.xiph.org/releases/opus/ which propagates to downloads.xiph.org, and copied manually to https://archive.mozilla.org/pub/opus/ -Website updates are committed to https://git.xiph.org/opus-website.git +Website updates are committed to https://gitlab.xiph.org/xiph/opus-website.git which propagates to https://opus-codec.org/ == Binary release == diff --git a/doc/trivial_example.c b/doc/trivial_example.c index 047ca0a2..9cf435b4 100644 --- a/doc/trivial_example.c +++ b/doc/trivial_example.c @@ -85,7 +85,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } inFile = argv[1]; - fin = fopen(inFile, "r"); + fin = fopen(inFile, "rb"); if (fin==NULL) { fprintf(stderr, "failed to open input file: %s\n", strerror(errno)); @@ -101,7 +101,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } outFile = argv[2]; - fout = fopen(outFile, "w"); + fout = fopen(outFile, "wb"); if (fout==NULL) { fprintf(stderr, "failed to open output file: %s\n", strerror(errno)); @@ -113,14 +113,25 @@ int main(int argc, char **argv) int i; unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2]; int frame_size; + size_t samples; /* Read a 16 bits/sample audio frame. */ - fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin); - if (feof(fin)) + samples = fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin); + + /* For simplicity, only read whole frames. In a real application, + * we'd pad the final partial frame with zeroes, record the exact + * duration, and trim the decoded audio to match. + */ + if (samples != FRAME_SIZE) + { break; + } + /* Convert from little-endian ordering. */ for (i=0;i<CHANNELS*FRAME_SIZE;i++) + { in[i]=pcm_bytes[2*i+1]<<8|pcm_bytes[2*i]; + } /* Encode the frame. */ nbBytes = opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE); diff --git a/include/opus_custom.h b/include/opus_custom.h index 41f36bf2..2227be01 100644 --- a/include/opus_custom.h +++ b/include/opus_custom.h @@ -178,7 +178,7 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encode ) OPUS_ARG_NONNULL(1); -/** Destroys a an encoder state. +/** Destroys an encoder state. * @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed. */ OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); @@ -286,7 +286,7 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decode int *error ) OPUS_ARG_NONNULL(1); -/** Destroys a an decoder state. +/** Destroys a decoder state. * @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed. */ OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); diff --git a/include/opus_defines.h b/include/opus_defines.h index fbf5d0eb..d141418b 100644 --- a/include/opus_defines.h +++ b/include/opus_defines.h @@ -168,6 +168,7 @@ extern "C" { /* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ #define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 #define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 +#define OPUS_GET_IN_DTX_REQUEST 4049 /** Defines for the presence of extended APIs. */ #define OPUS_HAVE_OPUS_PROJECTION_H @@ -715,6 +716,16 @@ extern "C" { * </dl> * @hideinitializer */ #define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x) +/** Gets the DTX state of the encoder. + * Returns whether the last encoded frame was either a comfort noise update + * during DTX or not encoded because of DTX. + * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values: + * <dl> + * <dt>0</dt><dd>The encoder is not in DTX.</dd> + * <dt>1</dt><dd>The encoder is in DTX.</dd> + * </dl> + * @hideinitializer */ +#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) /**@}*/ diff --git a/opus_sources.mk b/opus_sources.mk index b0763f99..44153b57 100644 --- a/opus_sources.mk +++ b/opus_sources.mk @@ -1,4 +1,5 @@ -OPUS_SOURCES = src/opus.c \ +OPUS_SOURCES = \ +src/opus.c \ src/opus_decoder.c \ src/opus_encoder.c \ src/opus_multistream.c \ diff --git a/releases.sha2 b/releases.sha2 index 76170ac9..334976b1 100644 --- a/releases.sha2 +++ b/releases.sha2 @@ -38,8 +38,12 @@ c0e90507259cf21ce7b2c82fb9ac55367d8543dae91cc3d4d2c59afd37f44023 opus-1.2-alpha cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732 opus-1.2.1.tar.gz 7f56e058c9549d03ae35511ad9e16ef6d1eb257836830d54abff0f495f17e187 opus-1.3-beta.tar.gz 96fa28598e8ccd558b297277ad59a045c551ba0e06d65a9675938e084f837669 opus-1.3-rc.tar.gz +f6bab321fb81db984766f1e4d340a9e71a5ca2c5d4d53f4ee072e84afda271ca opus-1.3-rc2.tar.gz +4f3d69aefdf2dbaf9825408e452a8a414ffc60494c70633560700398820dc550 opus-1.3.tar.gz +65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d opus-1.3.1.tar.gz 94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors-draft11.tar.gz 94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors.tar.gz +6b26a22f9ba87b2b836906a9bb7afec5f8e54d49553b1200382520ee6fedfa55 opus_testvectors-rfc8251.tar.gz 5d2b99757bcb628bab2611f3ed27af6f35276ce3abc96c0ed4399d6c6463dda5 opus-tools-0.1.2.tar.gz 008317297d6ce84f84992abf8cc948a048a4fa135e1d1caf429fafde8965a792 opus-tools-0.1.3.tar.gz de80485c5afa1fd83c0e16a0dd4860470c872997a7dd0a58e99b2ee8a93e5168 opus-tools-0.1.4.tar.gz @@ -49,7 +53,11 @@ e0f08d301555dffc417604269b5a85d2bd197f259c7d6c957f370ffd33d6d9cd opus-tools-0.1 e4e188579ea1c4e4d5066460d4a7214a7eafe3539e9a4466fdc98af41ba4a2f6 opus-tools-0.1.8.tar.gz b1873dd78c7fbc98cf65d6e10cfddb5c2c03b3af93f922139a2104baedb4643a opus-tools-0.1.9.tar.gz a2357532d19471b70666e0e0ec17d514246d8b3cb2eb168f68bb0f6fd372b28c opus-tools-0.1.10.tar.gz +b4e56cb00d3e509acfba9a9b627ffd8273b876b4e2408642259f6da28fa0ff86 opus-tools-0.2.tar.gz bd6d14e8897a2f80065ef34a516c70e74f8e00060abdbc238e79e5f99bca3e96 libopusenc-0.1.tar.gz +02e6e0b14cbbe0569d948a46420f9c9a81d93bba32dc576a4007cbf96da68ef3 libopusenc-0.1.1.tar.gz +c79e95eeee43a0b965e9b2c59a243763a8f8b0a7e71441df2aa9084f6171c73a libopusenc-0.2.tar.gz +8298db61a8d3d63e41c1a80705baa8ce9ff3f50452ea7ec1c19a564fe106cbb9 libopusenc-0.2.1.tar.gz 8071b968475c1a17f54b6840d6de9d9ee20f930e827b0401abe3c4cf4f3bf30a opusfile-0.1.tar.gz b4a678b3b6c4adfb6aff1f67ef658becfe146ea7c7ff228e99543762171557f9 opusfile-0.2.tar.gz 4248927f2c4e316ea5b84fb02bd100bfec8fa4624a6910d77f0af7f0c6cb8baa opusfile-0.3.tar.gz @@ -63,3 +71,9 @@ b940d62beb15b5974764574b9f265481fe5b6ee16902fb705727546caf956261 opusfile-0.5.z 346967d7989bb83b05949483b76bd0f69a12c59bd8b4457e864902b52bb0ac34 opusfile-0.7.zip 2c231ed3cfaa1b3173f52d740e5bbd77d51b9dfecb87014b404917fba4b855a4 opusfile-0.8.tar.gz 89dff4342c3b789574cbea5c57f11b96d4ebe4d28ab90248c1783ea569b1e9e3 opusfile-0.8.zip +f75fb500e40b122775ac1a71ad80c4477698842a8fe9da4a1b4a1a9f16e4e979 opusfile-0.9.tar.gz +e9591da4d4c9e857436c2d46a28a9e470fa5355ea5a76d4d582f137d18755d36 opusfile-0.9.zip +48e03526ba87ef9cf5f1c47b5ebe3aa195bd89b912a57060c36184a6cd19412f opusfile-0.10.tar.gz +9d9e95d01817ecf48bf6daaea8f071f9b45bd1751ca1fc8ce50e5075eb2bc3c8 opusfile-0.10.zip +74ce9b6cf4da103133e7b5c95df810ceb7195471e1162ed57af415fabf5603bf opusfile-0.11.tar.gz +23c5168026c4f1fc34843650135b409d0fc8cf452508163b4ece8077256ac6ff opusfile-0.11.zip @@ -118,6 +118,10 @@ void silk_CNG( /* Smooth gains */ for( i = 0; i < psDec->nb_subfr; i++ ) { psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + /* If the smoothed gain is 3 dB greater than this subframe's gain, use this subframe's gain to adapt faster. */ + if( silk_SMULWW( psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_THRESHOLD_Q16 ) > psDecCtrl->Gains_Q16[ i ] ) { + psCNG->CNG_smth_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + } } } diff --git a/silk/MacroCount.h b/silk/MacroCount.h index 78100ffe..dab2f57a 100644 --- a/silk/MacroCount.h +++ b/silk/MacroCount.h @@ -27,9 +27,9 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef SIGPROCFIX_API_MACROCOUNT_H #define SIGPROCFIX_API_MACROCOUNT_H -#include <stdio.h> #ifdef silk_MACRO_COUNT +#include <stdio.h> #define varDefine opus_int64 ops_count = 0; extern opus_int64 ops_count; diff --git a/silk/NSQ_del_dec.c b/silk/NSQ_del_dec.c index 3fd9fa0d..00e749c3 100644 --- a/silk/NSQ_del_dec.c +++ b/silk/NSQ_del_dec.c @@ -394,8 +394,8 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( /* Long-term shaping */ if( lag > 0 ) { /* Symmetric, packed FIR coefficients */ - n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); - n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMULWB( silk_ADD_SAT32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ shp_lag_ptr++; } else { @@ -451,9 +451,9 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( /* Input minus prediction plus noise feedback */ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ - tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp1 = silk_ADD_SAT32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ - tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_SUB_SAT32( tmp2, tmp1 ); /* Q13 */ tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ @@ -535,7 +535,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( /* Update states */ psSS[ 0 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); sLF_AR_shp_Q14 = silk_SUB32( psSS[ 0 ].Diff_Q14, n_AR_Q14 ); - psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB_SAT32( sLF_AR_shp_Q14, n_LF_Q14 ); psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; psSS[ 0 ].xq_Q14 = xq_Q14; @@ -555,7 +555,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( /* Update states */ psSS[ 1 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); sLF_AR_shp_Q14 = silk_SUB32( psSS[ 1 ].Diff_Q14, n_AR_Q14 ); - psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB_SAT32( sLF_AR_shp_Q14, n_LF_Q14 ); psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; psSS[ 1 ].xq_Q14 = xq_Q14; @@ -328,10 +328,8 @@ static OPUS_INLINE void silk_PLC_conceal( for( j = 0; j < LTP_ORDER; j++ ) { B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); } - if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) { - /* Gradually reduce excitation gain */ - rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); - } + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); /* Slowly increase pitch lag */ psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); diff --git a/silk/debug.c b/silk/debug.c index 9253faf7..71e69cc6 100644 --- a/silk/debug.c +++ b/silk/debug.c @@ -30,7 +30,10 @@ POSSIBILITY OF SUCH DAMAGE. #endif #include "debug.h" + +#if SILK_DEBUG || SILK_TIC_TOC #include "SigProc_FIX.h" +#endif #if SILK_TIC_TOC diff --git a/silk/debug.h b/silk/debug.h index 6f68c1ca..36163e47 100644 --- a/silk/debug.h +++ b/silk/debug.h @@ -28,28 +28,29 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef SILK_DEBUG_H #define SILK_DEBUG_H -#include "typedef.h" -#include <stdio.h> /* file writing */ -#include <string.h> /* strcpy, strcmp */ - -#ifdef __cplusplus -extern "C" -{ -#endif - -unsigned long GetHighResolutionTime(void); /* O time in usec*/ - /* Set to 1 to enable DEBUG_STORE_DATA() macros for dumping * intermediate signals from the codec. */ #define SILK_DEBUG 0 /* Flag for using timers */ -#define SILK_TIC_TOC 0 +#define SILK_TIC_TOC 0 +#if SILK_DEBUG || SILK_TIC_TOC +#include "typedef.h" +#include <string.h> /* strcpy, strcmp */ +#include <stdio.h> /* file writing */ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif #if SILK_TIC_TOC +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + #if (defined(_WIN32) || defined(_WINCE)) #include <windows.h> /* timer */ #else /* Linux or Mac*/ diff --git a/silk/decode_frame.c b/silk/decode_frame.c index e73825b2..4f36f854 100644 --- a/silk/decode_frame.c +++ b/silk/decode_frame.c @@ -97,7 +97,6 @@ opus_int silk_decode_frame( psDec->first_frame_after_reset = 0; } else { /* Handle packet loss by extrapolation */ - psDec->indices.signalType = psDec->prevSignalType; silk_PLC( psDec, psDecCtrl, pOut, 1, arch ); } diff --git a/silk/define.h b/silk/define.h index 247cb0bf..491c86f3 100644 --- a/silk/define.h +++ b/silk/define.h @@ -225,6 +225,7 @@ extern "C" /* Defines for CN generation */ #define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ #define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_GAIN_SMTH_THRESHOLD_Q16 46396 /* -3 dB */ #define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ #ifdef __cplusplus diff --git a/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h b/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h index fcbd96c8..66eb2ed2 100644 --- a/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h +++ b/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h @@ -41,15 +41,14 @@ POSSIBILITY OF SUCH DAMAGE. #define QS 14 /* Autocorrelations for a warped frequency axis */ -#define OVERRIDE_silk_warped_autocorrelation_FIX -void silk_warped_autocorrelation_FIX( +#define OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( opus_int32 *corr, /* O Result [order + 1] */ opus_int *scale, /* O Scaling of the correlation vector */ const opus_int16 *input, /* I Input data to correlate */ const opus_int warping_Q16, /* I Warping coefficient */ const opus_int length, /* I Length of input */ - const opus_int order, /* I Correlation order (even) */ - int arch /* I Run-time architecture */ + const opus_int order /* I Correlation order (even) */ ) { opus_int n, i, lsh; diff --git a/silk/fixed/warped_autocorrelation_FIX.c b/silk/fixed/warped_autocorrelation_FIX.c index 52002a11..5c79553b 100644 --- a/silk/fixed/warped_autocorrelation_FIX.c +++ b/silk/fixed/warped_autocorrelation_FIX.c @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. /* Autocorrelations for a warped frequency axis */ +#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c void silk_warped_autocorrelation_FIX_c( opus_int32 *corr, /* O Result [order + 1] */ opus_int *scale, /* O Scaling of the correlation vector */ @@ -88,3 +89,4 @@ void silk_warped_autocorrelation_FIX_c( } silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ } +#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ diff --git a/silk/float/warped_autocorrelation_FLP.c b/silk/float/warped_autocorrelation_FLP.c index 96662767..09186e73 100644 --- a/silk/float/warped_autocorrelation_FLP.c +++ b/silk/float/warped_autocorrelation_FLP.c @@ -42,8 +42,8 @@ void silk_warped_autocorrelation_FLP( { opus_int n, i; double tmp1, tmp2; - double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; - double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* Order must be even */ celt_assert( ( order & 1 ) == 0 ); diff --git a/silk/typedef.h b/silk/typedef.h index 97b7e709..793d2c0c 100644 --- a/silk/typedef.h +++ b/silk/typedef.h @@ -67,6 +67,9 @@ __attribute__((noreturn)) static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line) { fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); +#if defined(_MSC_VER) + _set_abort_behavior( 0, _WRITE_ABORT_MSG); +#endif abort(); } # define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} diff --git a/silk_sources.mk b/silk_sources.mk index 67c8a4fd..d2666e66 100644 --- a/silk_sources.mk +++ b/silk_sources.mk @@ -77,7 +77,8 @@ silk/stereo_find_predictor.c \ silk/stereo_quant_pred.c \ silk/LPC_fit.c -SILK_SOURCES_SSE4_1 = silk/x86/NSQ_sse4_1.c \ +SILK_SOURCES_SSE4_1 = \ +silk/x86/NSQ_sse4_1.c \ silk/x86/NSQ_del_dec_sse4_1.c \ silk/x86/x86_silk_map.c \ silk/x86/VAD_sse4_1.c \ @@ -115,7 +116,8 @@ silk/fixed/vector_ops_FIX.c \ silk/fixed/schur64_FIX.c \ silk/fixed/schur_FIX.c -SILK_SOURCES_FIXED_SSE4_1 = silk/fixed/x86/vector_ops_FIX_sse4_1.c \ +SILK_SOURCES_FIXED_SSE4_1 = \ +silk/fixed/x86/vector_ops_FIX_sse4_1.c \ silk/fixed/x86/burg_modified_FIX_sse4_1.c SILK_SOURCES_FIXED_ARM_NEON_INTR = \ diff --git a/src/analysis.c b/src/analysis.c index b192ae4e..058328f0 100644 --- a/src/analysis.c +++ b/src/analysis.c @@ -31,7 +31,9 @@ #define ANALYSIS_C +#ifdef MLP_TRAINING #include <stdio.h> +#endif #include "mathops.h" #include "kiss_fft.h" @@ -249,6 +251,15 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int if (curr_lookahead<0) curr_lookahead += DETECT_SIZE; + tonal->read_subframe += len/(tonal->Fs/400); + while (tonal->read_subframe>=8) + { + tonal->read_subframe -= 8; + tonal->read_pos++; + } + if (tonal->read_pos>=DETECT_SIZE) + tonal->read_pos-=DETECT_SIZE; + /* On long frames, look at the second analysis window rather than the first. */ if (len > tonal->Fs/50 && pos != tonal->write_pos) { @@ -262,6 +273,8 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int pos = DETECT_SIZE-1; pos0 = pos; OPUS_COPY(info_out, &tonal->info[pos], 1); + if (!info_out->valid) + return; tonality_max = tonality_avg = info_out->tonality; tonality_count = 1; /* Look at the neighbouring frames and pick largest bandwidth found (to be safe). */ @@ -393,14 +406,6 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int info_out->music_prob_max = prob_max; /* printf("%f %f %f %f %f\n", prob_min, prob_max, prob_avg/prob_count, vad_prob, info_out->music_prob); */ - tonal->read_subframe += len/(tonal->Fs/400); - while (tonal->read_subframe>=8) - { - tonal->read_subframe -= 8; - tonal->read_pos++; - } - if (tonal->read_pos>=DETECT_SIZE) - tonal->read_pos-=DETECT_SIZE; } static const float std_feature_bias[9] = { @@ -420,6 +425,24 @@ static const float std_feature_bias[9] = { #define SCALE_ENER(e) (e) #endif +#ifdef FIXED_POINT +static int is_digital_silence32(const opus_val32* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs32(pcm, frame_size*channels); + + silence = (sample_max == 0); + (void)lsb_depth; + return silence; +} +#else +#define is_digital_silence32(pcm, frame_size, channels, lsb_depth) is_digital_silence(pcm, frame_size, channels, lsb_depth) +#endif + static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix) { int i, b; @@ -464,8 +487,14 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt float layer_out[MAX_NEURONS]; float below_max_pitch; float above_max_pitch; + int is_silence; SAVE_STACK; + if (!tonal->initialized) + { + tonal->mem_fill = 240; + tonal->initialized = 1; + } alpha = 1.f/IMIN(10, 1+tonal->count); alphaE = 1.f/IMIN(25, 1+tonal->count); /* Noise floor related decay for bandwidth detection: -2.2 dB/second */ @@ -483,8 +512,6 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt } kfft = celt_mode->mdct.kfft[0]; - if (tonal->count==0) - tonal->mem_fill = 240; tonal->hp_ener_accum += (float)downmix_and_resample(downmix, x, &tonal->inmem[tonal->mem_fill], tonal->downmix_state, IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C, tonal->Fs); @@ -500,6 +527,8 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt if (tonal->write_pos>=DETECT_SIZE) tonal->write_pos-=DETECT_SIZE; + is_silence = is_digital_silence32(tonal->inmem, ANALYSIS_BUF_SIZE, 1, lsb_depth); + ALLOC(in, 480, kiss_fft_cpx); ALLOC(out, 480, kiss_fft_cpx); ALLOC(tonality, 240, float); @@ -518,6 +547,16 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt &tonal->inmem[240], tonal->downmix_state, remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C, tonal->Fs); tonal->mem_fill = 240 + remaining; + if (is_silence) + { + /* On silence, copy the previous analysis. */ + int prev_pos = tonal->write_pos-2; + if (prev_pos < 0) + prev_pos += DETECT_SIZE; + OPUS_COPY(info, &tonal->info[prev_pos], 1); + RESTORE_STACK; + return; + } opus_fft(kfft, in, out, tonal->arch); #ifndef FIXED_POINT /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */ @@ -654,7 +693,7 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt tonal->lowE[b] = logE[b]; tonal->highE[b] = MIN32(tonal->lowE[b]+15, tonal->highE[b]); } - relativeE += (logE[b]-tonal->lowE[b])/(1e-15f + (tonal->highE[b]-tonal->lowE[b])); + relativeE += (logE[b]-tonal->lowE[b])/(1e-5f + (tonal->highE[b]-tonal->lowE[b])); L1=L2=0; for (i=0;i<NB_FRAMES;i++) @@ -938,7 +977,6 @@ void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, co analysis->analysis_offset -= frame_size; } - analysis_info->valid = 0; tonality_get_info(analysis, analysis_info, frame_size); } diff --git a/src/analysis.h b/src/analysis.h index 289c845e..0b66555f 100644 --- a/src/analysis.h +++ b/src/analysis.h @@ -74,6 +74,7 @@ typedef struct { int read_pos; int read_subframe; float hp_ener_accum; + int initialized; float rnn_state[MAX_NEURONS]; opus_val32 downmix_state[3]; AnalysisInfo info[DETECT_SIZE]; diff --git a/src/mapping_matrix.h b/src/mapping_matrix.h index 9c20483e..98bc82df 100644 --- a/src/mapping_matrix.h +++ b/src/mapping_matrix.h @@ -53,7 +53,7 @@ opus_int32 mapping_matrix_get_size(int rows, int cols); opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix); void mapping_matrix_init( - MappingMatrix * const st, + MappingMatrix * const matrix, int rows, int cols, int gain, @@ -69,22 +69,29 @@ static OPUS_INLINE float sigmoid_approx(float x) return .5f + .5f*tansig_approx(.5f*x); } -void compute_dense(const DenseLayer *layer, float *output, const float *input) +static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, int col_stride, const float *x) { int i, j; + for (i=0;i<rows;i++) + { + for (j=0;j<cols;j++) + out[i] += weights[j*col_stride + i]*x[j]; + } +} + +void compute_dense(const DenseLayer *layer, float *output, const float *input) +{ + int i; int N, M; int stride; M = layer->nb_inputs; N = layer->nb_neurons; stride = N; for (i=0;i<N;i++) - { - /* Compute update gate. */ - float sum = layer->bias[i]; - for (j=0;j<M;j++) - sum += layer->input_weights[j*stride + i]*input[j]; - output[i] = WEIGHTS_SCALE*sum; - } + output[i] = layer->bias[i]; + gemm_accum(output, layer->input_weights, N, M, stride, input); + for (i=0;i<N;i++) + output[i] *= WEIGHTS_SCALE; if (layer->sigmoid) { for (i=0;i<N;i++) output[i] = sigmoid_approx(output[i]); @@ -96,45 +103,41 @@ void compute_dense(const DenseLayer *layer, float *output, const float *input) void compute_gru(const GRULayer *gru, float *state, const float *input) { - int i, j; + int i; int N, M; int stride; + float tmp[MAX_NEURONS]; float z[MAX_NEURONS]; float r[MAX_NEURONS]; float h[MAX_NEURONS]; M = gru->nb_inputs; N = gru->nb_neurons; stride = 3*N; + /* Compute update gate. */ for (i=0;i<N;i++) - { - /* Compute update gate. */ - float sum = gru->bias[i]; - for (j=0;j<M;j++) - sum += gru->input_weights[j*stride + i]*input[j]; - for (j=0;j<N;j++) - sum += gru->recurrent_weights[j*stride + i]*state[j]; - z[i] = sigmoid_approx(WEIGHTS_SCALE*sum); - } + z[i] = gru->bias[i]; + gemm_accum(z, gru->input_weights, N, M, stride, input); + gemm_accum(z, gru->recurrent_weights, N, N, stride, state); for (i=0;i<N;i++) - { - /* Compute reset gate. */ - float sum = gru->bias[N + i]; - for (j=0;j<M;j++) - sum += gru->input_weights[N + j*stride + i]*input[j]; - for (j=0;j<N;j++) - sum += gru->recurrent_weights[N + j*stride + i]*state[j]; - r[i] = sigmoid_approx(WEIGHTS_SCALE*sum); - } + z[i] = sigmoid_approx(WEIGHTS_SCALE*z[i]); + + /* Compute reset gate. */ for (i=0;i<N;i++) - { - /* Compute output. */ - float sum = gru->bias[2*N + i]; - for (j=0;j<M;j++) - sum += gru->input_weights[2*N + j*stride + i]*input[j]; - for (j=0;j<N;j++) - sum += gru->recurrent_weights[2*N + j*stride + i]*state[j]*r[j]; - h[i] = z[i]*state[i] + (1-z[i])*tansig_approx(WEIGHTS_SCALE*sum); - } + r[i] = gru->bias[N + i]; + gemm_accum(r, &gru->input_weights[N], N, M, stride, input); + gemm_accum(r, &gru->recurrent_weights[N], N, N, stride, state); + for (i=0;i<N;i++) + r[i] = sigmoid_approx(WEIGHTS_SCALE*r[i]); + + /* Compute output. */ + for (i=0;i<N;i++) + h[i] = gru->bias[2*N + i]; + for (i=0;i<N;i++) + tmp[i] = state[i] * r[i]; + gemm_accum(h, &gru->input_weights[2*N], N, M, stride, input); + gemm_accum(h, &gru->recurrent_weights[2*N], N, N, stride, tmp); + for (i=0;i<N;i++) + h[i] = z[i]*state[i] + (1-z[i])*tansig_approx(WEIGHTS_SCALE*h[i]); for (i=0;i<N;i++) state[i] = h[i]; } diff --git a/src/opus_encoder.c b/src/opus_encoder.c index 1c5a8b33..7b5f0abf 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -837,7 +837,7 @@ static opus_int32 compute_equiv_rate(opus_int32 bitrate, int channels, #ifndef DISABLE_FLOAT_API -static int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth) +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth) { int silence = 0; opus_val32 sample_max = 0; @@ -892,34 +892,15 @@ static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, in #endif /* Decides if DTX should be turned on (=1) or off (=0) */ -static int decide_dtx_mode(float activity_probability, /* probability that current frame contains speech/music */ - int *nb_no_activity_frames, /* number of consecutive frames with no activity */ - opus_val32 peak_signal_energy, /* peak energy of desired signal detected so far */ - const opus_val16 *pcm, /* input pcm signal */ - int frame_size, /* frame size */ - int channels, - int is_silence, /* only digital silence detected in this frame */ - int arch - ) -{ - opus_val32 noise_energy; - - if (!is_silence) - { - if (activity_probability < DTX_ACTIVITY_THRESHOLD) /* is noise */ - { - noise_energy = compute_frame_energy(pcm, frame_size, channels, arch); +static int decide_dtx_mode(opus_int activity, /* indicates if this frame contains speech/music */ + int *nb_no_activity_frames /* number of consecutive frames with no activity */ + ) - /* but is sufficiently quiet */ - is_silence = peak_signal_energy >= (PSEUDO_SNR_THRESHOLD * noise_energy); - } - } - - if (is_silence) +{ + if (!activity) { /* The number of consecutive DTX frames should be within the allowed bounds */ (*nb_no_activity_frames)++; - if (*nb_no_activity_frames > NB_SPEECH_FRAMES_BEFORE_DTX) { if (*nb_no_activity_frames <= (NB_SPEECH_FRAMES_BEFORE_DTX + MAX_CONSECUTIVE_DTX)) @@ -1102,6 +1083,8 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ int analysis_read_subframe_bak=-1; int is_silence = 0; #endif + opus_int activity = VAD_NO_DECISION; + VARDECL(opus_val16, tmp_prefill); ALLOC_STACK; @@ -1140,21 +1123,19 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->silk_mode.complexity >= 7 && st->Fs>=16000) #endif { - if (is_digital_silence(pcm, frame_size, st->channels, lsb_depth)) - { - is_silence = 1; - } else { - analysis_read_pos_bak = st->analysis.read_pos; - analysis_read_subframe_bak = st->analysis.read_subframe; - run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size, - c1, c2, analysis_channels, st->Fs, - lsb_depth, downmix, &analysis_info); - } + is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth); + analysis_read_pos_bak = st->analysis.read_pos; + analysis_read_subframe_bak = st->analysis.read_subframe; + run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size, + c1, c2, analysis_channels, st->Fs, + lsb_depth, downmix, &analysis_info); /* Track the peak signal energy */ if (!is_silence && analysis_info.activity_probability > DTX_ACTIVITY_THRESHOLD) st->peak_signal_energy = MAX32(MULT16_32_Q15(QCONST16(0.999f, 15), st->peak_signal_energy), compute_frame_energy(pcm, frame_size, st->channels, st->arch)); + } else if (st->analysis.initialized) { + tonality_analysis_reset(&st->analysis); } #else (void)analysis_pcm; @@ -1171,6 +1152,20 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (!is_silence) st->voice_ratio = -1; + if (is_silence) + { + activity = !is_silence; + } else if (analysis_info.valid) + { + activity = analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD; + if (!activity) + { + /* Mark as active if this noise frame is sufficiently loud */ + opus_val32 noise_energy = compute_frame_energy(pcm, frame_size, st->channels, st->arch); + activity = st->peak_signal_energy < (PSEUDO_SNR_THRESHOLD * noise_energy); + } + } + st->detected_bandwidth = 0; if (analysis_info.valid) { @@ -1338,6 +1333,14 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + /* Allow SILK DTX if DTX is enabled but the generalized DTX cannot be used, + e.g. because of the complexity setting or sample rate. */ +#ifndef DISABLE_FLOAT_API + st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence); +#else + st->silk_mode.useDTX = st->use_dtx; +#endif + /* Mode selection depending on application and signal type */ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) { @@ -1386,13 +1389,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) st->mode = MODE_SILK_ONLY; /* When encoding voice and DTX is enabled but the generalized DTX cannot be used, - because of complexity and sampling frequency settings, switch to SILK DTX and - set the encoder to SILK mode */ -#ifndef DISABLE_FLOAT_API - st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence); -#else - st->silk_mode.useDTX = st->use_dtx; -#endif + use SILK in order to make use of its DTX. */ if (st->silk_mode.useDTX && voice_est > 100) st->mode = MODE_SILK_ONLY; #endif @@ -1668,7 +1665,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_CELT_ONLY) { opus_int32 total_bitRate, celt_rate; - opus_int activity; #ifdef FIXED_POINT const opus_int16 *pcm_silk; #else @@ -1676,14 +1672,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ ALLOC(pcm_silk, st->channels*frame_size, opus_int16); #endif - activity = VAD_NO_DECISION; -#ifndef DISABLE_FLOAT_API - if( analysis_info.valid ) { - /* Inform SILK about the Opus VAD decision */ - activity = ( analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD ); - } -#endif - /* Distribute bits between SILK and CELT */ total_bitRate = 8 * bytes_target * frame_rate; if( st->mode == MODE_HYBRID ) { @@ -2144,14 +2132,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ #ifndef DISABLE_FLOAT_API if (st->use_dtx && (analysis_info.valid || is_silence)) { - if (decide_dtx_mode(analysis_info.activity_probability, &st->nb_no_activity_frames, - st->peak_signal_energy, pcm, frame_size, st->channels, is_silence, st->arch)) + if (decide_dtx_mode(activity, &st->nb_no_activity_frames)) { st->rangeFinal = 0; data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); RESTORE_STACK; return 1; } + } else { + st->nb_no_activity_frames = 0; } #endif @@ -2629,7 +2618,6 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) goto bad_arg; } st->variable_duration = value; - celt_encoder_ctl(celt_enc, OPUS_SET_EXPERT_FRAME_DURATION(value)); } break; case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: @@ -2726,7 +2714,33 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value)); } break; - + case OPUS_GET_IN_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->silk_mode.useDTX && (st->prev_mode == MODE_SILK_ONLY || st->prev_mode == MODE_HYBRID)) { + /* DTX determined by Silk. */ + silk_encoder *silk_enc = (silk_encoder*)(void *)((char*)st+st->silk_enc_offset); + *value = silk_enc->state_Fxx[0].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + /* Stereo: check second channel unless only the middle channel was encoded. */ + if(*value == 1 && st->silk_mode.nChannelsInternal == 2 && silk_enc->prev_decode_only_middle == 0) { + *value = silk_enc->state_Fxx[1].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + } + } +#ifndef DISABLE_FLOAT_API + else if (st->use_dtx) { + /* DTX determined by Opus. */ + *value = st->nb_no_activity_frames >= NB_SPEECH_FRAMES_BEFORE_DTX; + } +#endif + else { + *value = 0; + } + } + break; case CELT_GET_MODE_REQUEST: { const CELTMode ** value = va_arg(ap, const CELTMode**); diff --git a/src/opus_multistream_decoder.c b/src/opus_multistream_decoder.c index 562103cd..a2837c35 100644 --- a/src/opus_multistream_decoder.c +++ b/src/opus_multistream_decoder.c @@ -251,8 +251,11 @@ int opus_multistream_decode_native( } packet_offset = 0; ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); - data += packet_offset; - len -= packet_offset; + if (!do_plc) + { + data += packet_offset; + len -= packet_offset; + } if (ret <= 0) { RESTORE_STACK; @@ -487,7 +490,7 @@ int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, OpusDecoder **value; stream_id = va_arg(ap, opus_int32); if (stream_id<0 || stream_id >= st->layout.nb_streams) - ret = OPUS_BAD_ARG; + goto bad_arg; value = va_arg(ap, OpusDecoder**); if (!value) { diff --git a/src/opus_multistream_encoder.c b/src/opus_multistream_encoder.c index 9cb9bf34..93204a14 100644 --- a/src/opus_multistream_encoder.c +++ b/src/opus_multistream_encoder.c @@ -1249,7 +1249,7 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request, OpusEncoder **value; stream_id = va_arg(ap, opus_int32); if (stream_id<0 || stream_id >= st->layout.nb_streams) - ret = OPUS_BAD_ARG; + goto bad_arg; value = va_arg(ap, OpusEncoder**); if (!value) { diff --git a/src/opus_private.h b/src/opus_private.h index 09783cee..5e2463f5 100644 --- a/src/opus_private.h +++ b/src/opus_private.h @@ -135,6 +135,7 @@ typedef void (*opus_copy_channel_out_func)( typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int); void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth); int encode_size(int size, unsigned char *data); diff --git a/tests/opus_decode_fuzzer.c b/tests/opus_decode_fuzzer.c index 90026221..20fa1e5a 100644 --- a/tests/opus_decode_fuzzer.c +++ b/tests/opus_decode_fuzzer.c @@ -62,9 +62,10 @@ static void ParseToc(const uint8_t *toc, TocInfo *const info) { int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { OpusDecoder *dec; opus_int16 *pcm; - uint8_t *packet; + uint8_t *temp_data; TocInfo toc; - int i, err; + int i = 0; + int err = OPUS_OK; /* Not enough data to setup the decoder (+1 for the ToC) */ if (size < SETUP_BYTE_COUNT + 1) { @@ -75,26 +76,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ParseToc(&data[SETUP_BYTE_COUNT], &toc); dec = opus_decoder_create(toc.fs, toc.channels, &err); - if (err != OPUS_OK | dec == NULL) { + if (err != OPUS_OK || dec == NULL) { return 0; } pcm = (opus_int16*) malloc(sizeof(*pcm) * MAX_FRAME_SAMP * toc.channels); - packet = (uint8_t*) calloc(MAX_PACKET, sizeof(*packet)); - i = 0; - while (1) { + while (i + SETUP_BYTE_COUNT < size) { int len, fec; - if (i + SETUP_BYTE_COUNT >= size) { - break; - } - len = (opus_uint32) data[i ] << 24 | (opus_uint32) data[i + 1] << 16 | (opus_uint32) data[i + 2] << 8 | (opus_uint32) data[i + 3]; - if (len > MAX_PACKET || len < 0) { + if (len > MAX_PACKET || len < 0 || i + SETUP_BYTE_COUNT + len > size) { break; } @@ -102,17 +97,18 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { * Instead, byte 4 is repurposed to determine if FEC is used. */ fec = data[i + 4] & 1; - /* Lost packet */ if (len == 0) { + /* Lost packet */ int frame_size; opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&frame_size)); - (void) opus_decode(dec, NULL, size, pcm, frame_size, fec); + (void) opus_decode(dec, NULL, len, pcm, frame_size, fec); } else { - if (i + SETUP_BYTE_COUNT + len > size) { - break; - } - memcpy(pcm, &data[i + SETUP_BYTE_COUNT], len); - (void) opus_decode(dec, data, size, pcm, MAX_FRAME_SAMP, fec); + temp_data = (uint8_t*) malloc(len); + memcpy(temp_data, &data[i + SETUP_BYTE_COUNT], len); + + (void) opus_decode(dec, temp_data, len, pcm, MAX_FRAME_SAMP, fec); + + free(temp_data); } i += SETUP_BYTE_COUNT + len; @@ -120,7 +116,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { opus_decoder_destroy(dec); free(pcm); - free(packet); return 0; } diff --git a/tests/test_opus_common.h b/tests/test_opus_common.h index 235cf1c1..d96c7d84 100644 --- a/tests/test_opus_common.h +++ b/tests/test_opus_common.h @@ -75,6 +75,9 @@ static OPUS_INLINE void _test_failed(const char *file, int line) fprintf(stderr,"Please report this failure and include\n"); fprintf(stderr,"'make check SEED=%u fails %s at line %d for %s'\n",iseed,file,line,opus_get_version_string()); fprintf(stderr,"and any relevant details about your system.\n\n"); +#if defined(_MSC_VER) + _set_abort_behavior( 0, _WRITE_ABORT_MSG); +#endif abort(); } #define test_failed() _test_failed(__FILE__, __LINE__); diff --git a/tests/test_opus_encode.c b/tests/test_opus_encode.c index dae49c3d..00795a1e 100644 --- a/tests/test_opus_encode.c +++ b/tests/test_opus_encode.c @@ -140,7 +140,7 @@ int get_frame_size_enum(int frame_size, int sampling_rate) return frame_size_enum; } -void test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec, const char* debug_info) +int test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec) { int samp_count = 0; opus_int16 *inbuf; @@ -148,6 +148,7 @@ void test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *de int len; opus_int16 *outbuf; int out_samples; + int ret = 0; /* Generate input data */ inbuf = (opus_int16*)malloc(sizeof(*inbuf)*SSAMPLES); @@ -160,16 +161,16 @@ void test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *de do { len = opus_encode(enc, &inbuf[samp_count*channels], frame_size, packet, MAX_PACKET); if(len<0 || len>MAX_PACKET) { - fprintf(stderr,"%s\n",debug_info); fprintf(stderr,"opus_encode() returned %d\n",len); - test_failed(); + ret = -1; + break; } out_samples = opus_decode(dec, packet, len, outbuf, MAX_FRAME_SAMP, 0); if(out_samples!=frame_size) { - fprintf(stderr,"%s\n",debug_info); fprintf(stderr,"opus_decode() returned %d\n",out_samples); - test_failed(); + ret = -1; + break; } samp_count += frame_size; @@ -178,6 +179,7 @@ void test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *de /* Clean up */ free(inbuf); free(outbuf); + return ret; } void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes) @@ -205,7 +207,6 @@ void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes int prediction_disabled[3] = {0, 0, 1}; int use_dtx[2] = {0, 1}; int frame_sizes_ms_x2[9] = {5, 10, 20, 40, 80, 120, 160, 200, 240}; /* x2 to avoid 2.5 ms */ - char debug_info[512]; for (i=0; i<num_encoders; i++) { int sampling_rate = RAND_SAMPLE(sampling_rates); @@ -236,15 +237,6 @@ void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes int frame_size_enum = get_frame_size_enum(frame_size, sampling_rate); force_channel = IMIN(force_channel, num_channels); - sprintf(debug_info, - "fuzz_encoder_settings: %d kHz, %d ch, application: %d, " - "%d bps, force ch: %d, vbr: %d, vbr constraint: %d, complexity: %d, " - "max bw: %d, signal: %d, inband fec: %d, pkt loss: %d%%, lsb depth: %d, " - "pred disabled: %d, dtx: %d, (%d/2) ms\n", - sampling_rate/1000, num_channels, application, bitrate, - force_channel, vbr, vbr_constraint, complexity, max_bw, sig, inband_fec, - pkt_loss, lsb_depth, pred_disabled, dtx, frame_size_ms_x2); - if(opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)) != OPUS_OK) test_failed(); if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(force_channel)) != OPUS_OK) test_failed(); if(opus_encoder_ctl(enc, OPUS_SET_VBR(vbr)) != OPUS_OK) test_failed(); @@ -259,7 +251,17 @@ void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes if(opus_encoder_ctl(enc, OPUS_SET_DTX(dtx)) != OPUS_OK) test_failed(); if(opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(frame_size_enum)) != OPUS_OK) test_failed(); - test_encode(enc, num_channels, frame_size, dec, debug_info); + if(test_encode(enc, num_channels, frame_size, dec)) { + fprintf(stderr, + "fuzz_encoder_settings: %d kHz, %d ch, application: %d, " + "%d bps, force ch: %d, vbr: %d, vbr constraint: %d, complexity: %d, " + "max bw: %d, signal: %d, inband fec: %d, pkt loss: %d%%, lsb depth: %d, " + "pred disabled: %d, dtx: %d, (%d/2) ms\n", + sampling_rate/1000, num_channels, application, bitrate, + force_channel, vbr, vbr_constraint, complexity, max_bw, sig, inband_fec, + pkt_loss, lsb_depth, pred_disabled, dtx, frame_size_ms_x2); + test_failed(); + } } opus_encoder_destroy(enc); diff --git a/tests/test_opus_projection.c b/tests/test_opus_projection.c index 4d622e86..5f0d672c 100644 --- a/tests/test_opus_projection.c +++ b/tests/test_opus_projection.c @@ -360,6 +360,8 @@ void test_encode_decode(opus_int32 bitrate, opus_int32 channels, goto bad_cleanup; } + opus_projection_decoder_destroy(st_dec); + opus_projection_encoder_destroy(st_enc); free(buffer_in); free(buffer_out); return; diff --git a/training/rnn_dump.py b/training/rnn_dump.py new file mode 100755 index 00000000..c312088e --- /dev/null +++ b/training/rnn_dump.py @@ -0,0 +1,66 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K +import sys + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int8 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(max(-128,min(127,int(round(128*v[i])))))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +#model = load_model(sys.argv[1], custom_objects={'binary_crossentrop2': binary_crossentrop2}) +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh')(main_input) +x = GRU(24, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) +model.load_weights(sys.argv[1]) + +weights = model.get_weights() + +f = open(sys.argv[2], 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 32, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 32, 24\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 24, 2, 1\n};\n\n') + +f.close() diff --git a/training/rnn_train.py b/training/rnn_train.py new file mode 100755 index 00000000..29bcb034 --- /dev/null +++ b/training/rnn_train.py @@ -0,0 +1,177 @@ +#!/usr/bin/python3 + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import CuDNNGRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py +from keras.optimizers import Adam + +from keras.constraints import Constraint +from keras import backend as K +import numpy as np + +import tensorflow as tf +from keras.backend.tensorflow_backend import set_session +config = tf.ConfigProto() +config.gpu_options.per_process_gpu_memory_fraction = 0.44 +set_session(tf.Session(config=config)) + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_true, y_pred), axis=-1) + +def binary_accuracy2(y_true, y_pred): + return K.mean(K.cast(K.equal(y_true, K.round(y_pred)), 'float32') + K.cast(K.equal(y_true, 0.5), 'float32'), axis=-1) + +def quant_model(model): + weights = model.get_weights() + for k in range(len(weights)): + weights[k] = np.maximum(-128, np.minimum(127, np.round(128*weights[k])*0.0078125)) + model.set_weights(weights) + +class WeightClip(Constraint): + '''Clips the weights incident to each hidden unit to be inside a range + ''' + def __init__(self, c=2): + self.c = c + + def __call__(self, p): + return K.clip(p, -self.c, self.c) + + def get_config(self): + return {'name': self.__class__.__name__, + 'c': self.c} + +reg = 0.000001 +constraint = WeightClip(.998) + +print('Build model...') + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh', kernel_constraint=constraint, bias_constraint=constraint)(main_input) +#x = CuDNNGRU(24, return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = GRU(24, recurrent_activation='sigmoid', activation='tanh', return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = Dense(2, activation='sigmoid', kernel_constraint=constraint, bias_constraint=constraint)(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 2048 + +print('Loading data...') +with h5py.File('features10b.h5', 'r') as hf: + all_data = hf['data'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)//window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +print("Marking ignores") +for s in y_train: + for e in s: + if (e[1] >= 1): + break + e[0] = 0.5 + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +model.load_weights('newweights10a1b_ep206.hdf5') + +#weights = model.get_weights() +#for k in range(len(weights)): +# weights[k] = np.round(128*weights[k])*0.0078125 +#model.set_weights(weights) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +print('Train...') +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=10, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep10.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=50, initial_epoch=10) +model.save("newweights10a1c_ep50.hdf5") + +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=100, initial_epoch=50) +model.save("newweights10a1c_ep100.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=150, initial_epoch=100) +model.save("newweights10a1c_ep150.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, initial_epoch=150) +model.save("newweights10a1c_ep200.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=201, initial_epoch=200) +model.save("newweights10a1c_ep201.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=202, initial_epoch=201, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep202.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=203, initial_epoch=202, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep203.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=204, initial_epoch=203, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep204.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=205, initial_epoch=204, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep205.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=206, initial_epoch=205, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep206.hdf5") + diff --git a/training/txt2hdf5.py b/training/txt2hdf5.py new file mode 100755 index 00000000..9c602877 --- /dev/null +++ b/training/txt2hdf5.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from __future__ import print_function + +import numpy as np +import h5py +import sys + +data = np.loadtxt(sys.argv[1], dtype='float32') +h5f = h5py.File(sys.argv[2], 'w'); +h5f.create_dataset('data', data=data) +h5f.close() |