diff --git a/.gitignore b/.gitignore index 1ed76375..75f56b60 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ build *output/ +audio/dist/ +audio/fc_patch/ + docs/build/ docs/topic/ctc/warp-ctc/ @@ -42,6 +45,7 @@ tools/python-soundfile/ tools/onnx tools/onnxruntime tools/Paddle2ONNX +tools/onnx-simplifier/ speechx/fc_patch/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0435cfbe..15b842d5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,8 +3,13 @@ repos: rev: v0.16.0 hooks: - id: yapf - files: \.py$ - exclude: (?=third_party).*(\.py)$ + name: yapf + language: python + entry: yapf + args: [-i, -vv] + types: [python] + exclude: (?=speechx/speechx/kaldi|audio/paddleaudio/src|third_party).*(\.cpp|\.cc|\.h\.hpp|\.py)$ + - repo: https://github.com/pre-commit/pre-commit-hooks rev: a11d9314b22d8f8c7556443875b731ef05965464 hooks: @@ -30,7 +35,8 @@ repos: - --ignore=E501,E228,E226,E261,E266,E128,E402,W503 - --builtins=G,request - --jobs=1 - exclude: (?=third_party).*(\.py)$ + exclude: (?=speechx/speechx/kaldi|audio/paddleaudio/src|third_party).*(\.cpp|\.cc|\.h\.hpp|\.py)$ + - repo : https://github.com/Lucas-C/pre-commit-hooks rev: v1.0.1 hooks: @@ -42,6 +48,7 @@ repos: files: \.md$ - id: remove-tabs files: \.md$ + - repo: local hooks: - id: clang-format @@ -49,23 +56,17 @@ repos: description: Format files with ClangFormat entry: bash .pre-commit-hooks/clang-format.hook -i language: system - files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|cuh|proto)$ - exclude: (?=speechx/speechx/kaldi|speechx/patch|speechx/tools/fstbin|speechx/tools/lmbin|third_party/ctc_decoders).*(\.cpp|\.cc|\.h|\.py)$ - #- id: copyright_checker - # name: copyright_checker - # entry: python .pre-commit-hooks/copyright-check.hook - # language: system - # files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|proto|py)$ - # exclude: (?=third_party|pypinyin|speechx/speechx/kaldi|speechx/patch|speechx/tools/fstbin|speechx/tools/lmbin).*(\.cpp|\.cc|\.h|\.py)$ + files: \.(h\+\+|h|hh|hxx|hpp|cuh|c|cc|cpp|cu|c\+\+|cxx|tpp|txx)$ + exclude: (?=speechx/speechx/kaldi|audio/paddleaudio/src|speechx/patch|speechx/tools/fstbin|speechx/tools/lmbin|third_party/ctc_decoders).*(\.cpp|\.cc|\.h|\.hpp|\.py)$ - id: cpplint name: cpplint description: Static code analysis of C/C++ files language: python files: \.(h\+\+|h|hh|hxx|hpp|cuh|c|cc|cpp|cu|c\+\+|cxx|tpp|txx)$ - exclude: (?=speechx/speechx/kaldi|speechx/patch|speechx/tools/fstbin|speechx/tools/lmbin|third_party/ctc_decoders).*(\.cpp|\.cc|\.h|\.py)$ + exclude: (?=speechx/speechx/kaldi|audio/paddleaudio/src|speechx/patch|speechx/tools/fstbin|speechx/tools/lmbin|third_party/ctc_decoders).*(\.cpp|\.cc|\.h|\.hpp|\.py)$ entry: cpplint --filter=-build,-whitespace,+whitespace/comma,-whitespace/indent - repo: https://github.com/asottile/reorder_python_imports rev: v2.4.0 hooks: - id: reorder-python-imports - exclude: (?=third_party).*(\.py)$ + exclude: (?=speechx/speechx/kaldi|audio/paddleaudio/src|speechx/patch|speechx/tools/fstbin|speechx/tools/lmbin|third_party/ctc_decoders).*(\.cpp|\.cc|\.h\.hpp|\.py)$ diff --git a/.readthedocs.yml b/.readthedocs.yml index e922891e..dafc6bf3 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -23,4 +23,4 @@ python: - requirements: docs/requirements.txt - method: setuptools path: . - system_packages: true \ No newline at end of file + system_packages: true diff --git a/audio/CMakeLists.txt b/audio/CMakeLists.txt new file mode 100644 index 00000000..d9ae63cd --- /dev/null +++ b/audio/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 3.16 FATAL_ERROR) + +# Use compiler ID "AppleClang" instead of "Clang" for XCode. +# Not setting this sometimes makes XCode C compiler gets detected as "Clang", +# even when the C++ one is detected as "AppleClang". +cmake_policy(SET CMP0010 NEW) +cmake_policy(SET CMP0025 NEW) + +# Suppress warning flags in default MSVC configuration. It's not +# mandatory that we do this (and we don't if cmake is old), but it's +# nice when it's possible, and it's possible on our Windows configs. +if(NOT CMAKE_VERSION VERSION_LESS 3.15.0) + cmake_policy(SET CMP0092 NEW) +endif() + +project(paddleaudio) + +# check and set CMAKE_CXX_STANDARD +string(FIND "${CMAKE_CXX_FLAGS}" "-std=c++" env_cxx_standard) +if(env_cxx_standard GREATER -1) + message( + WARNING "C++ standard version definition detected in environment variable." + "paddleaudio requires -std=c++14. Please remove -std=c++ settings in your environment.") +endif() + + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_C_STANDARD 11) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_VERBOSE_MAKEFILE ON) + +# Options +option(BUILD_SOX "Build libsox statically" ON) +option(BUILD_MAD "Enable libmad" ON) +option(BUILD_KALDI "Build kaldi statically" ON) +option(BUILD_PADDLEAUDIO_PYTHON_EXTENSION "Build Python extension" ON) + + +# cmake +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake;${PROJECT_SOURCE_DIR}/cmake/external") + +if (NOT MSVC) + find_package(GFortranLibs REQUIRED) + include(FortranCInterface) + include(FindGFortranLibs REQUIRED) +endif() + +# fc_patch dir +set(FETCHCONTENT_QUIET off) +get_filename_component(fc_patch "fc_patch" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") +set(FETCHCONTENT_BASE_DIR ${fc_patch}) +set(THIRD_PARTY_PATH ${fc_patch}) + +include(openblas) + +set(PYBIND11_PYTHON_VERSION ${PY_VERSION}) +include(cmake/pybind.cmake) +include_directories(${PYTHON_INCLUDE_DIR}) + +# packages +find_package(Python3 COMPONENTS Interpreter Development) + +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -O0 -Wall -g") +add_subdirectory(paddleaudio) + +# Summary +include(cmake/summary.cmake) +onnx_print_configuration_summary() diff --git a/audio/README.md b/audio/README.md new file mode 100644 index 00000000..f336ac9a --- /dev/null +++ b/audio/README.md @@ -0,0 +1,35 @@ +# PaddleAudio + +安装方式: pip install paddleaudio + +目前支持的平台:Linux: + +## Environment + +## Build wheel + +Linux test build whl environment: +* docker - `registry.baidubce.com/paddlepaddle/paddle:2.2.2` +* os - Ubuntu 16.04.7 LTS +* gcc/g++/gfortran - 8.2.0 +* cmake - 3.18.0 (need install) + +* [How to Install Docker](https://docs.docker.com/engine/install/) +* [A Docker Tutorial for Beginners](https://docker-curriculum.com/) + +1. First to launch docker container. + +``` +docker run --privileged --net=host --ipc=host -it --rm -v $PWD:/workspace --name=dev registry.baidubce.com/paddlepaddle/paddle:2.2.2 /bin/bash +``` +2. python setup.py bdist_wheel + +MAC:test build whl envrioment: +* os +* gcc/g++/gfortran 12.2.0 +* cpu Intel Xeon E5 x86_64 + + +Windows: +not support: paddleaudio C++ extension lib (sox io, kaldi native fbank) +python setup.py bdist_wheel \ No newline at end of file diff --git a/audio/cmake/FindGFortranLibs.cmake b/audio/cmake/FindGFortranLibs.cmake new file mode 100644 index 00000000..0ac35662 --- /dev/null +++ b/audio/cmake/FindGFortranLibs.cmake @@ -0,0 +1,153 @@ +#.rst: +# FindGFortranLibs +# -------- +# https://github.com/Argonne-National-Laboratory/PIPS/blob/master/cmake/Modules/FindGFortranLibs.cmake +# https://enccs.github.io/cmake-workshop/cxx-fortran/ +# +# Find gcc Fortran compiler & library paths +# +# The module defines the following variables: +# +# :: +# +# +# GFORTRANLIBS_FOUND - true if system has gfortran +# LIBGFORTRAN_LIBRARIES - path to libgfortran +# LIBQUADMATH_LIBRARIES - path to libquadmath +# GFORTRAN_LIBARIES_DIR - directory containing libgfortran, libquadmath +# GFORTRAN_INCLUDE_DIR - directory containing gfortran/gcc headers +# LIBGOMP_LIBRARIES - path to libgomp +# LIBGOMP_INCLUDE_DIR - directory containing omp.h header +# GFORTRAN_VERSION_STRING - version of gfortran found +# +set(CMAKE_REQUIRED_QUIET ${LIBIOMP_FIND_QUIETLY}) + +if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for gfortran related libraries...") +endif() + +enable_language(Fortran) +if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU") + + # Basically, call "gfortran -v" to dump compiler info to the string + # GFORTRAN_VERBOSE_STR, which will be used to get necessary paths + message(STATUS "Extracting library and header information by calling 'gfortran -v'...") + execute_process(COMMAND "${CMAKE_Fortran_COMPILER}" "-v" ERROR_VARIABLE + GFORTRAN_VERBOSE_STR RESULT_VARIABLE FLAG) + + # For debugging + message(STATUS "'gfortran -v' returned:") + message(STATUS "${GFORTRAN_VERBOSE_STR}") + + # Detect gfortran version + string(REGEX MATCH "gcc version [^\t\n ]+" GFORTRAN_VER_STR "${GFORTRAN_VERBOSE_STR}") + string(REGEX REPLACE "gcc version ([^\t\n ]+)" "\\1" GFORTRAN_VERSION_STRING "${GFORTRAN_VER_STR}") + message(STATUS "Detected gfortran version ${GFORTRAN_VERSION_STRING}") + unset(GFORTRAN_VER_STR) + + set(MATCH_REGEX "[^\t\n ]+[\t\n ]+") + set(REPLACE_REGEX "([^\t\n ]+)") + + # Find architecture for compiler + string(REGEX MATCH "Target: [^\t\n ]+" + GFORTRAN_ARCH_STR "${GFORTRAN_VERBOSE_STR}") + message(STATUS "Architecture string: ${GFORTRAN_ARCH_STR}") + string(REGEX REPLACE "Target: ([^\t\n ]+)" "\\1" + GFORTRAN_ARCH "${GFORTRAN_ARCH_STR}") + message(STATUS "Detected gfortran architecture: ${GFORTRAN_ARCH}") + unset(GFORTRAN_ARCH_STR) + + # Find install prefix, if it exists; if not, use default + string(REGEX MATCH "--prefix=[^\t\n ]+[\t\n ]+" + GFORTRAN_PREFIX_STR "${GFORTRAN_VERBOSE_STR}") + if(NOT GFORTRAN_PREFIX_STR) + message(STATUS "Detected default gfortran prefix") + set(GFORTRAN_PREFIX_DIR "/usr/local") # default prefix for gcc install + else() + string(REGEX REPLACE "--prefix=([^\t\n ]+)" "\\1" + GFORTRAN_PREFIX_DIR "${GFORTRAN_PREFIX_STR}") + endif() + message(STATUS "Detected gfortran prefix: ${GFORTRAN_PREFIX_DIR}") + unset(GFORTRAN_PREFIX_STR) + + # Find install exec-prefix, if it exists; if not, use default + string(REGEX MATCH "--exec-prefix=[^\t\n ]+[\t\n ]+" "\\1" + GFORTRAN_EXEC_PREFIX_STR "${GFORTRAN_VERBOSE_STR}") + if(NOT GFORTRAN_EXEC_PREFIX_STR) + message(STATUS "Detected default gfortran exec-prefix") + set(GFORTRAN_EXEC_PREFIX_DIR "${GFORTRAN_PREFIX_DIR}") + else() + string(REGEX REPLACE "--exec-prefix=([^\t\n ]+)" "\\1" + GFORTRAN_EXEC_PREFIX_DIR "${GFORTRAN_EXEC_PREFIX_STR}") + endif() + message(STATUS "Detected gfortran exec-prefix: ${GFORTRAN_EXEC_PREFIX_DIR}") + UNSET(GFORTRAN_EXEC_PREFIX_STR) + + # Find library directory and include directory, if library directory specified + string(REGEX MATCH "--libdir=[^\t\n ]+" + GFORTRAN_LIB_DIR_STR "${GFORTRAN_VERBOSE_STR}") + if(NOT GFORTRAN_LIB_DIR_STR) + message(STATUS "Found --libdir flag -- not found") + message(STATUS "Using default gfortran library & include directory paths") + string(STRIP ${GFORTRAN_PREFIX_DIR} TMPLIBDIR) + set(GFORTRAN_LIBRARIES_DIR "${TMPLIBDIR}/lib64") + set(GFORTRAN_INCLUDE_DIR "${TMPLIBDIR}/include") + else() + message(STATUS "Found --libdir flag -- yes") + string(REGEX REPLACE "--libdir=([^\t\n ]+)" "\\1" + GFORTRAN_LIBRARIES_DIR "${GFORTRAN_LIB_DIR_STR}") + string(CONCAT GFORTRAN_INCLUDE_DIR "${GFORTRAN_LIBRARIES_DIR}" "/gcc/" "${GFORTRAN_ARCH}" "/" "${GFORTRAN_VERSION_STRING}" "/include") + endif() + message(STATUS "gfortran libraries path: ${GFORTRAN_LIBRARIES_DIR}") + message(STATUS "gfortran include path dir: ${GFORTRAN_INCLUDE_DIR}") + unset(GFORTRAN_LIB_DIR_STR) + + # There are lots of other build options for gcc & gfortran. For now, the + # options implemented above should cover a lot of common use cases. + + # Clean up be deleting the output string from "gfortran -v" + unset(GFORTRAN_VERBOSE_STR) + + # Find paths for libgfortran, libquadmath, libgomp + # libgomp needed for OpenMP support without Clang + find_library(LIBGFORTRAN_LIBRARIES NAMES gfortran libgfortran + HINTS ${GFORTRAN_LIBRARIES_DIR}) + find_library(LIBQUADMATH_LIBRARIES NAMES quadmath libquadmath + HINTS ${GFORTRAN_LIBRARIES_DIR}) + find_library(LIBGOMP_LIBRARIES NAMES gomp libgomp + HINTS ${GFORTRAN_LIBRARIES_DIR}) + + # Find OpenMP headers + find_path(LIBGOMP_INCLUDE_DIR NAMES omp.h HINTS ${GFORTRAN_INCLUDE_DIR}) + +else() + message(STATUS "CMAKE_Fortran_COMPILER_ID does not match 'GNU'!") +endif() + +include(FindPackageHandleStandardArgs) + +# Required: libgfortran, libquadmath, path for gfortran libraries +# Optional: libgomp, path for OpenMP headers, path for gcc/gfortran headers +find_package_handle_standard_args(GFortranLibs + REQUIRED_VARS LIBGFORTRAN_LIBRARIES LIBQUADMATH_LIBRARIES GFORTRAN_LIBRARIES_DIR + VERSION_VAR GFORTRAN_VERSION_STRING) + +if(GFORTRANLIBS_FOUND) + message(STATUS "Looking for gfortran libraries -- found") + message(STATUS "gfortran version: ${GFORTRAN_VERSION_STRING}") +else() + message(STATUS "Looking for gfortran libraries -- not found") +endif() + +mark_as_advanced(LIBGFORTRAN_LIBRARIES LIBQUADMATH_LIBRARIES + LIBGOMP_LIBRARIES LIBGOMP_INCLUDE_DIR + GFORTRAN_LIBRARIES_DIR GFORTRAN_INCLUDE_DIR) +# FindGFortranLIBS.cmake ends here + + +message(STATUS LIBGFORTRAN_LIBRARIES= ${LIBGFORTRAN_LIBRARIES}) +message(STATUS LIBQUADMATH_LIBRARIES= ${LIBQUADMATH_LIBRARIES}) +message(STATUS LIBGOMP_LIBRARIES= ${LIBGOMP_LIBRARIES}) +message(STATUS LIBGOMP_INCLUDE_DIR= ${LIBGOMP_INCLUDE_DIR}) +message(STATUS GFORTRAN_LIBRARIES_DIR= ${GFORTRAN_LIBRARIES_DIR}) +message(STATUS GFORTRAN_INCLUDE_DIR= ${GFORTRAN_INCLUDE_DIR}) diff --git a/audio/cmake/external/openblas.cmake b/audio/cmake/external/openblas.cmake new file mode 100644 index 00000000..9fee0063 --- /dev/null +++ b/audio/cmake/external/openblas.cmake @@ -0,0 +1,119 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include(ExternalProject) + +set(CBLAS_PREFIX_DIR ${THIRD_PARTY_PATH}/openblas) +set(CBLAS_INSTALL_DIR ${THIRD_PARTY_PATH}/install/openblas) +set(CBLAS_REPOSITORY https://github.com/xianyi/OpenBLAS.git) +set(CBLAS_TAG v0.3.10) + +if(NOT WIN32) + set(CBLAS_LIBRARIES + "${CBLAS_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}openblas${CMAKE_STATIC_LIBRARY_SUFFIX}" + CACHE FILEPATH "openblas library." FORCE) + set(CBLAS_INC_DIR + "${CBLAS_INSTALL_DIR}/include" + CACHE PATH "openblas include directory." FORCE) + set(OPENBLAS_CC + "${CMAKE_C_COMPILER} -Wno-unused-but-set-variable -Wno-unused-variable") + + if(APPLE) + set(OPENBLAS_CC "${CMAKE_C_COMPILER} -isysroot ${CMAKE_OSX_SYSROOT}") + endif() + set(OPTIONAL_ARGS "") + set(COMMON_ARGS "") + + if(APPLE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^x86(_64)?$") + set(OPTIONAL_ARGS DYNAMIC_ARCH=1 NUM_THREADS=64) + endif() + set(COMMON_ARGS CC=${OPENBLAS_CC} NO_SHARED=1) + endif() + + ExternalProject_Add( + OPENBLAS + URL "https://paddleaudio.bj.bcebos.com/build/OpenBLAS-0.3.10.zip" + GIT_SHALLOW YES + DOWNLOAD_DIR ${CBLAS_PREFIX_DIR} + SOURCE_DIR ${CBLAS_PREFIX_DIR} + INSTALL_DIR ${CBLAS_INSTALL_DIR} + BUILD_IN_SOURCE 1 + BUILD_COMMAND make -j${NPROC} ${COMMON_ARGS} ${OPTIONAL_ARGS} + INSTALL_COMMAND make install PREFIX= + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_BYPRODUCTS ${CBLAS_LIBRARIES}) + + ExternalProject_Get_Property(OPENBLAS INSTALL_DIR) + set(OpenBLAS_INSTALL_PREFIX ${INSTALL_DIR}) + add_library(openblas STATIC IMPORTED) + add_dependencies(openblas OPENBLAS) + set_target_properties(openblas PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES Fortran) + set_target_properties(openblas PROPERTIES IMPORTED_LOCATION ${OpenBLAS_INSTALL_PREFIX}/lib/libopenblas.a) + + link_directories(${OpenBLAS_INSTALL_PREFIX}/lib) + include_directories(${OpenBLAS_INSTALL_PREFIX}/include) + + set(OPENBLAS_LIBRARIES + ${OpenBLAS_INSTALL_PREFIX}/lib/libopenblas.a + ) + + add_library(libopenblas INTERFACE) + add_dependencies(libopenblas openblas) + target_include_directories(libopenblas INTERFACE ${OpenBLAS_INSTALL_PREFIX}/include/openblas) + target_link_libraries(libopenblas INTERFACE ${OPENBLAS_LIBRARIES}) +else() + set(CBLAS_LIBRARIES + "${CBLAS_INSTALL_DIR}/lib/openblas${CMAKE_STATIC_LIBRARY_SUFFIX}" + CACHE FILEPATH "openblas library." FORCE) + set(CBLAS_INC_DIR + "${CBLAS_INSTALL_DIR}/include/openblas" + CACHE PATH "openblas include directory." FORCE) + ExternalProject_Add( + extern_openblas + ${EXTERNAL_PROJECT_LOG_ARGS} + GIT_REPOSITORY ${CBLAS_REPOSITORY} + GIT_TAG ${CBLAS_TAG} + PREFIX ${CBLAS_PREFIX_DIR} + INSTALL_DIR ${CBLAS_INSTALL_DIR} + BUILD_IN_SOURCE 0 + UPDATE_COMMAND "" + CMAKE_ARGS -DCMAKE_C_COMPILER=clang-cl + -DCMAKE_CXX_COMPILER=clang-cl + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DCMAKE_INSTALL_PREFIX=${CBLAS_INSTALL_DIR} + -DCMAKE_BUILD_TYPE=Release #${THIRD_PARTY_BUILD_TYPE} + -DCMAKE_MT=mt + -DUSE_THREAD=OFF + -DBUILD_WITHOUT_LAPACK=NO + -DCMAKE_Fortran_COMPILER=flang + -DNOFORTRAN=0 + -DDYNAMIC_ARCH=ON + #${EXTERNAL_OPTIONAL_ARGS} + CMAKE_CACHE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH=${CBLAS_INSTALL_DIR} + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON + -DCMAKE_BUILD_TYPE:STRING=Release #${THIRD_PARTY_BUILD_TYPE} + # ninja need to know where openblas.lib comes from + BUILD_BYPRODUCTS ${CBLAS_LIBRARIES}) + set(OPENBLAS_SHARED_LIB + ${CBLAS_INSTALL_DIR}/bin/openblas${CMAKE_SHARED_LIBRARY_SUFFIX}) + + add_library(openblas INTERFACE) + add_dependencies(openblas extern_openblas) + include_directories(${CBLAS_INC_DIR}) + link_libraries(${CBLAS_LIBRARIES}) +endif() + diff --git a/audio/cmake/pybind.cmake b/audio/cmake/pybind.cmake new file mode 100644 index 00000000..0ce1f57f --- /dev/null +++ b/audio/cmake/pybind.cmake @@ -0,0 +1,42 @@ +#the pybind11 is from:https://github.com/pybind/pybind11 +# Copyright (c) 2016 Wenzel Jakob , All rights reserved. + +SET(PYBIND_ZIP "v2.10.0.zip") +SET(LOCAL_PYBIND_ZIP ${FETCHCONTENT_BASE_DIR}/${PYBIND_ZIP}) +SET(PYBIND_SRC ${FETCHCONTENT_BASE_DIR}/pybind11) +SET(DOWNLOAD_URL "https://paddleaudio.bj.bcebos.com/build/v2.10.0.zip") +SET(PYBIND_TIMEOUT 600 CACHE STRING "Timeout in seconds when downloading pybind.") + +IF(NOT EXISTS ${LOCAL_PYBIND_ZIP}) + FILE(DOWNLOAD ${DOWNLOAD_URL} + ${LOCAL_PYBIND_ZIP} + TIMEOUT ${PYBIND_TIMEOUT} + STATUS ERR + SHOW_PROGRESS + ) + + IF(ERR EQUAL 0) + MESSAGE(STATUS "download pybind success") + ELSE() + MESSAGE(FATAL_ERROR "download pybind fail") + ENDIF() +ENDIF() + +IF(NOT EXISTS ${PYBIND_SRC}) + EXECUTE_PROCESS( + COMMAND ${CMAKE_COMMAND} -E tar xfz ${LOCAL_PYBIND_ZIP} + WORKING_DIRECTORY ${FETCHCONTENT_BASE_DIR} + RESULT_VARIABLE tar_result + ) + + file(RENAME ${FETCHCONTENT_BASE_DIR}/pybind11-2.10.0 ${PYBIND_SRC}) + + IF (tar_result MATCHES 0) + MESSAGE(STATUS "unzip pybind success") + ELSE() + MESSAGE(FATAL_ERROR "unzip pybind fail") + ENDIF() + +ENDIF() + +include_directories(${PYBIND_SRC}/include) diff --git a/audio/cmake/summary.cmake b/audio/cmake/summary.cmake new file mode 100644 index 00000000..f04d4469 --- /dev/null +++ b/audio/cmake/summary.cmake @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Prints accumulated ONNX configuration summary +function (onnx_print_configuration_summary) + message(STATUS "") + message(STATUS "******** Summary ********") + message(STATUS " CMake version : ${CMAKE_VERSION}") + message(STATUS " CMake command : ${CMAKE_COMMAND}") + message(STATUS " System : ${CMAKE_SYSTEM_NAME}") + message(STATUS " C++ compiler : ${CMAKE_CXX_COMPILER}") + message(STATUS " C++ compiler version : ${CMAKE_CXX_COMPILER_VERSION}") + message(STATUS " CXX flags : ${CMAKE_CXX_FLAGS}") + message(STATUS " Build type : ${CMAKE_BUILD_TYPE}") + get_directory_property(tmp DIRECTORY ${PROJECT_SOURCE_DIR} COMPILE_DEFINITIONS) + message(STATUS " Compile definitions : ${tmp}") + message(STATUS " CMAKE_PREFIX_PATH : ${CMAKE_PREFIX_PATH}") + message(STATUS " CMAKE_INSTALL_PREFIX : ${CMAKE_INSTALL_PREFIX}") + message(STATUS " CMAKE_MODULE_PATH : ${CMAKE_MODULE_PATH}") + message(STATUS "") + message(STATUS " ONNX version : ${ONNX_VERSION}") + message(STATUS " ONNX NAMESPACE : ${ONNX_NAMESPACE}") + message(STATUS " ONNX_USE_LITE_PROTO : ${ONNX_USE_LITE_PROTO}") + message(STATUS " USE_PROTOBUF_SHARED_LIBS : ${ONNX_USE_PROTOBUF_SHARED_LIBS}") + message(STATUS " Protobuf_USE_STATIC_LIBS : ${Protobuf_USE_STATIC_LIBS}") + message(STATUS " ONNX_DISABLE_EXCEPTIONS : ${ONNX_DISABLE_EXCEPTIONS}") + message(STATUS " ONNX_WERROR : ${ONNX_WERROR}") + message(STATUS " ONNX_BUILD_TESTS : ${ONNX_BUILD_TESTS}") + message(STATUS " ONNX_BUILD_BENCHMARKS : ${ONNX_BUILD_BENCHMARKS}") + message(STATUS " ONNXIFI_DUMMY_BACKEND : ${ONNXIFI_DUMMY_BACKEND}") + message(STATUS " ONNXIFI_ENABLE_EXT : ${ONNXIFI_ENABLE_EXT}") + message(STATUS "") + message(STATUS " Protobuf compiler : ${PROTOBUF_PROTOC_EXECUTABLE}") + message(STATUS " Protobuf includes : ${PROTOBUF_INCLUDE_DIRS}") + message(STATUS " Protobuf libraries : ${PROTOBUF_LIBRARIES}") + message(STATUS " BUILD_ONNX_PYTHON : ${BUILD_ONNX_PYTHON}") + message(STATUS " Python version : ${Python_VERSION}") + message(STATUS " Python executable : ${Python_EXECUTABLE}") + message(STATUS " Python includes : ${Python_INCLUDE_DIR}") + message(STATUS " Python libraries : ${Python_LIBRARY}") + message(STATUS " PYBIND11 : ${pybind11_FOUND}") + message(STATUS " Pybind11 version : ${pybind11_VERSION}") + message(STATUS " Pybind11 include : ${pybind11_INCLUDE_DIR}") + message(STATUS " Pybind11 includes : ${pybind11_INCLUDE_DIRS}") + message(STATUS " Pybind11 libraries : ${pybind11_LIBRARIES}") +endfunction() \ No newline at end of file diff --git a/audio/paddleaudio/CMakeLists.txt b/audio/paddleaudio/CMakeLists.txt new file mode 100644 index 00000000..dbf2bd3e --- /dev/null +++ b/audio/paddleaudio/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_subdirectory(third_party) +add_subdirectory(src) + +if (APPLE) + file(COPY ${GFORTRAN_LIBRARIES_DIR}/libgcc_s.1.1.dylib + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/lib) +endif(APPLE) + +if (UNIX AND NOT APPLE) + file(COPY ${GFORTRAN_LIBRARIES_DIR}/libgfortran.so.5 + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/lib FOLLOW_SYMLINK_CHAIN) + + file(COPY ${GFORTRAN_LIBRARIES_DIR}/libquadmath.so.0 + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/lib FOLLOW_SYMLINK_CHAIN) + + file(COPY ${GFORTRAN_LIBRARIES_DIR}/libgcc_s.so.1 + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/lib FOLLOW_SYMLINK_CHAIN) +endif() diff --git a/paddlespeech/audio/backends/__init__.py b/audio/paddleaudio/__init__.py similarity index 72% rename from paddlespeech/audio/backends/__init__.py rename to audio/paddleaudio/__init__.py index 8eae07e8..3388b816 100644 --- a/paddlespeech/audio/backends/__init__.py +++ b/audio/paddleaudio/__init__.py @@ -11,9 +11,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from .soundfile_backend import depth_convert -from .soundfile_backend import load -from .soundfile_backend import normalize -from .soundfile_backend import resample -from .soundfile_backend import save -from .soundfile_backend import to_mono +from . import _extension +from . import backends +from . import compliance +from . import datasets +from . import features +from . import functional +from . import metric +from . import sox_effects +from . import utils diff --git a/audio/paddleaudio/_extension.py b/audio/paddleaudio/_extension.py new file mode 100644 index 00000000..13f4aabf --- /dev/null +++ b/audio/paddleaudio/_extension.py @@ -0,0 +1,167 @@ +import contextlib +import ctypes +import os +import sys +import types +import warnings +from pathlib import Path + +from ._internal import module_utils as _mod_utils # noqa: F401 + +# Query `hasattr` only once. +_SET_GLOBAL_FLAGS = hasattr(sys, 'getdlopenflags') and hasattr(sys, + 'setdlopenflags') + + +@contextlib.contextmanager +def dl_open_guard(): + """ + # https://manpages.debian.org/bullseye/manpages-dev/dlopen.3.en.html + Context manager to set the RTLD_GLOBAL dynamic linker flag while we open a + shared library to load custom operators. + """ + if _SET_GLOBAL_FLAGS: + old_flags = sys.getdlopenflags() + sys.setdlopenflags(old_flags | ctypes.RTLD_GLOBAL) + yield + if _SET_GLOBAL_FLAGS: + sys.setdlopenflags(old_flags) + + +def resolve_library_path(path: str) -> str: + return os.path.realpath(path) + + +class _Ops(types.ModuleType): + #__file__ = '_ops.py' + + def __init__(self): + super(_Ops, self).__init__('paddleaudio.ops') + self.loaded_libraries = set() + + def load_library(self, path): + """ + Loads a shared library from the given path into the current process. + This allows dynamically loading custom operators. For this, + you should compile your operator and + the static registration code into a shared library object, and then + call ``paddleaudio.ops.load_library('path/to/libcustom.so')`` to load the + shared object. + After the library is loaded, it is added to the + ``paddleaudio.ops.loaded_libraries`` attribute, a set that may be inspected + for the paths of all libraries loaded using this function. + Args: + path (str): A path to a shared library to load. + """ + path = resolve_library_path(path) + with dl_open_guard(): + # https://docs.python.org/3/library/ctypes.html?highlight=ctypes#loading-shared-libraries + # Import the shared library into the process, thus running its + # static (global) initialization code in order to register custom + # operators with the JIT. + ctypes.CDLL(path) + self.loaded_libraries.add(path) + + +_LIB_DIR = Path(__file__).parent / "lib" + + +def _get_lib_path(lib: str): + suffix = "pyd" if os.name == "nt" else "so" + path = _LIB_DIR / f"{lib}.{suffix}" + return path + + +def _load_lib(lib: str) -> bool: + """Load extension module + Note: + In case `paddleaudio` is deployed with `pex` format, the library file + is not in a standard location. + In this case, we expect that `libpaddlleaudio` is available somewhere + in the search path of dynamic loading mechanism, so that importing + `_paddlleaudio` will have library loader find and load `libpaddlleaudio`. + This is the reason why the function should not raising an error when the library + file is not found. + Returns: + bool: + True if the library file is found AND the library loaded without failure. + False if the library file is not found (like in the case where paddlleaudio + is deployed with pex format, thus the shared library file is + in a non-standard location.). + If the library file is found but there is an issue loading the library, + (such as missing dependency) then this function raises the exception as-is. + Raises: + Exception: + If the library file is found, but there is an issue loading the library file, + (when underlying `ctype.DLL` throws an exception), this function will pass + the exception as-is, instead of catching it and returning bool. + The expected case is `OSError` thrown by `ctype.DLL` when a dynamic dependency + is not found. + This behavior was chosen because the expected failure case is not recoverable. + If a dependency is missing, then users have to install it. + """ + path = _get_lib_path(lib) + if not path.exists(): + warnings.warn("lib path is not exists:" + str(path)) + return False + ops.load_library(path) + return True + + +_FFMPEG_INITIALIZED = False + + +def _init_ffmpeg(): + global _FFMPEG_INITIALIZED + if _FFMPEG_INITIALIZED: + return + + if not paddleaudio._paddlleaudio.is_ffmpeg_available(): + raise RuntimeError( + "paddlleaudio is not compiled with FFmpeg integration. Please set USE_FFMPEG=1 when compiling paddlleaudio." + ) + + try: + _load_lib("libpaddlleaudio_ffmpeg") + except OSError as err: + raise ImportError( + "FFmpeg libraries are not found. Please install FFmpeg.") from err + + import paddllespeech.audio._paddlleaudio_ffmpeg # noqa + + paddleaudio._paddlleaudio.ffmpeg_init() + if paddleaudio._paddlleaudio.ffmpeg_get_log_level() > 8: + paddleaudio._paddlleaudio.ffmpeg_set_log_level(8) + + _FFMPEG_INITIALIZED = True + + +def _init_extension(): + if not _mod_utils.is_module_available("paddleaudio._paddleaudio"): + warnings.warn( + "paddleaudio C++ extension is not available. sox_io, sox_effect, kaldi raw feature is not supported!!!") + return + + _load_lib("libpaddleaudio") + # This import is for initializing the methods registered via PyBind11 + # This has to happen after the base library is loaded + try: + from paddleaudio import _paddleaudio # noqa + except Exception: + warnings.warn( + "paddleaudio C++ extension is not available. sox_io, sox_effect, kaldi raw feature is not supported!!!") + return + + # Because this part is executed as part of `import torchaudio`, we ignore the + # initialization failure. + # If the FFmpeg integration is not properly initialized, then detailed error + # will be raised when client code attempts to import the dedicated feature. + try: + _init_ffmpeg() + except Exception: + pass + + +ops = _Ops() + +_init_extension() diff --git a/audio/paddleaudio/_internal/__init__.py b/audio/paddleaudio/_internal/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/audio/paddleaudio/_internal/module_utils.py b/audio/paddleaudio/_internal/module_utils.py new file mode 100644 index 00000000..7b3230de --- /dev/null +++ b/audio/paddleaudio/_internal/module_utils.py @@ -0,0 +1,151 @@ +import importlib.util +import platform +import warnings +from functools import wraps +from typing import Optional + +#code is from https://github.com/pytorch/audio/blob/main/torchaudio/_internal/module_utils.py with modification. + + +def is_module_available(*modules: str) -> bool: + r"""Returns if a top-level module with :attr:`name` exists *without** + importing it. This is generally safer than try-catch block around a + `import X`. It avoids third party libraries breaking assumptions of some of + our tests, e.g., setting multiprocessing start method when imported + (see librosa/#747, torchvision/#544). + """ + return all(importlib.util.find_spec(m) is not None for m in modules) + + +def requires_module(*modules: str): + """Decorate function to give error message if invoked without required optional modules. + This decorator is to give better error message to users rather + than raising ``NameError: name 'module' is not defined`` at random places. + """ + missing = [m for m in modules if not is_module_available(m)] + + if not missing: + # fall through. If all the modules are available, no need to decorate + def decorator(func): + return func + + else: + req = f"module: {missing[0]}" if len( + missing) == 1 else f"modules: {missing}" + + def decorator(func): + @wraps(func) + def wrapped(*args, **kwargs): + raise RuntimeError( + f"{func.__module__}.{func.__name__} requires {req}") + + return wrapped + + return decorator + + +def deprecated(direction: str, version: Optional[str]=None): + """Decorator to add deprecation message + Args: + direction (str): Migration steps to be given to users. + version (str or int): The version when the object will be removed + """ + + def decorator(func): + @wraps(func) + def wrapped(*args, **kwargs): + message = ( + f"{func.__module__}.{func.__name__} has been deprecated " + f'and will be removed from {"future" if version is None else version} release. ' + f"{direction}") + warnings.warn(message, stacklevel=2) + return func(*args, **kwargs) + + return wrapped + + return decorator + + +def is_kaldi_available(): + return is_module_available("paddleaudio._paddleaudio") + + +def requires_kaldi(): + if is_kaldi_available(): + + def decorator(func): + return func + + else: + + def decorator(func): + @wraps(func) + def wrapped(*args, **kwargs): + raise RuntimeError( + f"{func.__module__}.{func.__name__} requires libpaddleaudio build with kaldi") + + return wrapped + + return decorator + + +def _check_soundfile_importable(): + if not is_module_available("soundfile"): + return False + try: + import soundfile # noqa: F401 + + return True + except Exception: + warnings.warn( + "Failed to import soundfile. 'soundfile' backend is not available.") + return False + + +_is_soundfile_importable = _check_soundfile_importable() + + +def is_soundfile_available(): + return _is_soundfile_importable + + +def requires_soundfile(): + if is_soundfile_available(): + + def decorator(func): + return func + else: + + def decorator(func): + @wraps(func) + def wrapped(*args, **kwargs): + raise RuntimeError( + f"{func.__module__}.{func.__name__} requires soundfile") + + return wrapped + + return decorator + + +def is_sox_available(): + if platform.system() == "Windows": # not support sox in windows + return False + return is_module_available("paddleaudio._paddleaudio") + + +def requires_sox(): + if is_sox_available(): + + def decorator(func): + return func + else: + + def decorator(func): + @wraps(func) + def wrapped(*args, **kwargs): + raise RuntimeError( + f"{func.__module__}.{func.__name__} requires libpaddleaudio build with sox") + + return wrapped + + return decorator diff --git a/tests/unit/audio/backends/__init__.py b/audio/paddleaudio/backends/__init__.py similarity index 59% rename from tests/unit/audio/backends/__init__.py rename to audio/paddleaudio/backends/__init__.py index 97043fd7..e0250956 100644 --- a/tests/unit/audio/backends/__init__.py +++ b/audio/paddleaudio/backends/__init__.py @@ -11,3 +11,15 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from . import utils +from .soundfile_backend import depth_convert +from .soundfile_backend import normalize +from .soundfile_backend import resample +from .soundfile_backend import soundfile_load +from .soundfile_backend import soundfile_save +from .soundfile_backend import to_mono +from .utils import get_audio_backend +from .utils import list_audio_backends +from .utils import set_audio_backend + +utils._init_audio_backend() diff --git a/audio/paddleaudio/backends/common.py b/audio/paddleaudio/backends/common.py new file mode 100644 index 00000000..9d3edf81 --- /dev/null +++ b/audio/paddleaudio/backends/common.py @@ -0,0 +1,55 @@ +# Token form https://github.com/pytorch/audio/blob/main/torchaudio/backend/common.py with modification. + +class AudioInfo: + """return of info function. + + This class is used by :ref:`"sox_io" backend` and + :ref:`"soundfile" backend with the new interface`. + + :ivar int sample_rate: Sample rate + :ivar int num_frames: The number of frames + :ivar int num_channels: The number of channels + :ivar int bits_per_sample: The number of bits per sample. This is 0 for lossy formats, + or when it cannot be accurately inferred. + :ivar str encoding: Audio encoding + The values encoding can take are one of the following: + + * ``PCM_S``: Signed integer linear PCM + * ``PCM_U``: Unsigned integer linear PCM + * ``PCM_F``: Floating point linear PCM + * ``FLAC``: Flac, Free Lossless Audio Codec + * ``ULAW``: Mu-law + * ``ALAW``: A-law + * ``MP3`` : MP3, MPEG-1 Audio Layer III + * ``VORBIS``: OGG Vorbis + * ``AMR_WB``: Adaptive Multi-Rate + * ``AMR_NB``: Adaptive Multi-Rate Wideband + * ``OPUS``: Opus + * ``HTK``: Single channel 16-bit PCM + * ``UNKNOWN`` : None of above + """ + + def __init__( + self, + sample_rate: int, + num_frames: int, + num_channels: int, + bits_per_sample: int, + encoding: str, + ): + self.sample_rate = sample_rate + self.num_frames = num_frames + self.num_channels = num_channels + self.bits_per_sample = bits_per_sample + self.encoding = encoding + + def __str__(self): + return ( + f"AudioMetaData(" + f"sample_rate={self.sample_rate}, " + f"num_frames={self.num_frames}, " + f"num_channels={self.num_channels}, " + f"bits_per_sample={self.bits_per_sample}, " + f"encoding={self.encoding}" + f")" + ) diff --git a/audio/paddleaudio/backends/no_backend.py b/audio/paddleaudio/backends/no_backend.py new file mode 100644 index 00000000..157536f4 --- /dev/null +++ b/audio/paddleaudio/backends/no_backend.py @@ -0,0 +1,32 @@ +from pathlib import Path +from typing import Callable +from typing import Optional +from typing import Tuple +from typing import Union + +from paddle import Tensor + +#code is from: https://github.com/pytorch/audio/blob/main/torchaudio/backend/no_backend.py + + +def load( + filepath: Union[str, Path], + out: Optional[Tensor]=None, + normalization: Union[bool, float, Callable]=True, + channels_first: bool=True, + num_frames: int=0, + offset: int=0, + filetype: Optional[str]=None, ) -> Tuple[Tensor, int]: + raise RuntimeError("No audio I/O backend is available.") + + +def save(filepath: str, + src: Tensor, + sample_rate: int, + precision: int=16, + channels_first: bool=True) -> None: + raise RuntimeError("No audio I/O backend is available.") + + +def info(filepath: str) -> None: + raise RuntimeError("No audio I/O backend is available.") diff --git a/audio/paddleaudio/backends/soundfile_backend.py b/audio/paddleaudio/backends/soundfile_backend.py new file mode 100644 index 00000000..ae7b5b52 --- /dev/null +++ b/audio/paddleaudio/backends/soundfile_backend.py @@ -0,0 +1,677 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import warnings +from typing import Optional +from typing import Tuple + +import numpy as np +import paddle +import resampy +import soundfile +from scipy.io import wavfile + +from ..utils import depth_convert +from ..utils import ParameterError +from .common import AudioInfo + +__all__ = [ + 'resample', + 'to_mono', + 'normalize', + 'save', + 'soundfile_save', + 'load', + 'soundfile_load', + 'info', +] +NORMALMIZE_TYPES = ['linear', 'gaussian'] +MERGE_TYPES = ['ch0', 'ch1', 'random', 'average'] +RESAMPLE_MODES = ['kaiser_best', 'kaiser_fast'] +EPS = 1e-8 + + +def resample(y: np.ndarray, + src_sr: int, + target_sr: int, + mode: str='kaiser_fast') -> np.ndarray: + """Audio resampling. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + src_sr (int): Source sample rate. + target_sr (int): Target sample rate. + mode (str, optional): The resampling filter to use. Defaults to 'kaiser_fast'. + + Returns: + np.ndarray: `y` resampled to `target_sr` + """ + + if mode == 'kaiser_best': + warnings.warn( + f'Using resampy in kaiser_best to {src_sr}=>{target_sr}. This function is pretty slow, \ + we recommend the mode kaiser_fast in large scale audio trainning') + + if not isinstance(y, np.ndarray): + raise ParameterError( + 'Only support numpy np.ndarray, but received y in {type(y)}') + + if mode not in RESAMPLE_MODES: + raise ParameterError(f'resample mode must in {RESAMPLE_MODES}') + + return resampy.resample(y, src_sr, target_sr, filter=mode) + + +def to_mono(y: np.ndarray, merge_type: str='average') -> np.ndarray: + """Convert sterior audio to mono. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + merge_type (str, optional): Merge type to generate mono waveform. Defaults to 'average'. + + Returns: + np.ndarray: `y` with mono channel. + """ + + if merge_type not in MERGE_TYPES: + raise ParameterError( + f'Unsupported merge type {merge_type}, available types are {MERGE_TYPES}' + ) + if y.ndim > 2: + raise ParameterError( + f'Unsupported audio array, y.ndim > 2, the shape is {y.shape}') + if y.ndim == 1: # nothing to merge + return y + + if merge_type == 'ch0': + return y[0] + if merge_type == 'ch1': + return y[1] + if merge_type == 'random': + return y[np.random.randint(0, 2)] + + # need to do averaging according to dtype + + if y.dtype == 'float32': + y_out = (y[0] + y[1]) * 0.5 + elif y.dtype == 'int16': + y_out = y.astype('int32') + y_out = (y_out[0] + y_out[1]) // 2 + y_out = np.clip(y_out, np.iinfo(y.dtype).min, + np.iinfo(y.dtype).max).astype(y.dtype) + + elif y.dtype == 'int8': + y_out = y.astype('int16') + y_out = (y_out[0] + y_out[1]) // 2 + y_out = np.clip(y_out, np.iinfo(y.dtype).min, + np.iinfo(y.dtype).max).astype(y.dtype) + else: + raise ParameterError(f'Unsupported dtype: {y.dtype}') + return y_out + + +def soundfile_load_(file: os.PathLike, + offset: Optional[float]=None, + dtype: str='int16', + duration: Optional[int]=None) -> Tuple[np.ndarray, int]: + """Load audio using soundfile library. This function load audio file using libsndfile. + + Args: + file (os.PathLike): File of waveform. + offset (Optional[float], optional): Offset to the start of waveform. Defaults to None. + dtype (str, optional): Data type of waveform. Defaults to 'int16'. + duration (Optional[int], optional): Duration of waveform to read. Defaults to None. + + Returns: + Tuple[np.ndarray, int]: Waveform in ndarray and its samplerate. + """ + with soundfile.SoundFile(file) as sf_desc: + sr_native = sf_desc.samplerate + if offset: + sf_desc.seek(int(offset * sr_native)) + if duration is not None: + frame_duration = int(duration * sr_native) + else: + frame_duration = -1 + y = sf_desc.read(frames=frame_duration, dtype=dtype, always_2d=False).T + + return y, sf_desc.samplerate + + +def normalize(y: np.ndarray, norm_type: str='linear', + mul_factor: float=1.0) -> np.ndarray: + """Normalize an input audio with additional multiplier. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + norm_type (str, optional): Type of normalization. Defaults to 'linear'. + mul_factor (float, optional): Scaling factor. Defaults to 1.0. + + Returns: + np.ndarray: `y` after normalization. + """ + + if norm_type == 'linear': + amax = np.max(np.abs(y)) + factor = 1.0 / (amax + EPS) + y = y * factor * mul_factor + elif norm_type == 'gaussian': + amean = np.mean(y) + astd = np.std(y) + astd = max(astd, EPS) + y = mul_factor * (y - amean) / astd + else: + raise NotImplementedError(f'norm_type should be in {NORMALMIZE_TYPES}') + + return y + + +def soundfile_save(y: np.ndarray, sr: int, file: os.PathLike) -> None: + """Save audio file to disk. This function saves audio to disk using scipy.io.wavfile, with additional step to convert input waveform to int16. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + sr (int): Sample rate. + file (os.PathLike): Path of auido file to save. + """ + if not file.endswith('.wav'): + raise ParameterError( + f'only .wav file supported, but dst file name is: {file}') + + if sr <= 0: + raise ParameterError( + f'Sample rate should be larger than 0, recieved sr = {sr}') + + if y.dtype not in ['int16', 'int8']: + warnings.warn( + f'input data type is {y.dtype}, will convert data to int16 format before saving' + ) + y_out = depth_convert(y, 'int16') + else: + y_out = y + + wavfile.write(file, sr, y_out) + + +def soundfile_load( + file: os.PathLike, + sr: Optional[int]=None, + mono: bool=True, + merge_type: str='average', # ch0,ch1,random,average + normal: bool=True, + norm_type: str='linear', + norm_mul_factor: float=1.0, + offset: float=0.0, + duration: Optional[int]=None, + dtype: str='float32', + resample_mode: str='kaiser_fast') -> Tuple[np.ndarray, int]: + """Load audio file from disk. This function loads audio from disk using using audio beackend. + + Args: + file (os.PathLike): Path of auido file to load. + sr (Optional[int], optional): Sample rate of loaded waveform. Defaults to None. + mono (bool, optional): Return waveform with mono channel. Defaults to True. + merge_type (str, optional): Merge type of multi-channels waveform. Defaults to 'average'. + normal (bool, optional): Waveform normalization. Defaults to True. + norm_type (str, optional): Type of normalization. Defaults to 'linear'. + norm_mul_factor (float, optional): Scaling factor. Defaults to 1.0. + offset (float, optional): Offset to the start of waveform. Defaults to 0.0. + duration (Optional[int], optional): Duration of waveform to read. Defaults to None. + dtype (str, optional): Data type of waveform. Defaults to 'float32'. + resample_mode (str, optional): The resampling filter to use. Defaults to 'kaiser_fast'. + + Returns: + Tuple[np.ndarray, int]: Waveform in ndarray and its samplerate. + """ + + y, r = soundfile_load_(file, offset=offset, dtype=dtype, duration=duration) + + if not ((y.ndim == 1 and len(y) > 0) or (y.ndim == 2 and len(y[0]) > 0)): + raise ParameterError(f'audio file {file} looks empty') + + if mono: + y = to_mono(y, merge_type) + + if sr is not None and sr != r: + y = resample(y, r, sr, mode=resample_mode) + r = sr + + if normal: + y = normalize(y, norm_type, norm_mul_factor) + elif dtype in ['int8', 'int16']: + # still need to do normalization, before depth convertion + y = normalize(y, 'linear', 1.0) + + y = depth_convert(y, dtype) + return y, r + + +#the code below token form: https://github.com/pytorch/audio/blob/main/torchaudio/backend/soundfile_backend.py with modificaion. + + +def _get_subtype_for_wav(dtype: paddle.dtype, + encoding: str, + bits_per_sample: int): + if not encoding: + if not bits_per_sample: + subtype = { + paddle.uint8: "PCM_U8", + paddle.int16: "PCM_16", + paddle.int32: "PCM_32", + paddle.float32: "FLOAT", + paddle.float64: "DOUBLE", + }.get(dtype) + if not subtype: + raise ValueError(f"Unsupported dtype for wav: {dtype}") + return subtype + if bits_per_sample == 8: + return "PCM_U8" + return f"PCM_{bits_per_sample}" + if encoding == "PCM_S": + if not bits_per_sample: + return "PCM_32" + if bits_per_sample == 8: + raise ValueError("wav does not support 8-bit signed PCM encoding.") + return f"PCM_{bits_per_sample}" + if encoding == "PCM_U": + if bits_per_sample in (None, 8): + return "PCM_U8" + raise ValueError("wav only supports 8-bit unsigned PCM encoding.") + if encoding == "PCM_F": + if bits_per_sample in (None, 32): + return "FLOAT" + if bits_per_sample == 64: + return "DOUBLE" + raise ValueError("wav only supports 32/64-bit float PCM encoding.") + if encoding == "ULAW": + if bits_per_sample in (None, 8): + return "ULAW" + raise ValueError("wav only supports 8-bit mu-law encoding.") + if encoding == "ALAW": + if bits_per_sample in (None, 8): + return "ALAW" + raise ValueError("wav only supports 8-bit a-law encoding.") + raise ValueError(f"wav does not support {encoding}.") + + +def _get_subtype_for_sphere(encoding: str, bits_per_sample: int): + if encoding in (None, "PCM_S"): + return f"PCM_{bits_per_sample}" if bits_per_sample else "PCM_32" + if encoding in ("PCM_U", "PCM_F"): + raise ValueError(f"sph does not support {encoding} encoding.") + if encoding == "ULAW": + if bits_per_sample in (None, 8): + return "ULAW" + raise ValueError("sph only supports 8-bit for mu-law encoding.") + if encoding == "ALAW": + return "ALAW" + raise ValueError(f"sph does not support {encoding}.") + + +def _get_subtype(dtype: paddle.dtype, + format: str, + encoding: str, + bits_per_sample: int): + if format == "wav": + return _get_subtype_for_wav(dtype, encoding, bits_per_sample) + if format == "flac": + if encoding: + raise ValueError("flac does not support encoding.") + if not bits_per_sample: + return "PCM_16" + if bits_per_sample > 24: + raise ValueError("flac does not support bits_per_sample > 24.") + return "PCM_S8" if bits_per_sample == 8 else f"PCM_{bits_per_sample}" + if format in ("ogg", "vorbis"): + if encoding or bits_per_sample: + raise ValueError( + "ogg/vorbis does not support encoding/bits_per_sample.") + return "VORBIS" + if format == "sph": + return _get_subtype_for_sphere(encoding, bits_per_sample) + if format in ("nis", "nist"): + return "PCM_16" + raise ValueError(f"Unsupported format: {format}") + + +def save( + filepath: str, + src: paddle.Tensor, + sample_rate: int, + channels_first: bool=True, + compression: Optional[float]=None, + format: Optional[str]=None, + encoding: Optional[str]=None, + bits_per_sample: Optional[int]=None, ): + """Save audio data to file. + + Note: + The formats this function can handle depend on the soundfile installation. + This function is tested on the following formats; + + * WAV + + * 32-bit floating-point + * 32-bit signed integer + * 16-bit signed integer + * 8-bit unsigned integer + + * FLAC + * OGG/VORBIS + * SPHERE + + Note: + ``filepath`` argument is intentionally annotated as ``str`` only, even though it accepts + ``pathlib.Path`` object as well. This is for the consistency with ``"sox_io"`` backend, + + Args: + filepath (str or pathlib.Path): Path to audio file. + src (paddle.Tensor): Audio data to save. must be 2D tensor. + sample_rate (int): sampling rate + channels_first (bool, optional): If ``True``, the given tensor is interpreted as `[channel, time]`, + otherwise `[time, channel]`. + compression (float of None, optional): Not used. + It is here only for interface compatibility reson with "sox_io" backend. + format (str or None, optional): Override the audio format. + When ``filepath`` argument is path-like object, audio format is + inferred from file extension. If the file extension is missing or + different, you can specify the correct format with this argument. + + When ``filepath`` argument is file-like object, + this argument is required. + + Valid values are ``"wav"``, ``"ogg"``, ``"vorbis"``, + ``"flac"`` and ``"sph"``. + encoding (str or None, optional): Changes the encoding for supported formats. + This argument is effective only for supported formats, sush as + ``"wav"``, ``""flac"`` and ``"sph"``. Valid values are; + + - ``"PCM_S"`` (signed integer Linear PCM) + - ``"PCM_U"`` (unsigned integer Linear PCM) + - ``"PCM_F"`` (floating point PCM) + - ``"ULAW"`` (mu-law) + - ``"ALAW"`` (a-law) + + bits_per_sample (int or None, optional): Changes the bit depth for the + supported formats. + When ``format`` is one of ``"wav"``, ``"flac"`` or ``"sph"``, + you can change the bit depth. + Valid values are ``8``, ``16``, ``24``, ``32`` and ``64``. + + Supported formats/encodings/bit depth/compression are: + + ``"wav"`` + - 32-bit floating-point PCM + - 32-bit signed integer PCM + - 24-bit signed integer PCM + - 16-bit signed integer PCM + - 8-bit unsigned integer PCM + - 8-bit mu-law + - 8-bit a-law + + Note: + Default encoding/bit depth is determined by the dtype of + the input Tensor. + + ``"flac"`` + - 8-bit + - 16-bit (default) + - 24-bit + + ``"ogg"``, ``"vorbis"`` + - Doesn't accept changing configuration. + + ``"sph"`` + - 8-bit signed integer PCM + - 16-bit signed integer PCM + - 24-bit signed integer PCM + - 32-bit signed integer PCM (default) + - 8-bit mu-law + - 8-bit a-law + - 16-bit a-law + - 24-bit a-law + - 32-bit a-law + + """ + if src.ndim != 2: + raise ValueError(f"Expected 2D Tensor, got {src.ndim}D.") + if compression is not None: + warnings.warn( + '`save` function of "soundfile" backend does not support "compression" parameter. ' + "The argument is silently ignored.") + if hasattr(filepath, "write"): + if format is None: + raise RuntimeError( + "`format` is required when saving to file object.") + ext = format.lower() + else: + ext = str(filepath).split(".")[-1].lower() + + if bits_per_sample not in (None, 8, 16, 24, 32, 64): + raise ValueError("Invalid bits_per_sample.") + if bits_per_sample == 24: + warnings.warn( + "Saving audio with 24 bits per sample might warp samples near -1. " + "Using 16 bits per sample might be able to avoid this.") + subtype = _get_subtype(src.dtype, ext, encoding, bits_per_sample) + + # sph is a extension used in TED-LIUM but soundfile does not recognize it as NIST format, + # so we extend the extensions manually here + if ext in ["nis", "nist", "sph"] and format is None: + format = "NIST" + + if channels_first: + src = src.t() + + soundfile.write( + file=filepath, + data=src, + samplerate=sample_rate, + subtype=subtype, + format=format) + + +_SUBTYPE2DTYPE = { + "PCM_S8": "int8", + "PCM_U8": "uint8", + "PCM_16": "int16", + "PCM_32": "int32", + "FLOAT": "float32", + "DOUBLE": "float64", +} + + +def load( + filepath: str, + frame_offset: int=0, + num_frames: int=-1, + normalize: bool=True, + channels_first: bool=True, + format: Optional[str]=None, ) -> Tuple[paddle.Tensor, int]: + """Load audio data from file. + + Note: + The formats this function can handle depend on the soundfile installation. + This function is tested on the following formats; + + * WAV + + * 32-bit floating-point + * 32-bit signed integer + * 16-bit signed integer + * 8-bit unsigned integer + + * FLAC + * OGG/VORBIS + * SPHERE + + By default (``normalize=True``, ``channels_first=True``), this function returns Tensor with + ``float32`` dtype and the shape of `[channel, time]`. + The samples are normalized to fit in the range of ``[-1.0, 1.0]``. + + When the input format is WAV with integer type, such as 32-bit signed integer, 16-bit + signed integer and 8-bit unsigned integer (24-bit signed integer is not supported), + by providing ``normalize=False``, this function can return integer Tensor, where the samples + are expressed within the whole range of the corresponding dtype, that is, ``int32`` tensor + for 32-bit signed PCM, ``int16`` for 16-bit signed PCM and ``uint8`` for 8-bit unsigned PCM. + + ``normalize`` parameter has no effect on 32-bit floating-point WAV and other formats, such as + ``flac`` and ``mp3``. + For these formats, this function always returns ``float32`` Tensor with values normalized to + ``[-1.0, 1.0]``. + + Note: + ``filepath`` argument is intentionally annotated as ``str`` only, even though it accepts + ``pathlib.Path`` object as well. This is for the consistency with ``"sox_io"`` backend. + + Args: + filepath (path-like object or file-like object): + Source of audio data. + frame_offset (int, optional): + Number of frames to skip before start reading data. + num_frames (int, optional): + Maximum number of frames to read. ``-1`` reads all the remaining samples, + starting from ``frame_offset``. + This function may return the less number of frames if there is not enough + frames in the given file. + normalize (bool, optional): + When ``True``, this function always return ``float32``, and sample values are + normalized to ``[-1.0, 1.0]``. + If input file is integer WAV, giving ``False`` will change the resulting Tensor type to + integer type. + This argument has no effect for formats other than integer WAV type. + channels_first (bool, optional): + When True, the returned Tensor has dimension `[channel, time]`. + Otherwise, the returned Tensor's dimension is `[time, channel]`. + format (str or None, optional): + Not used. PySoundFile does not accept format hint. + + Returns: + (paddle.Tensor, int): Resulting Tensor and sample rate. + If the input file has integer wav format and normalization is off, then it has + integer type, else ``float32`` type. If ``channels_first=True``, it has + `[channel, time]` else `[time, channel]`. + """ + with soundfile.SoundFile(filepath, "r") as file_: + if file_.format != "WAV" or normalize: + dtype = "float32" + elif file_.subtype not in _SUBTYPE2DTYPE: + raise ValueError(f"Unsupported subtype: {file_.subtype}") + else: + dtype = _SUBTYPE2DTYPE[file_.subtype] + + frames = file_._prepare_read(frame_offset, None, num_frames) + waveform = file_.read(frames, dtype, always_2d=True) + sample_rate = file_.samplerate + + waveform = paddle.to_tensor(waveform) + if channels_first: + waveform = paddle.transpose(waveform, perm=[1, 0]) + return waveform, sample_rate + + +# Mapping from soundfile subtype to number of bits per sample. +# This is mostly heuristical and the value is set to 0 when it is irrelevant +# (lossy formats) or when it can't be inferred. +# For ADPCM (and G72X) subtypes, it's hard to infer the bit depth because it's not part of the standard: +# According to https://en.wikipedia.org/wiki/Adaptive_differential_pulse-code_modulation#In_telephony, +# the default seems to be 8 bits but it can be compressed further to 4 bits. +# The dict is inspired from +# https://github.com/bastibe/python-soundfile/blob/744efb4b01abc72498a96b09115b42a4cabd85e4/soundfile.py#L66-L94 +_SUBTYPE_TO_BITS_PER_SAMPLE = { + "PCM_S8": 8, # Signed 8 bit data + "PCM_16": 16, # Signed 16 bit data + "PCM_24": 24, # Signed 24 bit data + "PCM_32": 32, # Signed 32 bit data + "PCM_U8": 8, # Unsigned 8 bit data (WAV and RAW only) + "FLOAT": 32, # 32 bit float data + "DOUBLE": 64, # 64 bit float data + "ULAW": 8, # U-Law encoded. See https://en.wikipedia.org/wiki/G.711#Types + "ALAW": 8, # A-Law encoded. See https://en.wikipedia.org/wiki/G.711#Types + "IMA_ADPCM": 0, # IMA ADPCM. + "MS_ADPCM": 0, # Microsoft ADPCM. + "GSM610": + 0, # GSM 6.10 encoding. (Wikipedia says 1.625 bit depth?? https://en.wikipedia.org/wiki/Full_Rate) + "VOX_ADPCM": 0, # OKI / Dialogix ADPCM + "G721_32": 0, # 32kbs G721 ADPCM encoding. + "G723_24": 0, # 24kbs G723 ADPCM encoding. + "G723_40": 0, # 40kbs G723 ADPCM encoding. + "DWVW_12": 12, # 12 bit Delta Width Variable Word encoding. + "DWVW_16": 16, # 16 bit Delta Width Variable Word encoding. + "DWVW_24": 24, # 24 bit Delta Width Variable Word encoding. + "DWVW_N": 0, # N bit Delta Width Variable Word encoding. + "DPCM_8": 8, # 8 bit differential PCM (XI only) + "DPCM_16": 16, # 16 bit differential PCM (XI only) + "VORBIS": 0, # Xiph Vorbis encoding. (lossy) + "ALAC_16": 16, # Apple Lossless Audio Codec (16 bit). + "ALAC_20": 20, # Apple Lossless Audio Codec (20 bit). + "ALAC_24": 24, # Apple Lossless Audio Codec (24 bit). + "ALAC_32": 32, # Apple Lossless Audio Codec (32 bit). +} + + +def _get_bit_depth(subtype): + if subtype not in _SUBTYPE_TO_BITS_PER_SAMPLE: + warnings.warn( + f"The {subtype} subtype is unknown to PaddleAudio. As a result, the bits_per_sample " + "attribute will be set to 0. If you are seeing this warning, please " + "report by opening an issue on github (after checking for existing/closed ones). " + "You may otherwise ignore this warning.") + return _SUBTYPE_TO_BITS_PER_SAMPLE.get(subtype, 0) + + +_SUBTYPE_TO_ENCODING = { + "PCM_S8": "PCM_S", + "PCM_16": "PCM_S", + "PCM_24": "PCM_S", + "PCM_32": "PCM_S", + "PCM_U8": "PCM_U", + "FLOAT": "PCM_F", + "DOUBLE": "PCM_F", + "ULAW": "ULAW", + "ALAW": "ALAW", + "VORBIS": "VORBIS", +} + + +def _get_encoding(format: str, subtype: str): + if format == "FLAC": + return "FLAC" + return _SUBTYPE_TO_ENCODING.get(subtype, "UNKNOWN") + + +def info(filepath: str, format: Optional[str]=None) -> AudioInfo: + """Get signal information of an audio file. + + Note: + ``filepath`` argument is intentionally annotated as ``str`` only, even though it accepts + ``pathlib.Path`` object as well. This is for the consistency with ``"sox_io"`` backend, + + Args: + filepath (path-like object or file-like object): + Source of audio data. + format (str or None, optional): + Not used. PySoundFile does not accept format hint. + + Returns: + AudioInfo: meta data of the given audio. + + """ + sinfo = soundfile.info(filepath) + return AudioInfo( + sinfo.samplerate, + sinfo.frames, + sinfo.channels, + bits_per_sample=_get_bit_depth(sinfo.subtype), + encoding=_get_encoding(sinfo.format, sinfo.subtype), ) diff --git a/audio/paddleaudio/backends/sox_io_backend.py b/audio/paddleaudio/backends/sox_io_backend.py new file mode 100644 index 00000000..1c2d5f65 --- /dev/null +++ b/audio/paddleaudio/backends/sox_io_backend.py @@ -0,0 +1,106 @@ +import os +from typing import Optional +from typing import Tuple + +import paddle +import paddleaudio +from paddle import Tensor +from paddleaudio._internal import module_utils as _mod_utils + +from .common import AudioInfo + +#https://github.com/pytorch/audio/blob/main/torchaudio/backend/sox_io_backend.py + + +def _fail_info(filepath: str, format: Optional[str]) -> AudioInfo: + raise RuntimeError("Failed to fetch metadata from {}".format(filepath)) + + +def _fail_info_fileobj(fileobj, format: Optional[str]) -> AudioInfo: + raise RuntimeError("Failed to fetch metadata from {}".format(fileobj)) + + +# Note: need to comply TorchScript syntax -- need annotation and no f-string +def _fail_load( + filepath: str, + frame_offset: int=0, + num_frames: int=-1, + normalize: bool=True, + channels_first: bool=True, + format: Optional[str]=None, ) -> Tuple[Tensor, int]: + raise RuntimeError("Failed to load audio from {}".format(filepath)) + + +def _fail_load_fileobj(fileobj, *args, **kwargs): + raise RuntimeError(f"Failed to load audio from {fileobj}") + + +_fallback_info = _fail_info +_fallback_info_fileobj = _fail_info_fileobj +_fallback_load = _fail_load +_fallback_load_filebj = _fail_load_fileobj + + +@_mod_utils.requires_sox() +def load( + filepath: str, + frame_offset: int=0, + num_frames: int=-1, + normalize: bool=True, + channels_first: bool=True, + format: Optional[str]=None, ) -> Tuple[Tensor, int]: + if hasattr(filepath, "read"): + ret = paddleaudio._paddleaudio.load_audio_fileobj( + filepath, frame_offset, num_frames, normalize, channels_first, + format) + if ret is not None: + audio_tensor = paddle.to_tensor(ret[0]) + return (audio_tensor, ret[1]) + return _fallback_load_fileobj(filepath, frame_offset, num_frames, + normalize, channels_first, format) + filepath = os.fspath(filepath) + ret = paddleaudio._paddleaudio.sox_io_load_audio_file( + filepath, frame_offset, num_frames, normalize, channels_first, format) + if ret is not None: + audio_tensor = paddle.to_tensor(ret[0]) + return (audio_tensor, ret[1]) + return _fallback_load(filepath, frame_offset, num_frames, normalize, + channels_first, format) + + +@_mod_utils.requires_sox() +def save( + filepath: str, + src: Tensor, + sample_rate: int, + channels_first: bool=True, + compression: Optional[float]=None, + format: Optional[str]=None, + encoding: Optional[str]=None, + bits_per_sample: Optional[int]=None, ): + src_arr = src.numpy() + if hasattr(filepath, "write"): + paddleaudio._paddleaudio.save_audio_fileobj( + filepath, src_arr, sample_rate, channels_first, compression, format, + encoding, bits_per_sample) + return + filepath = os.fspath(filepath) + paddleaudio._paddleaudio.sox_io_save_audio_file( + filepath, src_arr, sample_rate, channels_first, compression, format, + encoding, bits_per_sample) + + +@_mod_utils.requires_sox() +def info( + filepath: str, + format: Optional[str]=None, ) -> AudioInfo: + if hasattr(filepath, "read"): + sinfo = paddleaudio._paddleaudio.get_info_fileobj(filepath, format) + if sinfo is not None: + return AudioInfo(*sinfo) + return _fallback_info_fileobj(filepath, format) + filepath = os.fspath(filepath) + sinfo = paddleaudio._paddleaudio.get_info_file(filepath, format) + if sinfo is not None: + return AudioInfo(*sinfo) + return _fallback_info(filepath, format) diff --git a/audio/paddleaudio/backends/utils.py b/audio/paddleaudio/backends/utils.py new file mode 100644 index 00000000..83c1a71c --- /dev/null +++ b/audio/paddleaudio/backends/utils.py @@ -0,0 +1,83 @@ +"""Defines utilities for switching audio backends""" +#code is from: https://github.com/pytorch/audio/blob/main/torchaudio/backend/utils.py +import warnings +from typing import List +from typing import Optional + +import paddleaudio +from paddleaudio._internal import module_utils as _mod_utils + +from . import no_backend +from . import soundfile_backend +from . import sox_io_backend + +__all__ = [ + "list_audio_backends", + "get_audio_backend", + "set_audio_backend", +] + + +def list_audio_backends() -> List[str]: + """List available backends + + Returns: + List[str]: The list of available backends. + """ + backends = [] + if _mod_utils.is_module_available("soundfile"): + backends.append("soundfile") + if _mod_utils.is_sox_available(): + backends.append("sox_io") + return backends + + +def set_audio_backend(backend: Optional[str]): + """Set the backend for I/O operation + + Args: + backend (str or None): Name of the backend. + One of ``"sox_io"`` or ``"soundfile"`` based on availability + of the system. If ``None`` is provided the current backend is unassigned. + """ + if backend is not None and backend not in list_audio_backends(): + raise RuntimeError(f'Backend "{backend}" is not one of ' + f"available backends: {list_audio_backends()}.") + + if backend is None: + module = no_backend + elif backend == "sox_io": + module = sox_io_backend + elif backend == "soundfile": + module = soundfile_backend + else: + raise NotImplementedError(f'Unexpected backend "{backend}"') + + for func in ["save", "load", "info"]: + setattr(paddleaudio, func, getattr(module, func)) + + +def _init_audio_backend(): + backends = list_audio_backends() + if "soundfile" in backends: + set_audio_backend("soundfile") + elif "sox_io" in backends: + set_audio_backend("sox_io") + else: + warnings.warn("No audio backend is available.") + set_audio_backend(None) + + +def get_audio_backend() -> Optional[str]: + """Get the name of the current backend + + Returns: + Optional[str]: The name of the current backend or ``None`` if no backend is assigned. + """ + if paddleaudio.load == no_backend.load: + return None + if paddleaudio.load == sox_io_backend.load: + return "sox_io" + if paddleaudio.load == soundfile_backend.load: + return "soundfile" + raise ValueError("Unknown backend.") diff --git a/paddlespeech/audio/compliance/__init__.py b/audio/paddleaudio/compliance/__init__.py similarity index 100% rename from paddlespeech/audio/compliance/__init__.py rename to audio/paddleaudio/compliance/__init__.py diff --git a/paddlespeech/audio/compliance/kaldi.py b/audio/paddleaudio/compliance/kaldi.py similarity index 100% rename from paddlespeech/audio/compliance/kaldi.py rename to audio/paddleaudio/compliance/kaldi.py diff --git a/paddlespeech/audio/compliance/librosa.py b/audio/paddleaudio/compliance/librosa.py similarity index 100% rename from paddlespeech/audio/compliance/librosa.py rename to audio/paddleaudio/compliance/librosa.py diff --git a/paddlespeech/audio/datasets/__init__.py b/audio/paddleaudio/datasets/__init__.py similarity index 100% rename from paddlespeech/audio/datasets/__init__.py rename to audio/paddleaudio/datasets/__init__.py diff --git a/paddlespeech/audio/datasets/dataset.py b/audio/paddleaudio/datasets/dataset.py similarity index 97% rename from paddlespeech/audio/datasets/dataset.py rename to audio/paddleaudio/datasets/dataset.py index 488187a6..f1dfc1ea 100644 --- a/paddlespeech/audio/datasets/dataset.py +++ b/audio/paddleaudio/datasets/dataset.py @@ -16,7 +16,7 @@ from typing import List import numpy as np import paddle -from ..backends import load as load_audio +from ..backends.soundfile_backend import soundfile_load as load_audio from ..compliance.kaldi import fbank as kaldi_fbank from ..compliance.kaldi import mfcc as kaldi_mfcc from ..compliance.librosa import melspectrogram diff --git a/paddlespeech/audio/datasets/esc50.py b/audio/paddleaudio/datasets/esc50.py similarity index 99% rename from paddlespeech/audio/datasets/esc50.py rename to audio/paddleaudio/datasets/esc50.py index f5c7050f..e7477d40 100644 --- a/paddlespeech/audio/datasets/esc50.py +++ b/audio/paddleaudio/datasets/esc50.py @@ -16,8 +16,8 @@ import os from typing import List from typing import Tuple -from ..utils import DATA_HOME from ..utils.download import download_and_decompress +from ..utils.env import DATA_HOME from .dataset import AudioClassificationDataset __all__ = ['ESC50'] diff --git a/paddlespeech/audio/datasets/gtzan.py b/audio/paddleaudio/datasets/gtzan.py similarity index 99% rename from paddlespeech/audio/datasets/gtzan.py rename to audio/paddleaudio/datasets/gtzan.py index 1f6835a5..cfea6f37 100644 --- a/paddlespeech/audio/datasets/gtzan.py +++ b/audio/paddleaudio/datasets/gtzan.py @@ -17,8 +17,8 @@ import random from typing import List from typing import Tuple -from ..utils import DATA_HOME from ..utils.download import download_and_decompress +from ..utils.env import DATA_HOME from .dataset import AudioClassificationDataset __all__ = ['GTZAN'] diff --git a/paddlespeech/audio/datasets/hey_snips.py b/audio/paddleaudio/datasets/hey_snips.py similarity index 100% rename from paddlespeech/audio/datasets/hey_snips.py rename to audio/paddleaudio/datasets/hey_snips.py diff --git a/paddlespeech/audio/datasets/rirs_noises.py b/audio/paddleaudio/datasets/rirs_noises.py similarity index 98% rename from paddlespeech/audio/datasets/rirs_noises.py rename to audio/paddleaudio/datasets/rirs_noises.py index 68639a60..74418daa 100644 --- a/paddlespeech/audio/datasets/rirs_noises.py +++ b/audio/paddleaudio/datasets/rirs_noises.py @@ -20,8 +20,8 @@ from typing import List from paddle.io import Dataset from tqdm import tqdm -from ..backends import load as load_audio -from ..backends import save as save_wav +from ..backends.soundfile_backend import soundfile_load as load_audio +from ..backends.soundfile_backend import soundfile_save as save_wav from ..utils import DATA_HOME from ..utils.download import download_and_decompress from .dataset import feat_funcs diff --git a/paddlespeech/audio/datasets/tess.py b/audio/paddleaudio/datasets/tess.py similarity index 99% rename from paddlespeech/audio/datasets/tess.py rename to audio/paddleaudio/datasets/tess.py index 1469fa5e..8faab9c3 100644 --- a/paddlespeech/audio/datasets/tess.py +++ b/audio/paddleaudio/datasets/tess.py @@ -17,8 +17,8 @@ import random from typing import List from typing import Tuple -from ..utils import DATA_HOME from ..utils.download import download_and_decompress +from ..utils.env import DATA_HOME from .dataset import AudioClassificationDataset __all__ = ['TESS'] diff --git a/paddlespeech/audio/datasets/urban_sound.py b/audio/paddleaudio/datasets/urban_sound.py similarity index 99% rename from paddlespeech/audio/datasets/urban_sound.py rename to audio/paddleaudio/datasets/urban_sound.py index 0389cd5f..d97c4d1d 100644 --- a/paddlespeech/audio/datasets/urban_sound.py +++ b/audio/paddleaudio/datasets/urban_sound.py @@ -16,8 +16,8 @@ import os from typing import List from typing import Tuple -from ..utils import DATA_HOME from ..utils.download import download_and_decompress +from ..utils.env import DATA_HOME from .dataset import AudioClassificationDataset __all__ = ['UrbanSound8K'] diff --git a/paddlespeech/audio/datasets/voxceleb.py b/audio/paddleaudio/datasets/voxceleb.py similarity index 99% rename from paddlespeech/audio/datasets/voxceleb.py rename to audio/paddleaudio/datasets/voxceleb.py index 07f44e0c..b7160b24 100644 --- a/paddlespeech/audio/datasets/voxceleb.py +++ b/audio/paddleaudio/datasets/voxceleb.py @@ -23,7 +23,7 @@ from paddle.io import Dataset from pathos.multiprocessing import Pool from tqdm import tqdm -from ..backends import load as load_audio +from ..backends.soundfile_backend import soundfile_load as load_audio from ..utils import DATA_HOME from ..utils import decompress from ..utils.download import download_and_decompress diff --git a/paddlespeech/audio/features/__init__.py b/audio/paddleaudio/features/__init__.py similarity index 100% rename from paddlespeech/audio/features/__init__.py rename to audio/paddleaudio/features/__init__.py diff --git a/paddlespeech/audio/features/layers.py b/audio/paddleaudio/features/layers.py similarity index 100% rename from paddlespeech/audio/features/layers.py rename to audio/paddleaudio/features/layers.py diff --git a/paddlespeech/audio/functional/__init__.py b/audio/paddleaudio/functional/__init__.py similarity index 100% rename from paddlespeech/audio/functional/__init__.py rename to audio/paddleaudio/functional/__init__.py diff --git a/paddlespeech/audio/functional/functional.py b/audio/paddleaudio/functional/functional.py similarity index 100% rename from paddlespeech/audio/functional/functional.py rename to audio/paddleaudio/functional/functional.py diff --git a/paddlespeech/audio/functional/window.py b/audio/paddleaudio/functional/window.py similarity index 60% rename from paddlespeech/audio/functional/window.py rename to audio/paddleaudio/functional/window.py index c99d5046..ebbbe46c 100644 --- a/paddlespeech/audio/functional/window.py +++ b/audio/paddleaudio/functional/window.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,127 +18,156 @@ from typing import Union import paddle from paddle import Tensor -__all__ = [ - 'get_window', -] +class WindowFunctionRegister(object): + def __init__(self): + self._functions_dict = dict() + def register(self): + def add_subfunction(func): + name = func.__name__ + self._functions_dict[name] = func + return func + + return add_subfunction + + def get(self, name): + return self._functions_dict[name] + + +window_function_register = WindowFunctionRegister() + + +@window_function_register.register() def _cat(x: List[Tensor], data_type: str) -> Tensor: l = [paddle.to_tensor(_, data_type) for _ in x] return paddle.concat(l) +@window_function_register.register() def _acosh(x: Union[Tensor, float]) -> Tensor: if isinstance(x, float): return math.log(x + math.sqrt(x**2 - 1)) return paddle.log(x + paddle.sqrt(paddle.square(x) - 1)) +@window_function_register.register() def _extend(M: int, sym: bool) -> bool: - """Extend window by 1 sample if needed for DFT-even symmetry. """ + """Extend window by 1 sample if needed for DFT-even symmetry.""" if not sym: return M + 1, True else: return M, False +@window_function_register.register() def _len_guards(M: int) -> bool: - """Handle small or incorrect window lengths. """ + """Handle small or incorrect window lengths.""" if int(M) != M or M < 0: raise ValueError('Window length M must be a non-negative integer') return M <= 1 +@window_function_register.register() def _truncate(w: Tensor, needed: bool) -> Tensor: - """Truncate window by 1 sample if needed for DFT-even symmetry. """ + """Truncate window by 1 sample if needed for DFT-even symmetry.""" if needed: return w[:-1] else: return w -def _general_gaussian(M: int, p, sig, sym: bool=True, - dtype: str='float64') -> Tensor: +@window_function_register.register() +def _general_gaussian( + M: int, p, sig, sym: bool = True, dtype: str = 'float64' +) -> Tensor: """Compute a window with a generalized Gaussian shape. This function is consistent with scipy.signal.windows.general_gaussian(). """ if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) n = paddle.arange(0, M, dtype=dtype) - (M - 1.0) / 2.0 - w = paddle.exp(-0.5 * paddle.abs(n / sig)**(2 * p)) + w = paddle.exp(-0.5 * paddle.abs(n / sig) ** (2 * p)) return _truncate(w, needs_trunc) -def _general_cosine(M: int, a: float, sym: bool=True, - dtype: str='float64') -> Tensor: +@window_function_register.register() +def _general_cosine( + M: int, a: float, sym: bool = True, dtype: str = 'float64' +) -> Tensor: """Compute a generic weighted sum of cosine terms window. This function is consistent with scipy.signal.windows.general_cosine(). """ if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) fac = paddle.linspace(-math.pi, math.pi, M, dtype=dtype) - w = paddle.zeros((M, ), dtype=dtype) + w = paddle.zeros((M,), dtype=dtype) for k in range(len(a)): w += a[k] * paddle.cos(k * fac) return _truncate(w, needs_trunc) -def _general_hamming(M: int, alpha: float, sym: bool=True, - dtype: str='float64') -> Tensor: +@window_function_register.register() +def _general_hamming( + M: int, alpha: float, sym: bool = True, dtype: str = 'float64' +) -> Tensor: """Compute a generalized Hamming window. This function is consistent with scipy.signal.windows.general_hamming() """ - return _general_cosine(M, [alpha, 1. - alpha], sym, dtype=dtype) + return _general_cosine(M, [alpha, 1.0 - alpha], sym, dtype=dtype) -def _taylor(M: int, - nbar=4, - sll=30, - norm=True, - sym: bool=True, - dtype: str='float64') -> Tensor: +@window_function_register.register() +def _taylor( + M: int, nbar=4, sll=30, norm=True, sym: bool = True, dtype: str = 'float64' +) -> Tensor: """Compute a Taylor window. The Taylor window taper function approximates the Dolph-Chebyshev window's constant sidelobe level for a parameterized number of near-in sidelobes. """ if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) # Original text uses a negative sidelobe level parameter and then negates # it in the calculation of B. To keep consistent with other methods we # assume the sidelobe level parameter to be positive. - B = 10**(sll / 20) + B = 10 ** (sll / 20) A = _acosh(B) / math.pi - s2 = nbar**2 / (A**2 + (nbar - 0.5)**2) + s2 = nbar**2 / (A**2 + (nbar - 0.5) ** 2) ma = paddle.arange(1, nbar, dtype=dtype) - Fm = paddle.empty((nbar - 1, ), dtype=dtype) + Fm = paddle.empty((nbar - 1,), dtype=dtype) signs = paddle.empty_like(ma) signs[::2] = 1 signs[1::2] = -1 m2 = ma * ma for mi in range(len(ma)): - numer = signs[mi] * paddle.prod(1 - m2[mi] / s2 / (A**2 + (ma - 0.5)**2 - )) + numer = signs[mi] * paddle.prod( + 1 - m2[mi] / s2 / (A**2 + (ma - 0.5) ** 2) + ) if mi == 0: - denom = 2 * paddle.prod(1 - m2[mi] / m2[mi + 1:]) + denom = 2 * paddle.prod(1 - m2[mi] / m2[mi + 1 :]) elif mi == len(ma) - 1: denom = 2 * paddle.prod(1 - m2[mi] / m2[:mi]) else: - denom = 2 * paddle.prod(1 - m2[mi] / m2[:mi]) * paddle.prod(1 - m2[ - mi] / m2[mi + 1:]) + denom = ( + 2 + * paddle.prod(1 - m2[mi] / m2[:mi]) + * paddle.prod(1 - m2[mi] / m2[mi + 1 :]) + ) Fm[mi] = numer / denom def W(n): return 1 + 2 * paddle.matmul( Fm.unsqueeze(0), - paddle.cos(2 * math.pi * ma.unsqueeze(1) * (n - M / 2. + 0.5) / M)) + paddle.cos(2 * math.pi * ma.unsqueeze(1) * (n - M / 2.0 + 0.5) / M), + ) w = W(paddle.arange(0, M, dtype=dtype)) @@ -150,7 +179,8 @@ def _taylor(M: int, return _truncate(w, needs_trunc) -def _hamming(M: int, sym: bool=True, dtype: str='float64') -> Tensor: +@window_function_register.register() +def _hamming(M: int, sym: bool = True, dtype: str = 'float64') -> Tensor: """Compute a Hamming window. The Hamming window is a taper formed by using a raised cosine with non-zero endpoints, optimized to minimize the nearest side lobe. @@ -158,7 +188,8 @@ def _hamming(M: int, sym: bool=True, dtype: str='float64') -> Tensor: return _general_hamming(M, 0.54, sym, dtype=dtype) -def _hann(M: int, sym: bool=True, dtype: str='float64') -> Tensor: +@window_function_register.register() +def _hann(M: int, sym: bool = True, dtype: str = 'float64') -> Tensor: """Compute a Hann window. The Hann window is a taper formed by using a raised cosine or sine-squared with ends that touch zero. @@ -166,15 +197,18 @@ def _hann(M: int, sym: bool=True, dtype: str='float64') -> Tensor: return _general_hamming(M, 0.5, sym, dtype=dtype) -def _tukey(M: int, alpha=0.5, sym: bool=True, dtype: str='float64') -> Tensor: +@window_function_register.register() +def _tukey( + M: int, alpha=0.5, sym: bool = True, dtype: str = 'float64' +) -> Tensor: """Compute a Tukey window. The Tukey window is also known as a tapered cosine window. """ if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) if alpha <= 0: - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) elif alpha >= 1.0: return hann(M, sym=sym) @@ -182,53 +216,48 @@ def _tukey(M: int, alpha=0.5, sym: bool=True, dtype: str='float64') -> Tensor: n = paddle.arange(0, M, dtype=dtype) width = int(alpha * (M - 1) / 2.0) - n1 = n[0:width + 1] - n2 = n[width + 1:M - width - 1] - n3 = n[M - width - 1:] + n1 = n[0 : width + 1] + n2 = n[width + 1 : M - width - 1] + n3 = n[M - width - 1 :] w1 = 0.5 * (1 + paddle.cos(math.pi * (-1 + 2.0 * n1 / alpha / (M - 1)))) w2 = paddle.ones(n2.shape, dtype=dtype) - w3 = 0.5 * (1 + paddle.cos(math.pi * (-2.0 / alpha + 1 + 2.0 * n3 / alpha / - (M - 1)))) + w3 = 0.5 * ( + 1 + + paddle.cos(math.pi * (-2.0 / alpha + 1 + 2.0 * n3 / alpha / (M - 1))) + ) w = paddle.concat([w1, w2, w3]) return _truncate(w, needs_trunc) -def _kaiser(M: int, beta: float, sym: bool=True, - dtype: str='float64') -> Tensor: - """Compute a Kaiser window. - The Kaiser window is a taper formed by using a Bessel function. - """ - raise NotImplementedError() - - -def _gaussian(M: int, std: float, sym: bool=True, - dtype: str='float64') -> Tensor: +@window_function_register.register() +def _gaussian( + M: int, std: float, sym: bool = True, dtype: str = 'float64' +) -> Tensor: """Compute a Gaussian window. The Gaussian widows has a Gaussian shape defined by the standard deviation(std). """ if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) n = paddle.arange(0, M, dtype=dtype) - (M - 1.0) / 2.0 sig2 = 2 * std * std - w = paddle.exp(-n**2 / sig2) + w = paddle.exp(-(n**2) / sig2) return _truncate(w, needs_trunc) -def _exponential(M: int, - center=None, - tau=1., - sym: bool=True, - dtype: str='float64') -> Tensor: - """Compute an exponential (or Poisson) window. """ +@window_function_register.register() +def _exponential( + M: int, center=None, tau=1.0, sym: bool = True, dtype: str = 'float64' +) -> Tensor: + """Compute an exponential (or Poisson) window.""" if sym and center is not None: raise ValueError("If sym==True, center must be None.") if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) if center is None: @@ -240,11 +269,11 @@ def _exponential(M: int, return _truncate(w, needs_trunc) -def _triang(M: int, sym: bool=True, dtype: str='float64') -> Tensor: - """Compute a triangular window. - """ +@window_function_register.register() +def _triang(M: int, sym: bool = True, dtype: str = 'float64') -> Tensor: + """Compute a triangular window.""" if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) n = paddle.arange(1, (M + 1) // 2 + 1, dtype=dtype) @@ -258,23 +287,26 @@ def _triang(M: int, sym: bool=True, dtype: str='float64') -> Tensor: return _truncate(w, needs_trunc) -def _bohman(M: int, sym: bool=True, dtype: str='float64') -> Tensor: +@window_function_register.register() +def _bohman(M: int, sym: bool = True, dtype: str = 'float64') -> Tensor: """Compute a Bohman window. The Bohman window is the autocorrelation of a cosine window. """ if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) fac = paddle.abs(paddle.linspace(-1, 1, M, dtype=dtype)[1:-1]) w = (1 - fac) * paddle.cos(math.pi * fac) + 1.0 / math.pi * paddle.sin( - math.pi * fac) + math.pi * fac + ) w = _cat([0, w, 0], dtype) return _truncate(w, needs_trunc) -def _blackman(M: int, sym: bool=True, dtype: str='float64') -> Tensor: +@window_function_register.register() +def _blackman(M: int, sym: bool = True, dtype: str = 'float64') -> Tensor: """Compute a Blackman window. The Blackman window is a taper formed by using the first three terms of a summation of cosines. It was designed to have close to the minimal @@ -284,31 +316,44 @@ def _blackman(M: int, sym: bool=True, dtype: str='float64') -> Tensor: return _general_cosine(M, [0.42, 0.50, 0.08], sym, dtype=dtype) -def _cosine(M: int, sym: bool=True, dtype: str='float64') -> Tensor: - """Compute a window with a simple cosine shape. - """ +@window_function_register.register() +def _cosine(M: int, sym: bool = True, dtype: str = 'float64') -> Tensor: + """Compute a window with a simple cosine shape.""" if _len_guards(M): - return paddle.ones((M, ), dtype=dtype) + return paddle.ones((M,), dtype=dtype) M, needs_trunc = _extend(M, sym) - w = paddle.sin(math.pi / M * (paddle.arange(0, M, dtype=dtype) + .5)) + w = paddle.sin(math.pi / M * (paddle.arange(0, M, dtype=dtype) + 0.5)) return _truncate(w, needs_trunc) -def get_window(window: Union[str, Tuple[str, float]], - win_length: int, - fftbins: bool=True, - dtype: str='float64') -> Tensor: +def get_window( + window: Union[str, Tuple[str, float]], + win_length: int, + fftbins: bool = True, + dtype: str = 'float64', +) -> Tensor: """Return a window of a given length and type. Args: - window (Union[str, Tuple[str, float]]): The window function applied to the signal before the Fourier transform. Supported window functions: 'hamming', 'hann', 'kaiser', 'gaussian', 'exponential', 'triang', 'bohman', 'blackman', 'cosine', 'tukey', 'taylor'. + window (Union[str, Tuple[str, float]]): The window function applied to the signal before the Fourier transform. Supported window functions: 'hamming', 'hann', 'gaussian', 'general_gaussian', 'exponential', 'triang', 'bohman', 'blackman', 'cosine', 'tukey', 'taylor'. win_length (int): Number of samples. fftbins (bool, optional): If True, create a "periodic" window. Otherwise, create a "symmetric" window, for use in filter design. Defaults to True. dtype (str, optional): The data type of the return window. Defaults to 'float64'. Returns: Tensor: The window represented as a tensor. + + Examples: + .. code-block:: python + + import paddle + + n_fft = 512 + cosine_window = paddle.audio.functional.get_window('cosine', n_fft) + + std = 7 + gaussian_window = paddle.audio.functional.get_window(('gaussian',std), n_fft) """ sym = not fftbins @@ -319,19 +364,22 @@ def get_window(window: Union[str, Tuple[str, float]], args = window[1:] elif isinstance(window, str): if window in ['gaussian', 'exponential']: - raise ValueError("The '" + window + "' window needs one or " - "more parameters -- pass a tuple.") + raise ValueError( + "The '" + window + "' window needs one or " + "more parameters -- pass a tuple." + ) else: winstr = window else: - raise ValueError("%s as window type is not supported." % - str(type(window))) + raise ValueError( + "%s as window type is not supported." % str(type(window)) + ) try: - winfunc = eval('_' + winstr) + winfunc = window_function_register.get('_' + winstr) except KeyError as e: raise ValueError("Unknown window type.") from e - params = (win_length, ) + args + params = (win_length,) + args kwargs = {'sym': sym} return winfunc(*params, dtype=dtype, **kwargs) diff --git a/tests/unit/audio/backends/soundfile/__init__.py b/audio/paddleaudio/kaldi/__init__.py similarity index 92% rename from tests/unit/audio/backends/soundfile/__init__.py rename to audio/paddleaudio/kaldi/__init__.py index 97043fd7..f951e280 100644 --- a/tests/unit/audio/backends/soundfile/__init__.py +++ b/audio/paddleaudio/kaldi/__init__.py @@ -11,3 +11,5 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from .kaldi import fbank +from .kaldi import pitch diff --git a/audio/paddleaudio/kaldi/kaldi.py b/audio/paddleaudio/kaldi/kaldi.py new file mode 100644 index 00000000..16969d77 --- /dev/null +++ b/audio/paddleaudio/kaldi/kaldi.py @@ -0,0 +1,132 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import paddleaudio +from paddleaudio._internal import module_utils + +__all__ = [ + 'fbank', + 'pitch', +] + + +@module_utils.requires_kaldi() +def fbank( + wav, + samp_freq: int=16000, + frame_shift_ms: float=10.0, + frame_length_ms: float=25.0, + dither: float=0.0, + preemph_coeff: float=0.97, + remove_dc_offset: bool=True, + window_type: str='povey', + round_to_power_of_two: bool=True, + blackman_coeff: float=0.42, + snip_edges: bool=True, + allow_downsample: bool=False, + allow_upsample: bool=False, + max_feature_vectors: int=-1, + num_bins: int=23, + low_freq: float=20, + high_freq: float=0, + vtln_low: float=100, + vtln_high: float=-500, + debug_mel: bool=False, + htk_mode: bool=False, + use_energy: bool=False, # fbank opts + energy_floor: float=0.0, + raw_energy: bool=True, + htk_compat: bool=False, + use_log_fbank: bool=True, + use_power: bool=True): + frame_opts = paddleaudio._paddleaudio.FrameExtractionOptions() + mel_opts = paddleaudio._paddleaudio.MelBanksOptions() + fbank_opts = paddleaudio._paddleaudio.FbankOptions() + frame_opts.samp_freq = samp_freq + frame_opts.frame_shift_ms = frame_shift_ms + frame_opts.frame_length_ms = frame_length_ms + frame_opts.dither = dither + frame_opts.preemph_coeff = preemph_coeff + frame_opts.remove_dc_offset = remove_dc_offset + frame_opts.window_type = window_type + frame_opts.round_to_power_of_two = round_to_power_of_two + frame_opts.blackman_coeff = blackman_coeff + frame_opts.snip_edges = snip_edges + frame_opts.allow_downsample = allow_downsample + frame_opts.allow_upsample = allow_upsample + frame_opts.max_feature_vectors = max_feature_vectors + + mel_opts.num_bins = num_bins + mel_opts.low_freq = low_freq + mel_opts.high_freq = high_freq + mel_opts.vtln_low = vtln_low + mel_opts.vtln_high = vtln_high + mel_opts.debug_mel = debug_mel + mel_opts.htk_mode = htk_mode + + fbank_opts.use_energy = use_energy + fbank_opts.energy_floor = energy_floor + fbank_opts.raw_energy = raw_energy + fbank_opts.htk_compat = htk_compat + fbank_opts.use_log_fbank = use_log_fbank + fbank_opts.use_power = use_power + feat = paddleaudio._paddleaudio.ComputeFbank(frame_opts, mel_opts, + fbank_opts, wav) + return feat + + +@module_utils.requires_kaldi() +def pitch(wav, + samp_freq: int=16000, + frame_shift_ms: float=10.0, + frame_length_ms: float=25.0, + preemph_coeff: float=0.0, + min_f0: int=50, + max_f0: int=400, + soft_min_f0: float=10.0, + penalty_factor: float=0.1, + lowpass_cutoff: int=1000, + resample_freq: int=4000, + delta_pitch: float=0.005, + nccf_ballast: int=7000, + lowpass_filter_width: int=1, + upsample_filter_width: int=5, + max_frames_latency: int=0, + frames_per_chunk: int=0, + simulate_first_pass_online: bool=False, + recompute_frame: int=500, + nccf_ballast_online: bool=False, + snip_edges: bool=True): + pitch_opts = paddleaudio._paddleaudio.PitchExtractionOptions() + pitch_opts.samp_freq = samp_freq + pitch_opts.frame_shift_ms = frame_shift_ms + pitch_opts.frame_length_ms = frame_length_ms + pitch_opts.preemph_coeff = preemph_coeff + pitch_opts.min_f0 = min_f0 + pitch_opts.max_f0 = max_f0 + pitch_opts.soft_min_f0 = soft_min_f0 + pitch_opts.penalty_factor = penalty_factor + pitch_opts.lowpass_cutoff = lowpass_cutoff + pitch_opts.resample_freq = resample_freq + pitch_opts.delta_pitch = delta_pitch + pitch_opts.nccf_ballast = nccf_ballast + pitch_opts.lowpass_filter_width = lowpass_filter_width + pitch_opts.upsample_filter_width = upsample_filter_width + pitch_opts.max_frames_latency = max_frames_latency + pitch_opts.frames_per_chunk = frames_per_chunk + pitch_opts.simulate_first_pass_online = simulate_first_pass_online + pitch_opts.recompute_frame = recompute_frame + pitch_opts.nccf_ballast_online = nccf_ballast_online + pitch_opts.snip_edges = snip_edges + pitch = paddleaudio._paddleaudio.ComputeKaldiPitch(pitch_opts, wav) + return pitch diff --git a/paddlespeech/audio/metric/__init__.py b/audio/paddleaudio/metric/__init__.py similarity index 100% rename from paddlespeech/audio/metric/__init__.py rename to audio/paddleaudio/metric/__init__.py diff --git a/paddlespeech/audio/metric/eer.py b/audio/paddleaudio/metric/eer.py similarity index 100% rename from paddlespeech/audio/metric/eer.py rename to audio/paddleaudio/metric/eer.py diff --git a/audio/paddleaudio/sox_effects/__init__.py b/audio/paddleaudio/sox_effects/__init__.py new file mode 100644 index 00000000..6ca26ec5 --- /dev/null +++ b/audio/paddleaudio/sox_effects/__init__.py @@ -0,0 +1,21 @@ +from paddleaudio._internal import module_utils as _mod_utils + +from .sox_effects import apply_effects_file +from .sox_effects import apply_effects_tensor +from .sox_effects import effect_names +from .sox_effects import init_sox_effects +from .sox_effects import shutdown_sox_effects + +if _mod_utils.is_sox_available(): + import atexit + + init_sox_effects() + atexit.register(shutdown_sox_effects) + +__all__ = [ + "init_sox_effects", + "shutdown_sox_effects", + "effect_names", + "apply_effects_tensor", + "apply_effects_file", +] diff --git a/audio/paddleaudio/sox_effects/sox_effects.py b/audio/paddleaudio/sox_effects/sox_effects.py new file mode 100644 index 00000000..cb7e1b0b --- /dev/null +++ b/audio/paddleaudio/sox_effects/sox_effects.py @@ -0,0 +1,241 @@ +import os +from typing import List +from typing import Optional +from typing import Tuple + +import paddle +import paddleaudio +from paddleaudio._internal import module_utils as _mod_utils +from paddleaudio.utils.sox_utils import list_effects + +#code is from: https://github.com/pytorch/audio/blob/main/torchaudio/sox_effects/sox_effects.py + + +@_mod_utils.requires_sox() +def init_sox_effects(): + """Initialize resources required to use sox effects. + + Note: + You do not need to call this function manually. It is called automatically. + + Once initialized, you do not need to call this function again across the multiple uses of + sox effects though it is safe to do so as long as :func:`shutdown_sox_effects` is not called yet. + Once :func:`shutdown_sox_effects` is called, you can no longer use SoX effects and initializing + again will result in error. + """ + paddleaudio._paddleaudio.sox_effects_initialize_sox_effects() + + +@_mod_utils.requires_sox() +def shutdown_sox_effects(): + """Clean up resources required to use sox effects. + + Note: + You do not need to call this function manually. It is called automatically. + + It is safe to call this function multiple times. + Once :py:func:`shutdown_sox_effects` is called, you can no longer use SoX effects and + initializing again will result in error. + """ + paddleaudio._paddleaudio.sox_effects_shutdown_sox_effects() + + +@_mod_utils.requires_sox() +def effect_names() -> List[str]: + """Gets list of valid sox effect names + + Returns: + List[str]: list of available effect names. + + Example + >>> paddleaudio.sox_effects.effect_names() + ['allpass', 'band', 'bandpass', ... ] + """ + return list(list_effects().keys()) + + +@_mod_utils.requires_sox() +def apply_effects_tensor( + tensor: paddle.Tensor, + sample_rate: int, + effects: List[List[str]], + channels_first: bool=True, ) -> Tuple[paddle.Tensor, int]: + """Apply sox effects to given Tensor + + .. devices:: CPU + + Note: + This function only works on CPU Tensors. + This function works in the way very similar to ``sox`` command, however there are slight + differences. For example, ``sox`` command adds certain effects automatically (such as + ``rate`` effect after ``speed`` and ``pitch`` and other effects), but this function does + only applies the given effects. (Therefore, to actually apply ``speed`` effect, you also + need to give ``rate`` effect with desired sampling rate.). + + Args: + tensor (paddle.Tensor): Input 2D CPU Tensor. + sample_rate (int): Sample rate + effects (List[List[str]]): List of effects. + channels_first (bool, optional): Indicates if the input Tensor's dimension is + `[channels, time]` or `[time, channels]` + + Returns: + (Tensor, int): Resulting Tensor and sample rate. + The resulting Tensor has the same ``dtype`` as the input Tensor, and + the same channels order. The shape of the Tensor can be different based on the + effects applied. Sample rate can also be different based on the effects applied. + + Example - Basic usage + >>> + >>> # Defines the effects to apply + >>> effects = [ + ... ['gain', '-n'], # normalises to 0dB + ... ['pitch', '5'], # 5 cent pitch shift + ... ['rate', '8000'], # resample to 8000 Hz + ... ] + >>> + >>> # Generate pseudo wave: + >>> # normalized, channels first, 2ch, sampling rate 16000, 1 second + >>> sample_rate = 16000 + >>> waveform = 2 * paddle.rand([2, sample_rate * 1]) - 1 + >>> waveform.shape + paddle.Size([2, 16000]) + >>> waveform + tensor([[ 0.3138, 0.7620, -0.9019, ..., -0.7495, -0.4935, 0.5442], + [-0.0832, 0.0061, 0.8233, ..., -0.5176, -0.9140, -0.2434]]) + >>> + >>> # Apply effects + >>> waveform, sample_rate = apply_effects_tensor( + ... wave_form, sample_rate, effects, channels_first=True) + >>> + >>> # Check the result + >>> # The new waveform is sampling rate 8000, 1 second. + >>> # normalization and channel order are preserved + >>> waveform.shape + paddle.Size([2, 8000]) + >>> waveform + tensor([[ 0.5054, -0.5518, -0.4800, ..., -0.0076, 0.0096, -0.0110], + [ 0.1331, 0.0436, -0.3783, ..., -0.0035, 0.0012, 0.0008]]) + >>> sample_rate + 8000 + + """ + tensor_np = tensor.numpy() + ret = paddleaudio._paddleaudio.sox_effects_apply_effects_tensor(tensor_np, sample_rate, + effects, channels_first) + if ret is not None: + return (paddle.to_tensor(ret[0]), ret[1]) + raise RuntimeError("Failed to apply sox effect") + + +@_mod_utils.requires_sox() +def apply_effects_file( + path: str, + effects: List[List[str]], + normalize: bool=True, + channels_first: bool=True, + format: Optional[str]=None, ) -> Tuple[paddle.Tensor, int]: + """Apply sox effects to the audio file and load the resulting data as Tensor + + Note: + This function works in the way very similar to ``sox`` command, however there are slight + differences. For example, ``sox`` commnad adds certain effects automatically (such as + ``rate`` effect after ``speed``, ``pitch`` etc), but this function only applies the given + effects. Therefore, to actually apply ``speed`` effect, you also need to give ``rate`` + effect with desired sampling rate, because internally, ``speed`` effects only alter sampling + rate and leave samples untouched. + + Args: + path (path-like object or file-like object): + effects (List[List[str]]): List of effects. + normalize (bool, optional): + When ``True``, this function always return ``float32``, and sample values are + normalized to ``[-1.0, 1.0]``. + If input file is integer WAV, giving ``False`` will change the resulting Tensor type to + integer type. This argument has no effect for formats other + than integer WAV type. + channels_first (bool, optional): When True, the returned Tensor has dimension `[channel, time]`. + Otherwise, the returned Tensor's dimension is `[time, channel]`. + format (str or None, optional): + Override the format detection with the given format. + Providing the argument might help when libsox can not infer the format + from header or extension, + + Returns: + (Tensor, int): Resulting Tensor and sample rate. + If ``normalize=True``, the resulting Tensor is always ``float32`` type. + If ``normalize=False`` and the input audio file is of integer WAV file, then the + resulting Tensor has corresponding integer type. (Note 24 bit integer type is not supported) + If ``channels_first=True``, the resulting Tensor has dimension `[channel, time]`, + otherwise `[time, channel]`. + + Example - Basic usage + >>> + >>> # Defines the effects to apply + >>> effects = [ + ... ['gain', '-n'], # normalises to 0dB + ... ['pitch', '5'], # 5 cent pitch shift + ... ['rate', '8000'], # resample to 8000 Hz + ... ] + >>> + >>> # Apply effects and load data with channels_first=True + >>> waveform, sample_rate = apply_effects_file("data.wav", effects, channels_first=True) + >>> + >>> # Check the result + >>> waveform.shape + paddle.Size([2, 8000]) + >>> waveform + tensor([[ 5.1151e-03, 1.8073e-02, 2.2188e-02, ..., 1.0431e-07, + -1.4761e-07, 1.8114e-07], + [-2.6924e-03, 2.1860e-03, 1.0650e-02, ..., 6.4122e-07, + -5.6159e-07, 4.8103e-07]]) + >>> sample_rate + 8000 + + Example - Apply random speed perturbation to dataset + >>> + >>> # Load data from file, apply random speed perturbation + >>> class RandomPerturbationFile(paddle.utils.data.Dataset): + ... \"\"\"Given flist, apply random speed perturbation + ... + ... Suppose all the input files are at least one second long. + ... \"\"\" + ... def __init__(self, flist: List[str], sample_rate: int): + ... super().__init__() + ... self.flist = flist + ... self.sample_rate = sample_rate + ... + ... def __getitem__(self, index): + ... speed = 0.5 + 1.5 * random.randn() + ... effects = [ + ... ['gain', '-n', '-10'], # apply 10 db attenuation + ... ['remix', '-'], # merge all the channels + ... ['speed', f'{speed:.5f}'], # duration is now 0.5 ~ 2.0 seconds. + ... ['rate', f'{self.sample_rate}'], + ... ['pad', '0', '1.5'], # add 1.5 seconds silence at the end + ... ['trim', '0', '2'], # get the first 2 seconds + ... ] + ... waveform, _ = paddleaudio.sox_effects.apply_effects_file( + ... self.flist[index], effects) + ... return waveform + ... + ... def __len__(self): + ... return len(self.flist) + ... + >>> dataset = RandomPerturbationFile(file_list, sample_rate=8000) + >>> loader = paddle.utils.data.DataLoader(dataset, batch_size=32) + >>> for batch in loader: + >>> pass + """ + if hasattr(path, "read"): + ret = paddleaudio._paddleaudio.apply_effects_fileobj(path, effects, normalize, + channels_first, format) + if ret is None: + raise RuntimeError("Failed to load audio from {}".format(path)) + return (paddle.to_tensor(ret[0]), ret[1]) + path = os.fspath(path) + ret = paddleaudio._paddleaudio.sox_effects_apply_effects_file(path, effects, normalize, + channels_first, format) + if ret is not None: + return (paddle.to_tensor(ret[0]), ret[1]) + raise RuntimeError("Failed to load audio from {}".format(path)) diff --git a/audio/paddleaudio/src/CMakeLists.txt b/audio/paddleaudio/src/CMakeLists.txt new file mode 100644 index 00000000..fb6f3209 --- /dev/null +++ b/audio/paddleaudio/src/CMakeLists.txt @@ -0,0 +1,217 @@ +if (MSVC) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + +if(APPLE) +set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") +endif(APPLE) + +################################################################################ +# libpaddleaudio +################################################################################ +set( + LIBPADDLEAUDIO_SOURCES + utils.cpp + ) + +set( + LIBPADDLEAUDIO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR} + ) + +set( + LIBPADDLEAUDIO_LINK_LIBRARIES + ) + +set( + LIBPADDLEAUDIO_COMPILE_DEFINITIONS) + +#------------------------------------------------------------------------------# +# START OF CUSTOMIZATION LOGICS +#------------------------------------------------------------------------------# + +if(BUILD_SOX) + list( + APPEND + LIBPADDLEAUDIO_LINK_LIBRARIES + libsox + ) + list( + APPEND + LIBPADDLEAUDIO_SOURCES + ) + list( + APPEND + LIBPADDLEAUDIO_COMPILE_DEFINITIONS + INCLUDE_SOX + ) +endif() + + +if(BUILD_KALDI) + list( + APPEND + LIBPADDLEAUDIO_LINK_LIBRARIES + libkaldi + ) + list( + APPEND + LIBPADDLEAUDIO_COMPILE_DEFINITIONS + INCLUDE_KALDI + COMPILE_WITHOUT_OPENFST + ) +endif() + +#------------------------------------------------------------------------------# +# END OF CUSTOMIZATION LOGICS +#------------------------------------------------------------------------------# + +function (define_library name source include_dirs link_libraries compile_defs) + add_library(${name} SHARED ${source}) + target_include_directories(${name} PRIVATE ${include_dirs}) + target_link_libraries(${name} ${link_libraries}) + target_compile_definitions(${name} PRIVATE ${compile_defs}) + set_target_properties(${name} PROPERTIES PREFIX "") + if (MSVC) + set_target_properties(${name} PROPERTIES SUFFIX ".pyd") + endif(MSVC) + + install( + TARGETS ${name} + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib # For Windows + ) +endfunction() + + +define_library( + libpaddleaudio + "${LIBPADDLEAUDIO_SOURCES}" + "${LIBPADDLEAUDIO_INCLUDE_DIRS}" + "${LIBPADDLEAUDIO_LINK_LIBRARIES}" + "${LIBPADDLEAUDIO_COMPILE_DEFINITIONS}" +) + +if (APPLE) + add_custom_command(TARGET libpaddleaudio POST_BUILD COMMAND install_name_tool -change "${GFORTRAN_LIBRARIES_DIR}/libgcc_s.1.1.dylib" "@loader_path/libgcc_s.1.1.dylib" libpaddleaudio.so) +endif(APPLE) + +if (UNIX AND NOT APPLE) + set_target_properties(libpaddleaudio PROPERTIES INSTALL_RPATH "$ORIGIN") +endif() + +if (APPLE) + set(AUDIO_LIBRARY libpaddleaudio CACHE INTERNAL "") +else() + set(AUDIO_LIBRARY -Wl,--no-as-needed libpaddleaudio -Wl,--as-needed CACHE INTERNAL "") +endif() + + ################################################################################ +# _paddleaudio.so +################################################################################ +if (BUILD_PADDLEAUDIO_PYTHON_EXTENSION) +if (WIN32) + find_package(Python3 ${PYTHON_VERSION} EXACT COMPONENTS Development) + set(ADDITIONAL_ITEMS Python3::Python) +endif() +function(define_extension name sources include_dirs libraries definitions) + add_library(${name} SHARED ${sources}) + target_compile_definitions(${name} PRIVATE "${definitions}") + target_include_directories( + ${name} PRIVATE ${PROJECT_SOURCE_DIR} ${Python_INCLUDE_DIR} ${pybind11_INCLUDE_DIR} ${include_dirs}) + target_link_libraries( + ${name} + ${libraries} + ${PYTHON_LIBRARY} + ${ADDITIONAL_ITEMS} + ) + set_target_properties(${name} PROPERTIES PREFIX "") + if (MSVC) + set_target_properties(${name} PROPERTIES SUFFIX ".pyd") + endif(MSVC) + if (APPLE) + # https://github.com/facebookarchive/caffe2/issues/854#issuecomment-364538485 + # https://github.com/pytorch/pytorch/commit/73f6715f4725a0723d8171d3131e09ac7abf0666 + set_target_properties(${name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") + endif() + install( + TARGETS ${name} + LIBRARY DESTINATION . + RUNTIME DESTINATION . # For Windows + ) +endfunction() + +set( + EXTENSION_SOURCES + pybind/pybind.cpp + ) +#----------------------------------------------------------------------------# +# START OF CUSTOMIZATION LOGICS +#----------------------------------------------------------------------------# +if(BUILD_SOX) + list( + APPEND + EXTENSION_SOURCES + pybind/sox/effects.cpp + pybind/sox/effects_chain.cpp + pybind/sox/io.cpp + pybind/sox/types.cpp + pybind/sox/utils.cpp + ) +endif() + +if(BUILD_KALDI) + list( + APPEND + EXTENSION_SOURCES + pybind/kaldi/kaldi_feature_wrapper.cc + pybind/kaldi/kaldi_feature.cc + ) +endif() +#----------------------------------------------------------------------------# +# END OF CUSTOMIZATION LOGICS +#----------------------------------------------------------------------------# +define_extension( + _paddleaudio + "${EXTENSION_SOURCES}" + "" + libpaddleaudio + "${LIBPADDLEAUDIO_COMPILE_DEFINITIONS}" + ) +# if(BUILD_CTC_DECODER) +# set( +# DECODER_EXTENSION_SOURCES +# decoder/bindings/pybind.cpp +# ) +# define_extension( +# _paddleaudio_decoder +# "${DECODER_EXTENSION_SOURCES}" +# "" +# "libpaddleaudio_decoder" +# "${LIBPADDLEAUDIO_DECODER_DEFINITIONS}" +# ) +# endif() +# if(USE_FFMPEG) +# set( +# FFMPEG_EXTENSION_SOURCES +# ffmpeg/pybind/typedefs.cpp +# ffmpeg/pybind/pybind.cpp +# ffmpeg/pybind/stream_reader.cpp +# ) +# define_extension( +# _paddleaudio_ffmpeg +# "${FFMPEG_EXTENSION_SOURCES}" +# "${FFMPEG_INCLUDE_DIRS}" +# "libpaddleaudio_ffmpeg" +# "${LIBPADDLEAUDIO_DECODER_DEFINITIONS}" +# ) +# endif() +endif() + +if (APPLE) + add_custom_command(TARGET _paddleaudio POST_BUILD COMMAND install_name_tool -change "${GFORTRAN_LIBRARIES_DIR}/libgcc_s.1.1.dylib" "@loader_path/lib/libgcc_s.1.1.dylib" _paddleaudio.so) +endif(APPLE) + +if (UNIX AND NOT APPLE) + set_target_properties(_paddleaudio PROPERTIES INSTALL_RPATH "$ORIGIN/lib") +endif() diff --git a/audio/paddleaudio/src/optional/COPYING b/audio/paddleaudio/src/optional/COPYING new file mode 100644 index 00000000..0e259d42 --- /dev/null +++ b/audio/paddleaudio/src/optional/COPYING @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/audio/paddleaudio/src/optional/optional.hpp b/audio/paddleaudio/src/optional/optional.hpp new file mode 100644 index 00000000..bceb4113 --- /dev/null +++ b/audio/paddleaudio/src/optional/optional.hpp @@ -0,0 +1,2182 @@ + +/// +// optional - An implementation of std::optional with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at https://tl.tartanllama.xyz/ +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// . +// https://github.com/TartanLlama/optional +/// + +#ifndef TL_OPTIONAL_HPP +#define TL_OPTIONAL_HPP + +#define TL_OPTIONAL_VERSION_MAJOR 1 +#define TL_OPTIONAL_VERSION_MINOR 0 +#define TL_OPTIONAL_VERSION_PATCH 0 + +#include +#include +#include +#include +#include + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_OPTIONAL_MSVC2015 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_OPTIONAL_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_OPTIONAL_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define TL_OPTIONAL_GCC55 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions +#define TL_OPTIONAL_NO_CONSTRR + +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor::value +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::has_trivial_copy_assign::value + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible::value + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks +// std::vector +// for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { +namespace detail { +template +struct is_trivially_copy_constructible + : std::is_trivially_copy_constructible {}; +#ifdef _GLIBCXX_VECTOR +template +struct is_trivially_copy_constructible> + : std::is_trivially_copy_constructible {}; +#endif +} +} +#endif + +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible::value +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable::value +#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible::value +#else +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible::value +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable::value +#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible::value +#endif + +#if __cplusplus > 201103L +#define TL_OPTIONAL_CXX14 +#endif + +// constexpr implies const in C++11, not C++14 +#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \ + defined(TL_OPTIONAL_GCC49)) +#define TL_OPTIONAL_11_CONSTEXPR +#else +#define TL_OPTIONAL_11_CONSTEXPR constexpr +#endif + +namespace tl { +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +/// Used to represent an optional with no data; essentially a bool +class monostate {}; + +/// A tag type to tell optional to construct its value in-place +struct in_place_t { + explicit in_place_t() = default; +}; +/// A tag to tell optional to construct its value in-place +static constexpr in_place_t in_place{}; +#endif + +template +class optional; + +namespace detail { +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX +// C++14-style aliases for brevity +template +using remove_const_t = typename std::remove_const::type; +template +using remove_reference_t = typename std::remove_reference::type; +template +using decay_t = typename std::decay::type; +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; + +// std::conjunction from C++17 +template +struct conjunction : std::true_type {}; +template +struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template +struct is_pointer_to_non_const_member_func : std::false_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; + +template +struct is_const_or_const_ref : std::false_type {}; +template +struct is_const_or_const_ref : std::true_type {}; +template +struct is_const_or_const_ref : std::true_type {}; +#endif + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template < + typename Fn, + typename... Args, +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t::value && + is_const_or_const_ref::value)>, +#endif + typename = enable_if_t>::value>, + int = 0> +constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} + +template >::value>> +constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} + +// std::invoke_result from C++17 +template +struct invoke_result_impl; + +template +struct invoke_result_impl< + F, + decltype(detail::invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = + decltype(detail::invoke(std::declval(), std::declval()...)); +}; + +template +using invoke_result = invoke_result_impl; + +template +using invoke_result_t = typename invoke_result::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template +struct is_swappable : std::true_type {}; + +template +struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template +tag swap(T &, T &); +template +tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template +std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); + +template +std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); + +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; + +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; + +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype( + detail::swap_adl_tests::uses_std(0))::value || + is_swappable::value)> {}; + +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value + &&detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> { +}; +#endif +#endif + +// std::void_t from C++17 +template +struct voider { + using type = void; +}; +template +using void_t = typename voider::type; + +// Trait for checking if a type is a tl::optional +template +struct is_optional_impl : std::false_type {}; +template +struct is_optional_impl> : std::true_type {}; +template +using is_optional = is_optional_impl>; + +// Change void to tl::monostate +template +using fixup_void = conditional_t::value, monostate, U>; + +template > +using get_map_return = optional>>; + +// Check if invoking F for some Us returns void +template +struct returns_void_impl; +template +struct returns_void_impl>, U...> + : std::is_void> {}; +template +using returns_void = returns_void_impl; + +template +using enable_if_ret_void = enable_if_t::value>; + +template +using disable_if_ret_void = enable_if_t::value>; + +template +using enable_forward_value = + detail::enable_if_t::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value>; + +template +using enable_from_other = detail::enable_if_t< + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; + +template +using enable_assign_forward = detail::enable_if_t< + !std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && std::is_assignable::value>; + +template +using enable_assign_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_assignable::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_assignable &>::value && + !std::is_assignable &&>::value && + !std::is_assignable &>::value && + !std::is_assignable &&>::value>; + +// The storage base manages the actual storage, and correctly propagates +// trivial destruction from T. This case is for when T is not trivially +// destructible. +template ::value> +struct optional_storage_base { + TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept + : m_dummy(), + m_has_value(false) {} + + template + TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) + : m_value(std::forward(u)...), m_has_value(true) {} + + ~optional_storage_base() { + if (m_has_value) { + m_value.~T(); + m_has_value = false; + } + } + + struct dummy {}; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value; +}; + +// This case is for when T is trivially destructible. +template +struct optional_storage_base { + TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept + : m_dummy(), + m_has_value(false) {} + + template + TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) + : m_value(std::forward(u)...), m_has_value(true) {} + + // No destructor, so this class is trivially destructible + + struct dummy {}; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value = false; +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct optional_operations_base : optional_storage_base { + using optional_storage_base::optional_storage_base; + + void hard_reset() noexcept { + get().~T(); + this->m_has_value = false; + } + + template + void construct(Args &&... args) noexcept { + new (std::addressof(this->m_value)) T(std::forward(args)...); + this->m_has_value = true; + } + + template + void assign(Opt &&rhs) { + if (this->has_value()) { + if (rhs.has_value()) { + this->m_value = std::forward(rhs).get(); + } else { + this->m_value.~T(); + this->m_has_value = false; + } + } + + else if (rhs.has_value()) { + construct(std::forward(rhs).get()); + } + } + + bool has_value() const { return this->m_has_value; } + + TL_OPTIONAL_11_CONSTEXPR T &get() & { return this->m_value; } + TL_OPTIONAL_11_CONSTEXPR const T &get() const & { return this->m_value; } + TL_OPTIONAL_11_CONSTEXPR T &&get() && { return std::move(this->m_value); } +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr const T &&get() const && { return std::move(this->m_value); } +#endif +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T is trivially copy constructible +template +struct optional_copy_base : optional_operations_base { + using optional_operations_base::optional_operations_base; +}; + +// This specialization is for when T is not trivially copy constructible +template +struct optional_copy_base : optional_operations_base { + using optional_operations_base::optional_operations_base; + + optional_copy_base() = default; + optional_copy_base(const optional_copy_base &rhs) + : optional_operations_base() { + if (rhs.has_value()) { + this->construct(rhs.get()); + } else { + this->m_has_value = false; + } + } + + optional_copy_base(optional_copy_base &&rhs) = default; + optional_copy_base &operator=(const optional_copy_base &rhs) = default; + optional_copy_base &operator=(optional_copy_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef TL_OPTIONAL_GCC49 +template ::value> +struct optional_move_base : optional_copy_base { + using optional_copy_base::optional_copy_base; +}; +#else +template +struct optional_move_base; +#endif +template +struct optional_move_base : optional_copy_base { + using optional_copy_base::optional_copy_base; + + optional_move_base() = default; + optional_move_base(const optional_move_base &rhs) = default; + + optional_move_base(optional_move_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value) { + if (rhs.has_value()) { + this->construct(std::move(rhs.get())); + } else { + this->m_has_value = false; + } + } + optional_move_base &operator=(const optional_move_base &rhs) = default; + optional_move_base &operator=(optional_move_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial copy assignment operator +template +struct optional_copy_assign_base : optional_move_base { + using optional_move_base::optional_move_base; +}; + +template +struct optional_copy_assign_base : optional_move_base { + using optional_move_base::optional_move_base; + + optional_copy_assign_base() = default; + optional_copy_assign_base(const optional_copy_assign_base &rhs) = default; + + optional_copy_assign_base(optional_copy_assign_base &&rhs) = default; + optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) { + this->assign(rhs); + return *this; + } + optional_copy_assign_base &operator=(optional_copy_assign_base &&rhs) = + default; +}; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef TL_OPTIONAL_GCC49 +template ::value + &&std::is_trivially_move_constructible::value + &&std::is_trivially_move_assignable::value> +struct optional_move_assign_base : optional_copy_assign_base { + using optional_copy_assign_base::optional_copy_assign_base; +}; +#else +template +struct optional_move_assign_base; +#endif + +template +struct optional_move_assign_base : optional_copy_assign_base { + using optional_copy_assign_base::optional_copy_assign_base; + + optional_move_assign_base() = default; + optional_move_assign_base(const optional_move_assign_base &rhs) = default; + + optional_move_assign_base(optional_move_assign_base &&rhs) = default; + + optional_move_assign_base &operator=(const optional_move_assign_base &rhs) = + default; + + optional_move_assign_base & + operator=(optional_move_assign_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value + &&std::is_nothrow_move_assignable::value) { + this->assign(std::move(rhs)); + return *this; + } +}; + +// optional_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template ::value, + bool EnableMove = std::is_move_constructible::value> +struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; + optional_delete_ctor_base &operator=(const optional_delete_ctor_base &) = + default; + optional_delete_ctor_base &operator=( + optional_delete_ctor_base &&) noexcept = default; +}; + +template +struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; + optional_delete_ctor_base &operator=(const optional_delete_ctor_base &) = + default; + optional_delete_ctor_base &operator=( + optional_delete_ctor_base &&) noexcept = default; +}; + +template +struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; + optional_delete_ctor_base &operator=(const optional_delete_ctor_base &) = + default; + optional_delete_ctor_base &operator=( + optional_delete_ctor_base &&) noexcept = default; +}; + +template +struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; + optional_delete_ctor_base &operator=(const optional_delete_ctor_base &) = + default; + optional_delete_ctor_base &operator=( + optional_delete_ctor_base &&) noexcept = default; +}; + +// optional_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible + assignable +template ::value && + std::is_copy_assignable::value), + bool EnableMove = (std::is_move_constructible::value && + std::is_move_assignable::value)> +struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base &operator=( + const optional_delete_assign_base &) = default; + optional_delete_assign_base &operator=( + optional_delete_assign_base &&) noexcept = default; +}; + +template +struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base &operator=( + const optional_delete_assign_base &) = default; + optional_delete_assign_base &operator=( + optional_delete_assign_base &&) noexcept = delete; +}; + +template +struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base &operator=( + const optional_delete_assign_base &) = delete; + optional_delete_assign_base &operator=( + optional_delete_assign_base &&) noexcept = default; +}; + +template +struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base &operator=( + const optional_delete_assign_base &) = delete; + optional_delete_assign_base &operator=( + optional_delete_assign_base &&) noexcept = delete; +}; + +} // namespace detail + +/// A tag type to represent an empty optional +struct nullopt_t { + struct do_not_use {}; + constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} +}; +/// Represents an empty optional +static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, + nullopt_t::do_not_use{}}; + +class bad_optional_access : public std::exception { + public: + bad_optional_access() = default; + const char *what() const noexcept { return "Optional has no value"; } +}; + +/// An optional object is an object that contains the storage for another +/// object and manages the lifetime of this contained object, if any. The +/// contained object may be initialized after the optional object has been +/// initialized, and may be destroyed before the optional object has been +/// destroyed. The initialization state of the contained object is tracked by +/// the optional object. +template +class optional : private detail::optional_move_assign_base, + private detail::optional_delete_ctor_base, + private detail::optional_delete_assign_base { + using base = detail::optional_move_assign_base; + + static_assert(!std::is_same::value, + "instantiation of optional with in_place_t is ill-formed"); + static_assert(!std::is_same, nullopt_t>::value, + "instantiation of optional with nullopt_t is ill-formed"); + + public: +// The different versions for C++14 and 11 are needed because deduced return +// types are not SFINAE-safe. This provides better support for things like +// generic lambdas. C.f. +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } + + template + constexpr auto and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr auto and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } +#endif +#else + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then( + F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } + + template + constexpr detail::invoke_result_t and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr detail::invoke_result_t and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } +#endif +#endif + +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { + return optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { + return optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr auto map(F &&f) const & { + return optional_map_impl(*this, std::forward(f)); + } + + template + constexpr auto map(F &&f) const && { + return optional_map_impl(std::move(*this), std::forward(f)); + } +#else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype( + optional_map_impl(std::declval(), std::declval())) + map(F &&f) & { + return optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype( + optional_map_impl(std::declval(), std::declval())) + map(F &&f) && { + return optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr decltype(optional_map_impl(std::declval(), + std::declval())) + map(F &&f) const & { + return optional_map_impl(*this, std::forward(f)); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(optional_map_impl(std::declval(), + std::declval())) + map(F &&f) const && { + return optional_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) & { + return optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) && { + return optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr auto transform(F &&f) const & { + return optional_map_impl(*this, std::forward(f)); + } + + template + constexpr auto transform(F &&f) const && { + return optional_map_impl(std::move(*this), std::forward(f)); + } +#else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype( + optional_map_impl(std::declval(), std::declval())) + transform(F &&f) & { + return optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype( + optional_map_impl(std::declval(), std::declval())) + transform(F &&f) && { + return optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr decltype(optional_map_impl(std::declval(), + std::declval())) + transform(F &&f) const & { + return optional_map_impl(*this, std::forward(f)); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(optional_map_impl(std::declval(), + std::declval())) + transform(F &&f) const && { + return optional_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + + /// Calls `f` if the optional is empty + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + if (has_value()) return *this; + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + return has_value() ? *this : std::forward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) && { + if (has_value()) return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { + return has_value() ? std::move(*this) : std::forward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) const & { + if (has_value()) return *this; + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { + return has_value() ? *this : std::forward(f)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template * = nullptr> + optional or_else(F &&f) const && { + if (has_value()) return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional or_else(F &&f) const && { + return has_value() ? std::move(*this) : std::forward(f)(); + } +#endif + + /// Maps the stored value with `f` if there is one, otherwise returns `u`. + template + U map_or(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + + template + U map_or(F &&f, U &&u) && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } + + template + U map_or(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + U map_or(F &&f, U &&u) const && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } +#endif + + /// Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } +#endif + + /// Returns `u` if `*this` has a value, otherwise an empty optional. + template + constexpr optional::type> conjunction(U &&u) const { + using result = optional>; + return has_value() ? result{u} : result{nullopt}; + } + + /// Returns `rhs` if `*this` is empty, otherwise the current value. + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { + return has_value() ? *this : rhs; + } + + constexpr optional disjunction(const optional &rhs) const & { + return has_value() ? *this : rhs; + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(const optional &rhs) const && { + return has_value() ? std::move(*this) : rhs; + } +#endif + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { + return has_value() ? *this : std::move(rhs); + } + + constexpr optional disjunction(optional &&rhs) const & { + return has_value() ? *this : std::move(rhs); + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(optional &&rhs) const && { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + optional take() { + optional ret = std::move(*this); + reset(); + return ret; + } + + using value_type = T; + + /// Constructs an optional that does not contain a value. + constexpr optional() noexcept = default; + + constexpr optional(nullopt_t) noexcept {} + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; + + /// Constructs the stored value in-place using the given arguments. + template + constexpr explicit optional( + detail::enable_if_t::value, + in_place_t>, + Args &&... args) + : base(in_place, std::forward(args)...) {} + + template + TL_OPTIONAL_11_CONSTEXPR explicit optional( + detail::enable_if_t &, + Args &&...>::value, + in_place_t>, + std::initializer_list il, + Args &&... args) { + this->construct(il, std::forward(args)...); + } + + /// Constructs the stored value with `u`. + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> + constexpr optional(U &&u) : base(in_place, std::forward(u)) {} + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> + constexpr explicit optional(U &&u) : base(in_place, std::forward(u)) {} + + /// Converting copy constructor. + template * = nullptr, + detail::enable_if_t::value> * = + nullptr> + optional(const optional &rhs) { + if (rhs.has_value()) { + this->construct(*rhs); + } + } + + template * = nullptr, + detail::enable_if_t::value> * = + nullptr> + explicit optional(const optional &rhs) { + if (rhs.has_value()) { + this->construct(*rhs); + } + } + + /// Converting move constructor. + template < + class U, + detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + optional(optional &&rhs) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + } + + template < + class U, + detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + explicit optional(optional &&rhs) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + } + + /// Destroys the stored value if there is one. + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional &operator=(nullopt_t) noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + + return *this; + } + + /// Copy assignment. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional &operator=(const optional &rhs) = default; + + /// Move assignment. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional &operator=(optional &&rhs) = default; + + /// Assigns the stored value from `u`, destroying the old value if there was + /// one. + template * = nullptr> + optional &operator=(U &&u) { + if (has_value()) { + this->m_value = std::forward(u); + } else { + this->construct(std::forward(u)); + } + + return *this; + } + + /// Converting copy assignment operator. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + template * = nullptr> + optional &operator=(const optional &rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = *rhs; + } else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(*rhs); + } + + return *this; + } + + // TODO check exception guarantee + /// Converting move assignment operator. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + template * = nullptr> + optional &operator=(optional &&rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = std::move(*rhs); + } else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. + template + T &emplace(Args &&... args) { + static_assert(std::is_constructible::value, + "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward(args)...); + return value(); + } + + template + detail::enable_if_t< + std::is_constructible &, Args &&...>::value, + T &> + emplace(std::initializer_list il, Args &&... args) { + *this = nullopt; + this->construct(il, std::forward(args)...); + return value(); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void swap(optional &rhs) noexcept( + std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value) { + using std::swap; + if (has_value()) { + if (rhs.has_value()) { + swap(**this, *rhs); + } else { + new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); + this->m_value.T::~T(); + } + } else if (rhs.has_value()) { + new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); + rhs.m_value.T::~T(); + } + swap(this->m_has_value, rhs.m_has_value); + } + + /// Returns a pointer to the stored value + constexpr const T *operator->() const { + return std::addressof(this->m_value); + } + + TL_OPTIONAL_11_CONSTEXPR T *operator->() { + return std::addressof(this->m_value); + } + + /// Returns the stored value + TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } + + constexpr const T &operator*() const & { return this->m_value; } + + TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { + return std::move(this->m_value); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr const T &&operator*() const && { + return std::move(this->m_value); + } +#endif + + /// Returns whether or not the optional has a value + constexpr bool has_value() const noexcept { return this->m_has_value; } + + constexpr explicit operator bool() const noexcept { + return this->m_has_value; + } + + /// Returns the contained value if there is one, otherwise throws + /// bad_optional_access + TL_OPTIONAL_11_CONSTEXPR T &value() & { + if (has_value()) return this->m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR const T &value() const & { + if (has_value()) return this->m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR T &&value() && { + if (has_value()) return std::move(this->m_value); + throw bad_optional_access(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + TL_OPTIONAL_11_CONSTEXPR const T &&value() const && { + if (has_value()) return std::move(this->m_value); + throw bad_optional_access(); + } +#endif + + /// Returns the stored value if there is one, otherwise returns `u` + template + constexpr T value_or(U &&u) const & { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + template + TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + } +}; // namespace tl + +/// Compares two optional objects +template +inline constexpr bool operator==(const optional &lhs, + const optional &rhs) { + return lhs.has_value() == rhs.has_value() && + (!lhs.has_value() || *lhs == *rhs); +} +template +inline constexpr bool operator!=(const optional &lhs, + const optional &rhs) { + return lhs.has_value() != rhs.has_value() || + (lhs.has_value() && *lhs != *rhs); +} +template +inline constexpr bool operator<(const optional &lhs, + const optional &rhs) { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); +} +template +inline constexpr bool operator>(const optional &lhs, + const optional &rhs) { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); +} +template +inline constexpr bool operator<=(const optional &lhs, + const optional &rhs) { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); +} +template +inline constexpr bool operator>=(const optional &lhs, + const optional &rhs) { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); +} + +/// Compares an optional to a `nullopt` +template +inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { + return !lhs.has_value(); +} +template +inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { + return !rhs.has_value(); +} +template +inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { + return lhs.has_value(); +} +template +inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { + return rhs.has_value(); +} +template +inline constexpr bool operator<(const optional &, nullopt_t) noexcept { + return false; +} +template +inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { + return rhs.has_value(); +} +template +inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { + return !lhs.has_value(); +} +template +inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { + return true; +} +template +inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { + return lhs.has_value(); +} +template +inline constexpr bool operator>(nullopt_t, const optional &) noexcept { + return false; +} +template +inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { + return true; +} +template +inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { + return !rhs.has_value(); +} + +/// Compares the optional with a value. +template +inline constexpr bool operator==(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs == rhs : false; +} +template +inline constexpr bool operator==(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs == *rhs : false; +} +template +inline constexpr bool operator!=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs != rhs : true; +} +template +inline constexpr bool operator!=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs != *rhs : true; +} +template +inline constexpr bool operator<(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs < rhs : true; +} +template +inline constexpr bool operator<(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs < *rhs : false; +} +template +inline constexpr bool operator<=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs <= rhs : true; +} +template +inline constexpr bool operator<=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs <= *rhs : false; +} +template +inline constexpr bool operator>(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs > rhs : false; +} +template +inline constexpr bool operator>(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs > *rhs : true; +} +template +inline constexpr bool operator>=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs >= rhs : false; +} +template +inline constexpr bool operator>=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs >= *rhs : true; +} + +template ::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> +void swap(optional &lhs, + optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { + return lhs.swap(rhs); +} + +namespace detail { +struct i_am_secret {}; +} // namespace detail + +template ::value, + detail::decay_t, + T>> +inline constexpr optional make_optional(U &&v) { + return optional(std::forward(v)); +} + +template +inline constexpr optional make_optional(Args &&... args) { + return optional(in_place, std::forward(args)...); +} +template +inline constexpr optional make_optional(std::initializer_list il, + Args &&... args) { + return optional(in_place, il, std::forward(args)...); +} + +#if __cplusplus >= 201703L +template +optional(T)->optional; +#endif + +/// \exclude +namespace detail { +#ifdef TL_OPTIONAL_CXX14 +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto optional_map_impl(Opt &&opt, F &&f) { + return opt.has_value() + ? detail::invoke(std::forward(f), *std::forward(opt)) + : optional(nullopt); +} + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +auto optional_map_impl(Opt &&opt, F &&f) { + if (opt.has_value()) { + detail::invoke(std::forward(f), *std::forward(opt)); + return make_optional(monostate{}); + } + + return optional(nullopt); +} +#else +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto optional_map_impl(Opt &&opt, F &&f) -> optional { + return opt.has_value() + ? detail::invoke(std::forward(f), *std::forward(opt)) + : optional(nullopt); +} + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto optional_map_impl(Opt &&opt, F &&f) -> optional { + if (opt.has_value()) { + detail::invoke(std::forward(f), *std::forward(opt)); + return monostate{}; + } + + return nullopt; +} +#endif +} // namespace detail + +/// Specialization for when `T` is a reference. `optional` acts similarly +/// to a `T*`, but provides more operations and shows intent more clearly. +template +class optional { + public: +// The different versions for C++14 and 11 are needed because deduced return +// types are not SFINAE-safe. This provides better support for things like +// generic lambdas. C.f. +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + template + constexpr auto and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr auto and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } +#endif +#else + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then( + F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + template + constexpr detail::invoke_result_t and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr detail::invoke_result_t and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } +#endif +#endif + +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { + return detail::optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr auto map(F &&f) const & { + return detail::optional_map_impl(*this, std::forward(f)); + } + + template + constexpr auto map(F &&f) const && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } +#else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( + std::declval(), std::declval())) + map(F &&f) & { + return detail::optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( + std::declval(), std::declval())) + map(F &&f) && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr decltype(detail::optional_map_impl( + std::declval(), std::declval())) + map(F &&f) const & { + return detail::optional_map_impl(*this, std::forward(f)); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(detail::optional_map_impl( + std::declval(), std::declval())) + map(F &&f) const && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) & { + return detail::optional_map_impl(*this, std::forward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr auto transform(F &&f) const & { + return detail::optional_map_impl(*this, std::forward(f)); + } + + template + constexpr auto transform(F &&f) const && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } +#else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( + std::declval(), std::declval())) + transform(F &&f) & { + return detail::optional_map_impl(*this, std::forward(f)); + } + + /// \group map + /// \synopsis template auto transform(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( + std::declval(), std::declval())) + transform(F &&f) && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } + + template + constexpr decltype(detail::optional_map_impl( + std::declval(), std::declval())) + transform(F &&f) const & { + return detail::optional_map_impl(*this, std::forward(f)); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(detail::optional_map_impl( + std::declval(), std::declval())) + transform(F &&f) const && { + return detail::optional_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + + /// Calls `f` if the optional is empty + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + if (has_value()) return *this; + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + return has_value() ? *this : std::forward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) && { + if (has_value()) return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { + return has_value() ? std::move(*this) : std::forward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) const & { + if (has_value()) return *this; + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { + return has_value() ? *this : std::forward(f)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template * = nullptr> + optional or_else(F &&f) const && { + if (has_value()) return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + template * = nullptr> + optional or_else(F &&f) const && { + return has_value() ? std::move(*this) : std::forward(f)(); + } +#endif + + /// Maps the stored value with `f` if there is one, otherwise returns `u` + template + U map_or(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + + template + U map_or(F &&f, U &&u) && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } + + template + U map_or(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + U map_or(F &&f, U &&u) const && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } +#endif + + /// Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && { + return has_value() + ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } +#endif + + /// Returns `u` if `*this` has a value, otherwise an empty optional. + template + constexpr optional::type> conjunction(U &&u) const { + using result = optional>; + return has_value() ? result{u} : result{nullopt}; + } + + /// Returns `rhs` if `*this` is empty, otherwise the current value. + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { + return has_value() ? *this : rhs; + } + + constexpr optional disjunction(const optional &rhs) const & { + return has_value() ? *this : rhs; + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(const optional &rhs) const && { + return has_value() ? std::move(*this) : rhs; + } +#endif + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { + return has_value() ? *this : std::move(rhs); + } + + constexpr optional disjunction(optional &&rhs) const & { + return has_value() ? *this : std::move(rhs); + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(optional &&rhs) const && { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + optional take() { + optional ret = std::move(*this); + reset(); + return ret; + } + + using value_type = T &; + + /// Constructs an optional that does not contain a value. + constexpr optional() noexcept : m_value(nullptr) {} + + constexpr optional(nullopt_t) noexcept : m_value(nullptr) {} + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) noexcept = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; + + /// Constructs the stored value with `u`. + template >::value> * = nullptr> + constexpr optional(U &&u) noexcept : m_value(std::addressof(u)) { + static_assert(std::is_lvalue_reference::value, + "U must be an lvalue"); + } + + template + constexpr explicit optional(const optional &rhs) noexcept + : optional(*rhs) {} + + /// No-op + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional &operator=(nullopt_t) noexcept { + m_value = nullptr; + return *this; + } + + /// Copy assignment. + /// + /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise + /// resets the stored value in `*this`. + optional &operator=(const optional &rhs) = default; + + /// Rebinds this optional to `u`. + template >::value> * = nullptr> + optional &operator=(U &&u) { + static_assert(std::is_lvalue_reference::value, + "U must be an lvalue"); + m_value = std::addressof(u); + return *this; + } + + /// Converting copy assignment operator. + /// + /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise + /// resets the stored value in `*this`. + template + optional &operator=(const optional &rhs) noexcept { + m_value = std::addressof(rhs.value()); + return *this; + } + + /// Rebinds this optional to `u`. + template >::value> * = nullptr> + optional &emplace(U &&u) noexcept { + return *this = std::forward(u); + } + + void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); } + + /// Returns a pointer to the stored value + constexpr const T *operator->() const noexcept { return m_value; } + + TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept { return m_value; } + + /// Returns the stored value + TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept { return *m_value; } + + constexpr const T &operator*() const noexcept { return *m_value; } + + constexpr bool has_value() const noexcept { return m_value != nullptr; } + + constexpr explicit operator bool() const noexcept { + return m_value != nullptr; + } + + /// Returns the contained value if there is one, otherwise throws + /// bad_optional_access + TL_OPTIONAL_11_CONSTEXPR T &value() { + if (has_value()) return *m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR const T &value() const { + if (has_value()) return *m_value; + throw bad_optional_access(); + } + + /// Returns the stored value if there is one, otherwise returns `u` + template + constexpr T value_or(U &&u) const &noexcept { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// \group value_or + template + TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && noexcept { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { m_value = nullptr; } + + private: + T *m_value; +}; // namespace tl + + +} // namespace tl + +namespace std { +// TODO SFINAE +template +struct hash> { + ::std::size_t operator()(const tl::optional &o) const { + if (!o.has_value()) return 0; + + return std::hash>()(*o); + } +}; +} // namespace std + +#endif diff --git a/audio/paddleaudio/src/pybind/kaldi/feature_common.h b/audio/paddleaudio/src/pybind/kaldi/feature_common.h new file mode 100644 index 00000000..05522bb7 --- /dev/null +++ b/audio/paddleaudio/src/pybind/kaldi/feature_common.h @@ -0,0 +1,49 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "pybind11/pybind11.h" +#include "pybind11/numpy.h" +#include "feat/feature-window.h" + +namespace paddleaudio { +namespace kaldi { + +namespace py = pybind11; + +template +class StreamingFeatureTpl { + public: + typedef typename F::Options Options; + StreamingFeatureTpl(const Options& opts); + bool ComputeFeature(const ::kaldi::VectorBase<::kaldi::BaseFloat>& wav, + ::kaldi::Vector<::kaldi::BaseFloat>* feats); + void Reset() { remained_wav_.Resize(0); } + + int Dim() { return computer_.Dim(); } + + private: + bool Compute(const ::kaldi::Vector<::kaldi::BaseFloat>& waves, + ::kaldi::Vector<::kaldi::BaseFloat>* feats); + Options opts_; + ::kaldi::FeatureWindowFunction window_function_; + ::kaldi::Vector<::kaldi::BaseFloat> remained_wav_; + F computer_; +}; + +} // namespace kaldi +} // namespace ppspeech + +#include "feature_common_inl.h" diff --git a/audio/paddleaudio/src/pybind/kaldi/feature_common_inl.h b/audio/paddleaudio/src/pybind/kaldi/feature_common_inl.h new file mode 100644 index 00000000..c894b977 --- /dev/null +++ b/audio/paddleaudio/src/pybind/kaldi/feature_common_inl.h @@ -0,0 +1,93 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "base/kaldi-common.h" + +namespace paddleaudio { +namespace kaldi { + +template +StreamingFeatureTpl::StreamingFeatureTpl(const Options& opts) + : opts_(opts), computer_(opts), window_function_(opts.frame_opts) { + // window_function_(computer_.GetFrameOptions()) { the opt set to zero +} + +template +bool StreamingFeatureTpl::ComputeFeature( + const ::kaldi::VectorBase<::kaldi::BaseFloat>& wav, + ::kaldi::Vector<::kaldi::BaseFloat>* feats) { + // append remaned waves + ::kaldi::int32 wav_len = wav.Dim(); + if (wav_len == 0) return false; + ::kaldi::int32 left_len = remained_wav_.Dim(); + ::kaldi::Vector<::kaldi::BaseFloat> waves(left_len + wav_len); + waves.Range(0, left_len).CopyFromVec(remained_wav_); + waves.Range(left_len, wav_len).CopyFromVec(wav); + + // cache remaned waves + ::kaldi::FrameExtractionOptions frame_opts = computer_.GetFrameOptions(); + ::kaldi::int32 num_frames = ::kaldi::NumFrames(waves.Dim(), frame_opts); + ::kaldi::int32 frame_shift = frame_opts.WindowShift(); + ::kaldi::int32 left_samples = waves.Dim() - frame_shift * num_frames; + remained_wav_.Resize(left_samples); + remained_wav_.CopyFromVec( + waves.Range(frame_shift * num_frames, left_samples)); + + // compute speech feature + Compute(waves, feats); + return true; +} + +// Compute feat +template +bool StreamingFeatureTpl::Compute( + const ::kaldi::Vector<::kaldi::BaseFloat>& waves, + ::kaldi::Vector<::kaldi::BaseFloat>* feats) { + ::kaldi::BaseFloat vtln_warp = 1.0; + const ::kaldi::FrameExtractionOptions& frame_opts = + computer_.GetFrameOptions(); + ::kaldi::int32 num_samples = waves.Dim(); + ::kaldi::int32 frame_length = frame_opts.WindowSize(); + ::kaldi::int32 sample_rate = frame_opts.samp_freq; + if (num_samples < frame_length) { + return false; + } + + ::kaldi::int32 num_frames = ::kaldi::NumFrames(num_samples, frame_opts); + feats->Resize(num_frames * Dim()); + + ::kaldi::Vector<::kaldi::BaseFloat> window; + bool need_raw_log_energy = computer_.NeedRawLogEnergy(); + for (::kaldi::int32 frame = 0; frame < num_frames; frame++) { + ::kaldi::BaseFloat raw_log_energy = 0.0; + ::kaldi::ExtractWindow(0, + waves, + frame, + frame_opts, + window_function_, + &window, + need_raw_log_energy ? &raw_log_energy : NULL); + + ::kaldi::Vector<::kaldi::BaseFloat> this_feature(computer_.Dim(), + ::kaldi::kUndefined); + computer_.Compute(raw_log_energy, vtln_warp, &window, &this_feature); + ::kaldi::SubVector<::kaldi::BaseFloat> output_row( + feats->Data() + frame * Dim(), Dim()); + output_row.CopyFromVec(this_feature); + } + return true; +} + +} // namespace kaldi +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/kaldi/kaldi_feature.cc b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature.cc new file mode 100644 index 00000000..40e3786e --- /dev/null +++ b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "paddleaudio/src/pybind/kaldi/kaldi_feature.h" +#include "feat/pitch-functions.h" + +namespace paddleaudio { +namespace kaldi { + +bool InitFbank( + ::kaldi::FrameExtractionOptions frame_opts, + ::kaldi::MelBanksOptions mel_opts, + FbankOptions fbank_opts) { + ::kaldi::FbankOptions opts; + opts.frame_opts = frame_opts; + opts.mel_opts = mel_opts; + opts.use_energy = fbank_opts.use_energy; + opts.energy_floor = fbank_opts.energy_floor; + opts.raw_energy = fbank_opts.raw_energy; + opts.htk_compat = fbank_opts.htk_compat; + opts.use_log_fbank = fbank_opts.use_log_fbank; + opts.use_power = fbank_opts.use_power; + paddleaudio::kaldi::KaldiFeatureWrapper::GetInstance()->InitFbank(opts); + return true; +} + +py::array_t ComputeFbankStreaming(const py::array_t& wav) { + return paddleaudio::kaldi::KaldiFeatureWrapper::GetInstance()->ComputeFbank( + wav); +} + +py::array_t ComputeFbank( + ::kaldi::FrameExtractionOptions frame_opts, + ::kaldi::MelBanksOptions mel_opts, + FbankOptions fbank_opts, + const py::array_t& wav) { + InitFbank(frame_opts, mel_opts, fbank_opts); + py::array_t result = ComputeFbankStreaming(wav); + paddleaudio::kaldi::KaldiFeatureWrapper::GetInstance()->ResetFbank(); + return result; +} + +void ResetFbank() { + paddleaudio::kaldi::KaldiFeatureWrapper::GetInstance()->ResetFbank(); +} + +py::array_t ComputeKaldiPitch( + const ::kaldi::PitchExtractionOptions& opts, + const py::array_t& wav) { + py::buffer_info info = wav.request(); + ::kaldi::SubVector<::kaldi::BaseFloat> input_wav((float*)info.ptr, info.size); + + ::kaldi::Matrix<::kaldi::BaseFloat> features; + ::kaldi::ComputeKaldiPitch(opts, input_wav, &features); + auto result = py::array_t({features.NumRows(), features.NumCols()}); + for (int row_idx = 0; row_idx < features.NumRows(); ++row_idx) { + std::memcpy(result.mutable_data(row_idx), features.Row(row_idx).Data(), + sizeof(float)*features.NumCols()); + } + return result; +} + +} // namespace kaldi +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/kaldi/kaldi_feature.h b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature.h new file mode 100644 index 00000000..e059c52c --- /dev/null +++ b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature.h @@ -0,0 +1,64 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.h" +#include "feat/pitch-functions.h" + +namespace py = pybind11; + +namespace paddleaudio { +namespace kaldi { + +struct FbankOptions{ + bool use_energy; // append an extra dimension with energy to the filter banks + float energy_floor; + bool raw_energy; // If true, compute energy before preemphasis and windowing + bool htk_compat; // If true, put energy last (if using energy) + bool use_log_fbank; // if true (default), produce log-filterbank, else linear + bool use_power; + FbankOptions(): use_energy(false), + energy_floor(0.0), + raw_energy(true), + htk_compat(false), + use_log_fbank(true), + use_power(true) {} +}; + +bool InitFbank( + ::kaldi::FrameExtractionOptions frame_opts, + ::kaldi::MelBanksOptions mel_opts, + FbankOptions fbank_opts); + +py::array_t ComputeFbank( + ::kaldi::FrameExtractionOptions frame_opts, + ::kaldi::MelBanksOptions mel_opts, + FbankOptions fbank_opts, + const py::array_t& wav); + +py::array_t ComputeFbankStreaming(const py::array_t& wav); + +void ResetFbank(); + +py::array_t ComputeKaldiPitch( + const ::kaldi::PitchExtractionOptions& opts, + const py::array_t& wav); + +} // namespace kaldi +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.cc b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.cc new file mode 100644 index 00000000..79558046 --- /dev/null +++ b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.h" + +namespace paddleaudio { +namespace kaldi { + +KaldiFeatureWrapper* KaldiFeatureWrapper::GetInstance() { + static KaldiFeatureWrapper instance; + return &instance; +} + +bool KaldiFeatureWrapper::InitFbank(::kaldi::FbankOptions opts) { + fbank_.reset(new Fbank(opts)); + return true; +} + +py::array_t KaldiFeatureWrapper::ComputeFbank( + const py::array_t wav) { + py::buffer_info info = wav.request(); + ::kaldi::SubVector<::kaldi::BaseFloat> input_wav((float*)info.ptr, info.size); + + ::kaldi::Vector<::kaldi::BaseFloat> feats; + bool flag = fbank_->ComputeFeature(input_wav, &feats); + if (flag == false || feats.Dim() == 0) return py::array_t(); + auto result = py::array_t(feats.Dim()); + py::buffer_info xs = result.request(); + std::cout << std::endl; + float* res_ptr = (float*)xs.ptr; + for (int idx = 0; idx < feats.Dim(); ++idx) { + *res_ptr = feats(idx); + res_ptr++; + } + + return result.reshape({feats.Dim() / Dim(), Dim()}); +} + +} // namesapce kaldi +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.h b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.h new file mode 100644 index 00000000..bee1eee0 --- /dev/null +++ b/audio/paddleaudio/src/pybind/kaldi/kaldi_feature_wrapper.h @@ -0,0 +1,40 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "base/kaldi-common.h" +#include "feat/feature-fbank.h" + +#include "paddleaudio/src/pybind/kaldi/feature_common.h" + +namespace paddleaudio { +namespace kaldi { + +typedef StreamingFeatureTpl<::kaldi::FbankComputer> Fbank; + +class KaldiFeatureWrapper { + public: + static KaldiFeatureWrapper* GetInstance(); + bool InitFbank(::kaldi::FbankOptions opts); + py::array_t ComputeFbank(const py::array_t wav); + int Dim() { return fbank_->Dim(); } + void ResetFbank() { fbank_->Reset(); } + + private: + std::unique_ptr fbank_; +}; + +} // namespace kaldi +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/pybind.cpp b/audio/paddleaudio/src/pybind/pybind.cpp new file mode 100644 index 00000000..c4dfa8d5 --- /dev/null +++ b/audio/paddleaudio/src/pybind/pybind.cpp @@ -0,0 +1,148 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. + +#include "paddleaudio/src/pybind/kaldi/kaldi_feature.h" +#include "paddleaudio/third_party/kaldi/feat/feature-fbank.h" + +#ifdef INCLUDE_SOX +#include "paddleaudio/src/pybind/sox/io.h" +#include "paddleaudio/src/pybind/sox/effects.h" +#endif + +#include +#include + +// `tl::optional` +#ifdef INCLUDE_SOX +namespace pybind11 { namespace detail { + template + struct type_caster> : optional_caster> {}; +}} +#endif + +PYBIND11_MODULE(_paddleaudio, m) { +#ifdef INCLUDE_SOX + m.def("get_info_file", + &paddleaudio::sox_io::get_info_file, + "Get metadata of audio file."); + // support obj later + m.def("get_info_fileobj", + &paddleaudio::sox_io::get_info_fileobj, + "Get metadata of audio in file object."); + m.def("load_audio_fileobj", + &paddleaudio::sox_io::load_audio_fileobj, + "Load audio from file object."); + m.def("save_audio_fileobj", + &paddleaudio::sox_io::save_audio_fileobj, + "Save audio to file obj."); + + // sox io + m.def("sox_io_get_info", &paddleaudio::sox_io::get_info_file); + m.def( + "sox_io_load_audio_file", + &paddleaudio::sox_io::load_audio_file); + m.def( + "sox_io_save_audio_file", + &paddleaudio::sox_io::save_audio_file); + + // sox utils + m.def("sox_utils_set_seed", &paddleaudio::sox_utils::set_seed); + m.def( + "sox_utils_set_verbosity", + &paddleaudio::sox_utils::set_verbosity); + m.def( + "sox_utils_set_use_threads", + &paddleaudio::sox_utils::set_use_threads); + m.def( + "sox_utils_set_buffer_size", + &paddleaudio::sox_utils::set_buffer_size); + m.def( + "sox_utils_list_effects", + &paddleaudio::sox_utils::list_effects); + m.def( + "sox_utils_list_read_formats", + &paddleaudio::sox_utils::list_read_formats); + m.def( + "sox_utils_list_write_formats", + &paddleaudio::sox_utils::list_write_formats); + m.def( + "sox_utils_get_buffer_size", + &paddleaudio::sox_utils::get_buffer_size); + + // effect + m.def("apply_effects_fileobj", + &paddleaudio::sox_effects::apply_effects_fileobj, + "Decode audio data from file-like obj and apply effects."); + m.def("sox_effects_initialize_sox_effects", + &paddleaudio::sox_effects::initialize_sox_effects); + m.def( + "sox_effects_shutdown_sox_effects", + &paddleaudio::sox_effects::shutdown_sox_effects); + m.def( + "sox_effects_apply_effects_tensor", + &paddleaudio::sox_effects::apply_effects_tensor); + m.def( + "sox_effects_apply_effects_file", + &paddleaudio::sox_effects::apply_effects_file); +#endif + +#ifdef INCLUDE_KALDI + m.def("ComputeFbank", &paddleaudio::kaldi::ComputeFbank, "compute fbank"); + py::class_(m, "PitchExtractionOptions") + .def(py::init<>()) + .def_readwrite("samp_freq", &kaldi::PitchExtractionOptions::samp_freq) + .def_readwrite("frame_shift_ms", &kaldi::PitchExtractionOptions::frame_shift_ms) + .def_readwrite("frame_length_ms", &kaldi::PitchExtractionOptions::frame_length_ms) + .def_readwrite("preemph_coeff", &kaldi::PitchExtractionOptions::preemph_coeff) + .def_readwrite("min_f0", &kaldi::PitchExtractionOptions::min_f0) + .def_readwrite("max_f0", &kaldi::PitchExtractionOptions::max_f0) + .def_readwrite("soft_min_f0", &kaldi::PitchExtractionOptions::soft_min_f0) + .def_readwrite("penalty_factor", &kaldi::PitchExtractionOptions::penalty_factor) + .def_readwrite("lowpass_cutoff", &kaldi::PitchExtractionOptions::lowpass_cutoff) + .def_readwrite("resample_freq", &kaldi::PitchExtractionOptions::resample_freq) + .def_readwrite("delta_pitch", &kaldi::PitchExtractionOptions::delta_pitch) + .def_readwrite("nccf_ballast", &kaldi::PitchExtractionOptions::nccf_ballast) + .def_readwrite("lowpass_filter_width", &kaldi::PitchExtractionOptions::lowpass_filter_width) + .def_readwrite("upsample_filter_width", &kaldi::PitchExtractionOptions::upsample_filter_width) + .def_readwrite("max_frames_latency", &kaldi::PitchExtractionOptions::max_frames_latency) + .def_readwrite("frames_per_chunk", &kaldi::PitchExtractionOptions::frames_per_chunk) + .def_readwrite("simulate_first_pass_online", &kaldi::PitchExtractionOptions::simulate_first_pass_online) + .def_readwrite("recompute_frame", &kaldi::PitchExtractionOptions::recompute_frame) + .def_readwrite("nccf_ballast_online", &kaldi::PitchExtractionOptions::nccf_ballast_online) + .def_readwrite("snip_edges", &kaldi::PitchExtractionOptions::snip_edges); + m.def("ComputeKaldiPitch", &paddleaudio::kaldi::ComputeKaldiPitch, "compute kaldi pitch"); + py::class_(m, "FrameExtractionOptions") + .def(py::init<>()) + .def_readwrite("samp_freq", &kaldi::FrameExtractionOptions::samp_freq) + .def_readwrite("frame_shift_ms", &kaldi::FrameExtractionOptions::frame_shift_ms) + .def_readwrite("frame_length_ms", &kaldi::FrameExtractionOptions::frame_length_ms) + .def_readwrite("dither", &kaldi::FrameExtractionOptions::dither) + .def_readwrite("preemph_coeff", &kaldi::FrameExtractionOptions::preemph_coeff) + .def_readwrite("remove_dc_offset", &kaldi::FrameExtractionOptions::remove_dc_offset) + .def_readwrite("window_type", &kaldi::FrameExtractionOptions::window_type) + .def_readwrite("round_to_power_of_two", &kaldi::FrameExtractionOptions::round_to_power_of_two) + .def_readwrite("blackman_coeff", &kaldi::FrameExtractionOptions::blackman_coeff) + .def_readwrite("snip_edges", &kaldi::FrameExtractionOptions::snip_edges) + .def_readwrite("allow_downsample", &kaldi::FrameExtractionOptions::allow_downsample) + .def_readwrite("allow_upsample", &kaldi::FrameExtractionOptions::allow_upsample) + .def_readwrite("max_feature_vectors", &kaldi::FrameExtractionOptions::max_feature_vectors); + py::class_(m, "MelBanksOptions") + .def(py::init<>()) + .def_readwrite("num_bins", &kaldi::MelBanksOptions::num_bins) + .def_readwrite("low_freq", &kaldi::MelBanksOptions::low_freq) + .def_readwrite("high_freq", &kaldi::MelBanksOptions::high_freq) + .def_readwrite("vtln_low", &kaldi::MelBanksOptions::vtln_low) + .def_readwrite("vtln_high", &kaldi::MelBanksOptions::vtln_high) + .def_readwrite("debug_mel", &kaldi::MelBanksOptions::debug_mel) + .def_readwrite("htk_mode", &kaldi::MelBanksOptions::htk_mode); + + py::class_(m, "FbankOptions") + .def(py::init<>()) + .def_readwrite("use_energy", &paddleaudio::kaldi::FbankOptions::use_energy) + .def_readwrite("energy_floor", &paddleaudio::kaldi::FbankOptions::energy_floor) + .def_readwrite("raw_energy", &paddleaudio::kaldi::FbankOptions::raw_energy) + .def_readwrite("htk_compat", &paddleaudio::kaldi::FbankOptions::htk_compat) + .def_readwrite("use_log_fbank", &paddleaudio::kaldi::FbankOptions::use_log_fbank) + .def_readwrite("use_power", &paddleaudio::kaldi::FbankOptions::use_power); +#endif + +} diff --git a/audio/paddleaudio/src/pybind/sox/effects.cpp b/audio/paddleaudio/src/pybind/sox/effects.cpp new file mode 100644 index 00000000..ea77527b --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/effects.cpp @@ -0,0 +1,259 @@ +// the code is from https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/effects.cpp with modification. + +#include +#include + +#include "paddleaudio/src/pybind/sox/effects.h" +#include "paddleaudio/src/pybind/sox/effects_chain.h" +#include "paddleaudio/src/pybind/sox/utils.h" + +using namespace paddleaudio::sox_utils; + +namespace paddleaudio::sox_effects { + +// Streaming decoding over file-like object is tricky because libsox operates on +// FILE pointer. The folloing is what `sox` and `play` commands do +// - file input -> FILE pointer +// - URL input -> call wget in suprocess and pipe the data -> FILE pointer +// - stdin -> FILE pointer +// +// We want to, instead, fetch byte strings chunk by chunk, consume them, and +// discard. +// +// Here is the approach +// 1. Initialize sox_format_t using sox_open_mem_read, providing the initial +// chunk of byte string +// This will perform header-based format detection, if necessary, then fill +// the metadata of sox_format_t. Internally, sox_open_mem_read uses fmemopen, +// which returns FILE* which points the buffer of the provided byte string. +// 2. Each time sox reads a chunk from the FILE*, we update the underlying +// buffer in a way that it +// starts with unseen data, and append the new data read from the given +// fileobj. This will trick libsox as if it keeps reading from the FILE* +// continuously. +// For Step 2. see `fileobj_input_drain` function in effects_chain.cpp +auto apply_effects_fileobj( + py::object fileobj, + const std::vector>& effects, + tl::optional normalize, + tl::optional channels_first, + tl::optional format) + -> tl::optional> { + // Prepare the buffer used throughout the lifecycle of SoxEffectChain. + // + // For certain format (such as FLAC), libsox keeps reading the content at + // the initialization unless it reaches EOF even when the header is properly + // parsed. (Making buffer size 8192, which is way bigger than the header, + // resulted in libsox consuming all the buffer content at the time it opens + // the file.) Therefore buffer has to always contain valid data, except after + // EOF. We default to `sox_get_globals()->bufsiz`* for buffer size and we + // first check if there is enough data to fill the buffer. `read_fileobj` + // repeatedly calls `read` method until it receives the requested length of + // bytes or it reaches EOF. If we get bytes shorter than requested, that means + // the whole audio data are fetched. + // + // * This can be changed with `paddleaudio.utils.sox_utils.set_buffer_size`. + const auto capacity = [&]() { + // NOTE: + // Use the abstraction provided by `libpaddleaudio` to access the global + // config defined by libsox. Directly using `sox_get_globals` function will + // end up retrieving the static variable defined in `_paddleaudio`, which is + // not correct. + const auto bufsiz = get_buffer_size(); + const int64_t kDefaultCapacityInBytes = 256; + return (bufsiz > kDefaultCapacityInBytes) ? bufsiz + : kDefaultCapacityInBytes; + }(); + std::string buffer(capacity, '\0'); + auto* in_buf = const_cast(buffer.data()); + auto num_read = read_fileobj(&fileobj, capacity, in_buf); + // If the file is shorter than 256, then libsox cannot read the header. + auto in_buffer_size = (num_read > 256) ? num_read : 256; + + // Open file (this starts reading the header) + // When opening a file there are two functions that can touches FILE*. + // * `auto_detect_format` + // https://github.com/dmkrepo/libsox/blob/b9dd1a86e71bbd62221904e3e59dfaa9e5e72046/src/formats.c#L43 + // * `startread` handler of detected format. + // https://github.com/dmkrepo/libsox/blob/b9dd1a86e71bbd62221904e3e59dfaa9e5e72046/src/formats.c#L574 + // To see the handler of a particular format, go to + // https://github.com/dmkrepo/libsox/blob/b9dd1a86e71bbd62221904e3e59dfaa9e5e72046/src/.c + // For example, voribs can be found + // https://github.com/dmkrepo/libsox/blob/b9dd1a86e71bbd62221904e3e59dfaa9e5e72046/src/vorbis.c#L97-L158 + SoxFormat sf(sox_open_mem_read( + in_buf, + in_buffer_size, + /*signal=*/nullptr, + /*encoding=*/nullptr, + /*filetype=*/format.has_value() ? format.value().c_str() : nullptr)); + + // In case of streamed data, length can be 0 + if (static_cast(sf) == nullptr || + sf->encoding.encoding == SOX_ENCODING_UNKNOWN) { + return {}; + } + + // Prepare output buffer + std::vector out_buffer; + out_buffer.reserve(sf->signal.length); + + // Create and run SoxEffectsChain + const auto dtype = get_dtype(sf->encoding.encoding, sf->signal.precision); + paddleaudio::sox_effects_chain::SoxEffectsChainPyBind chain( + /*input_encoding=*/sf->encoding, + /*output_encoding=*/get_tensor_encodinginfo(dtype)); + chain.addInputFileObj(sf, in_buf, in_buffer_size, &fileobj); + for (const auto& effect : effects) { + chain.addEffect(effect); + } + chain.addOutputBuffer(&out_buffer); + chain.run(); + + // Create tensor from buffer + bool channels_first_ = channels_first.value_or(true); + auto tensor = convert_to_tensor( + /*buffer=*/out_buffer.data(), + /*num_samples=*/out_buffer.size(), + /*num_channels=*/chain.getOutputNumChannels(), + dtype, + normalize.value_or(true), + channels_first_); + + return std::forward_as_tuple( + tensor, static_cast(chain.getOutputSampleRate())); +} + +namespace { + +enum SoxEffectsResourceState { NotInitialized, Initialized, ShutDown }; +SoxEffectsResourceState SOX_RESOURCE_STATE = NotInitialized; +std::mutex SOX_RESOUCE_STATE_MUTEX; + +} // namespace + +void initialize_sox_effects() { + const std::lock_guard lock(SOX_RESOUCE_STATE_MUTEX); + + switch (SOX_RESOURCE_STATE) { + case NotInitialized: + if (sox_init() != SOX_SUCCESS) { + throw std::runtime_error("Failed to initialize sox effects."); + }; + SOX_RESOURCE_STATE = Initialized; + break; + case Initialized: + break; + case ShutDown: + throw std::runtime_error( + "SoX Effects has been shut down. Cannot initialize again."); + } +}; + +void shutdown_sox_effects() { + const std::lock_guard lock(SOX_RESOUCE_STATE_MUTEX); + + switch (SOX_RESOURCE_STATE) { + case NotInitialized: + throw std::runtime_error( + "SoX Effects is not initialized. Cannot shutdown."); + case Initialized: + if (sox_quit() != SOX_SUCCESS) { + throw std::runtime_error("Failed to initialize sox effects."); + }; + SOX_RESOURCE_STATE = ShutDown; + break; + case ShutDown: + break; + } +} + +auto apply_effects_tensor( + py::array waveform, + int64_t sample_rate, + const std::vector>& effects, + bool channels_first) -> std::tuple { + validate_input_tensor(waveform); + + // Create SoxEffectsChain + const auto dtype = waveform.dtype(); + paddleaudio::sox_effects_chain::SoxEffectsChain chain( + /*input_encoding=*/get_tensor_encodinginfo(dtype), + /*output_encoding=*/get_tensor_encodinginfo(dtype)); + + // Prepare output buffer + std::vector out_buffer; + out_buffer.reserve(waveform.size()); + + // Build and run effects chain + chain.addInputTensor(&waveform, sample_rate, channels_first); + for (const auto& effect : effects) { + chain.addEffect(effect); + } + chain.addOutputBuffer(&out_buffer); + chain.run(); + + // Create tensor from buffer + auto out_tensor = convert_to_tensor( + /*buffer=*/out_buffer.data(), + /*num_samples=*/out_buffer.size(), + /*num_channels=*/chain.getOutputNumChannels(), + dtype, + /*normalize=*/false, + channels_first); + + return std::tuple( + out_tensor, chain.getOutputSampleRate()); +} + +auto apply_effects_file( + const std::string& path, + const std::vector>& effects, + tl::optional normalize, + tl::optional channels_first, + const tl::optional& format) + -> tl::optional> { + // Open input file + SoxFormat sf(sox_open_read( + path.c_str(), + /*signal=*/nullptr, + /*encoding=*/nullptr, + /*filetype=*/format.has_value() ? format.value().c_str() : nullptr)); + + if (static_cast(sf) == nullptr || + sf->encoding.encoding == SOX_ENCODING_UNKNOWN) { + return {}; + } + + const auto dtype = get_dtype(sf->encoding.encoding, sf->signal.precision); + + // Prepare output + std::vector out_buffer; + out_buffer.reserve(sf->signal.length); + + // Create and run SoxEffectsChain + paddleaudio::sox_effects_chain::SoxEffectsChain chain( + /*input_encoding=*/sf->encoding, + /*output_encoding=*/get_tensor_encodinginfo(dtype)); + + chain.addInputFile(sf); + for (const auto& effect : effects) { + chain.addEffect(effect); + } + chain.addOutputBuffer(&out_buffer); + chain.run(); + + // Create tensor from buffer + bool channels_first_ = channels_first.value_or(true); + auto tensor = convert_to_tensor( + /*buffer=*/out_buffer.data(), + /*num_samples=*/out_buffer.size(), + /*num_channels=*/chain.getOutputNumChannels(), + dtype, + normalize.value_or(true), + channels_first_); + + return std::tuple( + tensor, chain.getOutputSampleRate()); +} + +} // namespace paddleaudio::sox_effects diff --git a/audio/paddleaudio/src/pybind/sox/effects.h b/audio/paddleaudio/src/pybind/sox/effects.h new file mode 100644 index 00000000..5143db46 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/effects.h @@ -0,0 +1,37 @@ +// the code is from https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/effects.h with modification. +#include +#include + +#include "paddleaudio/src/optional/optional.hpp" + +namespace py = pybind11; + +namespace paddleaudio::sox_effects { + +auto apply_effects_fileobj( + py::object fileobj, + const std::vector>& effects, + tl::optional normalize, + tl::optional channels_first, + tl::optional format) + -> tl::optional>; + +void initialize_sox_effects(); + +void shutdown_sox_effects(); + +auto apply_effects_tensor( + py::array waveform, + int64_t sample_rate, + const std::vector>& effects, + bool channels_first) -> std::tuple; + +auto apply_effects_file( + const std::string& path, + const std::vector>& effects, + tl::optional normalize, + tl::optional channels_first, + const tl::optional& format) + -> tl::optional>; + +} // namespace paddleaudio::sox_effects diff --git a/audio/paddleaudio/src/pybind/sox/effects_chain.cpp b/audio/paddleaudio/src/pybind/sox/effects_chain.cpp new file mode 100644 index 00000000..0204fb30 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/effects_chain.cpp @@ -0,0 +1,597 @@ +// the code is from https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/effects_chain.cpp with modification. + +#include +#include +#include +#include "paddleaudio/src/pybind/sox/effects_chain.h" +#include "paddleaudio/src/pybind/sox/utils.h" + +using namespace paddleaudio::sox_utils; + +namespace paddleaudio::sox_effects_chain { + +namespace { + +/// helper classes for passing the location of input tensor and output buffer +/// +/// drain/flow callback functions require plaing C style function signature and +/// the way to pass extra data is to attach data to sox_effect_t::priv pointer. +/// The following structs will be assigned to sox_effect_t::priv pointer which +/// gives sox_effect_t an access to input Tensor and output buffer object. +struct TensorInputPriv { + size_t index; + py::array* waveform; + int64_t sample_rate; + bool channels_first; +}; + +struct TensorOutputPriv { + std::vector* buffer; +}; +struct FileOutputPriv { + sox_format_t* sf; +}; + +/// Callback function to feed Tensor data to SoxEffectChain. +int tensor_input_drain(sox_effect_t* effp, sox_sample_t* obuf, size_t* osamp) { + // Retrieve the input Tensor and current index + auto priv = static_cast(effp->priv); + auto index = priv->index; + auto tensor = *(priv->waveform); + auto num_channels = effp->out_signal.channels; + + // Adjust the number of samples to read + const size_t num_samples = tensor.size(); + if (index + *osamp > num_samples) { + *osamp = num_samples - index; + } + + // Ensure that it's a multiple of the number of channels + *osamp -= *osamp % num_channels; + + // Slice the input Tensor + // refacor this module, chunk + auto i_frame = index / num_channels; + auto num_frames = *osamp / num_channels; + + std::vector chunk(num_frames*num_channels); + py::buffer_info ori_info = tensor.request(); + void* ptr = ori_info.ptr; + // Convert to sox_sample_t (int32_t) + switch (tensor.dtype().num()) { + //case c10::ScalarType::Float: { + case 11: { + // Need to convert to 64-bit precision so that + // values around INT32_MIN/MAX are handled correctly. + for (int idx = 0; idx < chunk.size(); ++idx) { + int frame_idx = (idx + index) / num_channels; + int channels_idx = (idx + index) % num_channels; + double elem = 0; + if (priv->channels_first) { + elem = *(float*)tensor.data(channels_idx, frame_idx); + } else { + elem = *(float*)tensor.data(frame_idx, channels_idx); + } + elem = elem * 2147483648.; + // *new_ptr = std::clamp(elem, INT32_MIN, INT32_MAX); + if (elem > INT32_MAX) { + chunk[idx] = INT32_MAX; + } else if (elem < INT32_MIN) { + chunk[idx] = INT32_MIN; + } else { + chunk[idx] = elem; + } + } + break; + } + //case c10::ScalarType::Int: { + case 5: { + for (int idx = 0; idx < chunk.size(); ++idx) { + int frame_idx = (idx + index) / num_channels; + int channels_idx = (idx + index) % num_channels; + int elem = 0; + if (priv->channels_first) { + elem = *(int*)tensor.data(channels_idx, frame_idx); + } else { + elem = *(int*)tensor.data(frame_idx, channels_idx); + } + chunk[idx] = elem; + } + break; + } + // case short + case 3: { + for (int idx = 0; idx < chunk.size(); ++idx) { + int frame_idx = (idx + index) / num_channels; + int channels_idx = (idx + index) % num_channels; + int16_t elem = 0; + if (priv->channels_first) { + elem = *(int16_t*)tensor.data(channels_idx, frame_idx); + } else { + elem = *(int16_t*)tensor.data(frame_idx, channels_idx); + } + chunk[idx] = elem * 65536; + } + break; + } + // case byte + case 1: { + for (int idx = 0; idx < chunk.size(); ++idx) { + int frame_idx = (idx + index) / num_channels; + int channels_idx = (idx + index) % num_channels; + int8_t elem = 0; + if (priv->channels_first) { + elem = *(int8_t*)tensor.data(channels_idx, frame_idx); + } else { + elem = *(int8_t*)tensor.data(frame_idx, channels_idx); + } + chunk[idx] = (elem - 128) * 16777216; + } + break; + } + default: + throw std::runtime_error("Unexpected dtype."); + } + // Write to buffer + memcpy(obuf, chunk.data(), *osamp * 4); + priv->index += *osamp; + return (priv->index == num_samples) ? SOX_EOF : SOX_SUCCESS; +} + +/// Callback function to fetch data from SoxEffectChain. +int tensor_output_flow( + sox_effect_t* effp, + sox_sample_t const* ibuf, + sox_sample_t* obuf LSX_UNUSED, + size_t* isamp, + size_t* osamp) { + *osamp = 0; + // Get output buffer + auto out_buffer = static_cast(effp->priv)->buffer; + // Append at the end + out_buffer->insert(out_buffer->end(), ibuf, ibuf + *isamp); + return SOX_SUCCESS; +} + +int file_output_flow( + sox_effect_t* effp, + sox_sample_t const* ibuf, + sox_sample_t* obuf LSX_UNUSED, + size_t* isamp, + size_t* osamp) { + *osamp = 0; + if (*isamp) { + auto sf = static_cast(effp->priv)->sf; + if (sox_write(sf, ibuf, *isamp) != *isamp) { + if (sf->sox_errno) { + std::ostringstream stream; + stream << sf->sox_errstr << " " << sox_strerror(sf->sox_errno) << " " + << sf->filename; + throw std::runtime_error(stream.str()); + } + return SOX_EOF; + } + } + return SOX_SUCCESS; +} + +sox_effect_handler_t* get_tensor_input_handler() { + static sox_effect_handler_t handler{ + /*name=*/"input_tensor", + /*usage=*/NULL, + /*flags=*/SOX_EFF_MCHAN, + /*getopts=*/NULL, + /*start=*/NULL, + /*flow=*/NULL, + /*drain=*/tensor_input_drain, + /*stop=*/NULL, + /*kill=*/NULL, + /*priv_size=*/sizeof(TensorInputPriv)}; + return &handler; +} + +sox_effect_handler_t* get_tensor_output_handler() { + static sox_effect_handler_t handler{ + /*name=*/"output_tensor", + /*usage=*/NULL, + /*flags=*/SOX_EFF_MCHAN, + /*getopts=*/NULL, + /*start=*/NULL, + /*flow=*/tensor_output_flow, + /*drain=*/NULL, + /*stop=*/NULL, + /*kill=*/NULL, + /*priv_size=*/sizeof(TensorOutputPriv)}; + return &handler; +} + +sox_effect_handler_t* get_file_output_handler() { + static sox_effect_handler_t handler{ + /*name=*/"output_file", + /*usage=*/NULL, + /*flags=*/SOX_EFF_MCHAN, + /*getopts=*/NULL, + /*start=*/NULL, + /*flow=*/file_output_flow, + /*drain=*/NULL, + /*stop=*/NULL, + /*kill=*/NULL, + /*priv_size=*/sizeof(FileOutputPriv)}; + return &handler; +} + +} // namespace + +SoxEffect::SoxEffect(sox_effect_t* se) noexcept : se_(se) {} + +SoxEffect::~SoxEffect() { + if (se_ != nullptr) { + free(se_); + } +} + +SoxEffect::operator sox_effect_t*() const { + return se_; +} + +auto SoxEffect::operator->() noexcept -> sox_effect_t* { + return se_; +} + +SoxEffectsChain::SoxEffectsChain( + sox_encodinginfo_t input_encoding, + sox_encodinginfo_t output_encoding) + : in_enc_(input_encoding), + out_enc_(output_encoding), + in_sig_(), + interm_sig_(), + out_sig_(), + sec_(sox_create_effects_chain(&in_enc_, &out_enc_)) { + if (!sec_) { + throw std::runtime_error("Failed to create effect chain."); + } +} + +SoxEffectsChain::~SoxEffectsChain() { + if (sec_ != nullptr) { + sox_delete_effects_chain(sec_); + } +} + +void SoxEffectsChain::run() { + sox_flow_effects(sec_, NULL, NULL); +} + +void SoxEffectsChain::addInputTensor( + py::array* waveform, + int64_t sample_rate, + bool channels_first) { + in_sig_ = get_signalinfo(waveform, sample_rate, "wav", channels_first); + interm_sig_ = in_sig_; + SoxEffect e(sox_create_effect(get_tensor_input_handler())); + auto priv = static_cast(e->priv); + priv->index = 0; + priv->waveform = waveform; + priv->sample_rate = sample_rate; + priv->channels_first = channels_first; + if (sox_add_effect(sec_, e, &interm_sig_, &in_sig_) != SOX_SUCCESS) { + throw std::runtime_error( + "Internal Error: Failed to add effect: input_tensor"); + } +} + +void SoxEffectsChain::addOutputBuffer( + std::vector* output_buffer) { + SoxEffect e(sox_create_effect(get_tensor_output_handler())); + static_cast(e->priv)->buffer = output_buffer; + if (sox_add_effect(sec_, e, &interm_sig_, &in_sig_) != SOX_SUCCESS) { + throw std::runtime_error( + "Internal Error: Failed to add effect: output_tensor"); + } +} + +void SoxEffectsChain::addInputFile(sox_format_t* sf) { + in_sig_ = sf->signal; + interm_sig_ = in_sig_; + SoxEffect e(sox_create_effect(sox_find_effect("input"))); + char* opts[] = {(char*)sf}; + sox_effect_options(e, 1, opts); + if (sox_add_effect(sec_, e, &interm_sig_, &in_sig_) != SOX_SUCCESS) { + std::ostringstream stream; + stream << "Internal Error: Failed to add effect: input " << sf->filename; + throw std::runtime_error(stream.str()); + } +} + +void SoxEffectsChain::addOutputFile(sox_format_t* sf) { + out_sig_ = sf->signal; + SoxEffect e(sox_create_effect(get_file_output_handler())); + static_cast(e->priv)->sf = sf; + if (sox_add_effect(sec_, e, &interm_sig_, &out_sig_) != SOX_SUCCESS) { + std::ostringstream stream; + stream << "Internal Error: Failed to add effect: output " << sf->filename; + throw std::runtime_error(stream.str()); + } +} + +void SoxEffectsChain::addEffect(const std::vector effect) { + const auto num_args = effect.size(); + if (num_args == 0) { + throw std::runtime_error("Invalid argument: empty effect."); + } + const auto name = effect[0]; + if (UNSUPPORTED_EFFECTS.find(name) != UNSUPPORTED_EFFECTS.end()) { + std::ostringstream stream; + stream << "Unsupported effect: " << name; + throw std::runtime_error(stream.str()); + } + + auto returned_effect = sox_find_effect(name.c_str()); + if (!returned_effect) { + std::ostringstream stream; + stream << "Unsupported effect: " << name; + throw std::runtime_error(stream.str()); + } + SoxEffect e(sox_create_effect(returned_effect)); + const auto num_options = num_args - 1; + + std::vector opts; + for (size_t i = 1; i < num_args; ++i) { + opts.push_back((char*)effect[i].c_str()); + } + if (sox_effect_options(e, num_options, num_options ? opts.data() : nullptr) != + SOX_SUCCESS) { + std::ostringstream stream; + stream << "Invalid effect option:"; + for (const auto& v : effect) { + stream << " " << v; + } + throw std::runtime_error(stream.str()); + } + + if (sox_add_effect(sec_, e, &interm_sig_, &in_sig_) != SOX_SUCCESS) { + std::ostringstream stream; + stream << "Internal Error: Failed to add effect: \"" << name; + for (size_t i = 1; i < num_args; ++i) { + stream << " " << effect[i]; + } + stream << "\""; + throw std::runtime_error(stream.str()); + } +} + +int64_t SoxEffectsChain::getOutputNumChannels() { + return interm_sig_.channels; +} + +int64_t SoxEffectsChain::getOutputSampleRate() { + return interm_sig_.rate; +} + +namespace { + +/// helper classes for passing file-like object to SoxEffectChain +struct FileObjInputPriv { + sox_format_t* sf; + py::object* fileobj; + bool eof_reached; + char* buffer; + uint64_t buffer_size; +}; + +struct FileObjOutputPriv { + sox_format_t* sf; + py::object* fileobj; + char** buffer; + size_t* buffer_size; +}; + +/// Callback function to feed byte string +/// https://github.com/dmkrepo/libsox/blob/b9dd1a86e71bbd62221904e3e59dfaa9e5e72046/src/sox.h#L1268-L1278 +auto fileobj_input_drain(sox_effect_t* effp, sox_sample_t* obuf, size_t* osamp) + -> int { + auto priv = static_cast(effp->priv); + auto sf = priv->sf; + auto buffer = priv->buffer; + + // 1. Refresh the buffer + // + // NOTE: + // Since the underlying FILE* was opened with `fmemopen`, the only way + // libsox detect EOF is reaching the end of the buffer. (null byte won't + // help) Therefore we need to align the content at the end of buffer, + // otherwise, libsox will keep reading the content beyond intended length. + // + // Before: + // + // |<-------consumed------>|<---remaining--->| + // |***********************|-----------------| + // ^ ftell + // + // After: + // + // |<-offset->|<---remaining--->|<-new data->| + // |**********|-----------------|++++++++++++| + // ^ ftell + + // NOTE: + // Do not use `sf->tell_off` here. Presumably, `tell_off` and `fseek` are + // supposed to be in sync, but there are cases (Vorbis) they are not + // in sync and `tell_off` has seemingly uninitialized value, which + // leads num_remain to be negative and cause segmentation fault + // in `memmove`. + const auto tell = ftell((FILE*)sf->fp); + if (tell < 0) { + throw std::runtime_error("Internal Error: ftell failed."); + } + const auto num_consumed = static_cast(tell); + if (num_consumed > priv->buffer_size) { + throw std::runtime_error("Internal Error: buffer overrun."); + } + + const auto num_remain = priv->buffer_size - num_consumed; + + // 1.1. Fetch the data to see if there is data to fill the buffer + size_t num_refill = 0; + std::string chunk(num_consumed, '\0'); + if (num_consumed && !priv->eof_reached) { + num_refill = read_fileobj( + priv->fileobj, num_consumed, const_cast(chunk.data())); + if (num_refill < num_consumed) { + priv->eof_reached = true; + } + } + const auto offset = num_consumed - num_refill; + + // 1.2. Move the unconsumed data towards the beginning of buffer. + if (num_remain) { + auto src = static_cast(buffer + num_consumed); + auto dst = static_cast(buffer + offset); + memmove(dst, src, num_remain); + } + + // 1.3. Refill the remaining buffer. + if (num_refill) { + auto src = static_cast(const_cast(chunk.c_str())); + auto dst = buffer + offset + num_remain; + memcpy(dst, src, num_refill); + } + + // 1.4. Set the file pointer to the new offset + sf->tell_off = offset; + fseek((FILE*)sf->fp, offset, SEEK_SET); + + // 2. Perform decoding operation + // The following part is practically same as "input" effect + // https://github.com/dmkrepo/libsox/blob/b9dd1a86e71bbd62221904e3e59dfaa9e5e72046/src/input.c#L30-L48 + + // At this point, osamp represents the buffer size in bytes, + // but sox_read expects the maximum number of samples ready to read. + // Normally, this is fine, but in case when the samples are not 4-byte + // aligned, (e.g. sample is 24bits), the resulting signal is not correct. + // https://github.com/pytorch/audio/issues/2083 + if (sf->encoding.bits_per_sample > 0) + *osamp /= (sf->encoding.bits_per_sample / 8); + + // Ensure that it's a multiple of the number of channels + *osamp -= *osamp % effp->out_signal.channels; + + // Read up to *osamp samples into obuf; + // store the actual number read back to *osamp + *osamp = sox_read(sf, obuf, *osamp); + + // Decoding is finished when fileobject is exhausted and sox can no longer + // decode a sample. + return (priv->eof_reached && !*osamp) ? SOX_EOF : SOX_SUCCESS; +} + +auto fileobj_output_flow( + sox_effect_t* effp, + sox_sample_t const* ibuf, + sox_sample_t* obuf LSX_UNUSED, + size_t* isamp, + size_t* osamp) -> int { + *osamp = 0; + if (*isamp) { + auto priv = static_cast(effp->priv); + auto sf = priv->sf; + auto fp = static_cast(sf->fp); + auto fileobj = priv->fileobj; + auto buffer = priv->buffer; + + // Encode chunk + auto num_samples_written = sox_write(sf, ibuf, *isamp); + fflush(fp); + + // Copy the encoded chunk to python object. + fileobj->attr("write")(py::bytes(*buffer, ftell(fp))); + + // Reset FILE* + sf->tell_off = 0; + fseek(fp, 0, SEEK_SET); + + if (num_samples_written != *isamp) { + if (sf->sox_errno) { + std::ostringstream stream; + stream << sf->sox_errstr << " " << sox_strerror(sf->sox_errno) << " " + << sf->filename; + throw std::runtime_error(stream.str()); + } + return SOX_EOF; + } + } + return SOX_SUCCESS; +} + +auto get_fileobj_input_handler() -> sox_effect_handler_t* { + static sox_effect_handler_t handler{ + /*name=*/"input_fileobj_object", + /*usage=*/nullptr, + /*flags=*/SOX_EFF_MCHAN, + /*getopts=*/nullptr, + /*start=*/nullptr, + /*flow=*/nullptr, + /*drain=*/fileobj_input_drain, + /*stop=*/nullptr, + /*kill=*/nullptr, + /*priv_size=*/sizeof(FileObjInputPriv)}; + return &handler; +} + +auto get_fileobj_output_handler() -> sox_effect_handler_t* { + static sox_effect_handler_t handler{ + /*name=*/"output_fileobj_object", + /*usage=*/nullptr, + /*flags=*/SOX_EFF_MCHAN, + /*getopts=*/nullptr, + /*start=*/nullptr, + /*flow=*/fileobj_output_flow, + /*drain=*/nullptr, + /*stop=*/nullptr, + /*kill=*/nullptr, + /*priv_size=*/sizeof(FileObjOutputPriv)}; + return &handler; +} + +} // namespace + +void SoxEffectsChainPyBind::addInputFileObj( + sox_format_t* sf, + char* buffer, + uint64_t buffer_size, + py::object* fileobj) { + in_sig_ = sf->signal; + interm_sig_ = in_sig_; + + SoxEffect e(sox_create_effect(get_fileobj_input_handler())); + auto priv = static_cast(e->priv); + priv->sf = sf; + priv->fileobj = fileobj; + priv->eof_reached = false; + priv->buffer = buffer; + priv->buffer_size = buffer_size; + if (sox_add_effect(sec_, e, &interm_sig_, &in_sig_) != SOX_SUCCESS) { + throw std::runtime_error( + "Internal Error: Failed to add effect: input fileobj"); + } +} + +void SoxEffectsChainPyBind::addOutputFileObj( + sox_format_t* sf, + char** buffer, + size_t* buffer_size, + py::object* fileobj) { + out_sig_ = sf->signal; + SoxEffect e(sox_create_effect(get_fileobj_output_handler())); + auto priv = static_cast(e->priv); + priv->sf = sf; + priv->fileobj = fileobj; + priv->buffer = buffer; + priv->buffer_size = buffer_size; + if (sox_add_effect(sec_, e, &interm_sig_, &out_sig_) != SOX_SUCCESS) { + throw std::runtime_error( + "Internal Error: Failed to add effect: output fileobj"); + } +} + +} // namespace paddleaudio::sox_effects_chain diff --git a/audio/paddleaudio/src/pybind/sox/effects_chain.h b/audio/paddleaudio/src/pybind/sox/effects_chain.h new file mode 100644 index 00000000..d61de658 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/effects_chain.h @@ -0,0 +1,78 @@ +// the code is from https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/effects_chain.h with modification. + +#pragma once + +#include +#include "paddleaudio/src/pybind/sox/utils.h" + +namespace paddleaudio::sox_effects_chain { + +// Helper struct to safely close sox_effect_t* pointer returned by +// sox_create_effect + +struct SoxEffect { + explicit SoxEffect(sox_effect_t* se) noexcept; + SoxEffect(const SoxEffect& other) = delete; + SoxEffect(const SoxEffect&& other) = delete; + auto operator=(const SoxEffect& other) -> SoxEffect& = delete; + auto operator=(SoxEffect&& other) -> SoxEffect& = delete; + ~SoxEffect(); + operator sox_effect_t*() const; + auto operator->() noexcept -> sox_effect_t*; + + private: + sox_effect_t* se_; +}; + +// Helper struct to safely close sox_effects_chain_t with handy methods +class SoxEffectsChain { + const sox_encodinginfo_t in_enc_; + const sox_encodinginfo_t out_enc_; + + protected: + sox_signalinfo_t in_sig_; + sox_signalinfo_t interm_sig_; + sox_signalinfo_t out_sig_; + sox_effects_chain_t* sec_; + + public: + explicit SoxEffectsChain( + sox_encodinginfo_t input_encoding, + sox_encodinginfo_t output_encoding); + SoxEffectsChain(const SoxEffectsChain& other) = delete; + SoxEffectsChain(const SoxEffectsChain&& other) = delete; + SoxEffectsChain& operator=(const SoxEffectsChain& other) = delete; + SoxEffectsChain& operator=(SoxEffectsChain&& other) = delete; + ~SoxEffectsChain(); + void run(); + void addInputTensor( + py::array* waveform, + int64_t sample_rate, + bool channels_first); + void addInputFile(sox_format_t* sf); + void addOutputBuffer(std::vector* output_buffer); + void addOutputFile(sox_format_t* sf); + void addEffect(const std::vector effect); + int64_t getOutputNumChannels(); + int64_t getOutputSampleRate(); +}; + +class SoxEffectsChainPyBind : public SoxEffectsChain { + using SoxEffectsChain::SoxEffectsChain; + + public: + void addInputFileObj( + sox_format_t* sf, + char* buffer, + uint64_t buffer_size, + py::object* fileobj); + + void addOutputFileObj( + sox_format_t* sf, + char** buffer, + size_t* buffer_size, + py::object* fileobj); +}; + +} // namespace paddleaudio::sox_effects_chain + diff --git a/audio/paddleaudio/src/pybind/sox/io.cpp b/audio/paddleaudio/src/pybind/sox/io.cpp new file mode 100644 index 00000000..e0c41d5f --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/io.cpp @@ -0,0 +1,279 @@ +// the code is from https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/io.cpp with modification. + +#include "paddleaudio/src/pybind/sox/io.h" +#include "paddleaudio/src/pybind/sox/effects.h" +#include "paddleaudio/src/pybind/sox/types.h" +#include "paddleaudio/src/pybind/sox/effects_chain.h" +#include "paddleaudio/src/pybind/sox/utils.h" +#include "paddleaudio/src/optional/optional.hpp" + +using namespace paddleaudio::sox_utils; + +namespace paddleaudio { +namespace sox_io { + +auto get_info_file(const std::string &path, + const tl::optional &format) + -> std::tuple { + SoxFormat sf( + sox_open_read(path.data(), + /*signal=*/nullptr, + /*encoding=*/nullptr, + /*filetype=*/format.has_value() ? format.value().c_str() : nullptr)); + + + validate_input_file(sf, path); + + return std::make_tuple( + static_cast(sf->signal.rate), + static_cast(sf->signal.length / sf->signal.channels), + static_cast(sf->signal.channels), + static_cast(sf->encoding.bits_per_sample), + get_encoding(sf->encoding.encoding)); +} + +std::vector> get_effects( + const tl::optional& frame_offset, + const tl::optional& num_frames) { + const auto offset = frame_offset.value_or(0); + if (offset < 0) { + throw std::runtime_error( + "Invalid argument: frame_offset must be non-negative."); + } + const auto frames = num_frames.value_or(-1); + if (frames == 0 || frames < -1) { + throw std::runtime_error( + "Invalid argument: num_frames must be -1 or greater than 0."); + } + + std::vector> effects; + if (frames != -1) { + std::ostringstream os_offset, os_frames; + os_offset << offset << "s"; + os_frames << "+" << frames << "s"; + effects.emplace_back( + std::vector{"trim", os_offset.str(), os_frames.str()}); + } else if (offset != 0) { + std::ostringstream os_offset; + os_offset << offset << "s"; + effects.emplace_back(std::vector{"trim", os_offset.str()}); + } + return effects; +} + +auto get_info_fileobj(py::object fileobj, + const tl::optional &format) + -> std::tuple { + const auto capacity = [&]() { + const auto bufsiz = get_buffer_size(); + const int64_t kDefaultCapacityInBytes = 4096; + return (bufsiz > kDefaultCapacityInBytes) ? bufsiz + : kDefaultCapacityInBytes; + }(); + std::string buffer(capacity, '\0'); + auto *buf = const_cast(buffer.data()); + auto num_read = read_fileobj(&fileobj, capacity, buf); + // If the file is shorter than 256, then libsox cannot read the header. + auto buf_size = (num_read > 256) ? num_read : 256; + + SoxFormat sf(sox_open_mem_read( + buf, + buf_size, + /*signal=*/nullptr, + /*encoding=*/nullptr, + /*filetype=*/format.has_value() ? format.value().c_str() : nullptr)); + + // In case of streamed data, length can be 0 + validate_input_memfile(sf); + + return std::make_tuple( + static_cast(sf->signal.rate), + static_cast(sf->signal.length / sf->signal.channels), + static_cast(sf->signal.channels), + static_cast(sf->encoding.bits_per_sample), + get_encoding(sf->encoding.encoding)); +} + +tl::optional> load_audio_fileobj( + py::object fileobj, + const tl::optional& frame_offset, + const tl::optional& num_frames, + tl::optional normalize, + tl::optional channels_first, + const tl::optional& format) { + auto effects = get_effects(frame_offset, num_frames); + return paddleaudio::sox_effects::apply_effects_fileobj( + std::move(fileobj), effects, normalize, channels_first, std::move(format)); +} + +tl::optional> load_audio_file( + const std::string& path, + const tl::optional& frame_offset, + const tl::optional& num_frames, + tl::optional normalize, + tl::optional channels_first, + const tl::optional& format) { + auto effects = get_effects(frame_offset, num_frames); + return paddleaudio::sox_effects::apply_effects_file( + path, effects, normalize, channels_first, format); +} + +void save_audio_file(const std::string& path, + py::array tensor, + int64_t sample_rate, + bool channels_first, + tl::optional compression, + tl::optional format, + tl::optional encoding, + tl::optional bits_per_sample) { + validate_input_tensor(tensor); + + const auto filetype = [&]() { + if (format.has_value()) return format.value(); + return get_filetype(path); + }(); + + if (filetype == "amr-nb") { + const auto num_channels = tensor.shape(channels_first ? 0 : 1); + //TORCH_CHECK(num_channels == 1, + // "amr-nb format only supports single channel audio."); + assert(num_channels == 1); + } else if (filetype == "htk") { + const auto num_channels = tensor.shape(channels_first ? 0 : 1); + // TORCH_CHECK(num_channels == 1, + // "htk format only supports single channel audio."); + assert(num_channels == 1); + } else if (filetype == "gsm") { + const auto num_channels = tensor.shape(channels_first ? 0 : 1); + assert(num_channels == 1); + assert(sample_rate == 8000); + //TORCH_CHECK(num_channels == 1, + // "gsm format only supports single channel audio."); + //TORCH_CHECK(sample_rate == 8000, + // "gsm format only supports a sampling rate of 8kHz."); + } + const auto signal_info = + get_signalinfo(&tensor, sample_rate, filetype, channels_first); + const auto encoding_info = get_encodinginfo_for_save( + filetype, tensor.dtype(), compression, encoding, bits_per_sample); + + SoxFormat sf(sox_open_write(path.c_str(), + &signal_info, + &encoding_info, + /*filetype=*/filetype.c_str(), + /*oob=*/nullptr, + /*overwrite_permitted=*/nullptr)); + + if (static_cast(sf) == nullptr) { + throw std::runtime_error( + "Error saving audio file: failed to open file " + path); + } + + paddleaudio::sox_effects_chain::SoxEffectsChain chain( + /*input_encoding=*/get_tensor_encodinginfo(tensor.dtype()), + /*output_encoding=*/sf->encoding); + chain.addInputTensor(&tensor, sample_rate, channels_first); + chain.addOutputFile(sf); + chain.run(); +} + +namespace { +// helper class to automatically release buffer, to be used by +// save_audio_fileobj +struct AutoReleaseBuffer { + char* ptr; + size_t size; + + AutoReleaseBuffer() : ptr(nullptr), size(0) {} + AutoReleaseBuffer(const AutoReleaseBuffer& other) = delete; + AutoReleaseBuffer(AutoReleaseBuffer&& other) = delete; + auto operator=(const AutoReleaseBuffer& other) -> AutoReleaseBuffer& = delete; + auto operator=(AutoReleaseBuffer&& other) -> AutoReleaseBuffer& = delete; + ~AutoReleaseBuffer() { + if (ptr) { + free(ptr); + } + } +}; + +} // namespace + +void save_audio_fileobj( + py::object fileobj, + py::array tensor, + int64_t sample_rate, + bool channels_first, + tl::optional compression, + tl::optional format, + tl::optional encoding, + tl::optional bits_per_sample) { + + if (!format.has_value()) { + throw std::runtime_error( + "`format` is required when saving to file object."); + } + const auto filetype = format.value(); + + if (filetype == "amr-nb") { + const auto num_channels = tensor.shape(channels_first ? 0 : 1); + if (num_channels != 1) { + throw std::runtime_error( + "amr-nb format only supports single channel audio."); + } + } else if (filetype == "htk") { + const auto num_channels = tensor.shape(channels_first ? 0 : 1); + if (num_channels != 1) { + throw std::runtime_error( + "htk format only supports single channel audio."); + } + } else if (filetype == "gsm") { + const auto num_channels = tensor.shape(channels_first ? 0 : 1); + if (num_channels != 1) { + throw std::runtime_error( + "gsm format only supports single channel audio."); + } + if (sample_rate != 8000) { + throw std::runtime_error( + "gsm format only supports a sampling rate of 8kHz."); + } + } + + const auto signal_info = + get_signalinfo(&tensor, sample_rate, filetype, channels_first); + const auto encoding_info = get_encodinginfo_for_save( + filetype, + tensor.dtype(), + compression, + std::move(encoding), + bits_per_sample); + + AutoReleaseBuffer buffer; + + SoxFormat sf(sox_open_memstream_write( + &buffer.ptr, + &buffer.size, + &signal_info, + &encoding_info, + filetype.c_str(), + /*oob=*/nullptr)); + + if (static_cast(sf) == nullptr) { + throw std::runtime_error( + "Error saving audio file: failed to open memory stream."); + } + + paddleaudio::sox_effects_chain::SoxEffectsChainPyBind chain( + /*input_encoding=*/get_tensor_encodinginfo(tensor.dtype()), + /*output_encoding=*/sf->encoding); + chain.addInputTensor(&tensor, sample_rate, channels_first); + chain.addOutputFileObj(sf, &buffer.ptr, &buffer.size, &fileobj); + chain.run(); + + // Closing the sox_format_t is necessary for flushing the last chunk to the + // buffer + sf.close(); + fileobj.attr("write")(py::bytes(buffer.ptr, buffer.size)); +} + +} // namespace paddleaudio +} // namespace sox_io diff --git a/audio/paddleaudio/src/pybind/sox/io.h b/audio/paddleaudio/src/pybind/sox/io.h new file mode 100644 index 00000000..24144c38 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/io.h @@ -0,0 +1,61 @@ +// the code is from https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/io.h with modification. +#pragma once + +#include "paddleaudio/src/pybind/sox/utils.h" + +namespace py = pybind11; + +namespace paddleaudio { +namespace sox_io { + +auto get_info_file(const std::string &path, + const tl::optional &format) + -> std::tuple; + +auto get_info_fileobj(py::object fileobj, + const tl::optional &format) + -> std::tuple; + +tl::optional> load_audio_fileobj( + py::object fileobj, + const tl::optional& frame_offset, + const tl::optional& num_frames, + tl::optional normalize, + tl::optional channels_first, + const tl::optional& format); + +void save_audio_fileobj( + py::object fileobj, + py::array tensor, + int64_t sample_rate, + bool channels_first, + tl::optional compression, + tl::optional format, + tl::optional encoding, + tl::optional bits_per_sample); + +auto get_effects(const tl::optional& frame_offset, + const tl::optional& num_frames) + -> std::vector>; + + +tl::optional> load_audio_file( + const std::string& path, + const tl::optional& frame_offset, + const tl::optional& num_frames, + tl::optional normalize, + tl::optional channels_first, + const tl::optional& format); + +void save_audio_file(const std::string& path, + py::array tensor, + int64_t sample_rate, + bool channels_first, + tl::optional compression, + tl::optional format, + tl::optional encoding, + tl::optional bits_per_sample); + + +} // namespace paddleaudio +} // namespace sox_io diff --git a/audio/paddleaudio/src/pybind/sox/types.cpp b/audio/paddleaudio/src/pybind/sox/types.cpp new file mode 100644 index 00000000..b42984e6 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/types.cpp @@ -0,0 +1,143 @@ +//code is from: https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/types.cpp + +#include "paddleaudio/src/pybind/sox/types.h" +#include +#include + +namespace paddleaudio { +namespace sox_utils { + +Format get_format_from_string(const std::string& format) { + if (format == "wav") + return Format::WAV; + if (format == "mp3") + return Format::MP3; + if (format == "flac") + return Format::FLAC; + if (format == "ogg" || format == "vorbis") + return Format::VORBIS; + if (format == "amr-nb") + return Format::AMR_NB; + if (format == "amr-wb") + return Format::AMR_WB; + if (format == "amb") + return Format::AMB; + if (format == "sph") + return Format::SPHERE; + if (format == "htk") + return Format::HTK; + if (format == "gsm") + return Format::GSM; + std::ostringstream stream; + stream << "Internal Error: unexpected format value: " << format; + throw std::runtime_error(stream.str()); +} + +std::string to_string(Encoding v) { + switch (v) { + case Encoding::UNKNOWN: + return "UNKNOWN"; + case Encoding::PCM_SIGNED: + return "PCM_S"; + case Encoding::PCM_UNSIGNED: + return "PCM_U"; + case Encoding::PCM_FLOAT: + return "PCM_F"; + case Encoding::FLAC: + return "FLAC"; + case Encoding::ULAW: + return "ULAW"; + case Encoding::ALAW: + return "ALAW"; + case Encoding::MP3: + return "MP3"; + case Encoding::VORBIS: + return "VORBIS"; + case Encoding::AMR_WB: + return "AMR_WB"; + case Encoding::AMR_NB: + return "AMR_NB"; + case Encoding::OPUS: + return "OPUS"; + default: + throw std::runtime_error("Internal Error: unexpected encoding."); + } +} + +Encoding get_encoding_from_option(const tl::optional encoding) { + if (!encoding.has_value()) + return Encoding::NOT_PROVIDED; + std::string v = encoding.value(); + if (v == "PCM_S") + return Encoding::PCM_SIGNED; + if (v == "PCM_U") + return Encoding::PCM_UNSIGNED; + if (v == "PCM_F") + return Encoding::PCM_FLOAT; + if (v == "ULAW") + return Encoding::ULAW; + if (v == "ALAW") + return Encoding::ALAW; + std::ostringstream stream; + stream << "Internal Error: unexpected encoding value: " << v; + throw std::runtime_error(stream.str()); +} + +BitDepth get_bit_depth_from_option(const tl::optional bit_depth) { + if (!bit_depth.has_value()) + return BitDepth::NOT_PROVIDED; + int64_t v = bit_depth.value(); + switch (v) { + case 8: + return BitDepth::B8; + case 16: + return BitDepth::B16; + case 24: + return BitDepth::B24; + case 32: + return BitDepth::B32; + case 64: + return BitDepth::B64; + default: { + std::ostringstream s; + s << "Internal Error: unexpected bit depth value: " << v; + throw std::runtime_error(s.str()); + } + } +} + +std::string get_encoding(sox_encoding_t encoding) { + switch (encoding) { + case SOX_ENCODING_UNKNOWN: + return "UNKNOWN"; + case SOX_ENCODING_SIGN2: + return "PCM_S"; + case SOX_ENCODING_UNSIGNED: + return "PCM_U"; + case SOX_ENCODING_FLOAT: + return "PCM_F"; + case SOX_ENCODING_FLAC: + return "FLAC"; + case SOX_ENCODING_ULAW: + return "ULAW"; + case SOX_ENCODING_ALAW: + return "ALAW"; + case SOX_ENCODING_MP3: + return "MP3"; + case SOX_ENCODING_VORBIS: + return "VORBIS"; + case SOX_ENCODING_AMR_WB: + return "AMR_WB"; + case SOX_ENCODING_AMR_NB: + return "AMR_NB"; + case SOX_ENCODING_OPUS: + return "OPUS"; + case SOX_ENCODING_GSM: + return "GSM"; + default: + return "UNKNOWN"; + } +} + +} // namespace sox_utils +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/sox/types.h b/audio/paddleaudio/src/pybind/sox/types.h new file mode 100644 index 00000000..126e4faa --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/types.h @@ -0,0 +1,58 @@ +//code is from: https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/types.h +#pragma once + +#include +#include "paddleaudio/src/optional/optional.hpp" + +namespace paddleaudio { +namespace sox_utils { + +enum class Format { + WAV, + MP3, + FLAC, + VORBIS, + AMR_NB, + AMR_WB, + AMB, + SPHERE, + GSM, + HTK, +}; + +Format get_format_from_string(const std::string& format); + +enum class Encoding { + NOT_PROVIDED, + UNKNOWN, + PCM_SIGNED, + PCM_UNSIGNED, + PCM_FLOAT, + FLAC, + ULAW, + ALAW, + MP3, + VORBIS, + AMR_WB, + AMR_NB, + OPUS, +}; + +std::string to_string(Encoding v); +Encoding get_encoding_from_option(const tl::optional encoding); + +enum class BitDepth : unsigned { + NOT_PROVIDED = 0, + B8 = 8, + B16 = 16, + B24 = 24, + B32 = 32, + B64 = 64, +}; + +BitDepth get_bit_depth_from_option(const tl::optional bit_depth); + +std::string get_encoding(sox_encoding_t encoding); + +} // namespace sox_utils +} // namespace paddleaudio diff --git a/audio/paddleaudio/src/pybind/sox/utils.cpp b/audio/paddleaudio/src/pybind/sox/utils.cpp new file mode 100644 index 00000000..bc32b740 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/utils.cpp @@ -0,0 +1,550 @@ +//code is from: https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/utils.cpp with modification. +#include + +#include "paddleaudio/src/pybind/sox/utils.h" +#include "paddleaudio/src/pybind/sox/types.h" + +#include + +namespace paddleaudio { +namespace sox_utils { + +auto read_fileobj(py::object *fileobj, const uint64_t size, char *buffer) + -> uint64_t { + uint64_t num_read = 0; + while (num_read < size) { + auto request = size - num_read; + auto chunk = static_cast( + static_cast(fileobj->attr("read")(request))); + auto chunk_len = chunk.length(); + if (chunk_len == 0) { + break; + } + if (chunk_len > request) { + std::ostringstream message; + message + << "Requested up to " << request << " bytes but, " + << "received " << chunk_len << " bytes. " + << "The given object does not confirm to read protocol of file " + "object."; + throw std::runtime_error(message.str()); + } + memcpy(buffer, chunk.data(), chunk_len); + buffer += chunk_len; + num_read += chunk_len; + } + return num_read; +} + + +void set_seed(const int64_t seed) { + sox_get_globals()->ranqd1 = static_cast(seed); +} + +void set_verbosity(const int64_t verbosity) { + sox_get_globals()->verbosity = static_cast(verbosity); +} + +void set_use_threads(const bool use_threads) { + sox_get_globals()->use_threads = static_cast(use_threads); +} + +void set_buffer_size(const int64_t buffer_size) { + sox_get_globals()->bufsiz = static_cast(buffer_size); +} + +int64_t get_buffer_size() { + return sox_get_globals()->bufsiz; +} + +std::vector> list_effects() { + std::vector> effects; + for (const sox_effect_fn_t* fns = sox_get_effect_fns(); *fns; ++fns) { + const sox_effect_handler_t* handler = (*fns)(); + if (handler && handler->name) { + if (UNSUPPORTED_EFFECTS.find(handler->name) == + UNSUPPORTED_EFFECTS.end()) { + effects.emplace_back(std::vector{ + handler->name, + handler->usage ? std::string(handler->usage) : std::string("")}); + } + } + } + return effects; +} + +std::vector list_write_formats() { + std::vector formats; + for (const sox_format_tab_t* fns = sox_get_format_fns(); fns->fn; ++fns) { + const sox_format_handler_t* handler = fns->fn(); + for (const char* const* names = handler->names; *names; ++names) { + if (!strchr(*names, '/') && handler->write) + formats.emplace_back(*names); + } + } + return formats; +} + +std::vector list_read_formats() { + std::vector formats; + for (const sox_format_tab_t* fns = sox_get_format_fns(); fns->fn; ++fns) { + const sox_format_handler_t* handler = fns->fn(); + for (const char* const* names = handler->names; *names; ++names) { + if (!strchr(*names, '/') && handler->read) + formats.emplace_back(*names); + } + } + return formats; +} + +SoxFormat::SoxFormat(sox_format_t* fd) noexcept : fd_(fd) {} +SoxFormat::~SoxFormat() { + close(); +} + +sox_format_t* SoxFormat::operator->() const noexcept { + return fd_; +} +SoxFormat::operator sox_format_t*() const noexcept { + return fd_; +} + +void SoxFormat::close() { + if (fd_ != nullptr) { + sox_close(fd_); + fd_ = nullptr; + } +} + +void validate_input_file(const SoxFormat& sf, const std::string& path) { + if (static_cast(sf) == nullptr) { + throw std::runtime_error( + "Error loading audio file: failed to open file " + path); + } + if (sf->encoding.encoding == SOX_ENCODING_UNKNOWN) { + throw std::runtime_error("Error loading audio file: unknown encoding."); + } +} + +void validate_input_memfile(const SoxFormat &sf) { + return validate_input_file(sf, ""); +} + +void validate_input_tensor(const py::array tensor) { + if (tensor.ndim() != 2) { + throw std::runtime_error("Input tensor has to be 2D."); + } + + char dtype = tensor.dtype().char_(); + bool flag = (dtype == 'f') || (dtype == 'd') || (dtype == 'l') || (dtype == 'i'); + if (flag == false) { + throw std::runtime_error( + "Input tensor has to be one of float32, int32, int16 or uint8 type."); + } +} + +py::dtype get_dtype( + const sox_encoding_t encoding, + const unsigned precision) { + switch (encoding) { + case SOX_ENCODING_UNSIGNED: // 8-bit PCM WAV + return py::dtype('u1'); + case SOX_ENCODING_SIGN2: // 16-bit, 24-bit, or 32-bit PCM WAV + switch (precision) { + case 16: + return py::dtype("i2"); + case 24: // Cast 24-bit to 32-bit. + case 32: + return py::dtype('i'); + default: + throw std::runtime_error( + "Only 16, 24, and 32 bits are supported for signed PCM."); + } + default: + // default to float32 for the other formats, including + // 32-bit flaoting-point WAV, + // MP3, + // FLAC, + // VORBIS etc... + return py::dtype("f"); + } +} + +py::array convert_to_tensor( + sox_sample_t* buffer, + const int32_t num_samples, + const int32_t num_channels, + const py::dtype dtype, + const bool normalize, + const bool channels_first) { + // todo refector later(SGoat) + py::array t; + uint64_t dummy = 0; + SOX_SAMPLE_LOCALS; + int32_t num_rows = num_samples / num_channels; + if (normalize || dtype.char_() == 'f') { + t = py::array(dtype, {num_rows, num_channels}); + auto ptr = (float*)t.mutable_data(0, 0); + for (int32_t i = 0; i < num_samples; ++i) { + ptr[i] = SOX_SAMPLE_TO_FLOAT_32BIT(buffer[i], dummy); + } + if (channels_first) { + py::array t2 = py::array(dtype, {num_channels, num_rows}); + for (int32_t row_idx = 0; row_idx < num_channels; ++row_idx) { + for (int32_t col_idx = 0; col_idx < num_rows; ++col_idx) + *(float*)t2.mutable_data(row_idx, col_idx) = *(float*)t.data(col_idx, row_idx); + } + return t2; + } + } else if (dtype.char_() == 'i') { + t = py::array(dtype, {num_rows, num_channels}); + auto ptr = (int*)t.mutable_data(0, 0); + for (int32_t i = 0; i < num_samples; ++i) { + ptr[i] = buffer[i]; + } + if (channels_first) { + py::array t2 = py::array(dtype, {num_channels, num_rows}); + for (int32_t row_idx = 0; row_idx < num_channels; ++row_idx) { + for (int32_t col_idx = 0; col_idx < num_rows; ++col_idx) + *(int*)t2.mutable_data(row_idx, col_idx) = *(int*)t.data(col_idx, row_idx); + } + return t2; + } + } else if (dtype.char_() == 'h') { // int16 + t = py::array(dtype, {num_rows, num_channels}); + auto ptr = (int16_t*)t.mutable_data(0, 0); + for (int32_t i = 0; i < num_samples; ++i) { + ptr[i] = SOX_SAMPLE_TO_SIGNED_16BIT(buffer[i], dummy); + } + if (channels_first) { + py::array t2 = py::array(dtype, {num_channels, num_rows}); + for (int32_t row_idx = 0; row_idx < num_channels; ++row_idx) { + for (int32_t col_idx = 0; col_idx < num_rows; ++col_idx) + *(int16_t*)t2.mutable_data(row_idx, col_idx) = *(int16_t*)t.data(col_idx, row_idx); + } + return t2; + } + } else if (dtype.char_() == 'b') { + //t = torch::empty({num_samples / num_channels, num_channels}, torch::kUInt8); + t = py::array(dtype, {num_rows, num_channels}); + auto ptr = (uint8_t*)t.mutable_data(0,0); + for (int32_t i = 0; i < num_samples; ++i) { + ptr[i] = SOX_SAMPLE_TO_UNSIGNED_8BIT(buffer[i], dummy); + } + if (channels_first) { + py::array t2 = py::array(dtype, {num_channels, num_rows}); + for (int32_t row_idx = 0; row_idx < num_channels; ++row_idx) { + for (int32_t col_idx = 0; col_idx < num_rows; ++col_idx) + *(uint8_t*)t2.mutable_data(row_idx, col_idx) = *(uint8_t*)t.data(col_idx, row_idx); + } + return t2; + } + } else { + throw std::runtime_error("Unsupported dtype."); + } + return t; +} + +const std::string get_filetype(const std::string path) { + std::string ext = path.substr(path.find_last_of(".") + 1); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + return ext; +} + +namespace { + +std::tuple get_save_encoding_for_wav( + const std::string format, + py::dtype dtype, + const Encoding& encoding, + const BitDepth& bits_per_sample) { + switch (encoding) { + case Encoding::NOT_PROVIDED: + switch (bits_per_sample) { + case BitDepth::NOT_PROVIDED: + switch (dtype.num()) { + case 11: // float32 numpy dtype num + return std::make_tuple<>(SOX_ENCODING_FLOAT, 32); + case 5: // int numpy dtype num + return std::make_tuple<>(SOX_ENCODING_SIGN2, 32); + case 3: // int16 numpy + return std::make_tuple<>(SOX_ENCODING_SIGN2, 16); + case 1: // byte numpy + return std::make_tuple<>(SOX_ENCODING_UNSIGNED, 8); + default: + throw std::runtime_error("Internal Error: Unexpected dtype."); + } + case BitDepth::B8: + return std::make_tuple<>(SOX_ENCODING_UNSIGNED, 8); + default: + return std::make_tuple<>( + SOX_ENCODING_SIGN2, static_cast(bits_per_sample)); + } + case Encoding::PCM_SIGNED: + switch (bits_per_sample) { + case BitDepth::NOT_PROVIDED: + return std::make_tuple<>(SOX_ENCODING_SIGN2, 32); + case BitDepth::B8: + throw std::runtime_error( + format + " does not support 8-bit signed PCM encoding."); + default: + return std::make_tuple<>( + SOX_ENCODING_SIGN2, static_cast(bits_per_sample)); + } + case Encoding::PCM_UNSIGNED: + switch (bits_per_sample) { + case BitDepth::NOT_PROVIDED: + case BitDepth::B8: + return std::make_tuple<>(SOX_ENCODING_UNSIGNED, 8); + default: + throw std::runtime_error( + format + " only supports 8-bit for unsigned PCM encoding."); + } + case Encoding::PCM_FLOAT: + switch (bits_per_sample) { + case BitDepth::NOT_PROVIDED: + case BitDepth::B32: + return std::make_tuple<>(SOX_ENCODING_FLOAT, 32); + case BitDepth::B64: + return std::make_tuple<>(SOX_ENCODING_FLOAT, 64); + default: + throw std::runtime_error( + format + + " only supports 32-bit or 64-bit for floating-point PCM encoding."); + } + case Encoding::ULAW: + switch (bits_per_sample) { + case BitDepth::NOT_PROVIDED: + case BitDepth::B8: + return std::make_tuple<>(SOX_ENCODING_ULAW, 8); + default: + throw std::runtime_error( + format + " only supports 8-bit for mu-law encoding."); + } + case Encoding::ALAW: + switch (bits_per_sample) { + case BitDepth::NOT_PROVIDED: + case BitDepth::B8: + return std::make_tuple<>(SOX_ENCODING_ALAW, 8); + default: + throw std::runtime_error( + format + " only supports 8-bit for a-law encoding."); + } + default: + throw std::runtime_error( + format + " does not support encoding: " + to_string(encoding)); + } +} + +std::tuple get_save_encoding( + const std::string& format, + const py::dtype dtype, + const tl::optional encoding, + const tl::optional bits_per_sample) { + const Format fmt = get_format_from_string(format); + const Encoding enc = get_encoding_from_option(encoding); + const BitDepth bps = get_bit_depth_from_option(bits_per_sample); + + switch (fmt) { + case Format::WAV: + case Format::AMB: + return get_save_encoding_for_wav(format, dtype, enc, bps); + case Format::MP3: + if (enc != Encoding::NOT_PROVIDED) + throw std::runtime_error("mp3 does not support `encoding` option."); + if (bps != BitDepth::NOT_PROVIDED) + throw std::runtime_error( + "mp3 does not support `bits_per_sample` option."); + return std::make_tuple<>(SOX_ENCODING_MP3, 16); + case Format::HTK: + if (enc != Encoding::NOT_PROVIDED) + throw std::runtime_error("htk does not support `encoding` option."); + if (bps != BitDepth::NOT_PROVIDED) + throw std::runtime_error( + "htk does not support `bits_per_sample` option."); + return std::make_tuple<>(SOX_ENCODING_SIGN2, 16); + case Format::VORBIS: + if (enc != Encoding::NOT_PROVIDED) + throw std::runtime_error("vorbis does not support `encoding` option."); + if (bps != BitDepth::NOT_PROVIDED) + throw std::runtime_error( + "vorbis does not support `bits_per_sample` option."); + return std::make_tuple<>(SOX_ENCODING_VORBIS, 16); + case Format::AMR_NB: + if (enc != Encoding::NOT_PROVIDED) + throw std::runtime_error("amr-nb does not support `encoding` option."); + if (bps != BitDepth::NOT_PROVIDED) + throw std::runtime_error( + "amr-nb does not support `bits_per_sample` option."); + return std::make_tuple<>(SOX_ENCODING_AMR_NB, 16); + case Format::FLAC: + if (enc != Encoding::NOT_PROVIDED) + throw std::runtime_error("flac does not support `encoding` option."); + switch (bps) { + case BitDepth::B32: + case BitDepth::B64: + throw std::runtime_error( + "flac does not support `bits_per_sample` larger than 24."); + default: + return std::make_tuple<>( + SOX_ENCODING_FLAC, static_cast(bps)); + } + case Format::SPHERE: + switch (enc) { + case Encoding::NOT_PROVIDED: + case Encoding::PCM_SIGNED: + switch (bps) { + case BitDepth::NOT_PROVIDED: + return std::make_tuple<>(SOX_ENCODING_SIGN2, 32); + default: + return std::make_tuple<>( + SOX_ENCODING_SIGN2, static_cast(bps)); + } + case Encoding::PCM_UNSIGNED: + throw std::runtime_error( + "sph does not support unsigned integer PCM."); + case Encoding::PCM_FLOAT: + throw std::runtime_error("sph does not support floating point PCM."); + case Encoding::ULAW: + switch (bps) { + case BitDepth::NOT_PROVIDED: + case BitDepth::B8: + return std::make_tuple<>(SOX_ENCODING_ULAW, 8); + default: + throw std::runtime_error( + "sph only supports 8-bit for mu-law encoding."); + } + case Encoding::ALAW: + switch (bps) { + case BitDepth::NOT_PROVIDED: + case BitDepth::B8: + return std::make_tuple<>(SOX_ENCODING_ALAW, 8); + default: + return std::make_tuple<>( + SOX_ENCODING_ALAW, static_cast(bps)); + } + default: + throw std::runtime_error( + "sph does not support encoding: " + encoding.value()); + } + case Format::GSM: + if (enc != Encoding::NOT_PROVIDED) + throw std::runtime_error("gsm does not support `encoding` option."); + if (bps != BitDepth::NOT_PROVIDED) + throw std::runtime_error( + "gsm does not support `bits_per_sample` option."); + return std::make_tuple<>(SOX_ENCODING_GSM, 16); + + default: + throw std::runtime_error("Unsupported format: " + format); + } +} + +unsigned get_precision(const std::string filetype, py::dtype dtype) { + if (filetype == "mp3") + return SOX_UNSPEC; + if (filetype == "flac") + return 24; + if (filetype == "ogg" || filetype == "vorbis") + return SOX_UNSPEC; + if (filetype == "wav" || filetype == "amb") { + switch (dtype.num()) { + case 1: // byte in numpy dype num + return 8; + case 3: // short, in numpy dtype num + return 16; + case 5: // int, numpy dtype + return 32; + case 11: // float, numpy dtype + return 32; + default: + throw std::runtime_error("Unsupported dtype."); + } + } + if (filetype == "sph") + return 32; + if (filetype == "amr-nb") { + return 16; + } + if (filetype == "gsm") { + return 16; + } + if (filetype == "htk") { + return 16; + } + throw std::runtime_error("Unsupported file type: " + filetype); +} + +} // namespace + +sox_signalinfo_t get_signalinfo( + const py::array* waveform, + const int64_t sample_rate, + const std::string filetype, + const bool channels_first) { + return sox_signalinfo_t{ + /*rate=*/static_cast(sample_rate), + /*channels=*/ + static_cast(waveform->shape(channels_first ? 0 : 1)), + /*precision=*/get_precision(filetype, waveform->dtype()), + /*length=*/static_cast(waveform->size())}; +} + +sox_encodinginfo_t get_tensor_encodinginfo(py::dtype dtype) { + sox_encoding_t encoding = [&]() { + switch (dtype.num()) { + case 1: // byte + return SOX_ENCODING_UNSIGNED; + case 3: // short + return SOX_ENCODING_SIGN2; + case 5: // int32 + return SOX_ENCODING_SIGN2; + case 11: // float + return SOX_ENCODING_FLOAT; + default: + throw std::runtime_error("Unsupported dtype."); + } + }(); + unsigned bits_per_sample = [&]() { + switch (dtype.num()) { + case 1: // byte + return 8; + case 3: //short + return 16; + case 5: // int32 + return 32; + case 11: // float + return 32; + default: + throw std::runtime_error("Unsupported dtype."); + } + }(); + return sox_encodinginfo_t{ + /*encoding=*/encoding, + /*bits_per_sample=*/bits_per_sample, + /*compression=*/HUGE_VAL, + /*reverse_bytes=*/sox_option_default, + /*reverse_nibbles=*/sox_option_default, + /*reverse_bits=*/sox_option_default, + /*opposite_endian=*/sox_false}; +} + +sox_encodinginfo_t get_encodinginfo_for_save( + const std::string& format, + const py::dtype dtype, + const tl::optional compression, + const tl::optional encoding, + const tl::optional bits_per_sample) { + auto enc = get_save_encoding(format, dtype, encoding, bits_per_sample); + return sox_encodinginfo_t{ + /*encoding=*/std::get<0>(enc), + /*bits_per_sample=*/std::get<1>(enc), + /*compression=*/compression.value_or(HUGE_VAL), + /*reverse_bytes=*/sox_option_default, + /*reverse_nibbles=*/sox_option_default, + /*reverse_bits=*/sox_option_default, + /*opposite_endian=*/sox_false}; +} + +} // namespace paddleaudio +} // namespace sox_utils diff --git a/audio/paddleaudio/src/pybind/sox/utils.h b/audio/paddleaudio/src/pybind/sox/utils.h new file mode 100644 index 00000000..6fce6671 --- /dev/null +++ b/audio/paddleaudio/src/pybind/sox/utils.h @@ -0,0 +1,114 @@ +//code is from: https://github.com/pytorch/audio/blob/main/torchaudio/csrc/sox/utils.h with modification. +#pragma once + +#include +#include +#include +#include "paddleaudio/src/optional/optional.hpp" + +namespace py = pybind11; + +namespace paddleaudio { +namespace sox_utils { + +auto read_fileobj(py::object *fileobj, uint64_t size, char *buffer) -> uint64_t; + +void set_seed(const int64_t seed); + +void set_verbosity(const int64_t verbosity); + +void set_use_threads(const bool use_threads); + +void set_buffer_size(const int64_t buffer_size); + +int64_t get_buffer_size(); + +std::vector> list_effects(); + +std::vector list_read_formats(); + +std::vector list_write_formats(); + +//////////////////////////////////////////////////////////////////////////////// +// Utilities for sox_io / sox_effects implementations +//////////////////////////////////////////////////////////////////////////////// + +const std::unordered_set UNSUPPORTED_EFFECTS = + {"input", "output", "spectrogram", "noiseprof", "noisered", "splice"}; + +/// helper class to automatically close sox_format_t* +struct SoxFormat { + explicit SoxFormat(sox_format_t* fd) noexcept; + SoxFormat(const SoxFormat& other) = delete; + SoxFormat(SoxFormat&& other) = delete; + SoxFormat& operator=(const SoxFormat& other) = delete; + SoxFormat& operator=(SoxFormat&& other) = delete; + ~SoxFormat(); + sox_format_t* operator->() const noexcept; + operator sox_format_t*() const noexcept; + + void close(); + + private: + sox_format_t* fd_; +}; + +/// +/// Verify that input Tensor is 2D, CPU and either uin8, int16, int32 or float32 +void validate_input_tensor(const py::array); + +void validate_input_file(const SoxFormat& sf, const std::string& path); + +void validate_input_memfile(const SoxFormat &sf); +/// +/// Get target dtype for the given encoding and precision. +py::dtype get_dtype( + const sox_encoding_t encoding, + const unsigned precision); + +/// +/// Convert sox_sample_t buffer to uint8/int16/int32/float32 Tensor +/// NOTE: This function might modify the values in the input buffer to +/// reduce the number of memory copy. +/// @param buffer Pointer to buffer that contains audio data. +/// @param num_samples The number of samples to read. +/// @param num_channels The number of channels. Used to reshape the resulting +/// Tensor. +/// @param dtype Target dtype. Determines the output dtype and value range in +/// conjunction with normalization. +/// @param noramlize Perform normalization. Only effective when dtype is not +/// kFloat32. When effective, the output tensor is kFloat32 type and value range +/// is [-1.0, 1.0] +/// @param channels_first When True, output Tensor has shape of [num_channels, +/// num_frames]. +py::array convert_to_tensor( + sox_sample_t* buffer, + const int32_t num_samples, + const int32_t num_channels, + const py::dtype dtype, + const bool normalize, + const bool channels_first); + +/// Extract extension from file path +const std::string get_filetype(const std::string path); + +/// Get sox_signalinfo_t for passing a py::array object. +sox_signalinfo_t get_signalinfo( + const py::array* waveform, + const int64_t sample_rate, + const std::string filetype, + const bool channels_first); + +/// Get sox_encodinginfo_t for Tensor I/O +sox_encodinginfo_t get_tensor_encodinginfo(const py::dtype dtype); + +/// Get sox_encodinginfo_t for saving to file/file object +sox_encodinginfo_t get_encodinginfo_for_save( + const std::string& format, + const py::dtype dtype, + const tl::optional compression, + const tl::optional encoding, + const tl::optional bits_per_sample); + +} // namespace paddleaudio +} // namespace sox_utils diff --git a/audio/paddleaudio/src/utils.cpp b/audio/paddleaudio/src/utils.cpp new file mode 100644 index 00000000..a1e71822 --- /dev/null +++ b/audio/paddleaudio/src/utils.cpp @@ -0,0 +1,35 @@ +// this is from: https://github.com/pytorch/audio/blob/main/torchaudio/csrc/utils.cpp with modification. + +namespace paddleaudio { + +namespace { + +bool is_sox_available() { +#ifdef INCLUDE_SOX + return true; +#else + return false; +#endif +} + +bool is_kaldi_available() { +#ifdef INCLUDE_KALDI + return true; +#else + return false; +#endif +} + +// It tells whether paddleaudio was compiled with ffmpeg +// not the runtime availability. +bool is_ffmpeg_available() { +#ifdef USE_FFMPEG + return true; +#else + return false; +#endif +} + +} // namespace + +} // namespace paddleaudio diff --git a/audio/paddleaudio/third_party/.gitignore b/audio/paddleaudio/third_party/.gitignore new file mode 100644 index 00000000..2d788f6b --- /dev/null +++ b/audio/paddleaudio/third_party/.gitignore @@ -0,0 +1,2 @@ +archives/ +install/ diff --git a/audio/paddleaudio/third_party/CMakeLists.txt b/audio/paddleaudio/third_party/CMakeLists.txt new file mode 100644 index 00000000..43288f39 --- /dev/null +++ b/audio/paddleaudio/third_party/CMakeLists.txt @@ -0,0 +1,15 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") + +################################################################################ +# sox +################################################################################ +if (BUILD_SOX) + add_subdirectory(sox) +endif() + +################################################################################ +# kaldi +################################################################################ +if (BUILD_KALDI) + add_subdirectory(kaldi) +endif() \ No newline at end of file diff --git a/audio/paddleaudio/third_party/kaldi/CMakeLists.txt b/audio/paddleaudio/third_party/kaldi/CMakeLists.txt new file mode 100644 index 00000000..e63fb578 --- /dev/null +++ b/audio/paddleaudio/third_party/kaldi/CMakeLists.txt @@ -0,0 +1,111 @@ +# checkout the thirdparty/kaldi/base/kaldi-types.h +# compile kaldi without openfst +add_definitions("-DCOMPILE_WITHOUT_OPENFST") + +if ((NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/base)) + file(COPY ../../../../speechx/speechx/kaldi/base DESTINATION ${CMAKE_CURRENT_LIST_DIR}) + file(COPY ../../../../speechx/speechx/kaldi/feat DESTINATION ${CMAKE_CURRENT_LIST_DIR}) + file(COPY ../../../../speechx/speechx/kaldi/matrix DESTINATION ${CMAKE_CURRENT_LIST_DIR}) + file(COPY ../../../../speechx/speechx/kaldi/util DESTINATION ${CMAKE_CURRENT_LIST_DIR}) +endif() + +# kaldi-base +add_library(kaldi-base STATIC + base/io-funcs.cc + base/kaldi-error.cc + base/kaldi-math.cc + base/kaldi-utils.cc + base/timer.cc +) +target_include_directories(kaldi-base PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# kaldi-matrix +add_library(kaldi-matrix STATIC + matrix/compressed-matrix.cc + matrix/matrix-functions.cc + matrix/kaldi-matrix.cc + matrix/kaldi-vector.cc + matrix/optimization.cc + matrix/packed-matrix.cc + matrix/qr.cc + matrix/sparse-matrix.cc + matrix/sp-matrix.cc + matrix/srfft.cc + matrix/tp-matrix.cc +) +target_include_directories(kaldi-matrix PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +if (NOT MSVC) + target_link_libraries(kaldi-matrix PUBLIC kaldi-base libopenblas) +else() + target_link_libraries(kaldi-matrix PUBLIC kaldi-base openblas) +endif() + +# kaldi-util +add_library(kaldi-util STATIC + util/kaldi-holder.cc + util/kaldi-io.cc + util/kaldi-semaphore.cc + util/kaldi-table.cc + util/kaldi-thread.cc + util/parse-options.cc + util/simple-io-funcs.cc + util/simple-options.cc + util/text-utils.cc +) +target_include_directories(kaldi-util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(kaldi-util PUBLIC kaldi-base kaldi-matrix) + +# kaldi-feat-common +add_library(kaldi-feat-common STATIC + feat/cmvn.cc + feat/feature-functions.cc + feat/feature-window.cc + feat/mel-computations.cc + feat/pitch-functions.cc + feat/resample.cc + feat/signal.cc + feat/wave-reader.cc +) +target_include_directories(kaldi-feat-common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(kaldi-feat-common PUBLIC kaldi-base kaldi-matrix kaldi-util) + + +# kaldi-mfcc +add_library(kaldi-mfcc STATIC + feat/feature-mfcc.cc +) +target_include_directories(kaldi-mfcc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(kaldi-mfcc PUBLIC kaldi-feat-common) + + +# kaldi-fbank +add_library(kaldi-fbank STATIC + feat/feature-fbank.cc +) +target_include_directories(kaldi-fbank PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(kaldi-fbank PUBLIC kaldi-feat-common) + + +set(KALDI_LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/libkaldi-base.a + ${CMAKE_CURRENT_BINARY_DIR}/libkaldi-matrix.a + ${CMAKE_CURRENT_BINARY_DIR}/libkaldi-util.a + ${CMAKE_CURRENT_BINARY_DIR}/libkaldi-feat-common.a + ${CMAKE_CURRENT_BINARY_DIR}/libkaldi-mfcc.a + ${CMAKE_CURRENT_BINARY_DIR}/libkaldi-fbank.a +) + +add_library(libkaldi INTERFACE) +add_dependencies(libkaldi kaldi-base kaldi-matrix kaldi-util kaldi-feat-common kaldi-mfcc kaldi-fbank) +target_include_directories(libkaldi INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +if (APPLE) + target_link_libraries(libkaldi INTERFACE ${KALDI_LIBRARIES} libopenblas ${GFORTRAN_LIBRARIES_DIR}/libgfortran.a ${GFORTRAN_LIBRARIES_DIR}/libquadmath.a ${GFORTRAN_LIBRARIES_DIR}/libgcc_s.1.1.dylib) +elseif (MSVC) + target_link_libraries(libkaldi INTERFACE kaldi-base kaldi-matrix kaldi-util kaldi-feat-common kaldi-mfcc kaldi-fbank openblas) +else() + target_link_libraries(libkaldi INTERFACE -Wl,--start-group -Wl,--whole-archive ${KALDI_LIBRARIES} libopenblas.a gfortran -Wl,--no-whole-archive -Wl,--end-group) +endif() + +target_compile_definitions(libkaldi INTERFACE "-DCOMPILE_WITHOUT_OPENFST") diff --git a/audio/paddleaudio/third_party/patches/config.guess b/audio/paddleaudio/third_party/patches/config.guess new file mode 100644 index 00000000..7f76b622 --- /dev/null +++ b/audio/paddleaudio/third_party/patches/config.guess @@ -0,0 +1,1754 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-09' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +# +# Please send patches to . + + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2022 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Just in case it came from the environment. +GUESS= + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if test -f /.attbin/uname ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case $UNAME_SYSTEM in +Linux|GNU|GNU/*) + LIBC=unknown + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #elif defined(__GLIBC__) + LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif + #endif + EOF + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case $UNAME_MACHINE_ARCH in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case $UNAME_MACHINE_ARCH in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case $UNAME_VERSION in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + GUESS=$machine-${os}${release}${abi-} + ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; + *:ekkoBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; + *:SolidBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; + macppc:MirBSD:*:*) + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; + *:MirBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; + *:Sortix:*:*) + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; + alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case $ALPHA_CPU_TYPE in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; + Amiga*:UNIX_System_V:4.0:*) + GUESS=m68k-unknown-sysv4 + ;; + *:[Aa]miga[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; + *:[Mm]orph[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-morphos + ;; + *:OS/390:*:*) + GUESS=i370-ibm-openedition + ;; + *:z/VM:*:*) + GUESS=s390-ibm-zvmoe + ;; + *:OS400:*:*) + GUESS=powerpc-ibm-os400 + ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + GUESS=arm-unknown-riscos + ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + GUESS=hppa1.1-hitachi-hiuxmpp + ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; + NILE*:*:*:dcosx) + GUESS=pyramid-pyramid-svr4 + ;; + DRS?6000:unix:4.0:6*) + GUESS=sparc-icl-nx6 + ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; + s390x:SunOS:*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; + sun4H:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; + sun4*:SunOS:*:*) + case `/usr/bin/arch -k` in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; + sun3*:SunOS:*:*) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case `/bin/arch` in + sun3) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun4) + GUESS=sparc-sun-sunos$UNAME_RELEASE + ;; + esac + ;; + aushp:SunOS:*:*) + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; + m68k:machten:*:*) + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; + powerpc:machten:*:*) + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; + RISC*:Mach:*:*) + GUESS=mips-dec-mach_bsd4.3 + ;; + RISC*:ULTRIX:*:*) + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; + VAX*:ULTRIX*:*:*) + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; + Motorola:PowerMAX_OS:*:*) + GUESS=powerpc-motorola-powermax + ;; + Motorola:*:4.3:PL8-*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:Power_UNIX:*:*) + GUESS=powerpc-harris-powerunix + ;; + m88k:CX/UX:7*:*) + GUESS=m88k-harris-cxux7 + ;; + m88k:*:4*:R4*) + GUESS=m88k-motorola-sysv4 + ;; + m88k:*:3*:R3*) + GUESS=m88k-motorola-sysv3 + ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 + then + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x + then + GUESS=m88k-dg-dgux$UNAME_RELEASE + else + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE + fi + else + GUESS=i586-dg-dgux$UNAME_RELEASE + fi + ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + GUESS=m88k-dolphin-sysv3 + ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + GUESS=m88k-motorola-sysv3 + ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + GUESS=m88k-tektronix-sysv3 + ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + GUESS=m68k-tektronix-bsd + ;; + *:IRIX*:*:*) + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + GUESS=i386-ibm-aix + ;; + ia64:AIX:*:*) + if test -x /usr/bin/oslevel ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + GUESS=$SYSTEM_NAME + else + GUESS=rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + GUESS=rs6000-ibm-aix3.2.4 + else + GUESS=rs6000-ibm-aix3.2 + fi + ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; + *:AIX:*:*) + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + GUESS=rs6000-bull-bosx + ;; + DPX/2?00:B.O.S.:*:*) + GUESS=m68k-bull-sysv3 + ;; + 9000/[34]??:4.3bsd:1.*:*) + GUESS=m68k-hp-bsd + ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + GUESS=m68k-hp-bsd4.4 + ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if test -x /usr/bin/getconf; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case $sc_cpu_version in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case $sc_kernel_bits in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if test "$HP_ARCH" = hppa2.0w + then + set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; + 3050*:HI-UX:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; + 9000/8??:4.3bsd:*:*) + GUESS=hppa1.0-hp-bsd + ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; + hp8??:OSF1:*:*) + GUESS=hppa1.0-hp-osf + ;; + i*86:OSF1:*:*) + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk + else + GUESS=$UNAME_MACHINE-unknown-osf1 + fi + ;; + parisc*:Lites*:*:*) + GUESS=hppa1.1-hp-lites + ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + GUESS=c1-convex-bsd + ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + GUESS=c34-convex-bsd + ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + GUESS=c38-convex-bsd + ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + GUESS=c4-convex-bsd + ;; + CRAY*Y-MP:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; + CRAY*T3E:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; + CRAY*SV1:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; + *:UNICOS/mp:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; + sparc*:BSD/OS:*:*) + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; + *:BSD/OS:*:*) + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case $UNAME_PROCESSOR in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; + i*:CYGWIN*:*) + GUESS=$UNAME_MACHINE-pc-cygwin + ;; + *:MINGW64*:*) + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; + *:MINGW*:*) + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; + *:MSYS*:*) + GUESS=$UNAME_MACHINE-pc-msys + ;; + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; + *:Interix*:*) + case $UNAME_MACHINE in + x86) + GUESS=i586-pc-interix$UNAME_RELEASE + ;; + authenticamd | genuineintel | EM64T) + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; + IA64) + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; + esac ;; + i*:UWIN*:*) + GUESS=$UNAME_MACHINE-pc-uwin + ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + GUESS=x86_64-pc-cygwin + ;; + prep*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; + *:GNU:*:*) + # the GNU system + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi + else + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf + fi + fi + ;; + avr32*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + cris:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + crisv32:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + e2k:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + frv:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + hexagon:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:Linux:*:*) + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; + ia64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m32r*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m68*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + MIPS_ENDIAN=el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + MIPS_ENDIAN= + #else + MIPS_ENDIAN= + #endif + #endif +EOF + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + openrisc*:Linux:*:*) + GUESS=or1k-unknown-linux-$LIBC + ;; + or32:Linux:*:* | or1k*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + padre:Linux:*:*) + GUESS=sparc-unknown-linux-$LIBC + ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + GUESS=hppa64-unknown-linux-$LIBC + ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; + esac + ;; + ppc64:Linux:*:*) + GUESS=powerpc64-unknown-linux-$LIBC + ;; + ppc:Linux:*:*) + GUESS=powerpc-unknown-linux-$LIBC + ;; + ppc64le:Linux:*:*) + GUESS=powerpc64le-unknown-linux-$LIBC + ;; + ppcle:Linux:*:*) + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + s390:Linux:*:* | s390x:Linux:*:*) + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; + sh64*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sh*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + tile*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + vax:Linux:*:*) + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; + x86_64:Linux:*:*) + set_cc_for_build + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_X32 >/dev/null + then + LIBCABI=${LIBC}x32 + fi + fi + GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI + ;; + xtensa*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + GUESS=i386-sequent-sysv4 + ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; + i*86:XTS-300:*:STOP) + GUESS=$UNAME_MACHINE-unknown-stop + ;; + i*86:atheos:*:*) + GUESS=$UNAME_MACHINE-unknown-atheos + ;; + i*86:syllable:*:*) + GUESS=$UNAME_MACHINE-pc-syllable + ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; + i*86:*DOS:*:*) + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL + fi + ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv32 + fi + ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + GUESS=i586-pc-msdosdjgpp + ;; + Intel:Mach:3*:*) + GUESS=i386-pc-mach3 + ;; + paragon:*:*:*) + GUESS=i860-intel-osf1 + ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 + fi + ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + GUESS=m68010-convergent-sysv + ;; + mc68k:UNIX:SYSTEM5:3.51m) + GUESS=m68k-convergent-sysv + ;; + M680?0:D-NIX:5.3:*) + GUESS=m68k-diab-dnix + ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; + mc68030:UNIX_System_V:4.*:*) + GUESS=m68k-atari-sysv4 + ;; + TSUNAMI:LynxOS:2.*:*) + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; + rs6000:LynxOS:2.*:*) + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; + SM[BE]S:UNIX_SV:*:*) + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; + RM*:ReliantUNIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + RM*:SINIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 + else + GUESS=ns32k-sni-sysv + fi + ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + GUESS=i586-unisys-sysv4 + ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + GUESS=hppa1.1-stratus-sysv4 + ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + GUESS=i860-stratus-sysv4 + ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=$UNAME_MACHINE-stratus-vos + ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=hppa1.1-stratus-vos + ;; + mc68*:A/UX:*:*) + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; + news*:NEWS-OS:6*:*) + GUESS=mips-sony-newsos6 + ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE + else + GUESS=mips-unknown-sysv$UNAME_RELEASE + fi + ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + GUESS=powerpc-be-beos + ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + GUESS=powerpc-apple-beos + ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + GUESS=i586-pc-beos + ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + GUESS=i586-pc-haiku + ;; + x86_64:Haiku:*:*) + GUESS=x86_64-unknown-haiku + ;; + SX-4:SUPER-UX:*:*) + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; + SX-5:SUPER-UX:*:*) + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; + SX-6:SUPER-UX:*:*) + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; + SX-7:SUPER-UX:*:*) + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; + SX-8:SUPER-UX:*:*) + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; + SX-8R:SUPER-UX:*:*) + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; + SX-ACE:SUPER-UX:*:*) + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; + Power*:Rhapsody:*:*) + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; + *:Rhapsody:*:*) + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build + fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE + fi + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; + *:QNX:*:4*) + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; + NSE-*:NONSTOP_KERNEL:*:*) + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; + *:NonStop-UX:*:*) + GUESS=mips-compaq-nonstopux + ;; + BS2000:POSIX*:*:*) + GUESS=bs2000-siemens-sysv + ;; + DS/*:UNIX_System_V:*:*) + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "${cputype-}" = 386; then + UNAME_MACHINE=i386 + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype + fi + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; + *:TOPS-10:*:*) + GUESS=pdp10-unknown-tops10 + ;; + *:TENEX:*:*) + GUESS=pdp10-unknown-tenex + ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + GUESS=pdp10-dec-tops20 + ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + GUESS=pdp10-xkl-tops20 + ;; + *:TOPS-20:*:*) + GUESS=pdp10-unknown-tops20 + ;; + *:ITS:*:*) + GUESS=pdp10-unknown-its + ;; + SEI:*:*:SEIUX) + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; + *:DragonFly:*:*) + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; + esac ;; + *:XENIX:*:SysV) + GUESS=i386-pc-xenix + ;; + i*86:skyos:*:*) + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; + i*86:rdos:*:*) + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; + x86_64:VMkernel:*:*) + GUESS=$UNAME_MACHINE-unknown-esx + ;; + amd64:Isilon\ OneFS:*:*) + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; +esac + +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF +fi + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/audio/paddleaudio/third_party/patches/config.sub b/audio/paddleaudio/third_party/patches/config.sub new file mode 100644 index 00000000..dba16e84 --- /dev/null +++ b/audio/paddleaudio/third_party/patches/config.sub @@ -0,0 +1,1890 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-03' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2022 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x$basic_os != x +then + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-aix*) + vendor=ibm + ;; + *-beos*) + vendor=be + ;; + *-hpux*) + vendor=hp + ;; + *-mpeix*) + vendor=hp + ;; + *-hiux*) + vendor=hitachi + ;; + *-unos*) + vendor=crds + ;; + *-dgux*) + vendor=dg + ;; + *-luna*) + vendor=omron + ;; + *-genix*) + vendor=ns + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) + vendor=sequent + ;; + *-tpf*) + vendor=ibm + ;; + *-vxsim* | *-vxworks* | *-windiss*) + vendor=wrs + ;; + *-aux*) + vendor=apple + ;; + *-hms*) + vendor=hitachi + ;; + *-mpw* | *-macos*) + vendor=apple + ;; + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) + vendor=atari + ;; + *-vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor-${kernel:+$kernel-}$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/audio/paddleaudio/third_party/patches/libmad.patch b/audio/paddleaudio/third_party/patches/libmad.patch new file mode 100644 index 00000000..a8057878 --- /dev/null +++ b/audio/paddleaudio/third_party/patches/libmad.patch @@ -0,0 +1,86 @@ +See the followings for the origin of this patch +http://www.linuxfromscratch.org/blfs/view/svn/multimedia/libmad.html +http://www.linuxfromscratch.org/patches/blfs/svn/libmad-0.15.1b-fixes-1.patch +--- src/libmad/configure 2004-02-05 09:34:07.000000000 +0000 ++++ src/libmad/configure.new 2020-06-30 21:10:28.528018931 +0000 +@@ -19083,71 +19083,7 @@ + + if test "$GCC" = yes + then +- if test -z "$arch" +- then +- case "$host" in +- i386-*) ;; +- i?86-*) arch="-march=i486" ;; +- arm*-empeg-*) arch="-march=armv4 -mtune=strongarm1100" ;; +- armv4*-*) arch="-march=armv4 -mtune=strongarm" ;; +- powerpc-*) ;; +- mips*-agenda-*) arch="-mcpu=vr4100" ;; +- mips*-luxsonor-*) arch="-mips1 -mcpu=r3000 -Wa,-m4010" ;; +- esac +- fi +- +- case "$optimize" in +- -O|"-O "*) +- optimize="-O" +- optimize="$optimize -fforce-mem" +- optimize="$optimize -fforce-addr" +- : #x optimize="$optimize -finline-functions" +- : #- optimize="$optimize -fstrength-reduce" +- optimize="$optimize -fthread-jumps" +- optimize="$optimize -fcse-follow-jumps" +- optimize="$optimize -fcse-skip-blocks" +- : #x optimize="$optimize -frerun-cse-after-loop" +- : #x optimize="$optimize -frerun-loop-opt" +- : #x optimize="$optimize -fgcse" +- optimize="$optimize -fexpensive-optimizations" +- optimize="$optimize -fregmove" +- : #* optimize="$optimize -fdelayed-branch" +- : #x optimize="$optimize -fschedule-insns" +- optimize="$optimize -fschedule-insns2" +- : #? optimize="$optimize -ffunction-sections" +- : #? optimize="$optimize -fcaller-saves" +- : #> optimize="$optimize -funroll-loops" +- : #> optimize="$optimize -funroll-all-loops" +- : #x optimize="$optimize -fmove-all-movables" +- : #x optimize="$optimize -freduce-all-givs" +- : #? optimize="$optimize -fstrict-aliasing" +- : #* optimize="$optimize -fstructure-noalias" +- +- case "$host" in +- arm*-*) +- optimize="$optimize -fstrength-reduce" +- ;; +- mips*-*) +- optimize="$optimize -fstrength-reduce" +- optimize="$optimize -finline-functions" +- ;; +- i?86-*) +- optimize="$optimize -fstrength-reduce" +- ;; +- powerpc-apple-*) +- # this triggers an internal compiler error with gcc2 +- : #optimize="$optimize -fstrength-reduce" +- +- # this is really only beneficial with gcc3 +- : #optimize="$optimize -finline-functions" +- ;; +- *) +- # this sometimes provokes bugs in gcc 2.95.2 +- : #optimize="$optimize -fstrength-reduce" +- ;; +- esac +- ;; +- esac ++ optimize="-O2" + fi + + case "$host" in +@@ -21497,6 +21433,7 @@ + then + case "$host" in + i?86-*) FPM="INTEL" ;; ++ x86_64*) FPM="64BIT" ;; + arm*-*) FPM="ARM" ;; + mips*-*) FPM="MIPS" ;; + sparc*-*) FPM="SPARC" ;; diff --git a/audio/paddleaudio/third_party/patches/sox.patch b/audio/paddleaudio/third_party/patches/sox.patch new file mode 100644 index 00000000..fe8df945 --- /dev/null +++ b/audio/paddleaudio/third_party/patches/sox.patch @@ -0,0 +1,16 @@ +See https://github.com/pytorch/audio/pull/1297 +diff -ru sox/src/formats.c sox/src/formats.c +--- sox/src/formats.c 2014-10-26 19:55:50.000000000 -0700 ++++ sox/src/formats.c 2021-02-22 16:01:02.833144070 -0800 +@@ -333,6 +333,10 @@ + assert(ft); + if (!ft->fp) + return sox_false; +- fstat(fileno((FILE*)ft->fp), &st); ++ int fd = fileno((FILE*)ft->fp); ++ if (fd < 0) ++ return sox_false; ++ if (fstat(fd, &st) < 0) ++ return sox_false; + return ((st.st_mode & S_IFMT) == S_IFREG); + } diff --git a/audio/paddleaudio/third_party/sox/CMakeLists.txt b/audio/paddleaudio/third_party/sox/CMakeLists.txt new file mode 100644 index 00000000..8a5bc55c --- /dev/null +++ b/audio/paddleaudio/third_party/sox/CMakeLists.txt @@ -0,0 +1,254 @@ +find_package(PkgConfig REQUIRED) + +include(ExternalProject) + +set(INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../install) +set(ARCHIVE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../archives) +set(patch_dir ${CMAKE_CURRENT_SOURCE_DIR}/../patches) +set(COMMON_ARGS --quiet --disable-shared --enable-static --prefix=${INSTALL_DIR} --with-pic --disable-dependency-tracking --disable-debug --disable-examples --disable-doc) + +# To pass custom environment variables to ExternalProject_Add command, +# we need to do `${CMAKE_COMMAND} -E env ${envs} `. +# https://stackoverflow.com/a/62437353 +# We constrcut the custom environment variables here +set(envs + "PKG_CONFIG_PATH=${INSTALL_DIR}/lib/pkgconfig" + "LDFLAGS=-L${INSTALL_DIR}/lib $ENV{LDFLAGS}" + "CFLAGS=-I${INSTALL_DIR}/include -fvisibility=hidden $ENV{CFLAGS}" +) + +if (BUILD_MAD) + ExternalProject_Add(mad + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://downloads.sourceforge.net/project/mad/libmad/0.15.1b/libmad-0.15.1b.tar.gz + URL_HASH SHA256=bbfac3ed6bfbc2823d3775ebb931087371e142bb0e9bb1bee51a76a6e0078690 + PATCH_COMMAND patch < ${patch_dir}/libmad.patch && cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/mad/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/mad/configure ${COMMON_ARGS} + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON + ) +endif (BUILD_MAD) + +ExternalProject_Add(amr + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz + URL_HASH SHA256=2c006cb9d5f651bfb5e60156dbff6af3c9d35c7bbcc9015308c0aff1e14cd341 + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/amr/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/amr/configure ${COMMON_ARGS} + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +ExternalProject_Add(lame + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz + URL_HASH SHA256=24346b4158e4af3bd9f2e194bb23eb473c75fb7377011523353196b19b9a23ff + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/lame/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/lame/configure ${COMMON_ARGS} --enable-nasm + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +ExternalProject_Add(ogg + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://ftp.osuosl.org/pub/xiph/releases/ogg/libogg-1.3.3.tar.gz + URL_HASH SHA256=c2e8a485110b97550f453226ec644ebac6cb29d1caef2902c007edab4308d985 + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/ogg/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/ogg/configure ${COMMON_ARGS} + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +ExternalProject_Add(flac + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ogg + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.2.tar.xz + URL_HASH SHA256=91cfc3ed61dc40f47f050a109b08610667d73477af6ef36dcad31c31a4a8d53f + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/flac/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/flac/configure ${COMMON_ARGS} --with-ogg --disable-cpplibs + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +ExternalProject_Add(vorbis + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ogg + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://ftp.osuosl.org/pub/xiph/releases/vorbis/libvorbis-1.3.6.tar.gz + URL_HASH SHA256=6ed40e0241089a42c48604dc00e362beee00036af2d8b3f46338031c9e0351cb + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/vorbis/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/vorbis/configure ${COMMON_ARGS} --with-ogg + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +ExternalProject_Add(opus + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ogg + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://ftp.osuosl.org/pub/xiph/releases/opus/opus-1.3.1.tar.gz + URL_HASH SHA256=65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/opus/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/opus/configure ${COMMON_ARGS} --with-ogg + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +ExternalProject_Add(opusfile + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS opus + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://ftp.osuosl.org/pub/xiph/releases/opus/opusfile-0.12.tar.gz + URL_HASH SHA256=118d8601c12dd6a44f52423e68ca9083cc9f2bfe72da7a8c1acb22a80ae3550b + PATCH_COMMAND cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/opusfile/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/opusfile/configure ${COMMON_ARGS} --disable-http + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +# OpenMP is by default compiled against GNU OpenMP, which conflicts with the version of OpenMP that PyTorch uses. +# See https://github.com/pytorch/audio/pull/1026 +# TODO: Add flags like https://github.com/suphoff/pytorch_parallel_extension_cpp/blob/master/setup.py +set(SOX_OPTIONS + --disable-openmp + --with-amrnb + --with-amrwb + --with-flac + --with-lame + --with-oggvorbis + --with-opus + --without-alsa + --without-ao + --without-coreaudio + --without-oss + --without-id3tag + --without-ladspa + --without-magic + --without-png + --without-pulseaudio + --without-sndfile + --without-sndio + --without-sunaudio + --without-waveaudio + --without-wavpack + --without-twolame + ) + +set(SOX_LIBRARIES + ${INSTALL_DIR}/lib/libsox.a + ${INSTALL_DIR}/lib/libopencore-amrnb.a + ${INSTALL_DIR}/lib/libopencore-amrwb.a + ${INSTALL_DIR}/lib/libmp3lame.a + ${INSTALL_DIR}/lib/libFLAC.a + ${INSTALL_DIR}/lib/libopusfile.a + ${INSTALL_DIR}/lib/libopus.a + ${INSTALL_DIR}/lib/libvorbisenc.a + ${INSTALL_DIR}/lib/libvorbisfile.a + ${INSTALL_DIR}/lib/libvorbis.a + ${INSTALL_DIR}/lib/libogg.a + ) + +set(sox_depends + ogg flac vorbis opusfile lame amr + ) + +if (BUILD_MAD) + list( + APPEND + SOX_OPTIONS + --with-mad + ) + list( + APPEND + SOX_LIBRARIES + ${INSTALL_DIR}/lib/libmad.a + ) + list( + APPEND + sox_depends + mad + ) +else () + list( + APPEND + SOX_OPTIONS + --without-mad + ) +endif (BUILD_MAD) + +ExternalProject_Add(sox + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${sox_depends} + DOWNLOAD_DIR ${ARCHIVE_DIR} + URL https://downloads.sourceforge.net/project/sox/sox/14.4.2/sox-14.4.2.tar.bz2 + URL_HASH SHA256=81a6956d4330e75b5827316e44ae381e6f1e8928003c6aa45896da9041ea149c + PATCH_COMMAND patch -p1 < ${patch_dir}/sox.patch && cp ${patch_dir}/config.guess ${patch_dir}/config.sub ${CMAKE_CURRENT_BINARY_DIR}/src/sox/ + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${envs} ${CMAKE_CURRENT_BINARY_DIR}/src/sox/configure ${COMMON_ARGS} ${SOX_OPTIONS} + BUILD_BYPRODUCTS ${SOX_LIBRARIES} + DOWNLOAD_NO_PROGRESS ON + LOG_DOWNLOAD ON + LOG_UPDATE ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_MERGED_STDOUTERR ON + LOG_OUTPUT_ON_FAILURE ON +) + +add_library(libsox INTERFACE) +add_dependencies(libsox sox) +target_include_directories(libsox INTERFACE ${INSTALL_DIR}/include) +target_link_libraries(libsox INTERFACE ${SOX_LIBRARIES}) \ No newline at end of file diff --git a/audio/paddleaudio/utils/__init__.py b/audio/paddleaudio/utils/__init__.py new file mode 100644 index 00000000..e66d1ab4 --- /dev/null +++ b/audio/paddleaudio/utils/__init__.py @@ -0,0 +1,27 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License" +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from .download import decompress +from .download import download_and_decompress +from .download import load_state_dict_from_url +from .env import DATA_HOME +from .env import MODEL_HOME +from .env import PPAUDIO_HOME +from .env import USER_HOME +from .error import ParameterError +from .log import Logger +from .log import logger +from .numeric import depth_convert +from .numeric import pcm16to32 +from .time import seconds_to_hms +from .time import Timer diff --git a/audio/paddleaudio/utils/download.py b/audio/paddleaudio/utils/download.py new file mode 100644 index 00000000..07d5eea8 --- /dev/null +++ b/audio/paddleaudio/utils/download.py @@ -0,0 +1,64 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License" +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from typing import Dict +from typing import List + +from paddle.framework import load as load_state_dict +from paddle.utils import download + +from .log import logger + +download.logger = logger + +__all__ = [ + 'decompress', + 'download_and_decompress', + 'load_state_dict_from_url', +] + + +def decompress(file: str): + """ + Extracts all files from a compressed file. + """ + assert os.path.isfile(file), "File: {} not exists.".format(file) + download._decompress(file) + + +def download_and_decompress(archives: List[Dict[str, str]], + path: str, + decompress: bool=True): + """ + Download archieves and decompress to specific path. + """ + if not os.path.isdir(path): + os.makedirs(path) + + for archive in archives: + assert 'url' in archive and 'md5' in archive, \ + 'Dictionary keys of "url" and "md5" are required in the archive, but got: {list(archieve.keys())}' + download.get_path_from_url( + archive['url'], path, archive['md5'], decompress=decompress) + + +def load_state_dict_from_url(url: str, path: str, md5: str=None): + """ + Download and load a state dict from url + """ + if not os.path.isdir(path): + os.makedirs(path) + + download.get_path_from_url(url, path, md5) + return load_state_dict(os.path.join(path, os.path.basename(url))) diff --git a/audio/paddleaudio/utils/env.py b/audio/paddleaudio/utils/env.py new file mode 100644 index 00000000..a2d14b89 --- /dev/null +++ b/audio/paddleaudio/utils/env.py @@ -0,0 +1,60 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License" +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +''' +This module is used to store environmental variables in PaddleAudio. +PPAUDIO_HOME --> the root directory for storing PaddleAudio related data. Default to ~/.paddleaudio. Users can change the +├ default value through the PPAUDIO_HOME environment variable. +├─ MODEL_HOME --> Store model files. +└─ DATA_HOME --> Store automatically downloaded datasets. +''' +import os + +__all__ = [ + 'USER_HOME', + 'PPAUDIO_HOME', + 'MODEL_HOME', + 'DATA_HOME', +] + + +def _get_user_home(): + return os.path.expanduser('~') + + +def _get_ppaudio_home(): + if 'PPAUDIO_HOME' in os.environ: + home_path = os.environ['PPAUDIO_HOME'] + if os.path.exists(home_path): + if os.path.isdir(home_path): + return home_path + else: + raise RuntimeError( + 'The environment variable PPAUDIO_HOME {} is not a directory.'. + format(home_path)) + else: + return home_path + return os.path.join(_get_user_home(), '.paddleaudio') + + +def _get_sub_home(directory): + home = os.path.join(_get_ppaudio_home(), directory) + if not os.path.exists(home): + os.makedirs(home) + return home + + +USER_HOME = _get_user_home() +PPAUDIO_HOME = _get_ppaudio_home() +MODEL_HOME = _get_sub_home('models') +DATA_HOME = _get_sub_home('datasets') diff --git a/paddlespeech/audio/io/__init__.py b/audio/paddleaudio/utils/error.py similarity index 83% rename from paddlespeech/audio/io/__init__.py rename to audio/paddleaudio/utils/error.py index 185a92b8..f3977489 100644 --- a/paddlespeech/audio/io/__init__.py +++ b/audio/paddleaudio/utils/error.py @@ -11,3 +11,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + +__all__ = ['ParameterError'] + + +class ParameterError(Exception): + """Exception class for Parameter checking""" + pass diff --git a/audio/paddleaudio/utils/log.py b/audio/paddleaudio/utils/log.py new file mode 100644 index 00000000..5656b286 --- /dev/null +++ b/audio/paddleaudio/utils/log.py @@ -0,0 +1,139 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License" +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import contextlib +import functools +import logging +import threading +import time + +import colorlog + +__all__ = [ + 'Logger', + 'logger', +] + +log_config = { + 'DEBUG': { + 'level': 10, + 'color': 'purple' + }, + 'INFO': { + 'level': 20, + 'color': 'green' + }, + 'TRAIN': { + 'level': 21, + 'color': 'cyan' + }, + 'EVAL': { + 'level': 22, + 'color': 'blue' + }, + 'WARNING': { + 'level': 30, + 'color': 'yellow' + }, + 'ERROR': { + 'level': 40, + 'color': 'red' + }, + 'CRITICAL': { + 'level': 50, + 'color': 'bold_red' + } +} + + +class Logger(object): + ''' + Deafult logger in PaddleAudio + Args: + name(str) : Logger name, default is 'PaddleAudio' + ''' + + def __init__(self, name: str=None): + name = 'PaddleAudio' if not name else name + self.logger = logging.getLogger(name) + + for key, conf in log_config.items(): + logging.addLevelName(conf['level'], key) + self.__dict__[key] = functools.partial(self.__call__, conf['level']) + self.__dict__[key.lower()] = functools.partial(self.__call__, + conf['level']) + + self.format = colorlog.ColoredFormatter( + '%(log_color)s[%(asctime)-15s] [%(levelname)8s]%(reset)s - %(message)s', + log_colors={key: conf['color'] + for key, conf in log_config.items()}) + + self.handler = logging.StreamHandler() + self.handler.setFormatter(self.format) + + self.logger.addHandler(self.handler) + self.logLevel = 'DEBUG' + self.logger.setLevel(logging.DEBUG) + self.logger.propagate = False + self._is_enable = True + + def disable(self): + self._is_enable = False + + def enable(self): + self._is_enable = True + + @property + def is_enable(self) -> bool: + return self._is_enable + + def __call__(self, log_level: str, msg: str): + if not self.is_enable: + return + + self.logger.log(log_level, msg) + + @contextlib.contextmanager + def use_terminator(self, terminator: str): + old_terminator = self.handler.terminator + self.handler.terminator = terminator + yield + self.handler.terminator = old_terminator + + @contextlib.contextmanager + def processing(self, msg: str, interval: float=0.1): + ''' + Continuously print a progress bar with rotating special effects. + Args: + msg(str): Message to be printed. + interval(float): Rotation interval. Default to 0.1. + ''' + end = False + + def _printer(): + index = 0 + flags = ['\\', '|', '/', '-'] + while not end: + flag = flags[index % len(flags)] + with self.use_terminator('\r'): + self.info('{}: {}'.format(msg, flag)) + time.sleep(interval) + index += 1 + + t = threading.Thread(target=_printer) + t.start() + yield + end = True + + +logger = Logger() diff --git a/audio/paddleaudio/utils/numeric.py b/audio/paddleaudio/utils/numeric.py new file mode 100644 index 00000000..9fe00484 --- /dev/null +++ b/audio/paddleaudio/utils/numeric.py @@ -0,0 +1,107 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Union + +import numpy as np + +__all__ = ["pcm16to32", "depth_convert"] + + +def pcm16to32(audio: np.ndarray) -> np.ndarray: + """pcm int16 to float32 + + Args: + audio (np.ndarray): Waveform with dtype of int16. + + Returns: + np.ndarray: Waveform with dtype of float32. + """ + if audio.dtype == np.int16: + audio = audio.astype("float32") + bits = np.iinfo(np.int16).bits + audio = audio / (2**(bits - 1)) + return audio + + +def _safe_cast(y: np.ndarray, dtype: Union[type, str]) -> np.ndarray: + """Data type casting in a safe way, i.e., prevent overflow or underflow. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + dtype (Union[type, str]): Data type of waveform. + + Returns: + np.ndarray: `y` after safe casting. + """ + if 'float' in str(y.dtype): + return np.clip(y, np.finfo(dtype).min, + np.finfo(dtype).max).astype(dtype) + else: + return np.clip(y, np.iinfo(dtype).min, + np.iinfo(dtype).max).astype(dtype) + + +def depth_convert(y: np.ndarray, dtype: Union[type, str]) -> np.ndarray: + """Convert audio array to target dtype safely. + This function convert audio waveform to a target dtype, with addition steps of + preventing overflow/underflow and preserving audio range. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + dtype (Union[type, str]): Data type of waveform. + + Returns: + np.ndarray: `y` after safe casting. + """ + + SUPPORT_DTYPE = ['int16', 'int8', 'float32', 'float64'] + if y.dtype not in SUPPORT_DTYPE: + raise ParameterError( + 'Unsupported audio dtype, ' + f'y.dtype is {y.dtype}, supported dtypes are {SUPPORT_DTYPE}') + + if dtype not in SUPPORT_DTYPE: + raise ParameterError( + 'Unsupported audio dtype, ' + f'target dtype is {dtype}, supported dtypes are {SUPPORT_DTYPE}') + + if dtype == y.dtype: + return y + + if dtype == 'float64' and y.dtype == 'float32': + return _safe_cast(y, dtype) + if dtype == 'float32' and y.dtype == 'float64': + return _safe_cast(y, dtype) + + if dtype == 'int16' or dtype == 'int8': + if y.dtype in ['float64', 'float32']: + factor = np.iinfo(dtype).max + y = np.clip(y * factor, np.iinfo(dtype).min, + np.iinfo(dtype).max).astype(dtype) + y = y.astype(dtype) + else: + if dtype == 'int16' and y.dtype == 'int8': + factor = np.iinfo('int16').max / np.iinfo('int8').max - EPS + y = y.astype('float32') * factor + y = y.astype('int16') + + else: # dtype == 'int8' and y.dtype=='int16': + y = y.astype('int32') * np.iinfo('int8').max / \ + np.iinfo('int16').max + y = y.astype('int8') + + if dtype in ['float32', 'float64']: + org_dtype = y.dtype + y = y.astype(dtype) / np.iinfo(org_dtype).max + return y diff --git a/audio/paddleaudio/utils/sox_utils.py b/audio/paddleaudio/utils/sox_utils.py new file mode 100644 index 00000000..305bb68b --- /dev/null +++ b/audio/paddleaudio/utils/sox_utils.py @@ -0,0 +1,103 @@ +from typing import Dict +from typing import List + +import paddleaudio +from paddleaudio._internal import module_utils as _mod_utils + + +@_mod_utils.requires_sox() +def set_seed(seed: int): + """Set libsox's PRNG + + Args: + seed (int): seed value. valid range is int32. + + See Also: + http://sox.sourceforge.net/sox.html + """ + paddleaudio._paddleaudio.sox_utils_set_seed(seed) + + +@_mod_utils.requires_sox() +def set_verbosity(verbosity: int): + """Set libsox's verbosity + + Args: + verbosity (int): Set verbosity level of libsox. + + * ``1`` failure messages + * ``2`` warnings + * ``3`` details of processing + * ``4``-``6`` increasing levels of debug messages + + See Also: + http://sox.sourceforge.net/sox.html + """ + paddleaudio._paddleaudio.sox_utils_set_verbosity(verbosity) + + +@_mod_utils.requires_sox() +def set_buffer_size(buffer_size: int): + """Set buffer size for sox effect chain + + Args: + buffer_size (int): Set the size in bytes of the buffers used for processing audio. + + See Also: + http://sox.sourceforge.net/sox.html + """ + paddleaudio._paddleaudio.sox_utils_set_buffer_size(buffer_size) + + +@_mod_utils.requires_sox() +def set_use_threads(use_threads: bool): + """Set multithread option for sox effect chain + + Args: + use_threads (bool): When ``True``, enables ``libsox``'s parallel effects channels processing. + To use mutlithread, the underlying ``libsox`` has to be compiled with OpenMP support. + + See Also: + http://sox.sourceforge.net/sox.html + """ + paddleaudio._paddleaudio.sox_utils_set_use_threads(use_threads) + + +@_mod_utils.requires_sox() +def list_effects() -> Dict[str, str]: + """List the available sox effect names + + Returns: + Dict[str, str]: Mapping from ``effect name`` to ``usage`` + """ + return dict(paddleaudio._paddleaudio.sox_utils_list_effects()) + + +@_mod_utils.requires_sox() +def list_read_formats() -> List[str]: + """List the supported audio formats for read + + Returns: + List[str]: List of supported audio formats + """ + return paddleaudio._paddleaudio.sox_utils_list_read_formats() + + +@_mod_utils.requires_sox() +def list_write_formats() -> List[str]: + """List the supported audio formats for write + + Returns: + List[str]: List of supported audio formats + """ + return paddleaudio._paddleaudio.sox_utils_list_write_formats() + + +@_mod_utils.requires_sox() +def get_buffer_size() -> int: + """Get buffer size for sox effect chain + + Returns: + int: size in bytes of buffers used for processing audio. + """ + return paddleaudio._paddleaudio.sox_utils_get_buffer_size() diff --git a/audio/paddleaudio/utils/tensor_utils.py b/audio/paddleaudio/utils/tensor_utils.py new file mode 100644 index 00000000..16f60810 --- /dev/null +++ b/audio/paddleaudio/utils/tensor_utils.py @@ -0,0 +1,192 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Unility functions for Transformer.""" +from typing import List +from typing import Tuple + +import paddle + +from .log import Logger + +__all__ = ["pad_sequence", "add_sos_eos", "th_accuracy", "has_tensor"] + +logger = Logger(__name__) + + +def has_tensor(val): + if isinstance(val, (list, tuple)): + for item in val: + if has_tensor(item): + return True + elif isinstance(val, dict): + for k, v in val.items(): + print(k) + if has_tensor(v): + return True + else: + return paddle.is_tensor(val) + + +def pad_sequence(sequences: List[paddle.Tensor], + batch_first: bool=False, + padding_value: float=0.0) -> paddle.Tensor: + r"""Pad a list of variable length Tensors with ``padding_value`` + + ``pad_sequence`` stacks a list of Tensors along a new dimension, + and pads them to equal length. For example, if the input is list of + sequences with size ``L x *`` and if batch_first is False, and ``T x B x *`` + otherwise. + + `B` is batch size. It is equal to the number of elements in ``sequences``. + `T` is length of the longest sequence. + `L` is length of the sequence. + `*` is any number of trailing dimensions, including none. + + Example: + >>> from paddle.nn.utils.rnn import pad_sequence + >>> a = paddle.ones(25, 300) + >>> b = paddle.ones(22, 300) + >>> c = paddle.ones(15, 300) + >>> pad_sequence([a, b, c]).shape + paddle.Tensor([25, 3, 300]) + + Note: + This function returns a Tensor of size ``T x B x *`` or ``B x T x *`` + where `T` is the length of the longest sequence. This function assumes + trailing dimensions and type of all the Tensors in sequences are same. + + Args: + sequences (list[Tensor]): list of variable length sequences. + batch_first (bool, optional): output will be in ``B x T x *`` if True, or in + ``T x B x *`` otherwise + padding_value (float, optional): value for padded elements. Default: 0. + + Returns: + Tensor of size ``T x B x *`` if :attr:`batch_first` is ``False``. + Tensor of size ``B x T x *`` otherwise + """ + + # assuming trailing dimensions and type of all the Tensors + # in sequences are same and fetching those from sequences[0] + max_size = paddle.shape(sequences[0]) + # (TODO Hui Zhang): slice not supprot `end==start` + # trailing_dims = max_size[1:] + trailing_dims = tuple( + max_size[1:].numpy().tolist()) if sequences[0].ndim >= 2 else () + max_len = max([s.shape[0] for s in sequences]) + if batch_first: + out_dims = (len(sequences), max_len) + trailing_dims + else: + out_dims = (max_len, len(sequences)) + trailing_dims + out_tensor = paddle.full(out_dims, padding_value, sequences[0].dtype) + for i, tensor in enumerate(sequences): + length = tensor.shape[0] + # use index notation to prevent duplicate references to the tensor + if batch_first: + # TODO (Hui Zhang): set_value op not supprot `end==start` + # TODO (Hui Zhang): set_value op not support int16 + # TODO (Hui Zhang): set_varbase 2 rank not support [0,0,...] + # out_tensor[i, :length, ...] = tensor + if length != 0: + out_tensor[i, :length] = tensor + else: + out_tensor[i, length] = tensor + else: + # TODO (Hui Zhang): set_value op not supprot `end==start` + # out_tensor[:length, i, ...] = tensor + if length != 0: + out_tensor[:length, i] = tensor + else: + out_tensor[length, i] = tensor + + return out_tensor + + +def add_sos_eos(ys_pad: paddle.Tensor, sos: int, eos: int, + ignore_id: int) -> Tuple[paddle.Tensor, paddle.Tensor]: + """Add and labels. + Args: + ys_pad (paddle.Tensor): batch of padded target sequences (B, Lmax) + sos (int): index of + eos (int): index of + ignore_id (int): index of padding + Returns: + ys_in (paddle.Tensor) : (B, Lmax + 1) + ys_out (paddle.Tensor) : (B, Lmax + 1) + Examples: + >>> sos_id = 10 + >>> eos_id = 11 + >>> ignore_id = -1 + >>> ys_pad + tensor([[ 1, 2, 3, 4, 5], + [ 4, 5, 6, -1, -1], + [ 7, 8, 9, -1, -1]], dtype=paddle.int32) + >>> ys_in,ys_out=add_sos_eos(ys_pad, sos_id , eos_id, ignore_id) + >>> ys_in + tensor([[10, 1, 2, 3, 4, 5], + [10, 4, 5, 6, 11, 11], + [10, 7, 8, 9, 11, 11]]) + >>> ys_out + tensor([[ 1, 2, 3, 4, 5, 11], + [ 4, 5, 6, 11, -1, -1], + [ 7, 8, 9, 11, -1, -1]]) + """ + # TODO(Hui Zhang): using comment code, + #_sos = paddle.to_tensor( + # [sos], dtype=paddle.long, stop_gradient=True, place=ys_pad.place) + #_eos = paddle.to_tensor( + # [eos], dtype=paddle.long, stop_gradient=True, place=ys_pad.place) + #ys = [y[y != ignore_id] for y in ys_pad] # parse padded ys + #ys_in = [paddle.cat([_sos, y], dim=0) for y in ys] + #ys_out = [paddle.cat([y, _eos], dim=0) for y in ys] + #return pad_sequence(ys_in, padding_value=eos), pad_sequence(ys_out, padding_value=ignore_id) + B = ys_pad.shape[0] + _sos = paddle.ones([B, 1], dtype=ys_pad.dtype) * sos + _eos = paddle.ones([B, 1], dtype=ys_pad.dtype) * eos + ys_in = paddle.cat([_sos, ys_pad], dim=1) + mask_pad = (ys_in == ignore_id) + ys_in = ys_in.masked_fill(mask_pad, eos) + + ys_out = paddle.cat([ys_pad, _eos], dim=1) + ys_out = ys_out.masked_fill(mask_pad, eos) + mask_eos = (ys_out == ignore_id) + ys_out = ys_out.masked_fill(mask_eos, eos) + ys_out = ys_out.masked_fill(mask_pad, ignore_id) + return ys_in, ys_out + + +def th_accuracy(pad_outputs: paddle.Tensor, + pad_targets: paddle.Tensor, + ignore_label: int) -> float: + """Calculate accuracy. + Args: + pad_outputs (Tensor): Prediction tensors (B * Lmax, D). + pad_targets (LongTensor): Target label tensors (B, Lmax, D). + ignore_label (int): Ignore label id. + Returns: + float: Accuracy value (0.0 - 1.0). + """ + pad_pred = pad_outputs.view(pad_targets.shape[0], pad_targets.shape[1], + pad_outputs.shape[1]).argmax(2) + mask = pad_targets != ignore_label + #TODO(Hui Zhang): sum not support bool type + # numerator = paddle.sum( + # pad_pred.masked_select(mask) == pad_targets.masked_select(mask)) + numerator = ( + pad_pred.masked_select(mask) == pad_targets.masked_select(mask)) + numerator = paddle.sum(numerator.type_as(pad_targets)) + #TODO(Hui Zhang): sum not support bool type + # denominator = paddle.sum(mask) + denominator = paddle.sum(mask.type_as(pad_targets)) + return float(numerator) / float(denominator) diff --git a/audio/paddleaudio/utils/time.py b/audio/paddleaudio/utils/time.py new file mode 100644 index 00000000..105208f9 --- /dev/null +++ b/audio/paddleaudio/utils/time.py @@ -0,0 +1,72 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License" +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import math +import time + +__all__ = [ + 'Timer', + 'seconds_to_hms', +] + + +class Timer(object): + '''Calculate runing speed and estimated time of arrival(ETA)''' + + def __init__(self, total_step: int): + self.total_step = total_step + self.last_start_step = 0 + self.current_step = 0 + self._is_running = True + + def start(self): + self.last_time = time.time() + self.start_time = time.time() + + def stop(self): + self._is_running = False + self.end_time = time.time() + + def count(self) -> int: + if not self.current_step >= self.total_step: + self.current_step += 1 + return self.current_step + + @property + def timing(self) -> float: + run_steps = self.current_step - self.last_start_step + self.last_start_step = self.current_step + time_used = time.time() - self.last_time + self.last_time = time.time() + return run_steps / time_used + + @property + def is_running(self) -> bool: + return self._is_running + + @property + def eta(self) -> str: + if not self.is_running: + return '00:00:00' + scale = self.total_step / self.current_step + remaining_time = (time.time() - self.start_time) * scale + return seconds_to_hms(remaining_time) + + +def seconds_to_hms(seconds: int) -> str: + '''Convert the number of seconds to hh:mm:ss''' + h = math.floor(seconds / 3600) + m = math.floor((seconds - h * 3600) / 60) + s = int(seconds - h * 3600 - m * 60) + hms_str = '{:0>2}:{:0>2}:{:0>2}'.format(h, m, s) + return hms_str diff --git a/audio/setup.py b/audio/setup.py new file mode 100644 index 00000000..e8d90606 --- /dev/null +++ b/audio/setup.py @@ -0,0 +1,293 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import contextlib +import inspect +import io +import os +import platform +import subprocess as sp +import sys +from pathlib import Path +from typing import List +from typing import Tuple +from typing import Union + +import distutils.command.clean +from setuptools import Command +from setuptools import find_packages +from setuptools import setup +from setuptools.command.develop import develop +from setuptools.command.test import test + +from tools import setup_helpers + +ROOT_DIR = Path(__file__).parent.resolve() + +VERSION = '1.1.0' +COMMITID = 'none' + +base = [ + "kaldiio", + "librosa==0.8.1", + "scipy>=1.0.0", + "soundfile~=0.10", + "colorlog", + "pathos == 0.2.8", + "pybind11", + "parameterized", + "tqdm" +] + +requirements = { + "install": + base, + "develop": [ + "sox", + "soxbindings", + "pre-commit", + ], +} + +def check_call(cmd: str, shell=False, executable=None): + try: + sp.check_call( + cmd.split(), + shell=shell, + executable="/bin/bash" if shell else executable) + except sp.CalledProcessError as e: + print( + f"{__file__}:{inspect.currentframe().f_lineno}: CMD: {cmd}, Error:", + e.output, + file=sys.stderr) + raise e + + +def check_output(cmd: Union[str, List[str], Tuple[str]], shell=False): + try: + + if isinstance(cmd, (list, tuple)): + cmds = cmd + else: + cmds = cmd.split() + out_bytes = sp.check_output(cmds) + + except sp.CalledProcessError as e: + out_bytes = e.output # Output generated before error + code = e.returncode # Return code + print( + f"{__file__}:{inspect.currentframe().f_lineno}: CMD: {cmd}, Error:", + out_bytes, + file=sys.stderr) + return out_bytes.strip().decode('utf8') + +def _run_cmd(cmd): + try: + return subprocess.check_output( + cmd, cwd=ROOT_DIR, + stderr=subprocess.DEVNULL).decode("ascii").strip() + except Exception: + return None + +@contextlib.contextmanager +def pushd(new_dir): + old_dir = os.getcwd() + os.chdir(new_dir) + print(new_dir) + yield + os.chdir(old_dir) + print(old_dir) + +def read(*names, **kwargs): + with io.open( + os.path.join(os.path.dirname(__file__), *names), + encoding=kwargs.get("encoding", "utf8")) as fp: + return fp.read() + +def _remove(files: str): + for f in files: + f.unlink() + +################################# Install ################################## + + +def _post_install(install_lib_dir): + pass + +class DevelopCommand(develop): + def run(self): + develop.run(self) + # must after develop.run, or pkg install by shell will not see + self.execute(_post_install, (self.install_lib, ), msg="Post Install...") + + +class TestCommand(test): + def finalize_options(self): + test.finalize_options(self) + self.test_args = [] + self.test_suite = True + + def run_tests(self): + # Run nose ensuring that argv simulates running nosetests directly + import nose + nose.run_exit(argv=['nosetests', '-w', 'tests']) + + def run_benchmark(self): + for benchmark_item in glob.glob('tests/benchmark/*py'): + os.system(f'pytest {benchmark_item}') + + +# cmd: python setup.py upload +class UploadCommand(Command): + description = "Build and publish the package." + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + try: + print("Removing previous dist/ ...") + shutil.rmtree(str(ROOT_DIR / "dist")) + except OSError: + pass + print("Building source distribution...") + sp.check_call([sys.executable, "setup.py", "sdist"]) + print("Uploading package to PyPi...") + sp.check_call(["twine", "upload", "dist/*"]) + sys.exit() + + +################################# Version ################################## +def _get_version(sha): + version = VERSION + if os.getenv("BUILD_VERSION"): + version = os.getenv("BUILD_VERSION") + elif sha is not None: + version += "+" + sha[:7] + return version + + +def _make_version_file(version, sha): + sha = "Unknown" if sha is None else sha + version_path = ROOT_DIR / "paddleaudio" / "__init__.py" + with open(version_path, "a") as f: + f.write(f"__version__ = '{version}'\n") + +def _rm_version(): + file_ = ROOT_DIR / "paddleaudio" / "__init__.py" + with open(file_, "r") as f: + lines = f.readlines() + with open(file_, "w") as f: + for line in lines: + if "__version__" not in line: + f.write(line) + + +################################# Steup ################################## +class clean(distutils.command.clean.clean): + def run(self): + # Run default behavior first + distutils.command.clean.clean.run(self) + + # Remove paddleaudio extension + for path in (ROOT_DIR / "paddleaudio").glob("**/*.so"): + print(f"removing '{path}'") + path.unlink() + # Remove build directory + build_dirs = [ + ROOT_DIR / "build", + ] + for path in build_dirs: + if path.exists(): + print(f"removing '{path}' (and everything under it)") + shutil.rmtree(str(path), ignore_errors=True) + + +def main(): + + sha = _run_cmd(["git", "rev-parse", "HEAD"]) # commit id + branch = _run_cmd(["git", "rev-parse", "--abbrev-ref", "HEAD"]) + tag = _run_cmd(["git", "describe", "--tags", "--exact-match", "@"]) + print("-- Git branch:", branch) + print("-- Git SHA:", sha) + print("-- Git tag:", tag) + version = _get_version(sha) + print("-- Building version", version) + _rm_version() + + _make_version_file(version, sha) + lib_package_data = {} + if platform.system() != 'Windows' and platform.system() != 'Linux': + lib_package_data = {'paddleaudio': ['lib/libgcc_s.1.1.dylib']} + + if platform.system() == 'Linux': + lib_package_data = {'paddleaudio': ['lib/lib*']} + + setup_info = dict( + # Metadata + name='paddleaudio', + version=VERSION, + author='PaddlePaddle Speech and Language Team', + author_email='paddlesl@baidu.com', + url='https://github.com/PaddlePaddle/PaddleSpeech/audio', + license='Apache 2.0', + description='Speech audio tools based on Paddlepaddle', + keywords=[ + "audio process" + "paddlepaddle", + ], + python_requires='>=3.7', + install_requires=requirements["install"], + extras_require={ + 'develop': + requirements["develop"], + #'test': ["nose", "torchaudio==0.10.2", "pytest-benchmark", "librosa=0.8.1", "parameterized", "paddlepaddle"], + }, + cmdclass={ + "build_ext": setup_helpers.CMakeBuild, + 'develop': DevelopCommand, + 'test': TestCommand, + 'upload': UploadCommand, + "clean": clean, + }, + + # Package info + packages=find_packages(include=('paddleaudio*')), + package_data=lib_package_data, + ext_modules=setup_helpers.get_ext_modules(), + zip_safe=True, + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + ], + ) + + setup(**setup_info) + _rm_version() + +if __name__ == '__main__': + main() diff --git a/tests/unit/audio/backends/base.py b/audio/tests/backends/base.py similarity index 100% rename from tests/unit/audio/backends/base.py rename to audio/tests/backends/base.py diff --git a/audio/tests/backends/common.py b/audio/tests/backends/common.py new file mode 100644 index 00000000..79b922a9 --- /dev/null +++ b/audio/tests/backends/common.py @@ -0,0 +1,32 @@ + +def get_encoding(ext, dtype): + exts = { + "mp3", + "flac", + "vorbis", + } + encodings = { + "float32": "PCM_F", + "int32": "PCM_S", + "int16": "PCM_S", + "uint8": "PCM_U", + } + return ext.upper() if ext in exts else encodings[dtype] + + +def get_bit_depth(dtype): + bit_depths = { + "float32": 32, + "int32": 32, + "int16": 16, + "uint8": 8, + } + return bit_depths[dtype] + +def get_bits_per_sample(ext, dtype): + bits_per_samples = { + "flac": 24, + "mp3": 0, + "vorbis": 0, + } + return bits_per_samples.get(ext, get_bit_depth(dtype)) diff --git a/audio/tests/backends/soundfile/base.py b/audio/tests/backends/soundfile/base.py new file mode 100644 index 00000000..a6719188 --- /dev/null +++ b/audio/tests/backends/soundfile/base.py @@ -0,0 +1,34 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import unittest +import urllib.request + +mono_channel_wav = 'https://paddlespeech.bj.bcebos.com/PaddleAudio/zh.wav' +multi_channels_wav = 'https://paddlespeech.bj.bcebos.com/PaddleAudio/cat.wav' + + +class BackendTest(unittest.TestCase): + def setUp(self): + self.initWavInput() + + def initWavInput(self): + self.files = [] + for url in [mono_channel_wav, multi_channels_wav]: + if not os.path.isfile(os.path.basename(url)): + urllib.request.urlretrieve(url, os.path.basename(url)) + self.files.append(os.path.basename(url)) + + def initParmas(self): + raise NotImplementedError diff --git a/audio/tests/backends/soundfile/common.py b/audio/tests/backends/soundfile/common.py new file mode 100644 index 00000000..eecead97 --- /dev/null +++ b/audio/tests/backends/soundfile/common.py @@ -0,0 +1,89 @@ +import itertools +from unittest import skipIf + +from paddleaudio._internal.module_utils import is_module_available +from parameterized import parameterized + + +def name_func(func, _, params): + return f'{func.__name__}_{"_".join(str(arg) for arg in params.args)}' + + +def dtype2subtype(dtype): + return { + "float64": "DOUBLE", + "float32": "FLOAT", + "int32": "PCM_32", + "int16": "PCM_16", + "uint8": "PCM_U8", + "int8": "PCM_S8", + }[dtype] + + +def skipIfFormatNotSupported(fmt): + fmts = [] + if is_module_available("soundfile"): + import soundfile + + fmts = soundfile.available_formats() + return skipIf(fmt not in fmts, f'"{fmt}" is not supported by soundfile') + return skipIf(True, '"soundfile" not available.') + + +def parameterize(*params): + return parameterized.expand( + list(itertools.product(*params)), name_func=name_func) + + +def fetch_wav_subtype(dtype, encoding, bits_per_sample): + subtype = { + (None, None): dtype2subtype(dtype), + (None, 8): "PCM_U8", + ("PCM_U", None): "PCM_U8", + ("PCM_U", 8): "PCM_U8", + ("PCM_S", None): "PCM_32", + ("PCM_S", 16): "PCM_16", + ("PCM_S", 32): "PCM_32", + ("PCM_F", None): "FLOAT", + ("PCM_F", 32): "FLOAT", + ("PCM_F", 64): "DOUBLE", + ("ULAW", None): "ULAW", + ("ULAW", 8): "ULAW", + ("ALAW", None): "ALAW", + ("ALAW", 8): "ALAW", + }.get((encoding, bits_per_sample)) + if subtype: + return subtype + raise ValueError(f"wav does not support ({encoding}, {bits_per_sample}).") + +def get_encoding(ext, dtype): + exts = { + "mp3", + "flac", + "vorbis", + } + encodings = { + "float32": "PCM_F", + "int32": "PCM_S", + "int16": "PCM_S", + "uint8": "PCM_U", + } + return ext.upper() if ext in exts else encodings[dtype] + + +def get_bit_depth(dtype): + bit_depths = { + "float32": 32, + "int32": 32, + "int16": 16, + "uint8": 8, + } + return bit_depths[dtype] + +def get_bits_per_sample(ext, dtype): + bits_per_samples = { + "flac": 24, + "mp3": 0, + "vorbis": 0, + } + return bits_per_samples.get(ext, get_bit_depth(dtype)) diff --git a/audio/tests/backends/soundfile/common_utils b/audio/tests/backends/soundfile/common_utils new file mode 120000 index 00000000..3ff3cef8 --- /dev/null +++ b/audio/tests/backends/soundfile/common_utils @@ -0,0 +1 @@ +../../common_utils \ No newline at end of file diff --git a/audio/tests/backends/soundfile/info_test.py b/audio/tests/backends/soundfile/info_test.py new file mode 100644 index 00000000..6814369f --- /dev/null +++ b/audio/tests/backends/soundfile/info_test.py @@ -0,0 +1,199 @@ +#this code is from: https://github.com/pytorch/audio/blob/main/test/torchaudio_unittest/backend/soundfile/info_test.py +import tarfile +import unittest +import warnings +from unittest.mock import patch + +import paddle +import soundfile +from common import get_bits_per_sample +from common import get_encoding +from common import parameterize +from common import skipIfFormatNotSupported +from common_utils import get_wav_data +from common_utils import nested_params +from common_utils import save_wav +from common_utils import TempDirMixin +from paddleaudio.backends import soundfile_backend + + +class TestInfo(TempDirMixin, unittest.TestCase): + @parameterize( + ["float32", "int32"], + [8000, 16000], + [1, 2], ) + def test_wav(self, dtype, sample_rate, num_channels): + """`soundfile_backend.info` can check wav file correctly""" + duration = 1 + path = self.get_temp_path("data.wav") + data = get_wav_data( + dtype, + num_channels, + normalize=False, + num_frames=duration * sample_rate) + save_wav(path, data, sample_rate) + info = soundfile_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == sample_rate * duration + assert info.num_channels == num_channels + assert info.bits_per_sample == get_bits_per_sample("wav", dtype) + assert info.encoding == get_encoding("wav", dtype) + + @parameterize([8000, 16000], [1, 2]) + @skipIfFormatNotSupported("FLAC") + def test_flac(self, sample_rate, num_channels): + """`soundfile_backend.info` can check flac file correctly""" + duration = 1 + num_frames = sample_rate * duration + #data = torch.randn(num_frames, num_channels).numpy() + data = paddle.randn(shape=[num_frames, num_channels]).numpy() + + path = self.get_temp_path("data.flac") + soundfile.write(path, data, sample_rate) + + info = soundfile_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == num_frames + assert info.num_channels == num_channels + assert info.bits_per_sample == 16 + assert info.encoding == "FLAC" + + #@parameterize([8000, 16000], [1, 2]) + #@skipIfFormatNotSupported("OGG") + #def test_ogg(self, sample_rate, num_channels): + #"""`soundfile_backend.info` can check ogg file correctly""" + #duration = 1 + #num_frames = sample_rate * duration + ##data = torch.randn(num_frames, num_channels).numpy() + #data = paddle.randn(shape=[num_frames, num_channels]).numpy() + #print(len(data)) + #path = self.get_temp_path("data.ogg") + #soundfile.write(path, data, sample_rate) + + #info = soundfile_backend.info(path) + #print(info) + #assert info.sample_rate == sample_rate + #print("info") + #print(info.num_frames) + #print("jiji") + #print(sample_rate*duration) + ##assert info.num_frames == sample_rate * duration + #assert info.num_channels == num_channels + #assert info.bits_per_sample == 0 + #assert info.encoding == "VORBIS" + + @nested_params( + [8000, 16000], + [1, 2], + [("PCM_24", 24), ("PCM_32", 32)], ) + @skipIfFormatNotSupported("NIST") + def test_sphere(self, sample_rate, num_channels, subtype_and_bit_depth): + """`soundfile_backend.info` can check sph file correctly""" + duration = 1 + num_frames = sample_rate * duration + #data = torch.randn(num_frames, num_channels).numpy() + data = paddle.randn(shape=[num_frames, num_channels]).numpy() + path = self.get_temp_path("data.nist") + subtype, bits_per_sample = subtype_and_bit_depth + soundfile.write(path, data, sample_rate, subtype=subtype) + + info = soundfile_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == sample_rate * duration + assert info.num_channels == num_channels + assert info.bits_per_sample == bits_per_sample + assert info.encoding == "PCM_S" + + def test_unknown_subtype_warning(self): + """soundfile_backend.info issues a warning when the subtype is unknown + + This will happen if a new subtype is supported in SoundFile: the _SUBTYPE_TO_BITS_PER_SAMPLE + dict should be updated. + """ + + def _mock_info_func(_): + class MockSoundFileInfo: + samplerate = 8000 + frames = 356 + channels = 2 + subtype = "UNSEEN_SUBTYPE" + format = "UNKNOWN" + + return MockSoundFileInfo() + + with patch("soundfile.info", _mock_info_func): + with warnings.catch_warnings(record=True) as w: + info = soundfile_backend.info("foo") + assert len(w) == 1 + assert "UNSEEN_SUBTYPE subtype is unknown to PaddleAudio" in str( + w[-1].message) + assert info.bits_per_sample == 0 + + +class TestFileObject(TempDirMixin, unittest.TestCase): + def _test_fileobj(self, ext, subtype, bits_per_sample): + """Query audio via file-like object works""" + duration = 2 + sample_rate = 16000 + num_channels = 2 + num_frames = sample_rate * duration + path = self.get_temp_path(f"test.{ext}") + + #data = torch.randn(num_frames, num_channels).numpy() + data = paddle.randn(shape=[num_frames, num_channels]).numpy() + soundfile.write(path, data, sample_rate, subtype=subtype) + + with open(path, "rb") as fileobj: + info = soundfile_backend.info(fileobj) + assert info.sample_rate == sample_rate + assert info.num_frames == num_frames + assert info.num_channels == num_channels + assert info.bits_per_sample == bits_per_sample + assert info.encoding == "FLAC" if ext == "flac" else "PCM_S" + + def test_fileobj_wav(self): + """Loading audio via file-like object works""" + self._test_fileobj("wav", "PCM_16", 16) + + @skipIfFormatNotSupported("FLAC") + def test_fileobj_flac(self): + """Loading audio via file-like object works""" + self._test_fileobj("flac", "PCM_16", 16) + + def _test_tarobj(self, ext, subtype, bits_per_sample): + """Query compressed audio via file-like object works""" + duration = 2 + sample_rate = 16000 + num_channels = 2 + num_frames = sample_rate * duration + audio_file = f"test.{ext}" + audio_path = self.get_temp_path(audio_file) + archive_path = self.get_temp_path("archive.tar.gz") + + #data = torch.randn(num_frames, num_channels).numpy() + data = paddle.randn(shape=[num_frames, num_channels]).numpy() + soundfile.write(audio_path, data, sample_rate, subtype=subtype) + + with tarfile.TarFile(archive_path, "w") as tarobj: + tarobj.add(audio_path, arcname=audio_file) + with tarfile.TarFile(archive_path, "r") as tarobj: + fileobj = tarobj.extractfile(audio_file) + info = soundfile_backend.info(fileobj) + assert info.sample_rate == sample_rate + assert info.num_frames == num_frames + assert info.num_channels == num_channels + assert info.bits_per_sample == bits_per_sample + assert info.encoding == "FLAC" if ext == "flac" else "PCM_S" + + def test_tarobj_wav(self): + """Query compressed audio via file-like object works""" + self._test_tarobj("wav", "PCM_16", 16) + + @skipIfFormatNotSupported("FLAC") + def test_tarobj_flac(self): + """Query compressed audio via file-like object works""" + self._test_tarobj("flac", "PCM_16", 16) + + +if __name__ == '__main__': + unittest.main() diff --git a/audio/tests/backends/soundfile/load_test.py b/audio/tests/backends/soundfile/load_test.py new file mode 100644 index 00000000..78a25487 --- /dev/null +++ b/audio/tests/backends/soundfile/load_test.py @@ -0,0 +1,363 @@ +#this code is from: https://github.com/pytorch/audio/blob/main/test/torchaudio_unittest/backend/soundfile/load_test.py +import os +import tarfile +import unittest +from unittest.mock import patch + +import numpy as np +import paddle +import soundfile +from common import dtype2subtype +from common import parameterize +from common import skipIfFormatNotSupported +from common_utils import get_wav_data +from common_utils import load_wav +from common_utils import normalize_wav +from common_utils import save_wav +from common_utils import TempDirMixin +from paddleaudio.backends import soundfile_backend +from parameterized import parameterized + + +def _get_mock_path( + ext: str, + dtype: str, + sample_rate: int, + num_channels: int, + num_frames: int, ): + return f"{dtype}_{sample_rate}_{num_channels}_{num_frames}.{ext}" + + +def _get_mock_params(path: str): + filename, ext = path.split(".") + parts = filename.split("_") + return { + "ext": ext, + "dtype": parts[0], + "sample_rate": int(parts[1]), + "num_channels": int(parts[2]), + "num_frames": int(parts[3]), + } + + +class SoundFileMock: + def __init__(self, path, mode): + assert mode == "r" + self.path = path + self._params = _get_mock_params(path) + self._start = None + + @property + def samplerate(self): + return self._params["sample_rate"] + + @property + def format(self): + if self._params["ext"] == "wav": + return "WAV" + if self._params["ext"] == "flac": + return "FLAC" + if self._params["ext"] == "ogg": + return "OGG" + if self._params["ext"] in ["sph", "nis", "nist"]: + return "NIST" + + @property + def subtype(self): + if self._params["ext"] == "ogg": + return "VORBIS" + return dtype2subtype(self._params["dtype"]) + + def _prepare_read(self, start, stop, frames): + assert stop is None + self._start = start + return frames + + def read(self, frames, dtype, always_2d): + assert always_2d + data = get_wav_data( + dtype, + self._params["num_channels"], + normalize=False, + num_frames=self._params["num_frames"], + channels_first=False, ).numpy() + return data[self._start:self._start + frames] + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + pass + + +class MockedLoadTest(unittest.TestCase): + def assert_dtype(self, ext, dtype, sample_rate, num_channels, normalize, + channels_first): + """When format is WAV or NIST, normalize=False will return the native dtype Tensor, otherwise float32""" + num_frames = 3 * sample_rate + path = _get_mock_path(ext, dtype, sample_rate, num_channels, num_frames) + expected_dtype = paddle.float32 if normalize or ext not in [ + "wav", "nist" + ] else getattr(paddle, dtype) + with patch("soundfile.SoundFile", SoundFileMock): + found, sr = soundfile_backend.load( + path, normalize=normalize, channels_first=channels_first) + assert found.dtype == expected_dtype + assert sample_rate == sr + + @parameterize( + ["int32", "float32", "float64"], + [8000, 16000], + [1, 2], + [True, False], + [True, False], ) + def test_wav(self, dtype, sample_rate, num_channels, normalize, + channels_first): + """Returns native dtype when normalize=False else float32""" + self.assert_dtype("wav", dtype, sample_rate, num_channels, normalize, + channels_first) + + @parameterize( + ["int32"], + [8000, 16000], + [1, 2], + [True, False], + [True, False], ) + def test_sphere(self, dtype, sample_rate, num_channels, normalize, + channels_first): + """Returns float32 always""" + self.assert_dtype("sph", dtype, sample_rate, num_channels, normalize, + channels_first) + + @parameterize([8000, 16000], [1, 2], [True, False], [True, False]) + def test_ogg(self, sample_rate, num_channels, normalize, channels_first): + """Returns float32 always""" + self.assert_dtype("ogg", "int16", sample_rate, num_channels, normalize, + channels_first) + + @parameterize([8000, 16000], [1, 2], [True, False], [True, False]) + def test_flac(self, sample_rate, num_channels, normalize, channels_first): + """`soundfile_backend.load` can load ogg format.""" + self.assert_dtype("flac", "int16", sample_rate, num_channels, normalize, + channels_first) + + +class LoadTestBase(TempDirMixin, unittest.TestCase): + def assert_wav( + self, + dtype, + sample_rate, + num_channels, + normalize, + channels_first=True, + duration=1, ): + """`soundfile_backend.load` can load wav format correctly. + + Wav data loaded with soundfile backend should match those with scipy + """ + path = self.get_temp_path("reference.wav") + num_frames = duration * sample_rate + data = get_wav_data( + dtype, + num_channels, + normalize=normalize, + num_frames=num_frames, + channels_first=channels_first, ) + save_wav(path, data, sample_rate, channels_first=channels_first) + expected = load_wav( + path, normalize=normalize, channels_first=channels_first)[0] + data, sr = soundfile_backend.load( + path, normalize=normalize, channels_first=channels_first) + assert sr == sample_rate + np.testing.assert_array_almost_equal(data.numpy(), expected.numpy()) + + def assert_sphere( + self, + dtype, + sample_rate, + num_channels, + channels_first=True, + duration=1, ): + """`soundfile_backend.load` can load SPHERE format correctly.""" + path = self.get_temp_path("reference.sph") + num_frames = duration * sample_rate + raw = get_wav_data( + dtype, + num_channels, + num_frames=num_frames, + normalize=False, + channels_first=False, ) + soundfile.write( + path, raw, sample_rate, subtype=dtype2subtype(dtype), format="NIST") + expected = normalize_wav(raw.t() if channels_first else raw) + data, sr = soundfile_backend.load(path, channels_first=channels_first) + assert sr == sample_rate + #self.assertEqual(data, expected, atol=1e-4, rtol=1e-8) + np.testing.assert_array_almost_equal(data.numpy(), expected.numpy()) + + def assert_flac( + self, + dtype, + sample_rate, + num_channels, + channels_first=True, + duration=1, ): + """`soundfile_backend.load` can load FLAC format correctly.""" + path = self.get_temp_path("reference.flac") + num_frames = duration * sample_rate + raw = get_wav_data( + dtype, + num_channels, + num_frames=num_frames, + normalize=False, + channels_first=False, ) + soundfile.write(path, raw, sample_rate) + expected = normalize_wav(raw.t() if channels_first else raw) + data, sr = soundfile_backend.load(path, channels_first=channels_first) + assert sr == sample_rate + #self.assertEqual(data, expected, atol=1e-4, rtol=1e-8) + np.testing.assert_array_almost_equal(data.numpy(), expected.numpy()) + + +class TestLoad(LoadTestBase): + """Test the correctness of `soundfile_backend.load` for various formats""" + + @parameterize( + ["float32", "int32"], + [8000, 16000], + [1, 2], + [False, True], + [False, True], ) + def test_wav(self, dtype, sample_rate, num_channels, normalize, + channels_first): + """`soundfile_backend.load` can load wav format correctly.""" + self.assert_wav(dtype, sample_rate, num_channels, normalize, + channels_first) + + @parameterize( + ["int32"], + [16000], + [2], + [False], ) + def test_wav_large(self, dtype, sample_rate, num_channels, normalize): + """`soundfile_backend.load` can load large wav file correctly.""" + two_hours = 2 * 60 * 60 + self.assert_wav( + dtype, sample_rate, num_channels, normalize, duration=two_hours) + + @parameterize(["float32", "int32"], [4, 8, 16, 32], [False, True]) + def test_multiple_channels(self, dtype, num_channels, channels_first): + """`soundfile_backend.load` can load wav file with more than 2 channels.""" + sample_rate = 8000 + normalize = False + self.assert_wav(dtype, sample_rate, num_channels, normalize, + channels_first) + + #@parameterize(["int32"], [8000, 16000], [1, 2], [False, True]) + #@skipIfFormatNotSupported("NIST") + #def test_sphere(self, dtype, sample_rate, num_channels, channels_first): + #"""`soundfile_backend.load` can load sphere format correctly.""" + #self.assert_sphere(dtype, sample_rate, num_channels, channels_first) + + #@parameterize(["int32"], [8000, 16000], [1, 2], [False, True]) + #@skipIfFormatNotSupported("FLAC") + #def test_flac(self, dtype, sample_rate, num_channels, channels_first): + #"""`soundfile_backend.load` can load flac format correctly.""" + #self.assert_flac(dtype, sample_rate, num_channels, channels_first) + + +class TestLoadFormat(TempDirMixin, unittest.TestCase): + """Given `format` parameter, `so.load` can load files without extension""" + + original = None + path = None + + def _make_file(self, format_): + sample_rate = 8000 + path_with_ext = self.get_temp_path(f"test.{format_}") + data = get_wav_data("float32", num_channels=2).numpy().T + soundfile.write(path_with_ext, data, sample_rate) + expected = soundfile.read(path_with_ext, dtype="float32")[0].T + path = os.path.splitext(path_with_ext)[0] + os.rename(path_with_ext, path) + return path, expected + + def _test_format(self, format_): + """Providing format allows to read file without extension""" + path, expected = self._make_file(format_) + found, _ = soundfile_backend.load(path) + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(found, expected) + + @parameterized.expand([ + ("WAV", ), + ("wav", ), + ]) + def test_wav(self, format_): + self._test_format(format_) + + @parameterized.expand([ + ("FLAC", ), + ("flac", ), + ]) + @skipIfFormatNotSupported("FLAC") + def test_flac(self, format_): + self._test_format(format_) + + +class TestFileObject(TempDirMixin, unittest.TestCase): + def _test_fileobj(self, ext): + """Loading audio via file-like object works""" + sample_rate = 16000 + path = self.get_temp_path(f"test.{ext}") + + data = get_wav_data("float32", num_channels=2).numpy().T + soundfile.write(path, data, sample_rate) + expected = soundfile.read(path, dtype="float32")[0].T + + with open(path, "rb") as fileobj: + found, sr = soundfile_backend.load(fileobj) + assert sr == sample_rate + #self.assertEqual(expected, found) + np.testing.assert_array_almost_equal(found, expected) + + def test_fileobj_wav(self): + """Loading audio via file-like object works""" + self._test_fileobj("wav") + + def test_fileobj_flac(self): + """Loading audio via file-like object works""" + self._test_fileobj("flac") + + def _test_tarfile(self, ext): + """Loading audio via file-like object works""" + sample_rate = 16000 + audio_file = f"test.{ext}" + audio_path = self.get_temp_path(audio_file) + archive_path = self.get_temp_path("archive.tar.gz") + + data = get_wav_data("float32", num_channels=2).numpy().T + soundfile.write(audio_path, data, sample_rate) + expected = soundfile.read(audio_path, dtype="float32")[0].T + + with tarfile.TarFile(archive_path, "w") as tarobj: + tarobj.add(audio_path, arcname=audio_file) + with tarfile.TarFile(archive_path, "r") as tarobj: + fileobj = tarobj.extractfile(audio_file) + found, sr = soundfile_backend.load(fileobj) + + assert sr == sample_rate + #self.assertEqual(expected, found) + np.testing.assert_array_almost_equal(found.numpy(), expected) + + def test_tarfile_wav(self): + """Loading audio via file-like object works""" + self._test_tarfile("wav") + + def test_tarfile_flac(self): + """Loading audio via file-like object works""" + self._test_tarfile("flac") + + +if __name__ == '__main__': + unittest.main() diff --git a/audio/tests/backends/soundfile/save_test.py b/audio/tests/backends/soundfile/save_test.py new file mode 100644 index 00000000..4f3df6e4 --- /dev/null +++ b/audio/tests/backends/soundfile/save_test.py @@ -0,0 +1,323 @@ +import io +import unittest +from unittest.mock import patch + +import numpy as np +import paddle +import soundfile +from common import fetch_wav_subtype +from common import parameterize +from common import skipIfFormatNotSupported +from common_utils import get_wav_data +from common_utils import load_wav +from common_utils import nested_params +from common_utils import TempDirMixin +from paddleaudio.backends import soundfile_backend + + +class MockedSaveTest(unittest.TestCase): + @nested_params( + ["float32", "int32"], + [8000, 16000], + [1, 2], + [False, True], + [ + (None, None), + ("PCM_U", None), + ("PCM_U", 8), + ("PCM_S", None), + ("PCM_S", 16), + ("PCM_S", 32), + ("PCM_F", None), + ("PCM_F", 32), + ("PCM_F", 64), + ("ULAW", None), + ("ULAW", 8), + ("ALAW", None), + ("ALAW", 8), + ], ) + @patch("soundfile.write") + def test_wav(self, dtype, sample_rate, num_channels, channels_first, + enc_params, mocked_write): + """soundfile_backend.save passes correct subtype to soundfile.write when WAV""" + filepath = "foo.wav" + input_tensor = get_wav_data( + dtype, + num_channels, + num_frames=3 * sample_rate, + normalize=dtype == "float32", + channels_first=channels_first, ) + input_tensor = paddle.transpose(input_tensor, [1, 0]) + + encoding, bits_per_sample = enc_params + soundfile_backend.save( + filepath, + input_tensor, + sample_rate, + channels_first=channels_first, + encoding=encoding, + bits_per_sample=bits_per_sample, ) + + # on +Py3.8 call_args.kwargs is more descreptive + args = mocked_write.call_args[1] + assert args["file"] == filepath + assert args["samplerate"] == sample_rate + assert args["subtype"] == fetch_wav_subtype(dtype, encoding, + bits_per_sample) + assert args["format"] is None + tensor_result = paddle.transpose( + input_tensor, [1, 0]) if channels_first else input_tensor + #self.assertEqual(args["data"], tensor_result.numpy()) + np.testing.assert_array_almost_equal(args["data"].numpy(), + tensor_result.numpy()) + + @patch("soundfile.write") + def assert_non_wav( + self, + fmt, + dtype, + sample_rate, + num_channels, + channels_first, + mocked_write, + encoding=None, + bits_per_sample=None, ): + """soundfile_backend.save passes correct subtype and format to soundfile.write when SPHERE""" + filepath = f"foo.{fmt}" + input_tensor = get_wav_data( + dtype, + num_channels, + num_frames=3 * sample_rate, + normalize=False, + channels_first=channels_first, ) + input_tensor = paddle.transpose(input_tensor, [1, 0]) + + expected_data = paddle.transpose( + input_tensor, [1, 0]) if channels_first else input_tensor + + soundfile_backend.save( + filepath, + input_tensor, + sample_rate, + channels_first, + encoding=encoding, + bits_per_sample=bits_per_sample, ) + + # on +Py3.8 call_args.kwargs is more descreptive + args = mocked_write.call_args[1] + assert args["file"] == filepath + assert args["samplerate"] == sample_rate + if fmt in ["sph", "nist", "nis"]: + assert args["format"] == "NIST" + else: + assert args["format"] is None + np.testing.assert_array_almost_equal(args["data"].numpy(), + expected_data.numpy()) + #self.assertEqual(args["data"], expected_data) + + @nested_params( + ["sph", "nist", "nis"], + ["int32"], + [8000, 16000], + [1, 2], + [False, True], + [ + ("PCM_S", 8), + ("PCM_S", 16), + ("PCM_S", 24), + ("PCM_S", 32), + ("ULAW", 8), + ("ALAW", 8), + ("ALAW", 16), + ("ALAW", 24), + ("ALAW", 32), + ], ) + def test_sph(self, fmt, dtype, sample_rate, num_channels, channels_first, + enc_params): + """soundfile_backend.save passes default format and subtype (None-s) to + soundfile.write when not WAV""" + encoding, bits_per_sample = enc_params + self.assert_non_wav( + fmt, + dtype, + sample_rate, + num_channels, + channels_first, + encoding=encoding, + bits_per_sample=bits_per_sample) + + @parameterize( + ["int32"], + [8000, 16000], + [1, 2], + [False, True], + [8, 16, 24], ) + def test_flac(self, dtype, sample_rate, num_channels, channels_first, + bits_per_sample): + """soundfile_backend.save passes default format and subtype (None-s) to + soundfile.write when not WAV""" + self.assert_non_wav( + "flac", + dtype, + sample_rate, + num_channels, + channels_first, + bits_per_sample=bits_per_sample) + + @parameterize( + ["int32"], + [8000, 16000], + [1, 2], + [False, True], ) + def test_ogg(self, dtype, sample_rate, num_channels, channels_first): + """soundfile_backend.save passes default format and subtype (None-s) to + soundfile.write when not WAV""" + self.assert_non_wav("ogg", dtype, sample_rate, num_channels, + channels_first) + + +class SaveTestBase(TempDirMixin, unittest.TestCase): + def assert_wav(self, dtype, sample_rate, num_channels, num_frames): + """`soundfile_backend.save` can save wav format.""" + path = self.get_temp_path("data.wav") + expected = get_wav_data( + dtype, num_channels, num_frames=num_frames, normalize=False) + soundfile_backend.save(path, expected, sample_rate) + found, sr = load_wav(path, normalize=False) + assert sample_rate == sr + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + def _assert_non_wav(self, fmt, dtype, sample_rate, num_channels): + """`soundfile_backend.save` can save non-wav format. + + Due to precision missmatch, and the lack of alternative way to decode the + resulting files without using soundfile, only meta data are validated. + """ + num_frames = sample_rate * 3 + path = self.get_temp_path(f"data.{fmt}") + expected = get_wav_data( + dtype, num_channels, num_frames=num_frames, normalize=False) + soundfile_backend.save(path, expected, sample_rate) + sinfo = soundfile.info(path) + assert sinfo.format == fmt.upper() + #assert sinfo.frames == num_frames this go wrong + assert sinfo.channels == num_channels + assert sinfo.samplerate == sample_rate + + def assert_flac(self, dtype, sample_rate, num_channels): + """`soundfile_backend.save` can save flac format.""" + self._assert_non_wav("flac", dtype, sample_rate, num_channels) + + def assert_sphere(self, dtype, sample_rate, num_channels): + """`soundfile_backend.save` can save sph format.""" + self._assert_non_wav("nist", dtype, sample_rate, num_channels) + + def assert_ogg(self, dtype, sample_rate, num_channels): + """`soundfile_backend.save` can save ogg format. + + As we cannot inspect the OGG format (it's lossy), we only check the metadata. + """ + self._assert_non_wav("ogg", dtype, sample_rate, num_channels) + + +class TestSave(SaveTestBase): + @parameterize( + ["float32", "int32"], + [8000, 16000], + [1, 2], ) + def test_wav(self, dtype, sample_rate, num_channels): + """`soundfile_backend.save` can save wav format.""" + self.assert_wav(dtype, sample_rate, num_channels, num_frames=None) + + @parameterize( + ["float32", "int32"], + [4, 8, 16, 32], ) + def test_multiple_channels(self, dtype, num_channels): + """`soundfile_backend.save` can save wav with more than 2 channels.""" + sample_rate = 8000 + self.assert_wav(dtype, sample_rate, num_channels, num_frames=None) + + @parameterize( + ["int32"], + [8000, 16000], + [1, 2], ) + @skipIfFormatNotSupported("NIST") + def test_sphere(self, dtype, sample_rate, num_channels): + """`soundfile_backend.save` can save sph format.""" + self.assert_sphere(dtype, sample_rate, num_channels) + + @parameterize( + [8000, 16000], + [1, 2], ) + @skipIfFormatNotSupported("FLAC") + def test_flac(self, sample_rate, num_channels): + """`soundfile_backend.save` can save flac format.""" + self.assert_flac("float32", sample_rate, num_channels) + + @parameterize( + [8000, 16000], + [1, 2], ) + @skipIfFormatNotSupported("OGG") + def test_ogg(self, sample_rate, num_channels): + """`soundfile_backend.save` can save ogg/vorbis format.""" + self.assert_ogg("float32", sample_rate, num_channels) + + +class TestSaveParams(TempDirMixin, unittest.TestCase): + """Test the correctness of optional parameters of `soundfile_backend.save`""" + + @parameterize([True, False]) + def test_channels_first(self, channels_first): + """channels_first swaps axes""" + path = self.get_temp_path("data.wav") + data = get_wav_data("int32", 2, channels_first=channels_first) + soundfile_backend.save(path, data, 8000, channels_first=channels_first) + found = load_wav(path)[0] + expected = data if channels_first else data.transpose([1, 0]) + #self.assertEqual(found, expected, atol=1e-4, rtol=1e-8) + np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + +class TestFileObject(TempDirMixin, unittest.TestCase): + def _test_fileobj(self, ext): + """Saving audio to file-like object works""" + sample_rate = 16000 + path = self.get_temp_path(f"test.{ext}") + + subtype = "FLOAT" if ext == "wav" else None + data = get_wav_data("float32", num_channels=2) + soundfile.write(path, data.numpy().T, sample_rate, subtype=subtype) + expected = soundfile.read(path, dtype="float32")[0] + + fileobj = io.BytesIO() + soundfile_backend.save(fileobj, data, sample_rate, format=ext) + fileobj.seek(0) + found, sr = soundfile.read(fileobj, dtype="float32") + + assert sr == sample_rate + #self.assertEqual(expected, found, atol=1e-4, rtol=1e-8) + np.testing.assert_array_almost_equal(found, expected) + + def test_fileobj_wav(self): + """Saving audio via file-like object works""" + self._test_fileobj("wav") + + @skipIfFormatNotSupported("FLAC") + def test_fileobj_flac(self): + """Saving audio via file-like object works""" + self._test_fileobj("flac") + + @skipIfFormatNotSupported("NIST") + def test_fileobj_nist(self): + """Saving audio via file-like object works""" + self._test_fileobj("NIST") + + @skipIfFormatNotSupported("OGG") + def test_fileobj_ogg(self): + """Saving audio via file-like object works""" + self._test_fileobj("OGG") + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/audio/backends/soundfile/test_io.py b/audio/tests/backends/soundfile/test_io.py similarity index 88% rename from tests/unit/audio/backends/soundfile/test_io.py rename to audio/tests/backends/soundfile/test_io.py index 26276751..eed1b39f 100644 --- a/tests/unit/audio/backends/soundfile/test_io.py +++ b/audio/tests/backends/soundfile/test_io.py @@ -16,16 +16,17 @@ import os import unittest import numpy as np +from paddleaudio.backends import soundfile_load as load +from paddleaudio.backends import soundfile_save as save import soundfile as sf -import paddlespeech.audio -from ..base import BackendTest +from base import BackendTest class TestIO(BackendTest): def test_load_mono_channel(self): sf_data, sf_sr = sf.read(self.files[0]) - pa_data, pa_sr = paddlespeech.audio.load( + pa_data, pa_sr = load( self.files[0], normal=False, dtype='float64') self.assertEqual(sf_data.dtype, pa_data.dtype) @@ -35,7 +36,7 @@ class TestIO(BackendTest): def test_load_multi_channels(self): sf_data, sf_sr = sf.read(self.files[1]) sf_data = sf_data.T # Channel dim first - pa_data, pa_sr = paddlespeech.audio.load( + pa_data, pa_sr = load( self.files[1], mono=False, normal=False, dtype='float64') self.assertEqual(sf_data.dtype, pa_data.dtype) @@ -49,7 +50,7 @@ class TestIO(BackendTest): pa_tmp_file = 'pa_tmp.wav' sf.write(sf_tmp_file, waveform, sr) - paddlespeech.audio.save(waveform, sr, pa_tmp_file) + save(waveform, sr, pa_tmp_file) self.assertTrue(filecmp.cmp(sf_tmp_file, pa_tmp_file)) for file in [sf_tmp_file, pa_tmp_file]: @@ -62,7 +63,7 @@ class TestIO(BackendTest): pa_tmp_file = 'pa_tmp.wav' sf.write(sf_tmp_file, waveform.T, sr) - paddlespeech.audio.save(waveform.T, sr, pa_tmp_file) + save(waveform.T, sr, pa_tmp_file) self.assertTrue(filecmp.cmp(sf_tmp_file, pa_tmp_file)) for file in [sf_tmp_file, pa_tmp_file]: diff --git a/audio/tests/backends/sox_io/common.py b/audio/tests/backends/sox_io/common.py new file mode 100644 index 00000000..eecead97 --- /dev/null +++ b/audio/tests/backends/sox_io/common.py @@ -0,0 +1,89 @@ +import itertools +from unittest import skipIf + +from paddleaudio._internal.module_utils import is_module_available +from parameterized import parameterized + + +def name_func(func, _, params): + return f'{func.__name__}_{"_".join(str(arg) for arg in params.args)}' + + +def dtype2subtype(dtype): + return { + "float64": "DOUBLE", + "float32": "FLOAT", + "int32": "PCM_32", + "int16": "PCM_16", + "uint8": "PCM_U8", + "int8": "PCM_S8", + }[dtype] + + +def skipIfFormatNotSupported(fmt): + fmts = [] + if is_module_available("soundfile"): + import soundfile + + fmts = soundfile.available_formats() + return skipIf(fmt not in fmts, f'"{fmt}" is not supported by soundfile') + return skipIf(True, '"soundfile" not available.') + + +def parameterize(*params): + return parameterized.expand( + list(itertools.product(*params)), name_func=name_func) + + +def fetch_wav_subtype(dtype, encoding, bits_per_sample): + subtype = { + (None, None): dtype2subtype(dtype), + (None, 8): "PCM_U8", + ("PCM_U", None): "PCM_U8", + ("PCM_U", 8): "PCM_U8", + ("PCM_S", None): "PCM_32", + ("PCM_S", 16): "PCM_16", + ("PCM_S", 32): "PCM_32", + ("PCM_F", None): "FLOAT", + ("PCM_F", 32): "FLOAT", + ("PCM_F", 64): "DOUBLE", + ("ULAW", None): "ULAW", + ("ULAW", 8): "ULAW", + ("ALAW", None): "ALAW", + ("ALAW", 8): "ALAW", + }.get((encoding, bits_per_sample)) + if subtype: + return subtype + raise ValueError(f"wav does not support ({encoding}, {bits_per_sample}).") + +def get_encoding(ext, dtype): + exts = { + "mp3", + "flac", + "vorbis", + } + encodings = { + "float32": "PCM_F", + "int32": "PCM_S", + "int16": "PCM_S", + "uint8": "PCM_U", + } + return ext.upper() if ext in exts else encodings[dtype] + + +def get_bit_depth(dtype): + bit_depths = { + "float32": 32, + "int32": 32, + "int16": 16, + "uint8": 8, + } + return bit_depths[dtype] + +def get_bits_per_sample(ext, dtype): + bits_per_samples = { + "flac": 24, + "mp3": 0, + "vorbis": 0, + } + return bits_per_samples.get(ext, get_bit_depth(dtype)) diff --git a/audio/tests/backends/sox_io/common_utils b/audio/tests/backends/sox_io/common_utils new file mode 120000 index 00000000..3ff3cef8 --- /dev/null +++ b/audio/tests/backends/sox_io/common_utils @@ -0,0 +1 @@ +../../common_utils \ No newline at end of file diff --git a/audio/tests/backends/sox_io/info_test.py b/audio/tests/backends/sox_io/info_test.py new file mode 100644 index 00000000..c459a6c2 --- /dev/null +++ b/audio/tests/backends/sox_io/info_test.py @@ -0,0 +1,322 @@ +import io +import itertools +import os +import platform +import tarfile +import unittest +from contextlib import contextmanager +if platform.system() == "Windows": + import warnings + warnings.warn("sox io not support in Windows, please skip test.") + exit() + +from parameterized import parameterized +from common import get_bits_per_sample, get_encoding + +from paddleaudio.backends import sox_io_backend + +from common_utils import ( + get_wav_data, + save_wav, + TempDirMixin, + sox_utils, ) + +#code is from:https://github.com/pytorch/audio/blob/main/torchaudio/test/torchaudio_unittest/backend/sox_io/info_test.py + + +class TestInfo(TempDirMixin, unittest.TestCase): + @parameterized.expand( + list( + itertools.product( + [ + "float32", + "int32", + ], + [8000, 16000], + [1, 2], )), ) + def test_wav(self, dtype, sample_rate, num_channels): + """`sox_io_backend.info` can check wav file correctly""" + duration = 1 + path = self.get_temp_path("data.wav") + data = get_wav_data( + dtype, + num_channels, + normalize=False, + num_frames=duration * sample_rate) + save_wav(path, data, sample_rate) + info = sox_io_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == sample_rate * duration + assert info.num_channels == num_channels + assert info.bits_per_sample == sox_utils.get_bit_depth(dtype) + assert info.encoding == get_encoding("wav", dtype) + + @parameterized.expand( + list( + itertools.product( + ["float32", "int32"], + [8000, 16000], + [4, 8, 16, 32], )), ) + def test_wav_multiple_channels(self, dtype, sample_rate, num_channels): + """`sox_io_backend.info` can check wav file with channels more than 2 correctly""" + duration = 1 + path = self.get_temp_path("data.wav") + data = get_wav_data( + dtype, + num_channels, + normalize=False, + num_frames=duration * sample_rate) + save_wav(path, data, sample_rate) + info = sox_io_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == sample_rate * duration + assert info.num_channels == num_channels + assert info.bits_per_sample == sox_utils.get_bit_depth(dtype) + + def test_ulaw(self): + """`sox_io_backend.info` can check ulaw file correctly""" + duration = 1 + num_channels = 1 + sample_rate = 8000 + path = self.get_temp_path("data.wav") + sox_utils.gen_audio_file( + path, + sample_rate=sample_rate, + num_channels=num_channels, + bit_depth=8, + encoding="u-law", + duration=duration) + info = sox_io_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == sample_rate * duration + assert info.num_channels == num_channels + assert info.bits_per_sample == 8 + assert info.encoding == "ULAW" + + def test_alaw(self): + """`sox_io_backend.info` can check alaw file correctly""" + duration = 1 + num_channels = 1 + sample_rate = 8000 + path = self.get_temp_path("data.wav") + sox_utils.gen_audio_file( + path, + sample_rate=sample_rate, + num_channels=num_channels, + bit_depth=8, + encoding="a-law", + duration=duration) + info = sox_io_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_frames == sample_rate * duration + assert info.num_channels == num_channels + assert info.bits_per_sample == 8 + assert info.encoding == "ALAW" + + +#class TestInfoOpus(unittest.TestCase): +#@parameterized.expand( +#list( +#itertools.product( +#["96k"], +#[1, 2], +#[0, 5, 10], +#) +#), +#) +#def test_opus(self, bitrate, num_channels, compression_level): +#"""`sox_io_backend.info` can check opus file correcty""" +#path = data_utils.get_asset_path("io", f"{bitrate}_{compression_level}_{num_channels}ch.opus") +#info = sox_io_backend.info(path) +#assert info.sample_rate == 48000 +#assert info.num_frames == 32768 +#assert info.num_channels == num_channels +#assert info.bits_per_sample == 0 # bit_per_sample is irrelevant for compressed formats +#assert info.encoding == "OPUS" + + +class FileObjTestBase(TempDirMixin): + def _gen_file(self, + ext, + dtype, + sample_rate, + num_channels, + num_frames, + *, + comments=None): + path = self.get_temp_path(f"test.{ext}") + bit_depth = sox_utils.get_bit_depth(dtype) + duration = num_frames / sample_rate + comment_file = self._gen_comment_file(comments) if comments else None + + sox_utils.gen_audio_file( + path, + sample_rate, + num_channels=num_channels, + encoding=sox_utils.get_encoding(dtype), + bit_depth=bit_depth, + duration=duration, + comment_file=comment_file, ) + return path + + def _gen_comment_file(self, comments): + comment_path = self.get_temp_path("comment.txt") + with open(comment_path, "w") as file_: + file_.writelines(comments) + return comment_path + + +class Unseekable: + def __init__(self, fileobj): + self.fileobj = fileobj + + def read(self, n): + return self.fileobj.read(n) + + +class TestFileObject(FileObjTestBase, unittest.TestCase): + def _query_fileobj(self, + ext, + dtype, + sample_rate, + num_channels, + num_frames, + *, + comments=None): + path = self._gen_file( + ext, + dtype, + sample_rate, + num_channels, + num_frames, + comments=comments) + format_ = ext if ext in ["mp3"] else None + with open(path, "rb") as fileobj: + return sox_io_backend.info(fileobj, format_) + + def _query_bytesio(self, ext, dtype, sample_rate, num_channels, num_frames): + path = self._gen_file(ext, dtype, sample_rate, num_channels, num_frames) + format_ = ext if ext in ["mp3"] else None + with open(path, "rb") as file_: + fileobj = io.BytesIO(file_.read()) + return sox_io_backend.info(fileobj, format_) + + def _query_tarfile(self, ext, dtype, sample_rate, num_channels, num_frames): + audio_path = self._gen_file(ext, dtype, sample_rate, num_channels, + num_frames) + audio_file = os.path.basename(audio_path) + archive_path = self.get_temp_path("archive.tar.gz") + with tarfile.TarFile(archive_path, "w") as tarobj: + tarobj.add(audio_path, arcname=audio_file) + format_ = ext if ext in ["mp3"] else None + with tarfile.TarFile(archive_path, "r") as tarobj: + fileobj = tarobj.extractfile(audio_file) + return sox_io_backend.info(fileobj, format_) + + @contextmanager + def _set_buffer_size(self, buffer_size): + try: + original_buffer_size = get_buffer_size() + set_buffer_size(buffer_size) + yield + finally: + set_buffer_size(original_buffer_size) + + @parameterized.expand([ + ("wav", "float32"), + ("wav", "int32"), + ("wav", "int16"), + ("wav", "uint8"), + ]) + def test_fileobj(self, ext, dtype): + """Querying audio via file object works""" + sample_rate = 16000 + num_frames = 3 * sample_rate + num_channels = 2 + sinfo = self._query_fileobj(ext, dtype, sample_rate, num_channels, + num_frames) + + bits_per_sample = get_bits_per_sample(ext, dtype) + num_frames = 0 if ext in ["mp3", "vorbis"] else num_frames + + assert sinfo.sample_rate == sample_rate + assert sinfo.num_channels == num_channels + assert sinfo.num_frames == num_frames + assert sinfo.bits_per_sample == bits_per_sample + assert sinfo.encoding == get_encoding(ext, dtype) + + @parameterized.expand([ + ("wav", "float32"), + ("wav", "int32"), + ("wav", "int16"), + ("wav", "uint8"), + ]) + def test_bytesio(self, ext, dtype): + """Querying audio via ByteIO object works for small data""" + sample_rate = 16000 + num_frames = 3 * sample_rate + num_channels = 2 + sinfo = self._query_bytesio(ext, dtype, sample_rate, num_channels, + num_frames) + + bits_per_sample = get_bits_per_sample(ext, dtype) + num_frames = 0 if ext in ["mp3", "vorbis"] else num_frames + + assert sinfo.sample_rate == sample_rate + assert sinfo.num_channels == num_channels + assert sinfo.num_frames == num_frames + assert sinfo.bits_per_sample == bits_per_sample + assert sinfo.encoding == get_encoding(ext, dtype) + + @parameterized.expand([ + ("wav", "float32"), + ("wav", "int32"), + ("wav", "int16"), + ("wav", "uint8"), + ]) + def test_bytesio_tiny(self, ext, dtype): + """Querying audio via ByteIO object works for small data""" + sample_rate = 8000 + num_frames = 4 + num_channels = 2 + sinfo = self._query_bytesio(ext, dtype, sample_rate, num_channels, + num_frames) + + bits_per_sample = get_bits_per_sample(ext, dtype) + num_frames = 0 if ext in ["mp3", "vorbis"] else num_frames + + assert sinfo.sample_rate == sample_rate + assert sinfo.num_channels == num_channels + assert sinfo.num_frames == num_frames + assert sinfo.bits_per_sample == bits_per_sample + assert sinfo.encoding == get_encoding(ext, dtype) + + @parameterized.expand([ + ("wav", "float32"), + ("wav", "int32"), + ("wav", "int16"), + ("wav", "uint8"), + ("flac", "float32"), + ("vorbis", "float32"), + ("amb", "int16"), + ]) + def test_tarfile(self, ext, dtype): + """Querying compressed audio via file-like object works""" + sample_rate = 16000 + num_frames = 3.0 * sample_rate + num_channels = 2 + sinfo = self._query_tarfile(ext, dtype, sample_rate, num_channels, + num_frames) + + bits_per_sample = get_bits_per_sample(ext, dtype) + num_frames = 0 if ext in ["vorbis"] else num_frames + + assert sinfo.sample_rate == sample_rate + assert sinfo.num_channels == num_channels + assert sinfo.num_frames == num_frames + assert sinfo.bits_per_sample == bits_per_sample + assert sinfo.encoding == get_encoding(ext, dtype) + + +if __name__ == '__main__': + unittest.main() diff --git a/audio/tests/backends/sox_io/load_test.py b/audio/tests/backends/sox_io/load_test.py new file mode 100644 index 00000000..ca9bd7ad --- /dev/null +++ b/audio/tests/backends/sox_io/load_test.py @@ -0,0 +1,56 @@ +import itertools +import platform +import unittest +if platform.system() == "Windows": + import warnings + warnings.warn("sox io not support in Windows, please skip test.") + exit() + +from parameterized import parameterized +import numpy as np +from paddleaudio.backends import sox_io_backend + +from common_utils import ( + get_wav_data, + load_wav, + save_wav, ) + +#code is from:https://github.com/pytorch/audio/blob/main/torchaudio/test/torchaudio_unittest/backend/sox_io/load_test.py + + +class TestLoad(unittest.TestCase): + def assert_wav(self, dtype, sample_rate, num_channels, normalize, duration): + """`sox_io_backend.load` can load wav format correctly. + + Wav data loaded with sox_io backend should match those with scipy + """ + path = 'testdata/reference.wav' + data = get_wav_data( + dtype, + num_channels, + normalize=normalize, + num_frames=duration * sample_rate) + save_wav(path, data, sample_rate) + expected = load_wav(path, normalize=normalize)[0] + data, sr = sox_io_backend.load(path, normalize=normalize) + assert sr == sample_rate + np.testing.assert_array_almost_equal(data, expected, decimal=4) + + @parameterized.expand( + list( + itertools.product( + [ + "float64", + "float32", + "int32", + ], + [8000, 16000], + [1, 2], + [False, True], )), ) + def test_wav(self, dtype, sample_rate, num_channels, normalize): + """`sox_io_backend.load` can load wav format correctly.""" + self.assert_wav(dtype, sample_rate, num_channels, normalize, duration=1) + + +if __name__ == '__main__': + unittest.main() diff --git a/audio/tests/backends/sox_io/save_test.py b/audio/tests/backends/sox_io/save_test.py new file mode 100644 index 00000000..e73f9f63 --- /dev/null +++ b/audio/tests/backends/sox_io/save_test.py @@ -0,0 +1,188 @@ +import io +import platform +import unittest +if platform.system() == "Windows": + import warnings + warnings.warn("sox io not support in Windows, please skip test.") + exit() + +import numpy as np +from paddleaudio.backends import sox_io_backend + +from common_utils import (get_wav_data, load_wav, save_wav, nested_params, + TempDirMixin, sox_utils) + +#code is from:https://github.com/pytorch/audio/blob/main/torchaudio/test/torchaudio_unittest/backend/sox_io/save_test.py + + +def _get_sox_encoding(encoding): + encodings = { + "PCM_F": "floating-point", + "PCM_S": "signed-integer", + "PCM_U": "unsigned-integer", + "ULAW": "u-law", + "ALAW": "a-law", + } + return encodings.get(encoding) + + +class TestSaveBase(TempDirMixin): + def assert_save_consistency( + self, + format: str, + *, + compression: float=None, + encoding: str=None, + bits_per_sample: int=None, + sample_rate: float=8000, + num_channels: int=2, + num_frames: float=3 * 8000, + src_dtype: str="int32", + test_mode: str="path", ): + """`save` function produces file that is comparable with `sox` command + + To compare that the file produced by `save` function agains the file produced by + the equivalent `sox` command, we need to load both files. + But there are many formats that cannot be opened with common Python modules (like + SciPy). + So we use `sox` command to prepare the original data and convert the saved files + into a format that SciPy can read (PCM wav). + The following diagram illustrates this process. The difference is 2.1. and 3.1. + + This assumes that + - loading data with SciPy preserves the data well. + - converting the resulting files into WAV format with `sox` preserve the data well. + + x + | 1. Generate source wav file with SciPy + | + v + -------------- wav ---------------- + | | + | 2.1. load with scipy | 3.1. Convert to the target + | then save it into the target | format depth with sox + | format with paddleaudio | + v v + target format target format + | | + | 2.2. Convert to wav with sox | 3.2. Convert to wav with sox + | | + v v + wav wav + | | + | 2.3. load with scipy | 3.3. load with scipy + | | + v v + tensor -------> compare <--------- tensor + + """ + cmp_encoding = "floating-point" + cmp_bit_depth = 32 + + src_path = self.get_temp_path("1.source.wav") + tgt_path = self.get_temp_path(f"2.1.paddleaudio.{format}") + tst_path = self.get_temp_path("2.2.result.wav") + sox_path = self.get_temp_path(f"3.1.sox.{format}") + ref_path = self.get_temp_path("3.2.ref.wav") + + # 1. Generate original wav + data = get_wav_data( + src_dtype, num_channels, normalize=False, num_frames=num_frames) + save_wav(src_path, data, sample_rate) + + # 2.1. Convert the original wav to target format with paddleaudio + data = load_wav(src_path, normalize=False)[0] + if test_mode == "path": + sox_io_backend.save( + tgt_path, + data, + sample_rate, + compression=compression, + encoding=encoding, + bits_per_sample=bits_per_sample) + elif test_mode == "fileobj": + with open(tgt_path, "bw") as file_: + sox_io_backend.save( + file_, + data, + sample_rate, + format=format, + compression=compression, + encoding=encoding, + bits_per_sample=bits_per_sample, ) + elif test_mode == "bytesio": + file_ = io.BytesIO() + sox_io_backend.save( + file_, + data, + sample_rate, + format=format, + compression=compression, + encoding=encoding, + bits_per_sample=bits_per_sample, ) + file_.seek(0) + with open(tgt_path, "bw") as f: + f.write(file_.read()) + else: + raise ValueError(f"Unexpected test mode: {test_mode}") + # 2.2. Convert the target format to wav with sox + sox_utils.convert_audio_file( + tgt_path, tst_path, encoding=cmp_encoding, bit_depth=cmp_bit_depth) + # 2.3. Load with SciPy + found = load_wav(tst_path, normalize=False)[0] + + # 3.1. Convert the original wav to target format with sox + sox_encoding = _get_sox_encoding(encoding) + sox_utils.convert_audio_file( + src_path, + sox_path, + compression=compression, + encoding=sox_encoding, + bit_depth=bits_per_sample) + # 3.2. Convert the target format to wav with sox + sox_utils.convert_audio_file( + sox_path, ref_path, encoding=cmp_encoding, bit_depth=cmp_bit_depth) + # 3.3. Load with SciPy + expected = load_wav(ref_path, normalize=False)[0] + + np.testing.assert_array_almost_equal(found, expected) + + +class TestSave(TestSaveBase, unittest.TestCase): + @nested_params( + [ + "path", + ], + [ + ("PCM_U", 8), + ("PCM_S", 16), + ("PCM_S", 32), + ("PCM_F", 32), + ("PCM_F", 64), + ("ULAW", 8), + ("ALAW", 8), + ], ) + def test_save_wav(self, test_mode, enc_params): + encoding, bits_per_sample = enc_params + self.assert_save_consistency( + "wav", + encoding=encoding, + bits_per_sample=bits_per_sample, + test_mode=test_mode) + + @nested_params( + [ + "path", + ], + [ + ("float32", ), + ("int32", ), + ], ) + def test_save_wav_dtype(self, test_mode, params): + (dtype, ) = params + self.assert_save_consistency( + "wav", src_dtype=dtype, test_mode=test_mode) + + +if __name__ == '__main__': + unittest.main() diff --git a/audio/tests/backends/sox_io/smoke_test.py b/audio/tests/backends/sox_io/smoke_test.py new file mode 100644 index 00000000..89590d61 --- /dev/null +++ b/audio/tests/backends/sox_io/smoke_test.py @@ -0,0 +1,189 @@ +import io +import itertools +import platform +import unittest +if platform.system() == "Windows": + import warnings + warnings.warn("sox io not support in Windows, please skip test.") + exit() + +from parameterized import parameterized +from paddleaudio.backends import sox_io_backend +from common_utils import (get_wav_data, TempDirMixin, name_func) + + +class SmokeTest(TempDirMixin, unittest.TestCase): + """Run smoke test on various audio format + + The purpose of this test suite is to verify that sox_io_backend functionalities do not exhibit + abnormal behaviors. + + This test suite should be able to run without any additional tools (such as sox command), + however without such tools, the correctness of each function cannot be verified. + """ + + def run_smoke_test(self, + ext, + sample_rate, + num_channels, + *, + compression=None, + dtype="float32"): + duration = 1 + num_frames = sample_rate * duration + #path = self.get_temp_path(f"test.{ext}") + path = self.get_temp_path(f"test.{ext}") + original = get_wav_data( + dtype, num_channels, normalize=False, num_frames=num_frames) + + # 1. run save + sox_io_backend.save( + path, original, sample_rate, compression=compression) + # 2. run info + info = sox_io_backend.info(path) + assert info.sample_rate == sample_rate + assert info.num_channels == num_channels + # 3. run load + loaded, sr = sox_io_backend.load(path, normalize=False) + assert sr == sample_rate + assert loaded.shape[0] == num_channels + + @parameterized.expand( + list( + itertools.product( + ["float32", "int32"], + #["float32", "int32", "int16", "uint8"], + [8000, 16000], + [1, 2], )), + name_func=name_func, ) + def test_wav(self, dtype, sample_rate, num_channels): + """Run smoke test on wav format""" + self.run_smoke_test("wav", sample_rate, num_channels, dtype=dtype) + + #@parameterized.expand( + #list( + #itertools.product( + #[8000, 16000], + #[1, 2], + #[-4.2, -0.2, 0, 0.2, 96, 128, 160, 192, 224, 256, 320], + #) + #) + #) + #def test_mp3(self, sample_rate, num_channels, bit_rate): + #"""Run smoke test on mp3 format""" + #self.run_smoke_test("mp3", sample_rate, num_channels, compression=bit_rate) + + #@parameterized.expand( + #list( + #itertools.product( + #[8000, 16000], + #[1, 2], + #[-1, 0, 1, 2, 3, 3.6, 5, 10], + #) + #) + #) + #def test_vorbis(self, sample_rate, num_channels, quality_level): + #"""Run smoke test on vorbis format""" + #self.run_smoke_test("vorbis", sample_rate, num_channels, compression=quality_level) + + @parameterized.expand( + list(itertools.product( + [8000, 16000], + [1, 2], + list(range(9)), )), + name_func=name_func, ) + def test_flac(self, sample_rate, num_channels, compression_level): + """Run smoke test on flac format""" + self.run_smoke_test( + "flac", sample_rate, num_channels, compression=compression_level) + + +class SmokeTestFileObj(unittest.TestCase): + """Run smoke test on various audio format + + The purpose of this test suite is to verify that sox_io_backend functionalities do not exhibit + abnormal behaviors. + + This test suite should be able to run without any additional tools (such as sox command), + however without such tools, the correctness of each function cannot be verified. + """ + + def run_smoke_test(self, + ext, + sample_rate, + num_channels, + *, + compression=None, + dtype="float32"): + duration = 1 + num_frames = sample_rate * duration + original = get_wav_data( + dtype, num_channels, normalize=False, num_frames=num_frames) + + fileobj = io.BytesIO() + # 1. run save + sox_io_backend.save( + fileobj, original, sample_rate, compression=compression, format=ext) + # 2. run info + fileobj.seek(0) + info = sox_io_backend.info(fileobj, format=ext) + assert info.sample_rate == sample_rate + assert info.num_channels == num_channels + # 3. run load + fileobj.seek(0) + loaded, sr = sox_io_backend.load(fileobj, normalize=False, format=ext) + assert sr == sample_rate + assert loaded.shape[0] == num_channels + + @parameterized.expand( + list(itertools.product( + ["float32", "int32"], + [8000, 16000], + [1, 2], )), + name_func=name_func, ) + def test_wav(self, dtype, sample_rate, num_channels): + """Run smoke test on wav format""" + self.run_smoke_test("wav", sample_rate, num_channels, dtype=dtype) + + # not support yet + #@parameterized.expand( + #list( + #itertools.product( + #[8000, 16000], + #[1, 2], + #[-4.2, -0.2, 0, 0.2, 96, 128, 160, 192, 224, 256, 320], + #) + #) + #) + #def test_mp3(self, sample_rate, num_channels, bit_rate): + #"""Run smoke test on mp3 format""" + #self.run_smoke_test("mp3", sample_rate, num_channels, compression=bit_rate) + + #@parameterized.expand( + #list( + #itertools.product( + #[8000, 16000], + #[1, 2], + #[-1, 0, 1, 2, 3, 3.6, 5, 10], + #) + #) + #) + #def test_vorbis(self, sample_rate, num_channels, quality_level): + #"""Run smoke test on vorbis format""" + #self.run_smoke_test("vorbis", sample_rate, num_channels, compression=quality_level) + + @parameterized.expand( + list(itertools.product( + [8000, 16000], + [1, 2], + list(range(9)), )), + name_func=name_func, ) + def test_flac(self, sample_rate, num_channels, compression_level): + #"""Run smoke test on flac format""" + self.run_smoke_test( + "flac", sample_rate, num_channels, compression=compression_level) + + +if __name__ == '__main__': + #test_func() + unittest.main() diff --git a/audio/tests/backends/sox_io/sox_effect_test.py b/audio/tests/backends/sox_io/sox_effect_test.py new file mode 100644 index 00000000..4707afa2 --- /dev/null +++ b/audio/tests/backends/sox_io/sox_effect_test.py @@ -0,0 +1,364 @@ +#code is from: https://github.com/pytorch/audio/blob/main/test/torchaudio_unittest/sox_effect/sox_effect_test.py +import io +import itertools +import platform +import tarfile +import unittest +from pathlib import Path + +import numpy as np +if platform.system() == "Windows": + import warnings + warnings.warn("sox io not support in Windows, please skip test.") + exit() + +from parameterized import parameterized +from paddleaudio import sox_effects +from common_utils import (get_sinusoid, get_wav_data, load_wav, save_wav, + sox_utils, TempDirMixin, load_effects_params) + + +class TestSoxEffects(unittest.TestCase): + def test_init(self): + """Calling init_sox_effects multiple times does not crush""" + for _ in range(3): + sox_effects.init_sox_effects() + + +class TestSoxEffectsTensor(TempDirMixin, unittest.TestCase): + """Test suite for `apply_effects_tensor` function""" + + @parameterized.expand( + list( + itertools.product(["float32", "int32"], [8000, 16000], [1, 2, 4, 8], + [True, False])), ) + def test_apply_no_effect(self, dtype, sample_rate, num_channels, + channels_first): + """`apply_effects_tensor` without effects should return identical data as input""" + original = get_wav_data( + dtype, num_channels, channels_first=channels_first) + expected = original.clone() + + found, output_sample_rate = sox_effects.apply_effects_tensor( + expected, sample_rate, [], channels_first) + + assert (output_sample_rate == sample_rate) + # SoxEffect should not alter the input Tensor object + #self.assertEqual(original, expected) + np.testing.assert_array_almost_equal(original.numpy(), expected.numpy()) + + # SoxEffect should not return the same Tensor object + assert expected is not found + # Returned Tensor should equal to the input Tensor + #self.assertEqual(expected, found) + np.testing.assert_array_almost_equal(expected.numpy(), found.numpy()) + + @parameterized.expand( + load_effects_params("sox_effect_test_args.jsonl"), + name_func=lambda f, i, p: f'{f.__name__}_{i}_{p.args[0]["effects"][0][0]}', + ) + def test_apply_effects(self, args): + """`apply_effects_tensor` should return identical data as sox command""" + effects = args["effects"] + num_channels = args.get("num_channels", 2) + input_sr = args.get("input_sample_rate", 8000) + output_sr = args.get("output_sample_rate") + + input_path = self.get_temp_path("input.wav") + reference_path = self.get_temp_path("reference.wav") + + original = get_sinusoid( + frequency=800, + sample_rate=input_sr, + n_channels=num_channels, + dtype="float32") + save_wav(input_path, original, input_sr) + sox_utils.run_sox_effect( + input_path, reference_path, effects, output_sample_rate=output_sr) + + expected, expected_sr = load_wav(reference_path) + found, sr = sox_effects.apply_effects_tensor(original, input_sr, + effects) + + assert sr == expected_sr + #self.assertEqual(expected, found) + np.testing.assert_array_almost_equal(expected.numpy(), found.numpy()) + + +class TestSoxEffectsFile(TempDirMixin, unittest.TestCase): + """Test suite for `apply_effects_file` function""" + + @parameterized.expand( + list( + itertools.product( + ["float32", "int32"], + [8000, 16000], + [1, 2, 4, 8], + [False, True], )), + #name_func=name_func, + ) + def test_apply_no_effect(self, dtype, sample_rate, num_channels, + channels_first): + """`apply_effects_file` without effects should return identical data as input""" + path = self.get_temp_path("input.wav") + expected = get_wav_data( + dtype, num_channels, channels_first=channels_first) + save_wav(path, expected, sample_rate, channels_first=channels_first) + + found, output_sample_rate = sox_effects.apply_effects_file( + path, [], normalize=False, channels_first=channels_first) + + assert output_sample_rate == sample_rate + #self.assertEqual(expected, found) + np.testing.assert_array_almost_equal(expected.numpy(), found.numpy()) + + @parameterized.expand( + load_effects_params("sox_effect_test_args.jsonl"), + #name_func=lambda f, i, p: f'{f.__name__}_{i}_{p.args[0]["effects"][0][0]}', + ) + def test_apply_effects_str(self, args): + """`apply_effects_file` should return identical data as sox command""" + dtype = "int32" + channels_first = True + effects = args["effects"] + num_channels = args.get("num_channels", 2) + input_sr = args.get("input_sample_rate", 8000) + output_sr = args.get("output_sample_rate") + + input_path = self.get_temp_path("input.wav") + reference_path = self.get_temp_path("reference.wav") + data = get_wav_data(dtype, num_channels, channels_first=channels_first) + save_wav(input_path, data, input_sr, channels_first=channels_first) + sox_utils.run_sox_effect( + input_path, reference_path, effects, output_sample_rate=output_sr) + + expected, expected_sr = load_wav(reference_path) + found, sr = sox_effects.apply_effects_file( + input_path, effects, normalize=False, channels_first=channels_first) + + assert sr == expected_sr + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(expected.numpy(), found.numpy()) + + def test_apply_effects_path(self): + """`apply_effects_file` should return identical data as sox command when file path is given as a Path Object""" + dtype = "int32" + channels_first = True + effects = [["hilbert"]] + num_channels = 2 + input_sr = 8000 + output_sr = 8000 + + input_path = self.get_temp_path("input.wav") + reference_path = self.get_temp_path("reference.wav") + data = get_wav_data(dtype, num_channels, channels_first=channels_first) + save_wav(input_path, data, input_sr, channels_first=channels_first) + sox_utils.run_sox_effect( + input_path, reference_path, effects, output_sample_rate=output_sr) + + expected, expected_sr = load_wav(reference_path) + found, sr = sox_effects.apply_effects_file( + Path(input_path), + effects, + normalize=False, + channels_first=channels_first) + + assert sr == expected_sr + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(expected.numpy(), found.numpy()) + + +class TestFileFormats(TempDirMixin, unittest.TestCase): + """`apply_effects_file` gives the same result as sox on various file formats""" + + @parameterized.expand( + list(itertools.product( + ["float32", "int32"], + [8000, 16000], + [1, 2], )), + #name_func=lambda f, _, p: f'{f.__name__}_{"_".join(str(arg) for arg in p.args)}', + ) + def test_wav(self, dtype, sample_rate, num_channels): + """`apply_effects_file` works on various wav format""" + channels_first = True + effects = [["band", "300", "10"]] + + input_path = self.get_temp_path("input.wav") + reference_path = self.get_temp_path("reference.wav") + data = get_wav_data(dtype, num_channels, channels_first=channels_first) + save_wav(input_path, data, sample_rate, channels_first=channels_first) + sox_utils.run_sox_effect(input_path, reference_path, effects) + + expected, expected_sr = load_wav(reference_path) + found, sr = sox_effects.apply_effects_file( + input_path, effects, normalize=False, channels_first=channels_first) + + assert sr == expected_sr + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + #not support now + #@parameterized.expand( + #list( + #itertools.product( + #[8000, 16000], + #[1, 2], + #) + #), + ##name_func=lambda f, _, p: f'{f.__name__}_{"_".join(str(arg) for arg in p.args)}', + #) + #def test_flac(self, sample_rate, num_channels): + #"""`apply_effects_file` works on various flac format""" + #channels_first = True + #effects = [["band", "300", "10"]] + + #input_path = self.get_temp_path("input.flac") + #reference_path = self.get_temp_path("reference.wav") + #sox_utils.gen_audio_file(input_path, sample_rate, num_channels) + #sox_utils.run_sox_effect(input_path, reference_path, effects, output_bitdepth=32) + + #expected, expected_sr = load_wav(reference_path) + #found, sr = sox_effects.apply_effects_file(input_path, effects, channels_first=channels_first) + #save_wav(self.get_temp_path("result.wav"), found, sr, channels_first=channels_first) + + #assert sr == expected_sr + ##self.assertEqual(found, expected) + #np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + #@parameterized.expand( + #list( + #itertools.product( + #[8000, 16000], + #[1, 2], + #) + #), + ##name_func=lambda f, _, p: f'{f.__name__}_{"_".join(str(arg) for arg in p.args)}', + #) + #def test_vorbis(self, sample_rate, num_channels): + #"""`apply_effects_file` works on various vorbis format""" + #channels_first = True + #effects = [["band", "300", "10"]] + + #input_path = self.get_temp_path("input.vorbis") + #reference_path = self.get_temp_path("reference.wav") + #sox_utils.gen_audio_file(input_path, sample_rate, num_channels) + #sox_utils.run_sox_effect(input_path, reference_path, effects, output_bitdepth=32) + + #expected, expected_sr = load_wav(reference_path) + #found, sr = sox_effects.apply_effects_file(input_path, effects, channels_first=channels_first) + #save_wav(self.get_temp_path("result.wav"), found, sr, channels_first=channels_first) + + #assert sr == expected_sr + ##self.assertEqual(found, expected) + #np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + + #@skipIfNoExec("sox") + #@skipIfNoSox +class TestFileObject(TempDirMixin, unittest.TestCase): + @parameterized.expand([ + ("wav", None), + ]) + def test_fileobj(self, ext, compression): + """Applying effects via file object works""" + sample_rate = 16000 + channels_first = True + effects = [["band", "300", "10"]] + input_path = self.get_temp_path(f"input.{ext}") + reference_path = self.get_temp_path("reference.wav") + + #sox_utils.gen_audio_file(input_path, sample_rate, num_channels=2, compression=compression) + data = get_wav_data("int32", 2, channels_first=channels_first) + save_wav(input_path, data, sample_rate, channels_first=channels_first) + + sox_utils.run_sox_effect( + input_path, reference_path, effects, output_bitdepth=32) + expected, expected_sr = load_wav(reference_path) + + with open(input_path, "rb") as fileobj: + found, sr = sox_effects.apply_effects_file( + fileobj, effects, channels_first=channels_first) + save_wav( + self.get_temp_path("result.wav"), + found, + sr, + channels_first=channels_first) + assert sr == expected_sr + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + @parameterized.expand([ + ("wav", None), + ]) + def test_bytesio(self, ext, compression): + """Applying effects via BytesIO object works""" + sample_rate = 16000 + channels_first = True + effects = [["band", "300", "10"]] + input_path = self.get_temp_path(f"input.{ext}") + reference_path = self.get_temp_path("reference.wav") + + #sox_utils.gen_audio_file(input_path, sample_rate, num_channels=2, compression=compression) + data = get_wav_data("int32", 2, channels_first=channels_first) + save_wav(input_path, data, sample_rate, channels_first=channels_first) + sox_utils.run_sox_effect( + input_path, reference_path, effects, output_bitdepth=32) + expected, expected_sr = load_wav(reference_path) + + with open(input_path, "rb") as file_: + fileobj = io.BytesIO(file_.read()) + found, sr = sox_effects.apply_effects_file( + fileobj, effects, channels_first=channels_first) + save_wav( + self.get_temp_path("result.wav"), + found, + sr, + channels_first=channels_first) + assert sr == expected_sr + #self.assertEqual(found, expected) + print("found") + print(found) + print("expected") + print(expected) + np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + @parameterized.expand([ + ("wav", None), + ]) + def test_tarfile(self, ext, compression): + """Applying effects to compressed audio via file-like file works""" + sample_rate = 16000 + channels_first = True + effects = [["band", "300", "10"]] + audio_file = f"input.{ext}" + + input_path = self.get_temp_path(audio_file) + reference_path = self.get_temp_path("reference.wav") + archive_path = self.get_temp_path("archive.tar.gz") + data = get_wav_data("int32", 2, channels_first=channels_first) + save_wav(input_path, data, sample_rate, channels_first=channels_first) + + # sox_utils.gen_audio_file(input_path, sample_rate, num_channels=2, compression=compression) + sox_utils.run_sox_effect( + input_path, reference_path, effects, output_bitdepth=32) + + expected, expected_sr = load_wav(reference_path) + + with tarfile.TarFile(archive_path, "w") as tarobj: + tarobj.add(input_path, arcname=audio_file) + with tarfile.TarFile(archive_path, "r") as tarobj: + fileobj = tarobj.extractfile(audio_file) + found, sr = sox_effects.apply_effects_file( + fileobj, effects, channels_first=channels_first) + save_wav( + self.get_temp_path("result.wav"), + found, + sr, + channels_first=channels_first) + assert sr == expected_sr + #self.assertEqual(found, expected) + np.testing.assert_array_almost_equal(found.numpy(), expected.numpy()) + + +if __name__ == '__main__': + unittest.main() diff --git a/audio/tests/backends/sox_io/sox_effect_test_args.jsonl b/audio/tests/backends/sox_io/sox_effect_test_args.jsonl new file mode 100644 index 00000000..c1b5d19b --- /dev/null +++ b/audio/tests/backends/sox_io/sox_effect_test_args.jsonl @@ -0,0 +1,77 @@ +{"effects": [["allpass", "300", "10"]]} +{"effects": [["band", "300", "10"]]} +{"effects": [["bandpass", "300", "10"]]} +{"effects": [["bandreject", "300", "10"]]} +{"effects": [["bass", "-10"]]} +{"effects": [["biquad", "0.4", "0.2", "0.9", "0.7", "0.2", "0.6"]]} +{"effects": [["chorus", "0.7", "0.9", "55", "0.4", "0.25", "2", "-t"]]} +{"effects": [["chorus", "0.6", "0.9", "50", "0.4", "0.25", "2", "-t", "60", "0.32", "0.4", "1.3", "-s"]]} +{"effects": [["chorus", "0.5", "0.9", "50", "0.4", "0.25", "2", "-t", "60", "0.32", "0.4", "2.3", "-t", "40", "0.3", "0.3", "1.3", "-s"]]} +{"effects": [["channels", "1"]]} +{"effects": [["channels", "2"]]} +{"effects": [["channels", "3"]]} +{"effects": [["compand", "0.3,1", "6:-70,-60,-20", "-5", "-90", "0.2"]]} +{"effects": [["compand", ".1,.2", "-inf,-50.1,-inf,-50,-50", "0", "-90", ".1"]]} +{"effects": [["compand", ".1,.1", "-45.1,-45,-inf,0,-inf", "45", "-90", ".1"]]} +{"effects": [["contrast", "0"]]} +{"effects": [["contrast", "25"]]} +{"effects": [["contrast", "50"]]} +{"effects": [["contrast", "75"]]} +{"effects": [["contrast", "100"]]} +{"effects": [["dcshift", "1.0"]]} +{"effects": [["dcshift", "-1.0"]]} +{"effects": [["deemph"]], "input_sample_rate": 44100} +{"effects": [["dither", "-s"]]} +{"effects": [["dither", "-S"]]} +{"effects": [["divide"]]} +{"effects": [["downsample", "2"]], "input_sample_rate": 8000, "output_sample_rate": 4000} +{"effects": [["earwax"]], "input_sample_rate": 44100} +{"effects": [["echo", "0.8", "0.88", "60", "0.4"]]} +{"effects": [["echo", "0.8", "0.88", "6", "0.4"]]} +{"effects": [["echo", "0.8", "0.9", "1000", "0.3"]]} +{"effects": [["echo", "0.8", "0.9", "1000", "0.3", "1800", "0.25"]]} +{"effects": [["echos", "0.8", "0.7", "700", "0.25", "700", "0.3"]]} +{"effects": [["echos", "0.8", "0.7", "700", "0.25", "900", "0.3"]]} +{"effects": [["echos", "0.8", "0.7", "40", "0.25", "63", "0.3"]]} +{"effects": [["equalizer", "300", "10", "5"]]} +{"effects": [["fade", "q", "3"]]} +{"effects": [["fade", "h", "3"]]} +{"effects": [["fade", "t", "3"]]} +{"effects": [["fade", "l", "3"]]} +{"effects": [["fade", "p", "3"]]} +{"effects": [["fir", "0.0195", "-0.082", "0.234", "0.891", "-0.145", "0.043"]]} +{"effects": [["flanger"]]} +{"effects": [["gain", "-l", "-6"]]} +{"effects": [["highpass", "-1", "300"]]} +{"effects": [["highpass", "-2", "300"]]} +{"effects": [["hilbert"]]} +{"effects": [["loudness"]]} +{"effects": [["lowpass", "-1", "300"]]} +{"effects": [["lowpass", "-2", "300"]]} +{"effects": [["mcompand", "0.005,0.1 -47,-40,-34,-34,-17,-33", "100", "0.003,0.05 -47,-40,-34,-34,-17,-33", "400", "0.000625,0.0125 -47,-40,-34,-34,-15,-33", "1600", "0.0001,0.025 -47,-40,-34,-34,-31,-31,-0,-30", "6400", "0,0.025 -38,-31,-28,-28,-0,-25"]], "input_sample_rate": 44100} +{"effects": [["oops"]]} +{"effects": [["overdrive"]]} +{"effects": [["pad"]]} +{"effects": [["phaser"]]} +{"effects": [["remix", "6", "7", "8", "0"]], "num_channels": 8} +{"effects": [["remix", "1-3,7", "3"]], "num_channels": 8} +{"effects": [["repeat"]]} +{"effects": [["reverb"]]} +{"effects": [["reverse"]]} +{"effects": [["riaa"]], "input_sample_rate": 44100} +{"effects": [["silence", "0"]]} +{"effects": [["speed", "1.3"]], "input_sample_rate": 4000, "output_sample_rate": 5200} +{"effects": [["speed", "0.7"]], "input_sample_rate": 4000, "output_sample_rate": 2800} +{"effects": [["stat"]]} +{"effects": [["stats"]]} +{"effects": [["stretch"]]} +{"effects": [["swap"]]} +{"effects": [["synth"]]} +{"effects": [["tempo", "0.9"]]} +{"effects": [["tempo", "1.1"]]} +{"effects": [["treble", "3"]]} +{"effects": [["tremolo", "300", "40"]]} +{"effects": [["tremolo", "300", "50"]]} +{"effects": [["trim", "0", "0.1"]]} +{"effects": [["upsample", "2"]], "input_sample_rate": 8000, "output_sample_rate": 16000} +{"effects": [["vol", "3"]]} diff --git a/tests/benchmark/audio/README.md b/audio/tests/benchmark/README.md similarity index 97% rename from tests/benchmark/audio/README.md rename to audio/tests/benchmark/README.md index 9cade74e..b9034100 100644 --- a/tests/benchmark/audio/README.md +++ b/audio/tests/benchmark/README.md @@ -15,6 +15,7 @@ Result: ========================================================================== test session starts ========================================================================== platform linux -- Python 3.7.7, pytest-7.0.1, pluggy-1.0.0 benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000) +rootdir: /ssd3/chenxiaojie06/PaddleSpeech/DeepSpeech/paddleaudio plugins: typeguard-2.12.1, benchmark-3.4.1, anyio-3.5.0 collected 4 items diff --git a/tests/benchmark/audio/log_melspectrogram.py b/audio/tests/benchmark/log_melspectrogram.py similarity index 87% rename from tests/benchmark/audio/log_melspectrogram.py rename to audio/tests/benchmark/log_melspectrogram.py index c85fcecf..1d03c1df 100644 --- a/tests/benchmark/audio/log_melspectrogram.py +++ b/audio/tests/benchmark/log_melspectrogram.py @@ -17,17 +17,15 @@ import urllib.request import librosa import numpy as np import paddle +import paddleaudio import torch import torchaudio -import paddlespeech.audio - wav_url = 'https://paddlespeech.bj.bcebos.com/PaddleAudio/zh.wav' if not os.path.isfile(os.path.basename(wav_url)): urllib.request.urlretrieve(wav_url, os.path.basename(wav_url)) -waveform, sr = paddlespeech.audio.load( - os.path.abspath(os.path.basename(wav_url))) +waveform, sr = paddleaudio.backends.soundfile_load(os.path.abspath(os.path.basename(wav_url))) waveform_tensor = paddle.to_tensor(waveform).unsqueeze(0) waveform_tensor_torch = torch.from_numpy(waveform).unsqueeze(0) @@ -57,7 +55,7 @@ def enable_gpu_device(): paddle.set_device('gpu') -log_mel_extractor = paddlespeech.audio.features.LogMelSpectrogram( +log_mel_extractor = paddle.audio.features.LogMelSpectrogram( **mel_conf, f_min=0.0, top_db=80.0, dtype=waveform_tensor.dtype) @@ -67,20 +65,20 @@ def log_melspectrogram(): def test_log_melspect_cpu(benchmark): enable_cpu_device() - feature_audio = benchmark(log_melspectrogram) + feature_paddleaudio = benchmark(log_melspectrogram) feature_librosa = librosa.feature.melspectrogram(waveform, **mel_conf) feature_librosa = librosa.power_to_db(feature_librosa, top_db=80.0) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) def test_log_melspect_gpu(benchmark): enable_gpu_device() - feature_audio = benchmark(log_melspectrogram) + feature_paddleaudio = benchmark(log_melspectrogram) feature_librosa = librosa.feature.melspectrogram(waveform, **mel_conf) feature_librosa = librosa.power_to_db(feature_librosa, top_db=80.0) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=2) + feature_librosa, feature_paddleaudio, decimal=2) mel_extractor_torchaudio = torchaudio.transforms.MelSpectrogram( @@ -104,11 +102,11 @@ def test_log_melspect_cpu_torchaudio(benchmark): waveform_tensor_torch = waveform_tensor_torch.to('cpu') amplitude_to_DB = amplitude_to_DB.to('cpu') - feature_audio = benchmark(log_melspectrogram_torchaudio) + feature_paddleaudio = benchmark(log_melspectrogram_torchaudio) feature_librosa = librosa.feature.melspectrogram(waveform, **mel_conf) feature_librosa = librosa.power_to_db(feature_librosa, top_db=80.0) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) def test_log_melspect_gpu_torchaudio(benchmark): diff --git a/tests/benchmark/audio/melspectrogram.py b/audio/tests/benchmark/melspectrogram.py similarity index 85% rename from tests/benchmark/audio/melspectrogram.py rename to audio/tests/benchmark/melspectrogram.py index 49815894..28c4ac80 100644 --- a/tests/benchmark/audio/melspectrogram.py +++ b/audio/tests/benchmark/melspectrogram.py @@ -17,17 +17,15 @@ import urllib.request import librosa import numpy as np import paddle +import paddleaudio import torch import torchaudio -import paddlespeech.audio - wav_url = 'https://paddlespeech.bj.bcebos.com/PaddleAudio/zh.wav' if not os.path.isfile(os.path.basename(wav_url)): urllib.request.urlretrieve(wav_url, os.path.basename(wav_url)) -waveform, sr = paddlespeech.audio.load( - os.path.abspath(os.path.basename(wav_url))) +waveform, sr = paddleaudio.backends.soundfile_load(os.path.abspath(os.path.basename(wav_url))) waveform_tensor = paddle.to_tensor(waveform).unsqueeze(0) waveform_tensor_torch = torch.from_numpy(waveform).unsqueeze(0) @@ -57,7 +55,7 @@ def enable_gpu_device(): paddle.set_device('gpu') -mel_extractor = paddlespeech.audio.features.MelSpectrogram( +mel_extractor = paddle.audio.features.MelSpectrogram( **mel_conf, f_min=0.0, dtype=waveform_tensor.dtype) @@ -67,18 +65,18 @@ def melspectrogram(): def test_melspect_cpu(benchmark): enable_cpu_device() - feature_audio = benchmark(melspectrogram) + feature_paddleaudio = benchmark(melspectrogram) feature_librosa = librosa.feature.melspectrogram(waveform, **mel_conf) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) def test_melspect_gpu(benchmark): enable_gpu_device() - feature_audio = benchmark(melspectrogram) + feature_paddleaudio = benchmark(melspectrogram) feature_librosa = librosa.feature.melspectrogram(waveform, **mel_conf) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) mel_extractor_torchaudio = torchaudio.transforms.MelSpectrogram( @@ -93,10 +91,10 @@ def test_melspect_cpu_torchaudio(benchmark): global waveform_tensor_torch, mel_extractor_torchaudio mel_extractor_torchaudio = mel_extractor_torchaudio.to('cpu') waveform_tensor_torch = waveform_tensor_torch.to('cpu') - feature_audio = benchmark(melspectrogram_torchaudio) + feature_paddleaudio = benchmark(melspectrogram_torchaudio) feature_librosa = librosa.feature.melspectrogram(waveform, **mel_conf) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) def test_melspect_gpu_torchaudio(benchmark): diff --git a/tests/benchmark/audio/mfcc.py b/audio/tests/benchmark/mfcc.py similarity index 86% rename from tests/benchmark/audio/mfcc.py rename to audio/tests/benchmark/mfcc.py index 4e286de9..544a5371 100644 --- a/tests/benchmark/audio/mfcc.py +++ b/audio/tests/benchmark/mfcc.py @@ -17,17 +17,15 @@ import urllib.request import librosa import numpy as np import paddle +import paddleaudio import torch import torchaudio -import paddlespeech.audio - wav_url = 'https://paddlespeech.bj.bcebos.com/PaddleAudio/zh.wav' if not os.path.isfile(os.path.basename(wav_url)): urllib.request.urlretrieve(wav_url, os.path.basename(wav_url)) -waveform, sr = paddlespeech.audio.load( - os.path.abspath(os.path.basename(wav_url))) +waveform, sr = paddleaudio.backends.soundfile_load(os.path.abspath(os.path.basename(wav_url))) waveform_tensor = paddle.to_tensor(waveform).unsqueeze(0) waveform_tensor_torch = torch.from_numpy(waveform).unsqueeze(0) @@ -66,7 +64,7 @@ def enable_gpu_device(): paddle.set_device('gpu') -mfcc_extractor = paddlespeech.audio.features.MFCC( +mfcc_extractor = paddle.audio.features.MFCC( **mfcc_conf, f_min=0.0, dtype=waveform_tensor.dtype) @@ -76,18 +74,18 @@ def mfcc(): def test_mfcc_cpu(benchmark): enable_cpu_device() - feature_audio = benchmark(mfcc) + feature_paddleaudio = benchmark(mfcc) feature_librosa = librosa.feature.mfcc(waveform, **mel_conf) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) def test_mfcc_gpu(benchmark): enable_gpu_device() - feature_audio = benchmark(mfcc) + feature_paddleaudio = benchmark(mfcc) feature_librosa = librosa.feature.mfcc(waveform, **mel_conf) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) del mel_conf_torchaudio['sample_rate'] @@ -105,10 +103,10 @@ def test_mfcc_cpu_torchaudio(benchmark): mel_extractor_torchaudio = mfcc_extractor_torchaudio.to('cpu') waveform_tensor_torch = waveform_tensor_torch.to('cpu') - feature_audio = benchmark(mfcc_torchaudio) + feature_paddleaudio = benchmark(mfcc_torchaudio) feature_librosa = librosa.feature.mfcc(waveform, **mel_conf) np.testing.assert_array_almost_equal( - feature_librosa, feature_audio, decimal=3) + feature_librosa, feature_paddleaudio, decimal=3) def test_mfcc_gpu_torchaudio(benchmark): diff --git a/audio/tests/common_utils/__init__.py b/audio/tests/common_utils/__init__.py new file mode 100644 index 00000000..70e53315 --- /dev/null +++ b/audio/tests/common_utils/__init__.py @@ -0,0 +1,15 @@ +from .case_utils import name_func +from .case_utils import TempDirMixin +from .data_utils import get_sinusoid +from .data_utils import load_effects_params +from .data_utils import load_params +from .parameterized_utils import nested_params +from .wav_utils import get_wav_data +from .wav_utils import load_wav +from .wav_utils import normalize_wav +from .wav_utils import save_wav + +__all__ = [ + "get_wav_data", "load_wav", "save_wav", "normalize_wav", "load_params", + "nested_params", "get_sinusoid", "name_func", "load_effects_params" +] diff --git a/audio/tests/common_utils/case_utils.py b/audio/tests/common_utils/case_utils.py new file mode 100644 index 00000000..65a78c5d --- /dev/null +++ b/audio/tests/common_utils/case_utils.py @@ -0,0 +1,50 @@ +import os.path +import tempfile + +#code is from:https://github.com/pytorch/audio/blob/main/test/torchaudio_unittest/common_utils/case_utils.py + + +def name_func(func, _, params): + return f'{func.__name__}_{"_".join(str(arg) for arg in params.args)}' + + +class TempDirMixin: + """Mixin to provide easy access to temp dir""" + + temp_dir_ = None + + @classmethod + def get_base_temp_dir(cls): + # If PADDLEAUDIO_TEST_TEMP_DIR is set, use it instead of temporary directory. + # this is handy for debugging. + key = "PADDLEAUDIO_TEST_TEMP_DIR" + if key in os.environ: + return os.environ[key] + if cls.temp_dir_ is None: + cls.temp_dir_ = tempfile.TemporaryDirectory() + return cls.temp_dir_.name + + @classmethod + def tearDownClass(cls): + if cls.temp_dir_ is not None: + try: + cls.temp_dir_.cleanup() + cls.temp_dir_ = None + except PermissionError: + # On Windows there is a know issue with `shutil.rmtree`, + # which fails intermittenly. + # + # https://github.com/python/cpython/issues/74168 + # + # We observed this on CircleCI, where Windows job raises + # PermissionError. + # + # Following the above thread, we ignore it. + pass + super().tearDownClass() + + def get_temp_path(self, *paths): + temp_dir = os.path.join(self.get_base_temp_dir(), self.id()) + path = os.path.join(temp_dir, *paths) + os.makedirs(os.path.dirname(path), exist_ok=True) + return path diff --git a/audio/tests/common_utils/data_utils.py b/audio/tests/common_utils/data_utils.py new file mode 100644 index 00000000..b5618618 --- /dev/null +++ b/audio/tests/common_utils/data_utils.py @@ -0,0 +1,135 @@ +import json +import os.path + +import paddle +from parameterized import param +#code is from:https://github.com/pytorch/audio/blob/main/test/torchaudio_unittest/common_utils/data_utils.py with modification. + +_TEST_DIR_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), "..")) + + +def get_asset_path(*paths): + """Return full path of a test asset""" + return os.path.join(_TEST_DIR_PATH, "assets", *paths) + + +def load_params(*paths): + with open(get_asset_path(*paths), "r") as file: + return [param(json.loads(line)) for line in file] + + +def load_effects_params(*paths): + params = [] + with open(*paths, "r") as file: + for line in file: + data = json.loads(line) + for effect in data["effects"]: + for i, arg in enumerate(effect): + if arg.startswith(""): + effect[i] = arg.replace("", get_asset_path()) + params.append(param(data)) + return params + + +def convert_tensor_encoding( + tensor: paddle.tensor, + dtype: paddle.dtype, ): + """Convert input tensor with values between -1 and 1 to integer encoding + Args: + tensor: input tensor, assumed between -1 and 1 + dtype: desired output tensor dtype + Returns: + Tensor: shape of (n_channels, sample_rate * duration) + """ + if dtype == paddle.int32: + tensor *= (tensor > 0) * 2147483647 + (tensor < 0) * 2147483648 + if dtype == paddle.int16: + tensor *= (tensor > 0) * 32767 + (tensor < 0) * 32768 + if dtype == paddle.uint8: + tensor *= (tensor > 0) * 127 + (tensor < 0) * 128 + tensor += 128 + tensor = paddle.to_tensor(tensor, dtype) + return tensor + + +#def get_whitenoise( +#*, +#sample_rate: int = 16000, +#duration: float = 1, # seconds +#n_channels: int = 1, +#seed: int = 0, +#dtype: Union[str, paddle.dtype] = "float32", +#device: Union[str, paddle.device] = "cpu", +#channels_first=True, +#scale_factor: float = 1, +#): +#"""Generate pseudo audio data with whitenoise +#Args: +#sample_rate: Sampling rate +#duration: Length of the resulting Tensor in seconds. +#n_channels: Number of channels +#seed: Seed value used for random number generation. +#Note that this function does not modify global random generator state. +#dtype: Torch dtype +#device: device +#channels_first: whether first dimension is n_channels +#scale_factor: scale the Tensor before clamping and quantization +#Returns: +#Tensor: shape of (n_channels, sample_rate * duration) +#""" +#if isinstance(dtype, str): +#dtype = getattr(paddle, dtype) +#if dtype not in [paddle.float64, paddle.float32, paddle.int32, paddle.int16, paddle.uint8]: +#raise NotImplementedError(f"dtype {dtype} is not supported.") +## According to the doc, folking rng on all CUDA devices is slow when there are many CUDA devices, +## so we only fork on CPU, generate values and move the data to the given device +#with paddle.random.fork_rng([]): +#paddle.random.manual_seed(seed) +#tensor = paddle.randn([n_channels, int(sample_rate * duration)], dtype=paddle.float32, device="cpu") +#tensor /= 2.0 +#tensor *= scale_factor +#tensor.clamp_(-1.0, 1.0) +#if not channels_first: +#tensor = tensor.t() + +#tensor = tensor.to(device) + +#return convert_tensor_encoding(tensor, dtype) + + +def get_sinusoid( + *, + frequency: float=300, + sample_rate: int=16000, + duration: float=1, # seconds + n_channels: int=1, + dtype: str="float32", + device: str="cpu", + channels_first: bool=True, ): + """Generate pseudo audio data with sine wave. + + Args: + frequency: Frequency of sine wave + sample_rate: Sampling rate + duration: Length of the resulting Tensor in seconds. + n_channels: Number of channels + dtype: Torch dtype + device: device + + Returns: + Tensor: shape of (n_channels, sample_rate * duration) + """ + if isinstance(dtype, str): + dtype = getattr(paddle, dtype) + pie2 = 2 * 3.141592653589793 + end = pie2 * frequency * duration + num_frames = int(sample_rate * duration) + # Randomize the initial phase. (except the first channel) + theta0 = pie2 * paddle.randn([n_channels, 1], dtype=paddle.float32) + theta0[0, :] = 0 + theta = paddle.linspace(0, end, num_frames, dtype=paddle.float32) + theta = theta0 + theta + tensor = paddle.sin(theta) + if not channels_first: + tensor = paddle.t(tensor) + return convert_tensor_encoding(tensor, dtype) diff --git a/audio/tests/common_utils/parameterized_utils.py b/audio/tests/common_utils/parameterized_utils.py new file mode 100644 index 00000000..ca4d3f51 --- /dev/null +++ b/audio/tests/common_utils/parameterized_utils.py @@ -0,0 +1,44 @@ +from itertools import product + +from parameterized import param +from parameterized import parameterized + + +def _name_func(func, _, params): + strs = [] + for arg in params.args: + if isinstance(arg, tuple): + strs.append("_".join(str(a) for a in arg)) + else: + strs.append(str(arg)) + # sanitize the test name + name = "_".join(strs) + return parameterized.to_safe_name(f"{func.__name__}_{name}") + + +def nested_params(*params_set, name_func=_name_func): + """Generate the cartesian product of the given list of parameters. + + Args: + params_set (list of parameters): Parameters. When using ``parameterized.param`` class, + all the parameters have to be specified with the class, only using kwargs. + """ + flatten = [p for params in params_set for p in params] + + # Parameters to be nested are given as list of plain objects + if all(not isinstance(p, param) for p in flatten): + args = list(product(*params_set)) + return parameterized.expand(args, name_func=_name_func) + + # Parameters to be nested are given as list of `parameterized.param` + if not all(isinstance(p, param) for p in flatten): + raise TypeError("When using ``parameterized.param``, " + "all the parameters have to be of the ``param`` type.") + if any(p.args for p in flatten): + raise ValueError( + "When using ``parameterized.param``, " + "all the parameters have to be provided as keyword argument.") + args = [param()] + for params in params_set: + args = [param(**x.kwargs, **y.kwargs) for x in args for y in params] + return parameterized.expand(args) diff --git a/audio/tests/common_utils/sox_utils.py b/audio/tests/common_utils/sox_utils.py new file mode 100644 index 00000000..6ceae081 --- /dev/null +++ b/audio/tests/common_utils/sox_utils.py @@ -0,0 +1,116 @@ +import subprocess +import sys +import warnings + + +def get_encoding(dtype): + encodings = { + "float32": "floating-point", + "int32": "signed-integer", + "int16": "signed-integer", + "uint8": "unsigned-integer", + } + return encodings[dtype] + + +def get_bit_depth(dtype): + bit_depths = { + "float32": 32, + "int32": 32, + "int16": 16, + "uint8": 8, + } + return bit_depths[dtype] + + +def gen_audio_file( + path, + sample_rate, + num_channels, + *, + encoding=None, + bit_depth=None, + compression=None, + attenuation=None, + duration=1, + comment_file=None, +): + """Generate synthetic audio file with `sox` command.""" + if path.endswith(".wav"): + warnings.warn("Use get_wav_data and save_wav to generate wav file for accurate result.") + command = [ + "sox", + "-V3", # verbose + "--no-dither", # disable automatic dithering + "-R", + # -R is supposed to be repeatable, though the implementation looks suspicious + # and not setting the seed to a fixed value. + # https://fossies.org/dox/sox-14.4.2/sox_8c_source.html + # search "sox_globals.repeatable" + ] + if bit_depth is not None: + command += ["--bits", str(bit_depth)] + command += [ + "--rate", + str(sample_rate), + "--null", # no input + "--channels", + str(num_channels), + ] + if compression is not None: + command += ["--compression", str(compression)] + if bit_depth is not None: + command += ["--bits", str(bit_depth)] + if encoding is not None: + command += ["--encoding", str(encoding)] + if comment_file is not None: + command += ["--comment-file", str(comment_file)] + command += [ + str(path), + "synth", + str(duration), # synthesizes for the given duration [sec] + "sawtooth", + "1", + # saw tooth covers the both ends of value range, which is a good property for test. + # similar to linspace(-1., 1.) + # this introduces bigger boundary effect than sine when converted to mp3 + ] + if attenuation is not None: + command += ["vol", f"-{attenuation}dB"] + print(" ".join(command), file=sys.stderr) + subprocess.run(command, check=True) + + +def convert_audio_file(src_path, dst_path, *, encoding=None, bit_depth=None, compression=None): + """Convert audio file with `sox` command.""" + command = ["sox", "-V3", "--no-dither", "-R", str(src_path)] + if encoding is not None: + command += ["--encoding", str(encoding)] + if bit_depth is not None: + command += ["--bits", str(bit_depth)] + if compression is not None: + command += ["--compression", str(compression)] + command += [dst_path] + print(" ".join(command), file=sys.stderr) + subprocess.run(command, check=True) + + +def _flattern(effects): + if not effects: + return effects + if isinstance(effects[0], str): + return effects + return [item for sublist in effects for item in sublist] + + +def run_sox_effect(input_file, output_file, effect, *, output_sample_rate=None, output_bitdepth=None): + """Run sox effects""" + effect = _flattern(effect) + command = ["sox", "-V", "--no-dither", input_file] + if output_bitdepth: + command += ["--bits", str(output_bitdepth)] + command += [output_file] + effect + if output_sample_rate: + command += ["rate", str(output_sample_rate)] + print(" ".join(command)) + subprocess.run(command, check=True) diff --git a/audio/tests/common_utils/wav_utils.py b/audio/tests/common_utils/wav_utils.py new file mode 100644 index 00000000..5cae6d8e --- /dev/null +++ b/audio/tests/common_utils/wav_utils.py @@ -0,0 +1,102 @@ +from typing import Optional + +import paddle +import scipy.io.wavfile + + +def normalize_wav(tensor: paddle.Tensor) -> paddle.Tensor: + if tensor.dtype == paddle.float32: + pass + elif tensor.dtype == paddle.int32: + tensor = paddle.cast(tensor, paddle.float32) + tensor[tensor > 0] /= 2147483647.0 + tensor[tensor < 0] /= 2147483648.0 + elif tensor.dtype == paddle.int16: + tensor = paddle.cast(tensor, paddle.float32) + tensor[tensor > 0] /= 32767.0 + tensor[tensor < 0] /= 32768.0 + elif tensor.dtype == paddle.uint8: + tensor = paddle.cast(tensor, paddle.float32) - 128 + tensor[tensor > 0] /= 127.0 + tensor[tensor < 0] /= 128.0 + return tensor + + +def get_wav_data( + dtype: str, + num_channels: int, + *, + num_frames: Optional[int]=None, + normalize: bool=True, + channels_first: bool=True, ): + """Generate linear signal of the given dtype and num_channels + + Data range is + [-1.0, 1.0] for float32, + [-2147483648, 2147483647] for int32 + [-32768, 32767] for int16 + [0, 255] for uint8 + + num_frames allow to change the linear interpolation parameter. + Default values are 256 for uint8, else 1 << 16. + 1 << 16 as default is so that int16 value range is completely covered. + """ + dtype_ = getattr(paddle, dtype) + + if num_frames is None: + if dtype == "uint8": + num_frames = 256 + else: + num_frames = 1 << 16 + + # paddle linspace not support uint8, int8, int16 + #if dtype == "uint8": + # base = paddle.linspace(0, 255, num_frames, dtype=dtype_) + #dtype_np = getattr(np, dtype) + #base_np = np.linspace(0, 255, num_frames, dtype_np) + #base = paddle.to_tensor(base_np, dtype=dtype_) + #elif dtype == "int8": + # base = paddle.linspace(-128, 127, num_frames, dtype=dtype_) + #dtype_np = getattr(np, dtype) + #base_np = np.linspace(-128, 127, num_frames, dtype_np) + #base = paddle.to_tensor(base_np, dtype=dtype_) + if dtype == "float32": + base = paddle.linspace(-1.0, 1.0, num_frames, dtype=dtype_) + elif dtype == "float64": + base = paddle.linspace(-1.0, 1.0, num_frames, dtype=dtype_) + elif dtype == "int32": + base = paddle.linspace( + -2147483648, 2147483647, num_frames, dtype=dtype_) + #elif dtype == "int16": + # base = paddle.linspace(-32768, 32767, num_frames, dtype=dtype_) + #dtype_np = getattr(np, dtype) + #base_np = np.linspace(-32768, 32767, num_frames, dtype_np) + #base = paddle.to_tensor(base_np, dtype=dtype_) + else: + raise NotImplementedError(f"Unsupported dtype {dtype}") + data = base.tile([num_channels, 1]) + if not channels_first: + data = data.transpose([1, 0]) + if normalize: + data = normalize_wav(data) + return data + + +def load_wav(path: str, normalize=True, channels_first=True) -> paddle.Tensor: + """Load wav file without paddleaudio""" + sample_rate, data = scipy.io.wavfile.read(path) + data = paddle.to_tensor(data.copy()) + if data.ndim == 1: + data = data.unsqueeze(1) + if normalize: + data = normalize_wav(data) + if channels_first: + data = data.transpose([1, 0]) + return data, sample_rate + + +def save_wav(path, data, sample_rate, channels_first=True): + """Save wav file without paddleaudio""" + if channels_first: + data = data.transpose([1, 0]) + scipy.io.wavfile.write(path, sample_rate, data.numpy()) diff --git a/paddlespeech/audio/sox_effects/__init__.py b/audio/tests/features/__init__.py similarity index 100% rename from paddlespeech/audio/sox_effects/__init__.py rename to audio/tests/features/__init__.py diff --git a/tests/unit/audio/features/base.py b/audio/tests/features/base.py similarity index 96% rename from tests/unit/audio/features/base.py rename to audio/tests/features/base.py index 6d59f72b..d183b72a 100644 --- a/tests/unit/audio/features/base.py +++ b/audio/tests/features/base.py @@ -17,8 +17,7 @@ import urllib.request import numpy as np import paddle - -from paddlespeech.audio import load +from paddleaudio.backends import soundfile_load as load wav_url = 'https://paddlespeech.bj.bcebos.com/PaddleAudio/zh.wav' diff --git a/tests/unit/audio/features/test_istft.py b/audio/tests/features/test_istft.py similarity index 96% rename from tests/unit/audio/features/test_istft.py rename to audio/tests/features/test_istft.py index f1e6e4e3..9cf8cdd6 100644 --- a/tests/unit/audio/features/test_istft.py +++ b/audio/tests/features/test_istft.py @@ -15,9 +15,9 @@ import unittest import numpy as np import paddle +from paddleaudio.functional.window import get_window from .base import FeatTest -from paddlespeech.audio.functional.window import get_window from paddlespeech.s2t.transform.spectrogram import IStft from paddlespeech.s2t.transform.spectrogram import Stft diff --git a/tests/unit/audio/features/test_kaldi.py b/audio/tests/features/test_kaldi.py similarity index 86% rename from tests/unit/audio/features/test_kaldi.py rename to audio/tests/features/test_kaldi.py index 2b0ece89..2bd5dc73 100644 --- a/tests/unit/audio/features/test_kaldi.py +++ b/audio/tests/features/test_kaldi.py @@ -15,11 +15,11 @@ import unittest import numpy as np import paddle +import paddleaudio import torch import torchaudio -import paddlespeech.audio -from .base import FeatTest +from base import FeatTest class TestKaldi(FeatTest): @@ -40,17 +40,17 @@ class TestKaldi(FeatTest): self.window_size, periodic=False, dtype=eval(f'torch.{self.dtype}')).pow(0.85) - p_hann_window = paddlespeech.audio.functional.window.get_window( + p_hann_window = paddleaudio.functional.window.get_window( 'hann', self.window_size, fftbins=False, dtype=eval(f'paddle.{self.dtype}')) - p_hamm_window = paddlespeech.audio.functional.window.get_window( + p_hamm_window = paddleaudio.functional.window.get_window( 'hamming', self.window_size, fftbins=False, dtype=eval(f'paddle.{self.dtype}')) - p_povey_window = paddlespeech.audio.functional.window.get_window( + p_povey_window = paddleaudio.functional.window.get_window( 'hann', self.window_size, fftbins=False, @@ -63,7 +63,7 @@ class TestKaldi(FeatTest): def test_fbank(self): ta_features = torchaudio.compliance.kaldi.fbank( torch.from_numpy(self.waveform.astype(self.dtype))) - pa_features = paddlespeech.audio.compliance.kaldi.fbank( + pa_features = paddleaudio.compliance.kaldi.fbank( paddle.to_tensor(self.waveform.astype(self.dtype))) np.testing.assert_array_almost_equal( ta_features, pa_features, decimal=4) @@ -71,7 +71,7 @@ class TestKaldi(FeatTest): def test_mfcc(self): ta_features = torchaudio.compliance.kaldi.mfcc( torch.from_numpy(self.waveform.astype(self.dtype))) - pa_features = paddlespeech.audio.compliance.kaldi.mfcc( + pa_features = paddleaudio.compliance.kaldi.mfcc( paddle.to_tensor(self.waveform.astype(self.dtype))) np.testing.assert_array_almost_equal( ta_features, pa_features, decimal=4) diff --git a/audio/tests/features/test_kaldi_feat.py b/audio/tests/features/test_kaldi_feat.py new file mode 100644 index 00000000..172a88b4 --- /dev/null +++ b/audio/tests/features/test_kaldi_feat.py @@ -0,0 +1,55 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#import platform +import unittest + +import kaldiio +import numpy as np +from kaldiio import ReadHelper +from paddleaudio.kaldi import fbank as fbank +#from paddleaudio.kaldi import pitch as pitch + +# the groundtruth feats computed in kaldi command below. +#compute-fbank-feats --dither=0 scp:$wav_scp ark,t:fbank_feat.ark +#compute-kaldi-pitch-feats --sample-frequency=16000 scp:$wav_scp ark,t:pitch_feat.ark + + +class TestKaldiFbank(unittest.TestCase): + def test_fbank(self): + fbank_groundtruth = {} + with ReadHelper('ark:testdata/fbank_feat.ark') as reader: + for key, feat in reader: + fbank_groundtruth[key] = feat + + wav_rate, wav = kaldiio.wavio.read_wav('testdata/test.wav') + fbank_feat = fbank(wav) + fbank_check = fbank_groundtruth['test_wav'] + np.testing.assert_array_almost_equal(fbank_feat, fbank_check, decimal=4) + + #def test_pitch(self): + # pitch_groundtruth = {} + # if platform.system() != "Linux": + # pass + # with ReadHelper('ark:testdata/pitch_feat.ark') as reader: + # for key, feat in reader: + # pitch_groundtruth[key] = feat + + # wav_rate, wav = kaldiio.wavio.read_wav('testdata/test.wav') + # pitch_feat = pitch(wav) + # pitch_check = pitch_groundtruth['test_wav'] + # np.testing.assert_array_almost_equal(pitch_feat, pitch_check, decimal=4) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/audio/features/test_librosa.py b/audio/tests/features/test_librosa.py similarity index 89% rename from tests/unit/audio/features/test_librosa.py rename to audio/tests/features/test_librosa.py index ffdec3e7..8cda25b1 100644 --- a/tests/unit/audio/features/test_librosa.py +++ b/audio/tests/features/test_librosa.py @@ -16,10 +16,10 @@ import unittest import librosa import numpy as np import paddle +import paddleaudio +from paddleaudio.functional.window import get_window -import paddlespeech.audio -from .base import FeatTest -from paddlespeech.audio.functional.window import get_window +from base import FeatTest class TestLibrosa(FeatTest): @@ -117,7 +117,7 @@ class TestLibrosa(FeatTest): htk=False, norm='slaney', dtype=self.waveform.dtype, ) - feature_compliance = paddlespeech.audio.compliance.librosa.compute_fbank_matrix( + feature_compliance = paddleaudio.compliance.librosa.compute_fbank_matrix( sr=self.sr, n_fft=self.n_fft, n_mels=self.n_mels, @@ -127,7 +127,7 @@ class TestLibrosa(FeatTest): norm='slaney', dtype=self.waveform.dtype, ) x = paddle.to_tensor(self.waveform) - feature_functional = paddlespeech.audio.functional.compute_fbank_matrix( + feature_functional = paddleaudio.functional.compute_fbank_matrix( sr=self.sr, n_fft=self.n_fft, n_mels=self.n_mels, @@ -156,8 +156,8 @@ class TestLibrosa(FeatTest): n_mels=self.n_mels, fmin=self.fmin) - # paddlespeech.audio.compliance.librosa: - feature_compliance = paddlespeech.audio.compliance.librosa.melspectrogram( + # paddleaudio.compliance.librosa: + feature_compliance = paddleaudio.compliance.librosa.melspectrogram( x=self.waveform, sr=self.sr, window_size=self.n_fft, @@ -166,10 +166,10 @@ class TestLibrosa(FeatTest): fmin=self.fmin, to_db=False) - # paddlespeech.audio.features.layer + # paddleaudio.features.layer x = paddle.to_tensor( self.waveform, dtype=paddle.float64).unsqueeze(0) # Add batch dim. - feature_extractor = paddlespeech.audio.features.MelSpectrogram( + feature_extractor = paddle.audio.features.MelSpectrogram( sr=self.sr, n_fft=self.n_fft, hop_length=self.hop_length, @@ -198,8 +198,8 @@ class TestLibrosa(FeatTest): fmin=self.fmin) feature_librosa = librosa.power_to_db(feature_librosa, top_db=None) - # paddlespeech.audio.compliance.librosa: - feature_compliance = paddlespeech.audio.compliance.librosa.melspectrogram( + # paddleaudio.compliance.librosa: + feature_compliance = paddleaudio.compliance.librosa.melspectrogram( x=self.waveform, sr=self.sr, window_size=self.n_fft, @@ -207,10 +207,10 @@ class TestLibrosa(FeatTest): n_mels=self.n_mels, fmin=self.fmin) - # paddlespeech.audio.features.layer + # paddleaudio.features.layer x = paddle.to_tensor( self.waveform, dtype=paddle.float64).unsqueeze(0) # Add batch dim. - feature_extractor = paddlespeech.audio.features.LogMelSpectrogram( + feature_extractor = paddle.audio.features.LogMelSpectrogram( sr=self.sr, n_fft=self.n_fft, hop_length=self.hop_length, @@ -243,8 +243,8 @@ class TestLibrosa(FeatTest): n_mels=self.n_mels, fmin=self.fmin) - # paddlespeech.audio.compliance.librosa: - feature_compliance = paddlespeech.audio.compliance.librosa.mfcc( + # paddleaudio.compliance.librosa: + feature_compliance = paddleaudio.compliance.librosa.mfcc( x=self.waveform, sr=self.sr, n_mfcc=self.n_mfcc, @@ -257,10 +257,10 @@ class TestLibrosa(FeatTest): fmin=self.fmin, top_db=self.top_db) - # paddlespeech.audio.features.layer + # paddle.audio.features.layer x = paddle.to_tensor( self.waveform, dtype=paddle.float64).unsqueeze(0) # Add batch dim. - feature_extractor = paddlespeech.audio.features.MFCC( + feature_extractor = paddle.audio.features.MFCC( sr=self.sr, n_mfcc=self.n_mfcc, n_fft=self.n_fft, diff --git a/tests/unit/audio/features/test_log_melspectrogram.py b/audio/tests/features/test_log_melspectrogram.py similarity index 94% rename from tests/unit/audio/features/test_log_melspectrogram.py rename to audio/tests/features/test_log_melspectrogram.py index 59eb73e8..7d568038 100644 --- a/tests/unit/audio/features/test_log_melspectrogram.py +++ b/audio/tests/features/test_log_melspectrogram.py @@ -15,8 +15,8 @@ import unittest import numpy as np import paddle +import paddleaudio -import paddlespeech.audio from .base import FeatTest from paddlespeech.s2t.transform.spectrogram import LogMelSpectrogram @@ -33,7 +33,7 @@ class TestLogMelSpectrogram(FeatTest): ps_res = ps_melspect(self.waveform.T).squeeze(1).T x = paddle.to_tensor(self.waveform) - ps_melspect = paddlespeech.audio.features.LogMelSpectrogram( + ps_melspect = paddleaudio.features.LogMelSpectrogram( self.sr, self.n_fft, self.hop_length, diff --git a/tests/unit/audio/features/test_spectrogram.py b/audio/tests/features/test_spectrogram.py similarity index 93% rename from tests/unit/audio/features/test_spectrogram.py rename to audio/tests/features/test_spectrogram.py index 7d908a7e..5fe5afee 100644 --- a/tests/unit/audio/features/test_spectrogram.py +++ b/audio/tests/features/test_spectrogram.py @@ -15,8 +15,8 @@ import unittest import numpy as np import paddle +import paddleaudio -import paddlespeech.audio from .base import FeatTest from paddlespeech.s2t.transform.spectrogram import Spectrogram @@ -31,7 +31,7 @@ class TestSpectrogram(FeatTest): ps_res = ps_spect(self.waveform.T).squeeze(1).T # Magnitude x = paddle.to_tensor(self.waveform) - pa_spect = paddlespeech.audio.features.Spectrogram( + pa_spect = paddle.audio.features.Spectrogram( self.n_fft, self.hop_length, power=1.0) pa_res = pa_spect(x).squeeze(0).numpy() diff --git a/tests/unit/audio/features/test_stft.py b/audio/tests/features/test_stft.py similarity index 95% rename from tests/unit/audio/features/test_stft.py rename to audio/tests/features/test_stft.py index 03448ca8..58792ffe 100644 --- a/tests/unit/audio/features/test_stft.py +++ b/audio/tests/features/test_stft.py @@ -15,9 +15,9 @@ import unittest import numpy as np import paddle +from paddleaudio.functional.window import get_window from .base import FeatTest -from paddlespeech.audio.functional.window import get_window from paddlespeech.s2t.transform.spectrogram import Stft diff --git a/audio/tests/features/testdata/fbank_feat.ark b/audio/tests/features/testdata/fbank_feat.ark new file mode 100644 index 00000000..73b06188 Binary files /dev/null and b/audio/tests/features/testdata/fbank_feat.ark differ diff --git a/audio/tests/features/testdata/fbank_feat_txt.ark b/audio/tests/features/testdata/fbank_feat_txt.ark new file mode 100644 index 00000000..03c5bbb3 --- /dev/null +++ b/audio/tests/features/testdata/fbank_feat_txt.ark @@ -0,0 +1,942 @@ +test_wav [ + 8.86961 7.025289 6.664165 7.169617 7.317829 7.188704 8.351522 8.843228 7.711394 7.231504 6.903938 7.053499 7.293597 8.331067 7.871729 9.206844 9.434045 9.768963 10.01864 10.25888 10.68228 10.55968 10.62156 + 8.364346 7.526375 6.915925 6.705005 7.641569 7.827819 8.253532 7.794802 7.522578 7.222802 7.388284 7.493527 8.257078 9.141049 8.994849 9.348937 9.015431 9.343955 10.42236 10.13459 10.40709 10.39534 10.22199 + 7.230361 6.771988 6.422344 7.535786 7.164408 6.342811 8.723886 8.481328 6.804535 7.276428 7.471786 7.581892 8.757826 8.764767 8.570841 8.741215 9.756334 9.515329 9.720121 10.26671 10.67728 10.5581 10.61378 + 8.872903 7.371414 6.360067 6.153208 7.333708 8.0974 8.851793 8.730195 7.622618 7.169075 7.85181 7.04872 7.978426 8.408302 8.802312 8.395834 9.217923 8.381662 9.777567 10.40261 10.37856 10.31888 10.34441 + 7.532231 6.751142 8.175496 7.593341 8.063697 8.369373 7.881088 8.15251 7.428252 7.103447 7.989072 7.949497 8.124873 8.496659 8.553727 8.761693 9.109408 9.4684 10.13223 10.16827 9.71019 10.59482 10.90851 + 6.746207 6.833902 8.067636 7.6485 7.013279 7.693223 8.147296 8.030097 7.067122 8.186153 7.784977 8.756321 8.6457 8.458344 7.769485 8.669812 9.332602 9.097817 9.444702 9.950351 10.18657 10.94016 11.36237 + 7.128079 7.711221 6.469111 6.649592 6.508276 7.082622 7.440871 7.623552 7.594537 7.354738 8.278585 8.652099 8.709033 8.605441 8.353497 8.4307 9.50789 9.312969 9.785786 10.18853 10.35708 10.71134 11.13716 + 8.201805 8.373339 7.420624 6.559644 6.318965 6.861043 7.299667 7.459548 7.392651 7.774329 7.917755 8.39668 8.304465 7.503887 8.319722 9.310571 9.144365 9.811728 9.738833 9.825593 10.65616 10.42954 10.28108 + 8.140867 8.803907 7.842072 6.760153 6.040633 7.099484 7.671337 7.230731 7.280159 7.825505 8.67013 7.970374 7.691161 7.603088 8.121623 8.186304 8.884687 9.764359 9.774008 10.14217 10.57618 10.70955 10.46593 + 9.335081 7.443659 6.302314 6.274453 6.648484 7.101899 8.31965 7.279731 7.011406 7.738722 8.111496 7.826912 9.217668 8.704701 8.520703 9.237556 9.141415 9.966189 10.13588 10.02818 10.32232 10.5961 10.39195 + 8.623323 6.642638 6.092153 6.010561 6.961139 7.523609 7.631736 6.81785 6.3952 7.437364 7.784822 8.421501 8.569756 8.931039 8.394889 8.730085 8.568606 9.672934 10.10908 10.22258 10.30489 10.11329 10.44942 + 8.340079 7.404711 6.73463 6.621991 6.641872 6.501914 7.429152 7.325783 7.075316 7.198759 7.573832 7.726879 8.173958 8.713857 8.947656 9.52945 9.495684 10.04432 9.70799 9.853218 10.34904 10.31011 10.33581 + 9.458065 6.449831 5.764122 6.112749 6.633307 6.588135 7.683532 7.854395 7.497962 6.587214 7.522266 8.246718 7.842532 8.194103 8.769976 9.494311 9.410578 9.623136 9.262513 9.66307 9.958323 10.58842 10.94138 + 9.336168 7.658177 6.552251 4.668932 5.951582 7.329723 6.881893 7.673193 8.018956 7.765876 8.092113 7.657069 8.385877 8.804426 8.99403 9.033966 9.84664 9.652982 9.678547 9.901299 10.55994 10.98264 10.42628 + 8.845008 7.827737 6.934293 6.809871 7.603892 7.622493 7.295815 7.316114 7.707997 8.28838 7.455571 7.749361 8.357333 8.413839 8.780228 9.111949 8.773423 9.546294 9.316511 9.7621 9.853085 10.24652 10.58686 + 9.845795 7.653487 6.760835 6.417203 6.483883 8.249362 8.985138 7.782502 8.038197 7.994664 7.512061 7.712332 8.276911 8.76414 8.027122 8.730929 8.986988 9.50342 9.225771 9.793655 10.35338 10.19652 10.67655 + 8.068243 7.419188 7.323668 6.883723 7.588089 7.267737 7.464292 8.121238 7.117096 7.165044 7.638491 7.958453 8.368897 8.497821 8.06803 8.636445 9.186031 9.296571 9.991373 10.35782 10.44223 10.60756 10.9512 + 8.540399 7.109134 6.417945 6.851756 7.50145 7.613665 7.395747 8.489678 7.192803 8.40198 8.48846 7.516579 8.291675 9.133558 8.94935 9.040503 9.475376 9.886353 10.04679 10.23742 10.22118 10.67988 10.29023 + 9.943547 6.745187 7.141617 7.058182 7.203416 8.045156 7.670315 7.748672 7.009519 7.208478 7.261959 8.346151 8.425858 8.822375 8.973361 9.907825 9.710265 9.542497 9.383007 9.832958 10.30413 10.9831 10.99566 + 9.077311 7.305787 7.036552 6.220779 6.492191 6.642952 8.301676 8.177285 7.706949 7.897906 7.814847 7.765959 8.228884 8.499186 8.701291 8.90225 9.000106 9.510703 9.477421 9.869934 10.31142 10.33504 10.62863 + 9.609183 6.470312 6.850113 7.247727 6.606174 7.178535 7.569305 7.858948 7.907071 7.322339 7.393857 8.411836 8.555615 8.416198 8.268435 8.814535 9.016805 9.221167 8.856338 9.819329 10.63624 10.67038 10.4818 + 8.896682 6.96038 7.062835 6.841669 6.556721 7.257597 9.19041 8.196911 7.560658 7.475944 7.570982 8.699837 8.718691 8.698103 9.604801 9.410757 9.482757 9.489608 10.0253 10.21278 10.42956 10.25078 10.40438 + 10.05012 7.997848 8.523865 7.810099 7.064989 7.438704 8.866325 8.385101 8.702444 7.532755 6.970853 8.658536 8.904259 8.098039 8.240754 9.383977 9.924636 9.825594 10.16586 9.929379 10.33848 10.6166 10.88825 + 9.945673 7.943526 8.236642 7.982066 7.059935 7.337771 8.282602 7.669298 6.812744 7.241785 7.059946 8.290605 8.874635 8.206081 9.037805 9.692253 9.771944 9.658941 9.887684 9.687504 10.12401 10.5467 10.46784 + 9.24334 8.005972 8.029324 7.080775 6.692482 7.339699 6.330315 7.749064 7.191765 7.614157 7.584374 8.707373 8.633794 7.661246 8.89745 8.717183 8.727042 9.601094 9.761832 9.91165 10.89605 10.7561 10.4439 + 9.008655 7.696863 8.051159 6.21505 6.986367 7.75211 7.125566 8.008561 8.631255 7.692895 7.423654 8.070612 7.934104 7.481667 7.878049 8.699003 9.587379 9.81943 9.638152 10.14519 10.48706 10.67093 10.95845 + 9.56725 7.086317 7.604103 6.621353 6.861667 6.762026 7.150949 8.061196 7.548547 6.552682 7.445788 8.408651 8.276496 7.768121 8.235985 9.36837 9.303123 9.568222 9.907539 10.04948 10.3193 10.38864 11.01985 + 9.435867 7.065077 8.260999 7.606821 7.11696 6.622849 7.453804 7.729028 6.969114 7.593372 8.076168 8.142076 7.987474 7.750668 8.709545 9.194512 9.28443 9.696207 10.08809 10.43397 10.95729 10.62421 10.32698 + 7.326074 6.968657 7.991836 8.057238 8.277269 6.64677 8.417533 8.390658 7.716748 7.254366 8.046806 8.952176 8.943592 8.626341 8.475414 8.366508 9.379741 9.649915 9.956218 10.14107 10.0686 10.3009 10.63128 + 8.867029 7.436584 8.325071 8.151552 7.802304 7.204567 7.817641 8.41904 8.079826 7.800119 7.738661 8.019406 8.496906 8.371117 8.895446 8.874495 9.541505 9.603241 9.702045 9.520963 10.07405 10.22188 10.69203 + 7.892157 7.706676 8.708323 8.090714 7.298046 7.119635 7.677824 8.568966 9.065309 7.950867 7.361037 8.006032 7.704475 8.136228 9.241001 9.342211 9.766371 9.645364 10.53355 10.35027 10.26263 10.8308 10.88063 + 9.17825 6.552885 7.865911 7.314655 7.429624 7.467305 7.331274 8.097523 8.513691 7.603092 8.123087 8.988563 8.24368 7.665757 8.043156 9.323641 9.559673 10.4114 10.44213 10.46176 10.31303 10.41219 10.04096 + 9.499084 6.913695 8.680465 8.913202 7.983476 7.54614 8.20214 8.433187 7.619872 7.079637 7.59503 7.827682 8.021211 8.954014 8.512682 8.685501 9.039448 9.882102 10.09629 9.995301 10.25326 10.52707 10.41024 + 8.841949 7.852749 8.220187 8.067208 6.958006 6.525739 7.606658 8.743006 8.618779 7.857424 7.85938 6.839745 8.494206 7.93556 8.554915 9.17892 9.411014 9.403722 9.75618 9.915223 10.4127 10.62058 10.75261 + 8.80931 7.176473 8.226482 8.048065 6.875594 7.035853 8.159007 8.788584 7.998541 7.745961 7.02769 7.343524 8.768233 8.742394 8.993815 8.919962 8.948602 9.299537 9.644719 9.328181 10.0551 10.60812 10.26714 + 8.416738 7.433433 8.202932 7.654713 7.487177 7.454067 7.807778 8.21654 7.973643 7.745943 7.477229 7.699207 8.724244 8.921854 9.167027 9.329788 9.198338 9.449234 9.350556 9.504007 10.01113 10.77754 10.79311 + 7.265522 8.85788 8.794858 6.660202 5.630237 7.668158 8.690257 8.2572 7.200497 7.342714 7.748627 8.173976 8.632828 8.53996 9.053345 9.001765 9.227647 10.09744 9.63631 10.25264 9.908823 11.11253 11.10346 + 8.641815 8.838676 8.314915 6.847168 5.620167 7.186635 8.486069 8.301935 7.863872 7.790708 7.733249 8.113005 8.49118 7.827488 8.389672 8.932463 9.147495 10.10519 10.22344 10.33928 10.09212 10.47646 10.13575 + 7.634632 6.384978 8.24638 7.503924 6.99588 7.640463 7.480204 7.821477 7.610888 7.87086 8.010333 7.981211 7.871301 8.551961 8.90114 9.304276 8.653571 9.205483 9.727321 10.48769 10.20595 10.13756 10.41514 + 8.518332 7.862745 8.034936 8.2016 6.675735 7.573159 8.171587 8.14386 7.991887 6.929758 7.718138 7.759238 8.233613 7.833398 9.010793 8.673923 9.241878 10.12235 10.55527 10.50808 10.58219 10.75335 10.4664 + 8.728762 7.574676 6.733976 7.824086 8.000705 7.302856 7.860464 8.410678 7.924881 6.743472 7.201906 7.431501 7.915576 8.187505 8.869449 8.608752 9.654437 10.20065 9.895975 10.05015 10.0937 11.01951 10.82668 + 7.629794 6.486794 6.295053 7.050656 7.523815 7.511558 8.234637 8.500476 8.005258 7.928689 8.219633 8.856939 8.562517 8.864034 9.246393 9.440809 9.380711 10.00752 9.569251 9.957119 10.54277 10.3938 10.80297 + 9.755882 6.397912 7.59745 7.644662 7.147341 7.108955 8.413054 8.151018 7.909472 7.656272 9.413692 11.06461 10.69808 10.64652 11.38675 11.21603 11.1705 10.6691 9.91959 10.95611 11.29983 11.17031 10.97226 + 9.474765 7.803607 8.385871 6.384162 7.948147 7.78756 8.428943 8.824086 8.393611 8.634716 8.208453 8.799019 9.028046 9.011028 9.807654 10.60488 10.43945 10.06425 10.27431 9.998198 11.03344 10.98869 10.06162 + 8.450254 7.49551 6.799858 6.310681 7.20258 8.050933 8.205685 8.776224 7.973586 7.784925 7.730099 8.780946 9.105856 8.773993 8.182259 8.562423 9.90097 9.80205 10.24598 10.17385 10.20839 10.46425 10.26094 + 8.252859 7.287729 7.475165 7.372538 6.989303 7.400277 6.899447 8.107825 7.968466 7.659332 8.521437 9.400009 9.208941 8.744918 8.120193 8.727738 9.995106 9.742892 9.950342 9.993467 10.03006 10.28127 10.45164 + 8.592541 7.811454 7.721195 6.033926 7.451138 7.954978 7.936564 8.032441 8.207817 7.761642 7.824575 8.806037 8.584102 9.029242 9.405202 9.570443 10.0666 9.799012 10.14801 10.00847 10.26264 10.47974 10.30221 + 8.263712 7.622368 7.388706 6.853238 7.028842 8.005108 7.877354 8.477866 8.796792 8.305426 8.403102 8.24081 8.906131 8.901518 9.546893 9.517485 9.934557 9.7798 10.04766 9.671112 10.1303 10.74265 10.63667 + 9.357657 8.026215 7.907611 7.254067 6.912889 7.510985 8.215575 8.492505 8.151805 7.310562 8.163457 8.056206 8.009975 8.118791 8.972518 9.303927 9.412671 9.438314 9.8068 9.750667 10.35458 10.35285 10.09931 + 8.511848 7.523149 8.195268 7.966453 7.744322 8.485562 8.004887 7.922952 8.245237 7.383193 7.844249 8.127041 8.127259 8.443523 8.102531 8.774108 8.681726 9.477551 8.882012 9.804171 10.55685 10.48077 10.37192 + 7.975676 7.082146 7.933741 6.951503 6.272567 7.088233 7.917744 7.379583 8.238628 7.820266 8.475443 8.424726 8.05715 8.067741 8.94787 8.867351 9.374059 9.266661 9.49703 10.01138 10.3168 10.71612 10.27346 + 8.813721 8.656951 7.681757 7.203363 7.488046 8.216457 8.221495 7.714307 7.938663 7.708951 8.019526 7.926672 7.864351 7.698409 8.801851 8.555806 9.788485 9.553381 9.62245 10.2158 9.915847 10.40117 10.80687 + 6.477304 7.734454 8.373713 6.965827 8.077723 8.442548 7.893295 8.407219 7.909376 8.080144 8.55372 7.803288 6.868239 8.449481 8.860373 8.910608 9.437862 9.165442 9.82246 10.30201 10.48472 10.77984 11.18594 + 9.42877 10.45913 10.29159 9.716755 9.220295 8.658374 6.794528 6.873018 7.217855 8.288869 8.809176 8.809996 8.093638 8.87556 9.207784 9.647738 9.825712 10.08347 9.918015 10.10553 10.54475 11.02415 10.92163 + 13.23045 15.72255 15.14105 16.25381 15.65043 12.23466 10.81911 10.62931 10.80597 11.77175 12.40585 12.68368 13.26326 11.76209 10.96095 14.30546 15.08591 12.37251 12.23275 11.97119 10.67747 10.71765 10.87486 + 13.65519 16.94076 16.0239 18.20588 16.9831 13.7648 12.16126 11.07043 11.80799 12.73412 12.98298 12.90398 14.25156 11.9087 10.24638 14.79149 15.7653 13.01829 12.92099 13.79269 11.3934 11.02932 11.13173 + 13.2973 17.06046 16.08663 18.53358 17.69795 13.95008 12.40663 11.98961 12.74475 13.79677 14.19347 14.3372 14.89816 13.25463 12.57261 16.00417 16.9676 13.95466 13.9528 14.54457 12.07387 11.57656 11.49943 + 11.75321 16.53652 16.49979 19.33843 18.63615 13.93179 11.64835 11.64008 12.97903 13.87796 14.90638 15.14878 15.24947 14.3757 13.73179 15.41584 15.93701 14.80291 14.12144 14.58253 12.19397 12.21274 12.09839 + 12.51654 17.17333 16.62761 20.22687 19.77942 13.27525 11.65 12.57212 13.83558 14.21572 15.06257 15.13174 14.75701 15.54657 14.15343 15.183 16.24345 14.94379 14.57995 14.90003 12.3515 12.90885 12.08299 + 12.59919 17.27024 16.59142 20.83065 20.46106 14.01313 12.53942 13.63936 14.82475 14.79233 15.39594 15.28064 15.61105 15.19362 13.62629 15.96059 17.22206 15.25036 15.57805 15.82821 13.8464 14.34314 12.32957 + 12.87339 17.40207 16.69853 20.75185 20.27472 14.82241 13.57454 13.89783 14.86771 15.49655 15.69082 15.79947 15.61258 16.25987 14.84013 16.51847 18.01414 15.01476 15.3407 16.01681 14.13993 14.62834 12.70863 + 13.17359 17.59177 16.96258 19.95944 18.9106 15.22701 13.8382 13.31798 14.14737 14.76138 15.86723 16.08653 15.98195 16.09414 14.82789 16.4943 17.65386 15.15134 15.58843 16.19427 14.51803 15.25478 14.10639 + 13.61701 17.7865 17.24287 20.31397 19.26783 15.3012 14.27533 14.00652 14.06157 13.97732 15.41972 16.40127 16.03523 14.89164 14.54936 15.81458 16.71577 14.59401 15.69445 17.08231 15.19946 15.35905 13.67907 + 14.00184 17.83053 17.10755 20.32385 19.31859 16.05173 14.2608 13.70262 13.87365 13.57939 14.82414 15.85239 16.70191 15.73202 13.95968 14.90556 15.42773 15.31231 15.90333 16.87693 15.50014 15.44649 13.9608 + 14.57378 17.84243 16.76657 19.45782 18.36666 15.36792 13.44019 13.72313 14.92875 14.36976 14.25026 15.64569 15.89312 14.45428 13.3161 14.53451 15.62068 14.59393 15.80624 17.03548 14.96751 15.02374 13.4909 + 15.21447 18.18304 16.96745 19.16579 18.69295 14.50879 13.17371 13.65467 15.22889 14.17074 13.75207 14.95903 15.48484 14.01785 11.96252 13.67882 15.37274 14.30946 15.06645 16.43822 14.03593 14.029 12.96432 + 15.69557 18.73573 17.84295 20.32482 19.18899 14.03427 12.50394 12.18307 15.27329 13.74666 13.09154 14.42644 14.96374 13.87214 11.83368 12.93985 14.45116 14.00281 15.06362 16.09592 13.61044 13.31885 12.74485 + 15.98183 18.61076 17.23318 18.58419 17.75739 14.66514 11.80884 13.04507 15.05399 13.23005 12.31126 13.64777 13.9603 12.94314 11.54242 12.23427 13.46654 13.42021 14.35025 15.38576 13.45529 13.28467 13.43179 + 16.36983 18.49153 17.46072 19.55406 17.8304 14.26844 11.65388 12.54786 13.89278 12.02204 11.70842 12.86929 13.92763 13.19448 11.47678 11.02568 13.00155 13.05625 13.99241 14.93269 13.36193 12.62123 11.25201 + 16.91053 19.31395 17.91098 18.89643 16.86432 13.72694 11.87185 13.24254 14.00205 12.05257 10.76908 12.87949 13.28356 11.94633 11.05437 11.12533 12.75738 12.05501 13.33129 14.07069 12.3796 11.7192 11.05169 + 17.29174 19.6846 17.73157 17.35478 16.16297 14.15115 11.11073 12.40668 13.28362 11.18836 11.07174 12.54022 13.02938 11.88706 10.44743 11.13548 12.77041 12.04656 12.83903 12.8876 11.77514 11.40439 10.56045 + 17.23432 19.42053 17.20756 16.95235 16.25754 13.89139 11.49117 11.78105 11.14721 10.20588 10.31909 12.48863 12.60464 11.83299 12.36004 11.31453 12.29337 12.36164 12.43958 12.93882 11.9782 12.27852 11.67843 + 16.53074 18.71063 16.51751 16.94945 16.05041 12.74791 10.03071 10.72647 10.99932 9.982744 10.96635 12.68731 12.83623 11.30921 11.54913 10.90253 11.23106 11.50233 12.71762 13.18253 11.76622 12.38223 11.70104 + 15.69217 17.89815 15.7483 14.97377 14.53612 11.96516 11.12983 9.131196 10.96767 10.9673 12.05442 12.21859 12.5895 10.55106 10.79283 10.54876 11.01498 10.7606 11.54235 11.51353 10.85205 11.89782 11.11372 + 13.86923 16.57632 15.26331 14.85788 14.39067 12.7171 11.17243 11.00468 11.68423 13.25407 12.60769 12.59903 12.12048 12.90249 13.94144 13.63238 13.21792 12.05534 12.87838 14.90839 15.73015 16.02667 15.69104 + 13.61382 16.34682 14.90382 14.8893 14.40084 13.49422 12.6097 13.05071 13.73629 15.75304 15.30508 13.85447 13.98672 15.82224 16.32998 16.46949 16.51073 13.91432 14.74784 17.0687 18.13454 18.42613 18.47258 + 14.55605 16.97081 15.03501 15.3369 14.16967 11.95557 10.91977 11.08843 11.75058 13.24282 12.85878 12.96099 13.28478 15.59657 14.72278 15.30267 15.28392 13.16171 14.36229 17.22016 18.41889 19.45104 19.20117 + 15.47327 17.72926 15.78447 15.42446 15.40768 12.5729 10.11994 10.89366 12.10496 13.59284 13.03747 13.40623 12.94038 16.30528 16.32386 14.95233 14.70298 13.22234 14.0664 16.60508 17.89858 18.17508 18.00281 + 16.2211 18.26995 17.28866 17.57735 15.27353 13.3695 11.53266 11.68451 11.35421 11.92297 12.33619 13.06362 12.45224 15.49412 16.06547 15.92675 15.58576 12.58488 13.5124 15.40464 16.18043 15.33247 15.62229 + 16.40175 18.42591 17.84651 18.44906 15.41768 13.78307 12.2946 12.64999 11.22093 11.41927 11.63084 10.93246 11.98123 14.54343 16.20716 16.31189 15.47426 12.76656 13.13507 15.26896 15.09722 14.0725 14.46431 + 16.6757 18.54147 17.61383 18.17967 15.46035 13.83175 11.8658 12.33601 11.13389 11.20397 11.12461 11.22868 12.22488 13.94469 15.89769 16.34622 15.46319 12.74337 14.20451 15.74678 15.10971 14.52905 14.4963 + 16.76283 18.5887 17.68788 18.20937 15.80549 13.99685 12.14814 12.54838 10.8432 11.06379 11.41749 11.17507 11.48255 12.85203 14.78319 16.05849 16.08326 13.06919 13.94136 15.39909 14.80749 14.61425 14.66702 + 16.64995 18.30085 17.58634 18.3342 16.15151 14.58886 11.89366 12.30556 11.47828 11.79887 11.09667 11.30176 11.16868 14.35984 14.87677 16.13587 16.49911 13.06481 14.12372 15.51614 15.46192 15.01677 14.90916 + 16.52672 18.18384 17.63734 18.262 16.74109 15.33377 12.32343 12.43404 12.25445 12.18885 12.2143 11.90199 11.90509 14.61265 15.28587 16.9969 17.03483 13.91487 14.51653 15.79068 15.46326 15.15117 14.32447 + 16.60033 18.01448 17.0511 17.71783 17.75788 16.23282 12.81127 12.78385 12.44913 12.3739 12.64835 12.44617 11.88231 14.26506 14.75798 16.41036 16.44767 13.79646 14.08188 15.74754 15.21961 14.5229 14.27368 + 16.58554 18.17001 15.6192 15.79108 17.83907 16.49691 13.58467 13.87136 13.15251 15.34053 15.64338 14.75528 12.38052 13.428 14.05307 15.71102 16.18547 13.51842 13.2032 15.82146 15.4119 15.28212 14.9756 + 16.81706 18.37561 15.55623 15.33322 17.88172 16.29072 14.11057 14.21804 13.08518 13.69146 14.14797 14.73615 13.03893 13.11906 14.03352 14.95837 16.48228 13.51765 14.07395 15.32152 14.80149 14.38036 14.81253 + 16.95721 18.65568 15.88247 14.83851 17.85907 16.19847 14.35859 14.35917 13.97949 13.80073 14.48404 15.46158 12.86709 12.57524 13.31753 13.57888 14.20235 13.62078 13.80603 14.58132 14.26628 15.57101 15.81091 + 16.92929 18.59748 16.18815 16.21428 17.81978 16.08954 14.27445 14.10925 13.96899 14.1386 14.35728 14.62649 12.22072 11.41585 11.79407 12.69996 13.94304 14.1476 14.00437 14.08617 14.21517 16.62167 16.08522 + 16.71347 18.34732 16.52386 16.70664 17.32837 15.66043 14.25163 14.13859 14.01087 14.8577 14.49389 14.02374 12.22193 12.02307 12.09513 12.59532 14.0639 13.72341 13.91703 14.04354 14.41245 16.46469 16.29546 + 16.4208 18.01264 16.88099 17.1442 16.57642 14.64041 13.85327 13.94551 14.64954 14.75776 14.21291 14.0806 12.50921 12.25238 11.75339 12.30866 14.22572 14.74261 14.3222 14.56139 14.66986 16.32808 16.07767 + 16.02585 17.41488 16.75061 17.14062 15.60216 13.43982 13.3218 13.5059 15.12315 15.74747 15.12732 14.97423 11.94713 11.64201 11.86428 12.81159 14.43116 14.51448 14.0855 13.91175 13.53605 16.79836 16.27676 + 15.54676 16.81251 16.59787 16.86721 13.93739 12.5265 13.02697 13.58001 14.63541 15.0335 15.03953 14.87171 11.96232 11.17344 11.23595 12.35256 13.94297 14.62026 14.15592 14.0969 13.14401 15.85678 16.06257 + 15.29335 16.5896 16.2428 16.40902 13.19328 11.96381 13.15584 13.4573 13.83275 14.18077 14.74952 13.4333 11.54537 11.45848 11.20981 11.44254 13.91985 14.09482 13.83819 13.72444 12.47239 15.62782 15.47463 + 15.03695 16.41206 15.76506 15.74993 14.99031 12.53887 14.11596 13.88085 13.56149 13.86856 14.16082 13.18733 10.81969 11.83342 11.28586 11.12295 13.29487 13.72911 13.43846 13.1814 11.87428 13.31521 14.49123 + 15.19216 16.60078 14.61114 14.46758 15.01078 13.24106 14.01335 13.57776 12.27156 13.13906 14.44345 13.87597 11.4695 11.93211 11.51881 11.86933 13.54847 13.27814 13.21632 13.90559 14.1398 14.70719 14.13614 + 14.67921 16.36944 14.31438 14.29885 14.20024 12.58013 12.82334 12.93028 12.20578 13.60437 14.77291 14.12951 12.00097 12.08059 12.8358 12.58611 13.60779 13.56823 13.54014 15.80377 16.93598 17.07594 16.38759 + 14.09909 15.53763 14.35333 14.36311 13.46532 12.24172 11.28518 11.79358 12.87418 12.31148 14.00558 14.61462 12.33662 12.94618 13.78474 13.02037 13.37858 14.04721 15.38267 18.08268 19.1378 18.01291 17.87174 + 13.13866 14.28506 13.46247 13.33514 12.55707 11.26553 10.44495 10.7674 12.86463 12.67321 13.31184 12.77522 11.95182 13.00975 13.90651 13.2495 14.2042 14.69992 15.82987 18.51886 19.10749 19.2898 19.35597 + 12.87447 13.63893 12.77628 12.87282 11.82412 10.49559 11.2738 11.53943 12.46402 13.76956 13.33128 13.70105 13.19503 13.69975 14.5716 14.70375 14.28935 14.60292 15.83705 18.41346 19.52948 19.5496 19.50181 + 12.43892 14.00917 11.94452 12.23295 13.09062 11.04633 10.81847 11.03293 12.85549 13.9011 14.34009 14.35291 13.72982 13.88251 14.83228 14.69408 14.73889 15.0092 16.64098 19.92425 20.72796 20.62129 20.78949 + 12.57589 14.14755 12.76697 12.63588 12.86826 10.93601 10.81407 11.39892 13.70268 15.24565 15.25113 15.90769 15.04436 13.95307 14.30912 15.37132 15.7328 15.43253 17.88644 20.36236 20.81531 21.52759 20.81256 + 11.55697 13.42533 11.86985 12.06834 12.89067 12.34525 12.49656 12.66325 13.77704 15.66433 16.10908 16.22246 15.24011 14.59829 15.35136 15.66786 15.75713 15.76261 17.19726 20.20177 20.41369 21.18811 20.27664 + 11.83781 11.78476 10.88169 12.16515 12.8652 12.27359 12.28256 13.37679 14.12796 16.37236 16.86594 16.74899 13.97586 14.41109 15.27517 15.25704 16.5749 15.36801 16.12666 18.94821 19.08416 20.14678 19.19424 + 11.29138 12.42908 11.55172 11.38864 12.08098 11.84389 12.93314 13.31962 14.90897 16.77657 16.34854 15.3447 13.96065 14.13565 14.2487 14.35624 16.70179 14.96482 14.82867 17.15551 17.93615 17.96055 17.92477 + 11.65481 13.19278 11.53873 12.37848 11.75132 12.30172 13.64941 13.70718 15.32799 15.79656 16.56388 15.52489 14.06691 13.22153 13.50002 13.39991 15.37756 14.06801 14.822 16.09739 16.44575 16.48426 16.86766 + 10.83643 12.90215 11.20963 11.4503 12.48443 12.65709 14.0135 14.90167 14.40853 15.14135 14.69142 14.34933 13.56003 13.23642 13.07663 13.29242 14.56171 13.91872 14.96106 16.0597 15.73718 16.22322 16.35061 + 11.76764 14.94607 14.002 12.59242 13.17363 12.93256 14.04444 14.95929 14.73403 14.32073 13.673 13.46165 12.49231 11.98037 12.40751 12.22861 14.2252 13.65674 14.01322 15.1333 14.95369 15.47503 16.08985 + 13.89615 16.76128 15.37205 14.68637 14.55084 14.06249 14.60906 15.02118 14.96586 14.17659 13.32582 13.36398 12.40657 11.75675 12.20584 11.6482 13.49479 13.45353 13.88642 14.68982 14.64923 14.41646 14.38884 + 14.84046 17.53472 16.00968 16.66092 14.74903 14.52959 14.44483 14.51026 14.96541 13.62469 12.74818 12.63656 11.79429 10.7945 10.28362 10.71255 12.82129 13.17442 13.48379 14.43379 14.1143 13.92664 13.57136 + 15.24041 17.86895 16.36832 17.24933 15.26022 14.57038 14.41827 14.01725 15.12896 14.63774 13.50198 13.16672 10.8975 10.52911 10.55219 10.53394 12.4472 12.95718 13.381 14.41105 14.18102 13.43132 13.21059 + 15.70714 18.11394 16.63966 17.54475 15.6258 14.62249 13.44291 14.33535 15.30156 14.73038 12.71182 11.88729 11.21848 11.80892 11.28598 11.00321 12.07642 12.61302 12.96624 13.64967 13.5497 13.66227 15.18429 + 16.24144 18.45406 16.74632 17.26887 16.00562 15.20356 14.67932 14.5265 15.42036 15.9411 12.72794 11.28165 11.22411 11.92239 11.05458 10.47411 11.84302 12.45643 12.32757 13.31341 13.65614 14.01642 15.6444 + 16.61691 18.75608 16.65908 16.05809 16.49335 15.44349 14.24317 13.74861 15.73102 16.03167 12.45979 11.43863 12.06159 11.43628 11.58031 10.96982 12.73052 13.25921 12.43133 13.44257 13.17499 13.61122 15.05092 + 16.80972 18.82384 16.56598 15.89633 16.39415 14.86858 13.51579 13.62421 15.78119 15.96636 12.04702 12.23535 12.08618 11.75746 11.64274 11.03938 12.40111 12.2805 12.29179 13.94364 13.40477 14.06813 15.88864 + 16.63538 18.58344 16.62993 16.47061 16.84248 15.18759 14.40616 13.94959 15.81456 15.56275 13.3875 12.99495 11.75405 11.29325 11.58946 10.95365 11.4328 12.09967 12.70522 13.64252 13.03335 14.81887 16.09799 + 16.17998 17.74599 16.20119 16.20937 17.15302 15.38168 15.02195 14.70119 15.58851 15.20672 13.59827 13.00949 12.00444 11.9139 12.20626 11.42136 12.15257 13.27923 12.24949 13.81115 13.19789 14.65822 15.93385 + 15.63498 16.83412 15.9795 16.01633 16.73568 14.96041 15.20592 14.9941 15.25987 15.44159 13.90219 13.12603 12.1955 12.00728 11.73402 11.36467 12.2128 13.21522 12.46231 13.59565 12.94152 14.60943 15.73831 + 15.64667 16.88672 16.15878 16.30288 14.82288 12.78746 14.38334 14.24222 15.33887 15.6051 14.19205 13.4702 11.48957 11.67185 11.36558 11.50844 11.67504 12.6779 12.27801 13.62284 12.4663 13.766 14.50554 + 16.1116 17.70094 16.61898 16.63179 14.50537 13.00403 14.49458 14.1091 14.77081 16.03117 14.69265 13.87188 11.65564 11.77306 11.69971 10.80465 11.53343 12.87404 11.97025 13.6426 11.97943 14.26168 15.0657 + 16.30089 17.96895 16.63384 16.78599 15.04495 13.30599 14.34233 14.00725 14.74239 15.8376 14.84421 13.98984 11.77159 11.99564 11.91329 11.26901 12.10066 14.10714 12.30086 12.97296 11.96393 13.5807 13.9249 + 16.11331 17.73792 16.50445 16.31737 15.14762 13.18915 13.33717 13.48801 15.0379 14.98231 14.6054 13.371 10.87303 10.89191 11.57216 11.3191 12.55595 13.71982 12.37777 13.36162 12.34734 12.24435 12.79598 + 15.58554 16.86545 15.76826 16.14976 14.84043 12.69869 13.17145 12.83138 13.56788 13.88323 12.82279 11.39667 10.49319 10.13156 10.41932 9.690503 11.98269 12.59705 11.74903 12.81073 11.81398 12.05253 12.92546 + 15.40506 16.56629 15.7819 16.15461 15.12686 13.06547 13.38418 13.28866 11.46526 12.2537 12.2489 12.08193 10.35587 10.30065 10.11564 10.48493 11.5637 11.96607 11.58659 11.82748 10.88299 11.80397 12.83247 + 15.64443 17.13461 15.25182 15.23267 14.96755 12.78958 12.95011 12.96703 12.13067 12.01262 11.68263 11.51331 10.19018 10.40131 10.45652 9.893003 10.72811 11.31659 10.82685 11.00283 10.72475 11.77716 12.83387 + 15.71785 17.45413 15.5854 15.01698 14.3412 11.71642 10.96577 11.03219 11.98035 12.71681 11.61681 10.26505 9.601998 11.02885 11.42186 10.48678 11.01715 11.48228 11.22338 11.53144 10.79359 11.5774 11.99054 + 15.35344 17.22778 14.87986 13.97491 13.06646 10.3242 10.27509 10.32014 10.23042 10.61678 9.737593 10.01495 9.896219 9.359041 9.507567 9.67006 10.14279 10.65076 10.4929 10.57693 10.33899 11.15093 10.91731 + 14.73678 16.47514 14.2816 13.68988 13.41362 11.12034 10.6353 10.23782 10.21636 10.79559 10.0661 10.10203 9.259908 9.090837 9.185848 9.923974 9.884459 10.10081 10.24038 10.84077 10.28913 10.66675 10.87501 + 13.34543 15.10439 13.62741 13.43057 13.13955 11.26525 10.73161 10.48361 8.931073 10.65594 10.13154 10.01275 7.661518 8.794694 8.97205 9.528334 9.832764 10.47726 10.19211 10.24871 10.08061 10.30916 10.30075 + 10.66386 12.08491 13.25964 13.39106 12.19863 10.12935 11.24597 11.23391 9.032432 10.34383 9.701096 9.622985 8.836775 8.976686 8.384194 8.839561 9.518727 10.43447 10.18111 9.936262 10.31167 10.56191 10.62938 + 9.864835 11.36032 12.31589 12.7327 11.80678 10.03503 10.97492 10.7874 9.752045 8.775429 8.095765 8.616365 8.481807 8.58884 9.057997 9.505718 10.19115 10.05057 10.04556 10.14044 10.41077 10.46338 10.77466 + 8.924618 11.12906 12.26638 12.40822 11.61309 9.230251 10.80107 10.44947 9.52743 9.636349 8.786553 9.209707 8.387288 8.182937 8.243385 9.326593 9.774284 10.1685 10.02218 10.17269 10.70011 10.49688 10.61065 + 10.46031 12.47213 11.88194 11.74302 11.8674 10.72511 11.42089 11.52294 12.66962 13.42245 12.90012 11.16923 10.26218 10.81529 10.76803 10.16122 9.826 9.915348 9.86139 10.30795 11.00059 11.42232 11.84945 + 12.26625 14.16075 12.72903 14.60278 14.37007 13.44235 12.87462 13.86045 15.57594 16.44231 16.44123 15.36868 13.77279 15.25738 15.21306 14.52211 13.27622 12.97607 12.30169 14.6017 16.36056 17.2046 17.79084 + 12.88817 14.4487 12.22028 13.27812 13.9757 13.02691 12.24403 13.3259 14.29199 15.57484 15.93701 16.14005 13.74489 14.87244 15.91617 16.46932 15.27049 13.81515 13.83679 16.70215 18.24577 19.36378 19.67374 + 12.00124 15.37659 15.7605 14.22926 13.0174 13.10144 11.59302 12.30477 13.87144 16.48501 16.24954 14.65436 13.44942 13.95702 15.1756 15.80813 15.05493 13.84618 12.97811 14.7254 15.89062 17.37466 17.80906 + 11.40193 16.41908 17.10656 18.07596 18.44994 14.86982 11.46446 13.08391 15.70103 16.6888 15.61081 14.1348 12.79728 13.32965 13.90944 13.99649 13.78145 12.89573 11.9253 13.4449 14.24946 14.72222 15.25539 + 11.44434 16.72986 17.13328 18.86685 20.06189 16.01924 13.17847 12.7762 17.20245 16.84163 15.03655 13.80424 11.7222 13.07261 13.83397 13.96507 13.21282 12.76647 11.96956 12.39547 12.90304 13.23651 13.36372 + 10.10038 17.35346 17.76299 18.8912 20.46964 16.98438 14.85764 12.72846 16.86143 16.67736 14.81743 13.0213 12.2606 12.59028 13.18198 14.63323 13.8833 13.29084 11.56619 12.33959 12.88427 13.18531 13.93617 + 11.39528 17.46929 17.92314 19.14353 20.62991 16.99307 15.65434 13.20797 15.76896 15.81176 13.97282 12.77619 11.2707 11.88343 12.92847 13.32276 13.7076 13.56002 11.07274 11.85992 12.23533 13.28798 15.04418 + 11.27983 17.707 18.24305 19.08735 20.56552 17.11422 16.33149 13.43726 14.52213 14.48029 13.66881 12.0331 11.1849 10.85902 12.006 12.63326 13.76072 13.75976 11.0928 11.39149 11.49694 13.85464 15.78272 + 10.4093 17.90809 18.4453 18.32235 20.13852 17.31362 17.00359 13.08082 13.30086 13.77682 13.61921 11.83928 11.08163 10.67048 11.6871 11.93983 13.32355 13.21966 11.60241 12.79556 10.68321 13.65361 15.63675 + 11.84527 18.06657 18.71371 18.15455 20.01794 17.42912 17.4063 13.26461 13.40163 13.82001 13.56594 12.01353 11.27739 11.76238 11.80556 12.06823 13.41709 13.49274 11.33103 12.29501 11.13933 13.40397 15.07014 + 11.17124 18.38477 19.04682 18.43799 20.28102 17.52682 17.30856 12.02493 13.38366 14.0256 12.96288 11.21294 11.00717 11.76898 11.5427 11.69634 12.18315 13.27228 12.24852 12.80867 11.54512 13.54795 14.91226 + 11.79911 18.40328 19.16708 18.38249 20.19378 17.33193 16.52722 12.74763 13.76983 14.43673 13.70339 10.60393 10.94744 11.23283 11.7214 10.93908 12.70267 13.61965 12.34297 12.93185 11.72894 13.06544 14.49717 + 11.53892 18.40511 19.1988 17.54394 19.24091 16.508 15.51558 11.58755 12.57494 12.96985 12.25272 10.15904 10.6575 10.79901 10.68679 10.70864 12.52 13.14616 11.88523 13.06559 11.90712 13.5841 14.07163 + 11.24507 18.51727 19.28405 15.55707 16.47013 15.3894 15.69263 12.4398 12.47237 12.42525 11.96187 10.67544 11.41625 11.04646 10.61635 10.52443 12.70697 13.38649 11.35408 12.26194 11.28505 13.45126 13.82557 + 11.66839 18.54571 19.34097 15.28023 16.99143 15.16772 15.61421 11.90284 12.48574 13.0267 11.92334 10.24209 11.53736 11.04919 10.13369 10.87534 12.32853 13.07113 11.1777 12.35379 11.42702 13.24903 13.47682 + 11.33042 18.52498 19.28227 15.3864 16.97915 14.79772 15.07273 11.31091 12.86657 13.35474 11.33974 9.940867 11.48389 10.81812 9.995729 10.97024 12.09934 12.44435 10.87501 12.38766 11.07067 13.29669 13.62211 + 11.3056 18.38368 19.13547 14.39207 16.36372 14.8709 14.99244 11.87787 12.69045 13.26806 11.46194 8.540175 10.51303 10.84584 10.27139 10.64636 11.47711 11.95679 10.57964 11.26044 10.76696 12.47983 12.5918 + 11.55642 18.09599 18.73145 15.37899 17.526 15.3725 15.14406 11.61225 12.45738 12.59422 10.7795 8.732772 9.834822 10.28893 9.671982 10.17871 10.94767 11.20057 10.26523 10.61838 10.52447 10.65674 11.38504 + 10.35312 17.61216 18.04445 15.89868 17.93677 15.43736 14.92465 10.95503 10.74119 11.10365 10.10367 8.769894 9.549344 9.448477 10.16095 9.991289 10.12919 10.67581 10.30081 10.2757 10.61878 11.08467 11.66054 + 10.57029 16.80257 17.43232 15.33712 17.40169 14.69754 13.7979 10.32226 10.54766 10.62139 9.538151 8.558439 8.763721 9.43328 9.823753 9.941569 10.20876 10.29988 9.839418 10.4947 10.67628 10.63656 11.36743 + 10.88069 16.40481 16.94452 14.63999 16.55998 13.75831 12.04815 10.07983 9.779847 9.41483 9.367539 8.638872 7.551649 8.591156 9.22356 9.253392 9.312204 10.12255 9.771526 10.66726 10.28885 10.70903 10.99041 + 10.68995 15.9614 16.66981 12.87561 15.32809 13.38852 13.34967 10.08965 9.267484 8.510974 8.937634 8.066225 7.492024 8.559677 9.379137 8.934621 9.395594 9.947574 9.762503 10.16802 10.52471 10.62313 10.52163 + 10.10682 15.73363 16.55744 12.98704 15.02876 13.22308 13.64594 9.306398 8.513678 8.840482 8.639846 8.813548 8.690471 9.372956 9.21609 9.271674 10.22423 10.17199 9.91317 10.44354 10.81481 10.71306 10.58567 + 10.53498 15.85452 16.48894 13.69206 15.73015 14.98417 13.35866 12.12415 12.66079 12.8636 12.57128 11.65822 10.42173 9.932479 10.30401 10.88577 10.69672 11.60742 10.67614 10.5448 11.20179 12.58635 13.41792 + 10.96499 15.49205 16.39072 14.58421 16.09194 14.12068 12.85947 10.9668 11.6846 11.61401 11.32033 10.1519 9.595464 9.126978 9.282423 9.871722 10.47498 11.93141 10.77083 10.79808 10.82797 12.26179 13.4949 + 10.02513 14.95054 15.62905 12.19269 13.6047 13.04639 12.49895 9.641859 10.20514 10.12763 9.829097 9.059594 8.440591 8.796917 9.133607 9.019018 10.19306 11.17522 10.55359 10.32446 10.81375 11.08818 12.5863 + 9.422004 14.69329 15.27407 12.65151 13.94985 12.99975 11.70039 9.886936 9.611949 10.09684 9.314202 9.766679 9.321723 8.8813 8.354034 8.528647 9.770875 10.59045 9.79849 10.28119 10.74567 10.74199 12.01325 + 11.32263 15.05788 15.25787 15.88041 15.08022 14.13194 12.75217 11.34698 9.656963 9.717936 9.331264 8.585823 9.124638 8.87212 8.442982 8.890512 9.943332 10.48704 10.23122 10.30991 10.68609 11.49976 11.52623 + 13.40004 15.62923 17.28662 19.34645 17.7522 14.88166 15.30356 13.29276 11.17599 10.1756 8.496209 8.687905 8.767036 7.138587 7.905816 9.155358 9.870092 11.34072 10.64145 10.56284 10.93426 11.27267 11.83103 + 14.40832 16.92628 18.28235 19.92572 17.42484 16.51931 17.17439 13.85876 11.32172 10.88191 9.843261 8.557543 8.702249 8.43864 8.905317 9.214272 10.79284 11.19663 10.4797 10.33966 11.11496 11.59549 12.62567 + 15.07293 17.23655 18.7453 20.03891 18.20394 17.32358 16.8287 15.43667 13.0998 12.50691 10.92344 10.46035 9.055417 9.849059 9.764614 11.06528 13.47688 13.99895 12.79779 12.12013 14.56175 14.29823 14.93593 + 15.40606 17.37957 18.26671 19.24368 19.16639 17.99058 16.59817 14.71303 12.86606 12.04343 11.7385 9.705905 9.335643 9.112566 9.626029 10.41576 13.39695 13.71364 12.28225 11.58019 13.76471 13.65422 14.2695 + 15.64262 17.64327 17.19793 17.43849 19.78349 18.46711 16.14888 16.3467 13.90007 12.84516 12.72527 10.46768 9.428706 9.794108 10.62751 11.56921 13.06464 12.97483 12.06074 12.42412 15.20449 15.17994 15.41442 + 15.52258 17.33565 17.81485 18.67915 20.30933 18.47157 16.206 16.37829 16.18498 14.41841 13.32267 11.18768 9.268024 10.2243 10.31914 12.25662 14.13956 13.31647 12.61077 13.04033 15.24885 15.47131 15.91226 + 14.72044 16.24851 17.39948 18.02982 19.91796 18.15676 16.86558 16.89674 18.34361 15.89882 13.7806 11.83443 10.31598 9.947871 10.88693 13.04681 14.78731 14.09249 13.07614 13.30486 14.96555 15.89365 16.21339 + 12.94438 14.262 17.79223 17.94734 18.41548 17.99884 16.59502 17.46818 19.89834 17.3267 14.68132 12.74071 10.74997 11.11081 11.97623 14.37372 15.06054 13.62777 12.74747 14.17785 13.22865 15.07573 15.67369 + 11.9413 14.24815 17.19899 17.78853 19.11386 17.95886 17.36403 17.78174 19.56396 18.41936 15.83994 13.5232 11.30285 11.13494 12.42168 14.83165 15.21284 13.93472 14.22501 15.48852 14.69647 14.61711 15.37134 + 13.80032 15.34109 17.01766 17.4297 17.96654 17.89771 17.45484 16.8976 18.80153 19.64696 17.77114 13.78843 12.49898 11.85447 13.19477 15.72658 16.27253 14.45719 14.41123 16.36125 15.85711 15.05885 15.80895 + 14.42734 15.95719 16.8165 17.40023 17.72437 18.32386 18.0716 16.22936 18.2776 19.88119 18.43486 14.89068 13.09634 12.62326 14.15393 16.27906 16.78207 14.59756 14.30995 16.8557 16.74701 13.89337 15.01136 + 13.1981 15.42621 17.47243 17.46376 16.60345 17.87163 18.14639 15.80742 17.8999 18.86058 18.78569 15.2696 12.82393 12.26846 14.426 16.64136 16.84205 14.60646 14.58007 16.73913 16.8489 13.78548 15.02061 + 14.53758 16.3012 17.77195 17.30224 18.26668 17.24618 16.88194 15.98161 16.4734 18.86712 18.13484 16.05925 12.78708 12.62607 14.48131 16.29807 16.06342 14.38513 14.33487 16.47281 16.5306 13.28973 14.15116 + 13.29329 15.40082 17.00095 16.67248 17.51397 17.87264 17.22511 15.87745 16.17892 17.66627 18.2972 16.80437 14.20589 12.99962 14.83743 16.62644 15.83631 14.91555 14.99209 17.03086 17.57478 15.26948 15.94518 + 12.60118 14.90419 15.67589 16.70849 16.94395 16.61985 16.03358 15.05487 15.99355 17.37237 17.7354 17.29265 14.00175 12.25772 14.06873 15.4484 15.89154 14.37778 13.64605 15.54983 15.959 14.05933 14.62753 + 13.46687 15.90945 16.95177 16.9344 16.38556 16.47206 16.12689 15.33399 16.03906 17.06773 16.99802 17.40662 13.44633 12.45146 13.97935 15.02217 15.57034 14.04656 14.18954 15.08655 15.59686 13.81427 14.97765 + 13.90775 15.34541 16.23319 17.18387 17.43214 17.35052 16.137 15.33103 15.5793 15.9622 16.35075 16.71717 13.52683 12.29098 13.29745 15.11607 15.76651 13.92764 14.35643 15.45294 15.56918 14.29957 14.75815 + 12.64945 15.05234 16.66335 17.67402 17.42719 17.03349 15.29472 13.20675 14.79218 16.15494 16.06722 15.88496 14.37258 12.09099 13.10366 14.55416 15.20259 14.15096 14.36049 15.3579 14.84148 14.77236 15.21402 + 13.63886 15.13448 17.12833 17.25077 17.57319 16.51949 14.79358 14.33071 15.40003 15.31295 14.707 15.51841 15.19862 12.16728 12.38076 13.97288 15.01122 13.84911 14.36896 15.99493 15.19653 15.71203 15.79622 + 14.08951 15.27791 16.67466 17.38719 17.48137 15.49804 14.64399 13.99431 14.06412 14.96719 14.45313 15.07616 15.22869 11.85608 11.80214 13.4829 14.47193 13.28767 13.82474 15.54498 14.68076 15.78218 15.55037 + 13.55869 15.54187 15.30116 16.07854 15.19114 14.89549 14.28598 13.40435 12.58551 12.71723 13.51417 14.44852 13.74717 11.34321 11.73631 12.8637 13.46484 12.86962 13.4271 14.9927 16.06477 17.438 17.00769 + 14.03767 15.96629 15.7353 15.65322 14.90481 14.81491 13.83562 13.2442 12.39499 12.31491 12.90394 14.30139 13.67956 10.38161 11.00745 11.82061 12.68529 12.26423 13.03794 13.27276 13.62125 14.79159 14.69412 + 14.69835 16.23426 15.85394 14.956 15.55784 15.1201 13.12001 11.77338 12.35275 13.03831 12.70205 13.89809 13.49535 10.74578 10.39047 11.01446 12.48515 11.93507 12.14398 12.33028 12.54093 12.23906 11.828 + 13.74119 15.01042 14.63525 14.21064 15.04048 14.53166 13.30235 11.51442 11.54563 12.75932 12.87387 12.97661 12.22388 9.737226 8.855085 10.95898 12.41875 11.5811 11.65182 12.16752 11.78344 11.6825 11.58462 + 13.79247 14.65056 14.39971 14.56042 14.50872 14.48325 12.4725 11.32357 11.69767 11.76651 11.72759 11.75854 11.63687 9.03346 8.632442 10.05544 11.80099 11.283 11.6399 11.7433 11.51521 11.30795 11.44739 + 12.4817 13.96644 14.94901 14.22443 14.7217 14.6918 12.00653 11.63244 11.49402 12.39865 11.62017 11.95335 10.76735 9.714913 9.972126 10.44865 11.5843 10.77267 11.39896 11.29488 11.80279 12.45774 12.97729 + 10.99601 12.48925 13.91558 13.39563 12.76022 12.97499 10.67527 11.2872 11.05415 11.66541 11.35227 12.07333 10.91728 8.470509 9.390297 9.98071 10.65596 10.24184 11.05679 11.06191 11.15756 11.02771 10.34172 + 11.55889 13.16734 13.01277 13.71551 11.48029 11.84606 12.16008 11.11222 11.96976 12.21278 12.98672 12.49252 11.65213 12.38936 13.03628 13.42355 12.62503 11.73549 11.11625 12.92801 14.35214 14.86793 15.02906 + 10.42775 12.77446 12.08269 12.53821 11.88333 11.98844 12.13725 11.12525 12.48612 13.17795 13.38511 12.48855 11.81891 12.69561 13.0315 13.13174 12.79269 11.96432 12.52114 14.89753 16.66616 17.80948 17.48282 + 11.87147 13.35178 12.29651 13.07613 13.38078 12.15471 11.58152 10.57638 11.48294 11.66988 10.83331 10.95618 10.80718 12.60706 13.70898 13.6584 13.12783 12.36247 13.81388 16.36983 18.19867 19.32249 19.17922 + 11.74805 13.03258 11.83647 10.99839 11.53884 11.58733 9.78068 10.00441 11.77152 12.2512 12.23087 13.11207 12.52222 13.45929 14.83094 14.73086 14.22945 13.92837 15.33029 17.7077 19.34477 20.7841 21.06674 + 12.91207 13.92127 12.60293 11.2707 11.34953 11.66406 10.61612 10.41087 11.90737 12.03745 12.62049 12.73641 12.31181 15.63897 15.29306 15.0111 14.84808 15.03202 16.69465 18.62388 20.75715 22.16574 21.82943 + 11.44404 13.17524 11.91981 11.4003 11.81657 10.4973 11.08138 10.91362 11.54249 11.68209 11.96895 12.71395 12.69716 15.29071 16.25213 15.87629 15.68893 14.98099 17.12889 18.67869 20.67893 22.07556 22.39026 + 12.4943 14.38828 15.40293 14.53412 12.63508 10.61958 11.04276 10.82849 11.58219 11.86627 13.09368 11.76773 11.85476 15.56555 15.54773 14.94056 15.46294 14.71608 16.38725 18.32511 19.88208 20.835 20.72138 + 12.06502 16.88607 18.26798 18.51961 18.70255 16.0556 11.92916 12.43737 13.55841 13.30871 12.92406 12.8846 12.13316 15.64249 15.85884 15.73912 15.52897 14.45106 15.96146 17.69323 18.59188 19.02813 19.20515 + 11.12339 17.63247 18.67913 18.09006 20.21992 17.90995 12.6137 12.48078 12.48313 12.308 12.5629 13.46077 13.18955 15.1113 15.49067 16.01841 16.40285 15.20319 16.30907 17.38044 16.9833 16.74973 17.5288 + 11.91933 17.71219 18.231 18.7819 20.81494 18.03944 12.80576 12.62215 13.70358 14.11044 12.98072 13.73609 12.88998 16.17216 15.98503 15.40534 16.2627 14.74855 14.94189 16.8815 16.57269 16.14612 17.22886 + 10.80071 17.88858 18.37441 19.57571 20.85023 16.92813 14.54551 14.11315 14.60858 14.76622 14.24647 13.50114 13.44903 15.14018 15.77174 16.55495 16.70045 14.63158 14.95225 16.897 16.51554 16.39054 16.95824 + 10.11735 17.24759 17.42141 19.76315 20.66429 16.31513 15.35933 15.46266 14.2526 14.75529 14.8134 13.60172 13.60854 15.0717 15.27205 15.8339 16.31969 14.84996 15.4993 17.3387 16.82842 15.77378 16.33088 + 11.58894 15.94406 15.80265 19.82332 19.81112 16.33015 15.83328 16.12075 14.11878 13.67492 14.12749 13.19047 13.91129 14.98374 14.91681 15.74825 16.61319 15.2014 15.57807 17.29531 16.63654 15.11069 16.41315 + 12.11817 16.37547 16.11933 19.74942 19.52616 15.253 15.60251 15.62886 13.73787 12.94972 14.53512 13.22932 13.03554 14.42677 14.02384 14.75253 15.97637 14.65869 15.00835 17.03261 16.1345 14.50001 16.3125 + 12.40414 17.09673 16.56095 19.30345 18.83337 15.53385 15.46334 15.14222 13.0195 13.65549 14.05797 13.27337 13.1787 13.58766 13.74914 13.84215 14.70384 13.81669 14.36711 16.36557 16.29565 15.23389 17.42854 + 13.11347 16.62823 16.08442 18.65703 19.09037 15.8935 15.2197 14.41059 14.00731 14.22315 14.2603 13.98392 12.74996 12.83496 12.62025 12.43474 14.70534 14.04083 13.31598 15.78194 16.0346 15.06308 16.98965 + 13.64474 17.90531 17.46792 19.65909 19.84337 16.36866 15.0947 14.08054 14.56519 14.61388 14.04171 13.45949 11.97165 12.38503 12.46181 12.36982 13.73913 13.27664 12.86066 14.10406 13.75239 13.30816 15.46512 + 14.14659 17.85538 16.63506 17.69785 17.37612 14.4621 14.21311 14.33 14.55272 14.0266 13.34313 12.6474 11.67851 12.07374 11.39458 12.00585 13.00983 13.07051 12.53945 13.83851 13.02929 13.78781 15.03182 + 14.42228 17.95903 16.79436 17.2867 17.37424 14.4423 12.56357 13.39425 14.97358 14.38745 12.16811 12.31725 11.24478 11.62687 11.66598 11.82592 13.17022 13.03793 12.44336 12.93122 12.50479 13.24247 14.70499 + 14.74926 17.10213 16.10866 18.41386 17.76688 14.66671 12.0519 12.36404 14.64657 13.54079 11.52991 11.67943 10.9411 11.91207 12.82024 12.68861 12.79371 12.74705 12.14265 12.87091 12.87852 13.3739 14.64138 + 14.77377 17.52547 16.45933 18.03106 17.99345 14.37569 12.28482 12.38711 13.49167 12.96972 12.2464 11.9446 12.06746 13.32547 13.42399 12.804 13.77554 13.8069 12.38337 13.585 13.03204 13.04344 13.17559 + 14.33936 16.05802 15.20399 17.29784 16.82894 14.67938 13.40503 14.50885 16.62795 16.48669 15.85748 14.00688 13.75563 13.0535 13.17885 13.77508 14.15859 14.48487 13.08349 14.30881 13.77487 13.4736 14.49444 + 14.44479 16.99548 15.77001 17.10963 16.52903 14.38944 13.44239 14.06731 16.73449 17.81567 16.47066 14.45036 13.36218 11.99206 12.16488 12.52671 13.19155 13.33347 12.81071 14.34716 14.2478 14.17321 15.78081 + 14.02579 17.08305 15.59479 15.89314 16.72221 14.24861 13.47705 14.10365 17.43085 18.94127 17.04 14.55132 12.30284 11.67238 12.13895 11.74947 12.48997 12.62799 12.61127 14.23425 14.47474 14.48953 16.6846 + 12.98601 16.43487 15.30097 15.82755 15.67639 13.93307 12.06077 14.01533 17.31017 17.03305 16.06872 14.63635 13.17454 12.51504 12.19607 11.30268 12.40507 12.31048 13.08197 14.41822 14.24439 14.75511 16.61187 + 12.36717 14.63769 12.81204 14.45165 13.75739 14.0802 13.48325 14.81929 17.03195 17.97369 16.36871 14.08131 13.45929 13.48154 13.22458 13.06752 12.79095 12.71402 13.04852 14.30993 14.63789 14.94942 16.90777 + 11.93372 14.51598 12.94251 14.97276 14.5037 13.14109 12.6004 15.28386 17.44633 17.41194 15.19083 13.97468 12.30335 11.49983 12.01657 12.22904 12.7571 12.17981 13.11903 15.56299 14.76678 16.0535 16.8217 + 12.47566 14.19673 11.79418 12.79603 13.27397 13.03157 14.51644 15.58098 16.45773 16.79338 14.77104 13.59812 12.80408 11.51495 12.39793 12.11381 12.55917 12.43729 13.31075 15.56109 14.98054 15.78551 17.06624 + 12.2613 15.1282 13.99666 13.71514 14.27644 13.59662 14.62273 14.96381 16.1037 15.93762 14.79321 13.20536 12.09543 11.00414 11.58279 11.8383 12.9191 12.51326 13.47569 16.26331 15.60605 16.11314 16.97496 + 12.43962 14.93872 12.93799 13.37484 14.13616 13.94297 13.31241 15.01747 17.49583 16.37276 14.13916 12.80372 11.91654 10.96919 11.34828 11.55524 13.11632 12.65655 13.44765 15.82003 15.211 15.98718 16.41879 + 12.20704 14.56072 12.76487 14.66424 14.36893 13.81488 12.67005 14.58511 15.8139 15.15328 13.72443 12.0736 11.75713 10.39046 10.3162 11.07518 13.42291 12.18517 12.6754 14.56121 13.61762 14.73406 15.99769 + 12.26719 14.83184 13.45157 13.9031 13.37387 13.42337 13.16261 14.01834 13.45282 14.0881 12.42882 10.71366 10.67623 9.888527 9.556181 10.42893 12.93971 12.08191 12.30767 14.6603 13.51334 14.00465 15.0682 + 13.72396 15.37463 14.90107 14.14883 14.71334 14.23447 14.62967 15.41844 13.9625 13.62733 12.02162 10.61794 9.693156 9.38163 9.607562 10.24143 12.10383 11.62002 11.61677 13.37127 12.76904 12.98495 13.14606 + 12.20455 15.08801 16.28204 15.02526 14.91302 14.54155 16.05799 15.24317 13.17851 13.23946 11.95253 10.98236 9.365788 9.214337 9.505456 10.4926 10.92743 11.19956 12.08282 12.89608 12.90349 12.21022 12.78775 + 13.37813 14.82368 16.03482 15.19005 16.00402 15.02282 15.84676 15.76265 13.34728 12.43027 11.99226 11.34601 9.200621 9.239662 9.540243 11.00728 12.16874 11.82533 11.95636 13.50077 12.4501 12.26641 12.92042 + 12.66223 14.38916 15.40475 14.94944 16.37963 15.2842 15.38037 15.8695 13.61753 13.21642 11.7801 11.01452 9.542067 9.19785 9.696535 10.70263 12.5226 12.46992 12.17822 13.79243 13.24585 13.34737 13.80106 + 11.79797 13.75565 14.85456 15.8272 16.72862 15.18555 15.07867 15.58954 14.36672 13.03338 12.42223 11.01965 9.557907 9.226222 9.848079 10.37486 11.38179 11.42391 12.02948 13.78323 12.73048 13.11424 13.94043 + 12.11479 14.20692 15.95607 15.77075 15.94264 15.04848 14.68504 15.58499 16.73163 14.876 13.04782 11.34189 9.554831 9.312258 9.405445 10.54039 12.08341 11.93015 12.28186 14.35123 13.82728 13.614 15.07887 + 11.63898 13.24526 15.91903 15.04351 15.44301 14.33202 14.69388 15.04394 16.66434 15.8622 13.70809 11.39564 9.984374 9.255429 9.771338 10.38831 12.17067 12.11052 12.20296 14.49279 14.43369 13.75218 14.74203 + 12.24345 14.6031 16.65611 14.82507 16.38684 15.87055 14.16241 14.53406 16.72972 16.78175 14.29714 11.9692 10.40499 9.319419 10.12237 10.74756 13.3062 12.89304 12.51923 15.03736 15.23477 14.65409 15.5749 + 12.77314 15.07554 16.98285 15.57631 16.88236 15.60186 13.31313 14.22181 15.56985 16.22102 14.96699 12.77368 10.60659 9.910019 11.08181 11.14588 13.15701 12.80074 12.45314 14.14474 14.5937 14.61545 14.75511 + 11.81499 14.35236 15.86184 15.37682 15.91093 14.51173 12.01213 12.23065 14.53028 15.26377 14.16712 12.59848 10.46429 9.104154 9.218637 9.824287 12.90368 12.61128 11.938 13.29911 13.48286 12.61785 12.90715 + 13.13115 13.74104 13.82935 14.62105 13.24596 12.30486 11.74188 12.57558 13.35646 14.14618 12.51182 9.92897 9.892784 8.203323 8.843456 9.73543 11.10688 11.40638 11.2225 11.48934 11.82256 11.33256 11.55696 + 13.5014 14.46064 13.74532 13.76357 14.51184 13.47387 12.36466 13.09748 12.37077 13.78026 12.56234 10.40441 9.652602 9.258573 9.640882 10.48315 11.37579 11.28799 11.69723 12.14306 11.93345 12.913 12.47232 + 12.11707 14.41063 14.2667 13.93633 13.81357 11.92622 11.39311 12.56514 11.91435 12.2172 11.83334 10.78043 8.693699 9.34746 10.5232 10.74675 11.27402 11.17691 11.69285 11.59679 11.87287 12.48645 13.45397 + 12.73287 14.28872 14.12864 14.03616 13.14685 12.7475 12.18416 12.10903 11.98855 12.79712 14.14206 13.79637 12.14143 12.49956 13.05192 13.06696 12.86376 11.90433 12.45795 13.79512 14.72743 15.6082 16.03671 + 13.99284 14.59781 15.86497 15.46929 15.35721 14.4506 13.86872 13.70982 12.77764 13.87713 16.70483 16.12365 13.74394 14.14882 14.72046 14.79044 14.55702 13.26187 13.4715 15.52675 16.2828 17.03688 16.70895 + 13.34487 14.76827 16.66223 16.6201 16.95358 16.41091 14.59964 14.13615 14.98613 15.52808 16.94203 16.33436 13.65864 12.67898 12.89719 13.15985 13.87055 13.7345 13.81801 15.46476 15.5521 15.17291 16.18393 + 11.05816 13.38546 16.02215 16.0239 16.26703 16.0995 16.00097 15.06918 15.39436 16.33123 17.5566 17.69474 14.73381 12.76004 13.46956 13.62351 14.9516 14.46614 13.86967 15.92621 15.77614 15.14017 16.05052 + 13.44674 14.49088 16.24643 15.87667 15.80228 16.08157 16.27578 16.11953 15.71647 16.77408 17.38955 17.5013 14.82175 12.91548 12.99751 13.53425 14.71743 14.50213 14.5002 15.80028 15.50727 14.7684 16.64701 + 14.21669 14.68321 15.45795 15.69659 15.90129 16.00284 16.18194 16.61241 15.75285 16.67905 17.6036 17.33829 14.63122 13.52661 13.50696 13.30114 14.47372 14.06641 14.2557 16.1715 16.02145 14.45178 16.56786 + 13.89403 13.90886 13.8904 15.63989 16.239 16.28278 16.61728 16.93481 16.17262 16.97161 18.37757 18.09198 15.23442 13.31642 13.7317 13.67162 14.61277 14.06051 14.15388 16.12131 16.52321 14.41898 16.15249 + 13.62738 14.29071 14.26743 15.39755 16.17412 15.93856 16.81614 17.35265 17.03794 17.52091 19.20687 18.71931 15.41284 13.25959 14.02276 14.49864 15.36796 14.59919 14.92057 16.34993 16.91476 14.57673 16.4135 + 13.91304 14.38333 15.62968 15.92608 15.88913 15.46424 17.23949 17.6737 17.75764 18.32361 19.38836 18.81548 14.75313 13.59059 14.47715 15.14762 15.94664 14.38755 14.47487 16.32241 16.61687 13.88076 16.03177 + 13.85443 14.63751 16.63829 16.22158 16.00957 14.22576 17.54068 17.94837 17.70362 18.35151 19.07424 18.78005 15.38741 13.65261 14.89409 15.66142 16.46598 15.04117 14.94388 16.69312 17.13902 14.49912 16.41131 + 14.16736 15.20732 17.17613 15.65355 14.81104 14.93489 17.35307 17.69239 17.67073 17.9412 18.96013 18.70328 15.56409 14.20707 14.99696 15.9745 17.04941 15.52152 15.42804 16.55275 17.19493 14.82115 16.61891 + 14.55787 15.56332 17.40187 15.79714 15.16877 15.23872 17.43352 17.88713 17.42919 17.76297 19.16017 18.89678 16.21667 14.49569 15.32538 16.22569 17.27599 15.67997 14.60294 16.08368 16.37376 14.28088 16.07994 + 14.28819 15.29579 16.9726 15.32225 14.96721 14.86766 17.3646 17.55653 16.88566 16.39165 17.97582 17.84254 15.61118 13.325 13.99773 15.29101 16.41687 14.61869 14.14026 15.54824 15.78234 13.5513 15.05351 + 12.89534 14.19264 16.16715 15.45553 14.97155 14.18898 16.54575 16.86909 17.18435 16.91364 17.95696 17.44936 14.9484 14.08921 14.70956 16.02505 16.75773 14.69309 14.29639 15.83831 15.93069 13.20353 15.10151 + 11.07287 14.01731 15.98684 15.85503 15.7026 14.17124 15.66209 16.81634 16.69689 17.06315 17.20102 16.85413 14.60714 13.95707 14.35706 15.67642 16.10085 14.48048 13.75637 15.7046 15.97279 12.9786 14.57301 + 13.20215 14.88027 16.1391 15.30331 14.56342 14.65112 16.31849 16.70032 16.30379 16.66877 17.15785 17.35987 14.50481 13.62881 13.80476 16.18898 16.30147 13.83495 13.66053 14.89267 14.77247 12.55925 14.45503 + 13.06126 13.95905 14.72861 15.52299 15.57437 14.80034 15.9755 16.06871 15.0617 16.14234 17.04153 17.21765 14.65441 13.15693 13.40964 15.61284 16.12287 13.8438 13.76604 15.52066 15.88898 13.41924 15.27078 + 12.30977 13.65725 15.62276 15.12077 15.0009 14.32717 15.56222 15.53802 15.59415 16.0091 15.70288 16.7213 14.29013 13.25526 13.82748 14.57323 15.08817 13.3787 13.22771 15.28969 15.54399 12.92044 15.89454 + 13.2355 12.87303 14.13755 14.8824 14.98317 14.09578 15.47559 14.69907 14.95037 15.00035 15.11841 15.08056 14.14125 13.50607 13.85954 13.90839 15.27832 13.46804 13.2138 15.63453 15.70406 13.72386 16.19327 + 14.09465 13.80971 14.12421 15.16251 15.51726 14.75089 15.25305 14.35832 14.27529 14.6144 14.28123 15.06938 13.85847 13.27495 13.16495 13.6391 14.85534 13.8216 13.19121 14.84105 14.6136 13.33247 14.90938 + 14.17169 14.05926 14.38466 15.14356 15.18883 14.75758 14.63411 13.4688 13.57265 14.68271 14.24092 14.8144 14.59175 13.15273 12.52619 13.557 14.39644 13.34105 12.86075 15.03354 14.76084 13.2114 14.36096 + 12.94696 14.0161 14.38512 14.93382 15.28973 13.96826 13.00536 14.16216 12.7634 13.37025 13.69937 14.27973 14.28271 12.20191 11.58065 13.0691 13.86918 12.99897 12.07017 12.88836 13.36119 13.8559 13.72427 + 14.00163 14.74522 13.96561 13.84176 13.14617 12.28493 13.21515 13.64575 12.21422 12.96211 13.65326 13.52429 13.38388 11.56683 10.93623 12.6721 12.94885 11.75394 11.93754 12.60298 12.66667 13.39652 13.23497 + 14.01837 14.65643 14.34931 12.89079 12.44645 12.47288 12.34212 12.92817 12.88704 12.13856 13.52651 14.26985 13.20721 11.13747 10.50563 12.04486 13.04915 12.82268 12.21847 14.11812 14.85144 15.37979 15.23997 + 13.68709 14.73938 13.74758 13.45861 13.16367 13.00546 12.78111 12.54126 11.39514 11.72749 12.81818 13.32782 12.47606 10.72879 11.57598 13.16603 12.89361 13.47785 12.73763 14.78968 15.50553 18.04643 17.43831 + 12.58177 13.59478 14.05649 13.31381 13.11898 12.32821 13.0021 12.62218 11.5436 12.16554 12.48717 11.81394 10.50265 8.973746 10.09016 12.06378 12.39155 12.9348 12.42843 14.2313 14.86099 18.31309 17.32769 + 12.75411 12.6887 12.49659 12.86026 12.59906 11.34449 12.41792 12.40671 10.25577 10.55363 11.62938 11.7192 11.39313 9.014958 9.833184 11.20295 11.54293 12.10884 12.57974 14.2528 15.04182 16.35394 17.43106 + 13.07687 12.93932 12.05013 11.10465 10.92198 10.16203 11.9019 12.00359 11.20652 11.09058 11.98129 10.94307 10.32444 9.561 10.09412 11.1652 11.89071 12.46157 13.37886 14.81377 15.79583 16.46983 16.3099 + 12.44068 12.16542 12.749 11.51701 11.75818 10.98072 11.45177 11.79877 11.41194 10.86352 11.39708 11.80494 10.21916 10.17022 10.94074 12.73651 13.22818 13.90771 14.318 16.45604 17.52512 18.12885 17.99037 + 12.84129 12.74346 11.62644 11.11886 11.60124 9.904121 10.04816 10.7376 10.31966 11.05361 11.45463 12.15746 11.15053 10.69711 11.84554 13.98456 14.60289 15.31413 15.49967 16.84238 18.05069 19.01266 18.84834 + 12.53398 11.96433 9.244778 8.572387 10.26614 9.39289 10.5042 10.72253 10.65647 12.75043 13.54582 13.20332 12.30947 11.8775 13.39289 15.73803 16.03198 17.65893 17.08116 18.5041 19.5771 20.24899 20.35165 + 12.00563 12.20351 10.276 9.838881 10.18145 9.774684 9.775256 10.85217 11.57201 12.9943 13.72266 13.57533 12.36394 12.41757 14.64912 16.40559 16.40833 17.94178 17.0117 19.56192 20.42689 21.10626 20.54123 + 11.91491 12.22656 10.11695 11.68905 13.45684 12.16579 11.17595 11.02882 13.19395 13.89767 15.23678 15.18915 13.55568 14.68092 15.77575 16.75733 17.13061 17.34155 17.21397 19.74595 20.57611 22.05666 21.36359 + 11.47355 11.28028 10.45217 11.66897 13.02617 12.40421 12.3838 12.38136 13.96514 15.68431 16.50488 16.14618 15.39929 15.91039 16.42896 17.51905 18.45585 18.59583 17.75705 19.62965 20.81224 22.27122 21.80147 + 12.52662 11.94858 10.55505 12.42413 13.77102 13.32065 12.9342 13.66854 14.39565 16.63391 17.94618 17.4248 17.46566 16.57822 16.48766 17.86062 18.27674 18.54208 17.23242 19.31924 20.2264 21.92178 21.3364 + 12.02873 11.26655 9.571183 11.58556 13.19479 12.65055 12.59585 14.40476 14.95008 16.4713 18.34317 18.11756 17.86362 16.10263 16.13897 16.93494 18.05787 17.58092 17.09885 18.80086 19.4799 20.65734 19.97151 + 10.86476 9.108546 9.552567 11.91356 12.38227 12.85921 11.95166 14.44887 16.19041 17.26532 17.9296 17.84677 17.18984 16.35882 15.73214 17.40462 17.33592 16.97078 16.5151 16.88156 17.47563 18.54997 17.5454 + 12.60442 11.37389 10.2908 11.55008 13.28062 14.39302 13.83146 14.80365 16.86215 17.7065 17.82295 16.90414 16.20468 15.93856 16.19014 16.84039 17.83888 16.61141 15.98524 16.43695 16.56059 17.5152 17.1277 + 12.41213 11.59318 10.9033 11.81183 13.5534 12.9817 12.88539 14.86807 16.76102 18.08833 17.84195 17.58156 15.95464 15.7454 16.94265 17.86619 18.44193 16.60484 16.43938 17.78119 16.30627 18.12034 18.17815 + 13.1731 10.92382 11.44889 11.58021 12.51424 12.61171 11.91807 14.35635 16.45222 18.2344 18.02634 18.44849 16.43503 15.31518 16.52777 16.50167 17.21136 16.07273 16.42845 17.90891 16.48678 18.03056 17.71963 + 12.32748 11.78882 9.929072 11.31927 12.64543 11.5685 10.86378 14.32529 17.28631 17.74572 17.08748 16.90873 15.3218 14.87652 15.57612 15.72205 15.87119 15.72217 15.76832 16.80227 16.46172 17.64037 17.64002 + 12.19527 11.26126 10.91108 11.51357 11.88646 12.82152 12.50746 15.10742 17.22483 18.49776 18.38831 17.32627 15.58188 14.17714 15.13854 16.44323 16.22381 16.09768 16.18013 17.33267 16.986 16.6601 17.38706 + 12.38316 10.9315 10.43465 10.56535 12.23314 11.90101 12.91362 14.65029 16.51646 18.22181 17.65647 16.37604 14.34329 13.71848 14.16311 15.41569 16.0204 15.15731 15.41514 16.67949 17.00598 15.89455 16.97392 + 11.30577 10.28441 9.945932 11.39331 12.30649 11.96362 11.83533 14.81513 17.35564 18.33072 18.05184 15.06798 14.07956 13.20424 13.25025 14.4972 15.11539 14.80095 14.70875 16.30007 16.03745 14.93294 16.70602 + 11.03609 11.63719 10.21918 10.6167 10.88359 11.86974 11.941 14.54243 18.29357 19.38234 16.87861 14.88691 13.15115 12.30057 13.38792 13.84875 14.85546 14.83342 14.70834 15.97845 15.37833 14.04472 16.18783 + 13.34986 14.78248 13.79236 13.17295 12.78349 12.70567 12.45625 14.42082 17.43404 18.18635 15.59477 14.50266 12.80653 12.16918 12.35644 12.73297 13.97416 14.38635 13.72448 14.86592 14.04201 13.30526 16.08755 + 13.90898 15.20264 15.9369 14.62706 13.72583 13.84371 14.70597 16.07141 18.13611 18.26731 15.36589 14.14722 12.81018 11.74895 11.73215 12.83022 13.8598 14.30199 14.02788 15.60954 14.73503 13.21847 15.28059 + 12.65622 13.64794 16.40841 15.1159 12.92702 14.19901 14.66136 16.53231 18.85972 18.87691 15.47901 14.02315 13.04305 11.90804 12.02419 12.18788 13.65167 14.87863 14.52754 15.9854 15.23429 13.42042 14.61205 + 13.16586 14.09224 15.83176 14.90314 13.58085 14.20237 14.74656 16.52872 18.05439 17.30598 14.93832 14.26765 12.49032 11.86487 11.99516 12.17831 14.06437 14.65313 14.55127 15.61084 14.85131 13.26807 13.69388 + 13.4008 14.57262 15.16415 15.02138 13.99929 13.74122 14.89686 16.43497 18.12129 17.57994 14.38773 13.34021 11.77359 11.37652 10.77275 11.62928 13.2342 14.23693 14.04607 15.04497 14.55735 12.52344 13.15258 + 12.58941 13.8753 16.66035 16.01036 13.94624 12.86215 14.91205 15.55473 17.18862 16.32199 14.95177 13.18178 11.81485 11.68483 12.10907 10.99695 12.64363 13.92735 13.98247 14.74136 14.57911 14.06635 14.69018 + 12.09153 13.84327 16.73779 16.22157 14.56728 12.37056 15.10593 15.10421 16.23268 15.88102 14.39125 12.42256 11.36509 10.85059 10.98364 10.62551 11.97378 13.79792 13.98639 13.31582 13.83742 14.01882 14.74063 + 14.35417 15.46001 15.97281 15.97872 15.05301 13.271 14.85252 14.8182 15.14593 14.99852 13.87889 12.85231 11.08199 10.78992 11.17402 10.49343 12.2052 13.27493 13.57413 13.50568 12.8814 12.89545 14.14766 + 15.11954 16.42943 16.03817 15.8695 14.94205 13.81331 14.11605 13.90077 13.72665 14.46259 13.50304 12.15606 10.48165 10.17465 10.4161 9.912415 11.29775 13.10989 13.52075 12.40094 12.22526 13.01442 14.24785 + 15.51706 16.90478 15.31721 15.63563 14.91287 12.8936 13.76248 14.32526 14.25805 14.36927 12.66967 12.0761 10.97497 9.48582 10.20874 10.5375 11.10218 12.73337 12.90427 12.4544 12.51494 12.39871 13.89166 + 15.83766 17.44094 15.59742 15.76098 14.73724 13.33175 13.09907 14.17982 13.79805 13.84968 12.17967 12.07957 11.02122 10.35668 10.95256 10.26702 11.17187 12.12873 12.05996 12.1097 11.7091 12.38269 13.66632 + 16.28121 17.97894 15.37001 15.30069 15.23669 13.93175 13.33285 13.58994 12.95194 12.94088 12.26932 12.17642 10.4537 10.94146 11.22272 10.16105 10.75595 11.85875 11.60317 11.8685 11.6532 12.81746 14.03694 + 16.65678 18.48001 16.02887 15.72611 14.88948 13.75212 13.00821 13.84919 13.9075 12.9391 12.38781 11.60378 10.67275 10.77736 11.13959 10.14937 11.14159 12.06991 11.99633 12.57936 11.69493 12.77214 13.83402 + 16.88027 18.81418 16.32965 15.89062 14.08585 12.9283 13.01355 14.09655 14.04627 13.70805 12.55457 12.14791 10.23291 10.64731 10.54774 10.34701 11.31384 11.85837 11.31565 12.61369 11.56602 12.69893 13.17958 + 16.86315 18.90851 16.74496 16.61073 13.71159 11.98781 12.37382 13.89134 13.772 14.01257 12.72022 12.62209 10.90394 10.19925 10.34741 10.43047 10.72284 11.89819 11.36431 12.45117 11.00326 12.7707 13.43279 + 16.55088 18.7428 16.48301 16.17187 14.55713 13.0492 13.09207 14.58359 13.44237 13.92513 13.25501 12.62462 10.7068 10.42912 10.70771 10.98847 11.20761 12.1386 10.86133 11.76409 10.89257 12.65522 13.48968 + 16.31133 18.53433 16.33694 15.77417 14.38188 12.95522 13.08407 14.4475 12.69577 13.27632 12.01401 11.38529 10.35604 10.744 10.78147 10.85441 10.54302 12.20752 11.1479 11.46902 11.70803 13.0295 13.62829 + 16.08484 18.22621 16.04434 15.1363 12.58238 11.89639 12.57116 13.53181 14.12426 14.20648 11.83826 11.15889 9.9625 10.32529 9.984441 10.63607 11.00616 12.5833 11.28041 11.6917 11.89614 12.90713 13.29698 + 15.68179 17.81505 16.00374 14.72812 14.84708 11.26076 12.04008 13.00523 14.13205 13.28368 11.21361 10.097 9.955743 10.26499 9.792438 9.863858 11.07145 12.3472 10.51815 10.99274 11.61275 13.19388 13.72785 + 14.55198 16.86638 15.5845 14.5592 14.73209 12.26241 10.81983 11.97698 13.21972 12.68782 10.91807 10.4126 9.59472 10.19615 9.584566 9.555467 10.64191 12.16234 10.07995 11.50145 12.38194 12.66189 12.71277 + 13.01004 15.59743 15.64693 14.08796 13.8486 11.90227 10.5667 10.79841 12.75414 11.89225 9.598926 9.206168 9.479238 8.989665 8.048623 9.163903 10.12297 11.2002 10.10107 10.59673 10.9262 11.29577 11.6629 + 13.91573 16.00849 15.0316 13.62253 12.95412 9.966305 10.1017 9.991467 9.596074 9.605503 9.343888 9.190509 8.865524 8.973734 8.919617 9.209815 10.08192 10.85753 10.00404 9.867455 10.36516 11.38496 11.67881 + 14.8278 16.76171 14.70668 13.6729 13.04084 9.941384 9.693533 10.51062 10.44051 10.19218 9.282916 9.032 8.986729 8.863693 9.409104 9.42415 9.590022 10.41179 9.549519 9.795614 10.16903 11.44894 11.5452 + 14.85072 16.98533 15.18039 13.29803 13.33594 9.623359 9.158119 10.2534 10.32673 9.353215 9.035355 9.315903 9.19397 9.060982 9.5213 9.576943 9.395948 9.738444 9.638402 9.812303 10.30602 10.88667 10.86766 + 14.6904 17.03413 15.28008 14.86307 14.88218 11.42855 9.846802 11.10628 10.92814 10.19661 10.62403 11.59551 10.50513 9.933274 11.18404 11.79196 12.68107 11.0639 9.99734 11.25623 10.75933 12.35911 12.92669 + 14.66271 16.80819 14.93047 15.11656 14.37493 12.24518 9.898335 10.41227 10.94259 9.562234 9.82956 10.52575 10.91687 11.3688 12.16531 13.12481 13.59379 11.50523 10.77534 12.16117 11.03448 13.25059 13.33833 + 14.15415 16.37178 13.99285 14.13001 14.35129 12.60274 10.18616 9.21813 9.342664 9.430008 10.54196 10.54733 10.69073 12.74719 13.28319 14.68884 15.19119 12.57943 11.37738 12.86609 11.79551 14.11093 13.75384 + 13.90892 16.035 14.79413 14.31352 13.37496 11.89549 10.30609 9.863048 9.564677 9.050714 9.766609 9.916749 9.736766 12.76469 13.29292 14.07608 15.34341 12.62214 11.65098 12.8247 11.93356 14.02104 13.58228 + 13.60849 15.51042 14.56466 14.77384 14.10931 12.00589 9.922771 10.00272 9.233529 8.90524 9.197906 9.287741 9.224826 11.10517 11.75283 12.47408 14.07385 11.81659 10.66715 11.48033 10.96836 11.95531 11.53177 + 12.63871 14.4074 14.43942 15.18537 14.02158 12.20864 10.17488 10.41652 8.884479 8.93423 10.05001 9.872001 10.05358 11.18607 11.13514 11.16448 12.71593 10.94455 10.9008 11.7045 11.48672 11.77495 11.38987 + 9.470507 13.9183 15.38312 15.29352 14.31409 12.62442 10.19246 9.844234 9.015466 8.645416 9.272799 8.95722 9.29404 9.842471 10.79908 11.95937 12.56295 10.62304 10.97254 11.55685 10.80731 10.67443 10.93567 + 9.689436 12.1227 15.04778 14.65507 12.59609 11.3594 10.29826 9.403631 8.485927 8.846539 8.928617 8.97279 8.096455 9.521686 11.13479 12.4645 12.32434 10.56936 10.17078 10.82339 10.85006 11.1649 11.38804 + 10.98928 14.05137 14.64129 16.00715 14.09278 11.13883 9.941337 9.854771 8.722589 9.290672 8.857082 8.991954 8.21919 9.559203 12.24082 13.63578 12.84687 11.02113 10.59677 11.14553 10.55739 11.74764 11.36405 + 12.63155 15.67096 14.68544 16.10676 14.76892 11.35606 9.204973 8.561191 8.504937 9.011736 8.932889 8.941728 8.647584 9.663374 12.39362 13.74842 12.88115 11.69389 10.94999 12.21108 11.19174 12.30093 11.63438 + 12.10139 15.86091 14.87627 15.61644 14.75041 11.31224 8.924519 8.241544 8.472549 8.927956 8.740888 9.051448 8.190333 9.251281 12.88241 13.90231 12.65679 11.89317 11.16821 12.41968 11.02865 12.32125 11.54047 + 11.38513 15.89259 15.55978 16.49071 15.93176 11.26818 9.120329 8.472344 9.292308 9.625569 9.129047 9.180802 8.588961 11.19132 14.33207 15.09559 13.56647 11.99036 11.61518 12.64687 10.69325 12.63932 11.8825 + 11.33489 16.01806 16.14634 17.10612 17.0976 11.94706 10.30982 9.953162 10.28553 10.87142 10.28722 9.505128 9.044598 12.70718 15.12737 15.38648 14.23596 12.67216 11.409 11.88481 10.85025 11.92107 11.80873 + 11.93121 16.69381 17.38387 17.6749 17.98742 13.28621 11.70719 10.43649 10.91934 11.77147 11.88422 11.13052 11.38345 13.80934 14.99402 15.98011 14.9559 12.99995 11.91326 12.93166 10.28887 13.55714 13.66834 + 11.91258 16.81928 16.99542 18.31518 19.14895 14.40946 11.01381 11.08671 11.39375 13.21682 13.19212 12.36498 12.30863 14.04659 13.71266 15.38462 14.6618 12.61307 12.04058 12.94022 10.91476 13.20159 13.73922 + 11.46789 17.38041 17.82477 18.2752 19.65061 15.74574 11.42097 11.61401 12.88716 14.96064 15.02348 12.79885 12.33007 13.6574 13.31771 14.41018 14.14105 12.70052 11.94269 13.00976 10.96539 14.06782 14.93854 + 10.82074 17.51527 17.82471 18.72139 20.24971 16.65067 13.19277 11.47689 13.75297 16.15981 15.89948 12.82615 11.78095 12.68962 13.03443 13.99312 14.44622 12.8687 12.09715 12.6253 11.04033 14.82887 15.41104 + 9.789128 17.60623 17.95166 19.12147 20.36291 16.45957 14.5175 11.95895 14.00584 15.58451 15.58284 13.09798 11.42349 12.38721 12.11636 14.10925 15.14098 13.66024 12.47174 12.31593 11.41416 15.35977 16.09952 + 10.03751 16.87819 17.14559 18.82435 19.69844 15.54911 14.925 13.47285 13.4415 14.02402 13.91976 12.55425 11.28404 11.29449 11.12666 12.90026 14.52994 14.08993 12.81467 12.58953 11.19166 14.11535 15.23785 + 10.93798 15.34559 15.48075 18.89332 19.13994 15.17251 14.3534 14.04348 13.22518 13.32802 12.83179 11.63252 10.8536 11.23855 11.16474 11.8378 13.7653 13.51799 12.46745 12.35123 10.79845 14.09694 15.23058 + 11.39907 15.94585 15.80858 18.99041 19.07972 14.78049 14.1376 14.13164 12.62071 13.95744 12.93874 11.53029 10.4269 11.58948 11.19517 11.35314 12.57921 12.77587 11.52973 10.72114 11.27394 14.35466 15.65102 + 12.50065 16.98081 16.2958 18.53826 18.03814 14.84136 14.63556 13.97874 13.23756 13.85454 13.35822 12.12458 10.75648 11.73495 10.99577 10.73339 12.26947 13.05336 11.80032 11.86604 11.52577 14.2759 16.10515 + 14.11917 17.50495 16.44348 18.44194 18.71619 15.23897 15.50647 14.00227 12.22151 13.66027 13.43431 11.87765 10.321 11.40836 10.86816 10.51086 12.05384 13.00603 11.8335 11.91356 11.91522 14.54532 16.75152 + 14.99379 17.92895 16.8975 18.70519 18.95995 15.73521 15.49823 12.87329 13.83215 13.62185 13.06669 12.05937 10.42773 10.73961 11.01464 10.88707 11.64818 12.58473 11.62818 11.58135 11.51648 14.55052 16.08885 + 15.54145 17.85107 16.98327 18.49837 17.73919 15.18074 14.75038 12.77507 14.06172 13.54413 12.30926 11.52931 10.36564 11.26507 11.33629 10.336 12.06124 12.62648 11.26266 11.69004 11.93004 14.61818 15.63297 + 16.0619 17.99921 16.89255 18.13565 17.83411 15.88005 14.93022 13.40796 14.59884 14.0794 12.40723 11.15436 10.18998 10.83631 11.137 10.82108 12.08101 13.16273 11.88929 11.08195 13.06093 14.60555 15.1582 + 16.41592 18.74591 17.24427 17.45222 17.14775 15.69397 14.63761 13.72616 14.99289 14.96222 12.8571 11.36845 10.90592 10.93947 10.72949 10.99991 12.06396 12.11599 11.73193 12.9482 13.76328 14.24961 14.51857 + 16.59169 18.33644 16.6729 17.92939 17.99472 15.11923 13.68678 12.95239 14.18037 14.98073 13.72894 12.48612 11.10576 11.19653 10.8321 11.57918 12.45367 12.50688 11.21697 13.96683 14.07828 13.39284 13.05171 + 16.37931 18.53983 17.11295 17.0422 17.68007 15.11545 13.4979 12.7253 12.83473 13.30683 14.44711 13.53261 11.2399 11.29604 10.66569 11.51261 12.52057 12.61519 11.1287 14.42613 14.21188 12.91073 13.62521 + 15.77711 16.81826 15.82284 16.26417 14.77699 13.92578 12.86666 12.48366 12.62949 12.08785 13.24057 12.46911 10.74334 10.64687 10.51021 10.52875 12.20348 12.29009 10.30058 13.55652 13.26817 13.30325 14.35986 + 15.82015 17.46225 15.50791 15.47983 15.53145 14.01977 13.48505 11.83372 11.23159 11.60364 11.24516 11.02851 9.994411 10.127 9.874244 9.952956 11.45186 11.57752 10.71201 11.31057 11.925 12.24183 13.13455 + 15.76488 17.33266 15.47503 15.67266 14.76409 13.55282 13.16781 10.86405 10.00527 10.30678 10.84636 10.38855 9.692888 10.62687 10.82284 10.76016 11.56705 11.6752 10.60772 11.25967 11.79259 12.14699 12.2975 + 15.79346 17.73031 15.68137 14.88974 13.31264 11.70068 10.75016 9.699461 11.59397 11.09019 10.58869 9.898376 8.929638 9.302467 9.637378 10.49889 11.22649 10.7973 10.0415 11.52228 10.99211 11.29036 11.60892 + 15.62056 17.43279 15.06023 14.50031 13.94001 11.11427 10.53508 10.24727 10.84226 10.2417 9.97341 9.786078 8.522814 8.529009 8.403295 8.864924 9.860689 10.12548 10.1109 10.64103 10.51032 10.91088 10.99742 + 14.92246 17.0135 15.04857 14.46992 14.52418 12.18941 11.24207 11.29555 12.0192 13.37018 13.99349 13.40953 12.65679 13.28639 14.09664 14.8326 14.6762 13.23665 11.35561 12.54946 14.12629 15.38962 14.67778 + 14.08548 16.16105 14.25179 13.72728 14.2951 12.56719 11.60147 10.79406 11.7847 13.46562 14.78914 15.1487 13.70664 13.32854 14.55988 16.36461 17.04605 15.91949 14.81793 16.99095 18.20212 19.37614 18.60077 + 13.56568 15.41561 13.65116 13.80278 12.35432 10.98944 10.19834 9.714845 10.88012 12.79503 15.31259 16.04332 15.07261 13.3139 16.37029 18.55497 19.72721 18.21986 16.88817 18.66231 19.42877 21.17449 21.34429 + 12.81052 14.82067 12.89596 12.89064 12.7278 9.884626 10.07492 10.31998 11.56146 13.61393 16.51963 16.62613 15.85953 13.70052 15.65685 20.09129 21.61243 19.28339 18.15581 19.5183 20.06223 21.13614 22.15731 + 12.4148 13.93226 11.91046 12.1541 12.28745 11.01894 10.5866 10.27591 12.31247 14.79986 17.28344 17.50844 16.46629 14.32873 15.63348 20.89158 21.659 18.84053 18.39215 19.79963 20.31273 21.56329 22.12888 + 12.91297 14.79987 12.71113 13.29154 13.44041 11.56215 10.49496 10.6033 12.03684 15.29325 17.49444 18.31451 16.88695 15.08641 17.40228 20.39707 21.17206 19.49123 17.8341 19.26415 20.69028 21.98025 21.82807 + 13.12175 14.64588 12.15094 11.35538 12.11017 10.95849 11.28366 11.61484 12.85101 16.09893 18.0477 18.62724 16.99242 15.1852 17.51782 19.87419 20.87705 19.48903 17.96088 19.17698 20.07501 21.74238 22.1084 + 13.00411 14.90964 12.85213 12.4642 12.19896 10.9285 11.4324 11.96293 13.98125 16.61734 18.89468 19.34385 16.26028 15.6907 16.13703 19.2197 20.6384 19.75793 18.03179 18.44206 20.21319 21.34424 21.91418 + 12.53915 14.56936 12.39721 13.01271 12.77172 11.97516 11.71099 11.24299 14.61106 16.86008 19.35301 19.43951 16.80698 15.8419 16.63168 19.33833 20.47225 19.18408 17.29919 18.15383 19.49329 20.5814 20.88459 + 12.15284 13.47757 10.60758 12.20281 13.0343 11.11187 10.97446 10.88111 14.17981 17.2116 19.27656 19.46944 16.21806 14.89002 15.36739 17.92939 19.41214 17.94695 16.58801 16.62714 18.35245 19.04712 19.02948 + 11.57865 13.99112 12.93595 11.18491 10.64367 10.56507 10.97282 12.65517 14.05695 15.92091 18.14322 18.23843 15.92175 14.87526 15.68978 16.53125 18.24236 17.28429 16.56872 15.94291 16.28687 17.53417 17.20242 + 11.28529 12.6209 11.65753 11.60241 11.58626 10.83581 10.27027 12.12041 14.267 15.48161 18.20242 17.39253 15.21907 14.75703 15.08057 16.2598 17.26633 17.07322 16.03636 15.15166 15.24807 16.5594 16.19338 + 10.91567 13.44223 11.93005 10.71006 11.31781 11.7807 10.22369 12.09495 13.98265 15.85598 16.988 16.82117 15.11764 13.72713 14.96652 15.93681 17.34565 16.43155 15.34467 14.63535 14.80754 16.85585 15.56012 + 11.37683 12.73687 10.39089 9.336987 9.831561 11.17227 10.51462 11.394 13.52753 17.06892 18.22289 16.58073 14.50473 13.4536 14.32212 15.69642 17.59365 16.24478 14.84533 14.05617 14.99095 16.48585 15.65335 + 11.15164 13.128 10.98207 9.10566 10.39393 10.70634 10.84463 11.06166 13.15317 16.16613 17.48376 16.13078 14.46833 12.60861 13.22436 15.39284 16.83496 15.80455 14.54673 13.42426 14.11045 16.32096 15.15128 + 11.15148 13.08558 11.24186 10.75418 11.27332 10.83193 10.16917 10.71663 12.71503 15.8612 16.86666 15.34324 13.83714 12.93292 12.91148 14.20864 16.26399 15.44005 14.26241 13.12186 13.5547 15.73553 15.21248 + 10.32435 11.80502 10.71903 10.12998 9.243139 10.32276 10.51204 9.885305 13.37798 15.24079 15.56827 14.59323 13.25549 12.08573 12.08292 13.83259 15.49082 14.31401 13.56349 12.58398 12.93209 15.15023 14.39397 + 9.55196 13.14198 12.09491 11.57915 11.7868 10.55393 9.688849 10.1536 12.66342 15.51936 15.60778 14.23114 13.59677 11.5554 12.35998 13.28365 14.88144 13.88197 13.16487 12.75849 12.51151 14.26958 14.14925 + 11.14226 15.27234 14.74488 14.24864 14.20611 12.25802 11.94632 12.10342 13.43625 15.97755 15.82204 14.68259 12.32215 10.68163 11.67134 13.07826 14.39713 13.78414 12.79398 12.32595 12.68034 13.86888 14.63672 + 11.82192 16.13304 15.37651 16.57404 16.01068 12.65684 12.84768 13.69928 14.84385 16.28752 15.21064 13.4215 11.93544 10.11553 10.96781 12.73654 13.93202 13.7597 12.7366 13.53805 13.78219 14.34586 15.65966 + 11.16597 15.60295 14.91919 17.65105 17.25035 13.94595 13.03636 13.82953 15.81298 16.99026 16.38386 13.44202 10.67358 10.54342 11.52007 12.54199 15.2073 14.85921 13.04932 13.6851 13.8579 15.4532 16.68387 + 10.51662 15.43471 14.99521 18.16862 17.72067 15.69889 14.12805 14.29307 16.52756 17.99657 16.64942 14.49547 11.61017 10.99339 11.64379 12.93506 15.5309 15.33103 13.2612 14.26317 14.55778 16.36224 17.4065 + 11.90673 16.09601 15.16525 18.22427 17.79523 16.65013 14.95471 14.57647 17.00873 18.48756 16.99238 14.55247 11.84007 11.13602 12.00641 12.06635 14.78719 14.60945 13.60264 14.37275 14.25254 15.76529 16.61269 + 11.77753 15.94984 15.05677 17.97174 17.373 17.41905 15.6169 14.73355 17.46013 18.81142 17.14954 15.49692 12.20508 11.44368 12.23865 12.73304 15.18181 14.84058 13.51544 14.6217 13.58304 15.94587 16.794 + 10.41407 15.72303 15.14866 17.70807 17.07916 17.71496 15.88798 14.64032 17.55777 18.87132 17.8488 15.62309 12.12702 11.63624 12.23076 13.35091 14.845 14.49619 13.87168 14.96588 14.34432 16.30333 17.20194 + 11.354 16.18204 15.44579 17.66172 16.96994 17.44448 15.66464 14.72198 17.39568 18.71137 18.22394 15.33202 11.91729 11.85658 12.49095 13.32615 14.09961 14.23158 14.58506 15.50219 16.31929 16.47316 17.44572 + 11.67818 16.44463 15.64772 17.72272 16.90357 16.48343 15.1468 14.66261 17.37626 18.67665 18.43763 16.17672 12.68573 12.12047 12.56644 13.53683 15.69811 15.11192 15.10006 15.99792 16.72847 15.30137 16.12518 + 11.81452 16.51302 15.8351 18.05065 17.12857 14.78708 14.79863 14.54577 17.14968 18.40389 18.33661 16.81234 12.45416 12.26822 13.33935 13.42922 16.02875 15.44887 14.45614 16.00752 17.02212 15.07159 15.84839 + 11.66775 16.09326 15.45326 18.56066 17.73905 16.56577 15.80819 14.98165 16.93577 18.54793 18.7565 16.84025 13.44262 11.95572 12.87634 13.43538 15.80291 15.6723 14.43189 16.38626 16.87126 15.30465 16.12741 + 11.18154 15.3121 14.98711 18.80246 18.00036 17.79539 16.50552 15.6597 16.54539 18.6693 18.88139 16.73647 13.84423 12.21505 12.68858 12.8891 14.96932 14.98377 14.47017 15.99248 16.69073 16.01393 17.04851 + 11.39253 14.84143 14.70809 18.75023 17.97756 18.1698 16.63218 15.90916 15.77523 18.6932 18.87343 16.30272 14.07881 12.17943 12.72991 13.99461 15.09284 14.90023 14.86968 15.68508 16.95284 15.82605 17.11721 + 11.86377 15.31133 14.59444 18.38207 17.6422 17.60731 16.2254 15.42659 15.86426 17.45585 17.54583 14.96311 13.32989 12.32241 12.82136 13.80614 16.04843 15.70225 14.60214 15.79691 16.55345 14.48477 16.21475 + 11.73533 15.70459 14.84644 17.80892 16.99964 15.85337 15.77551 15.02913 15.56236 17.03756 17.23155 14.80542 13.2883 11.4158 12.61335 13.34564 15.46394 15.25104 14.61511 15.47291 15.86379 15.43297 16.33346 + 10.81638 15.52154 14.9054 17.31289 16.38354 15.1073 15.92739 15.73638 16.55172 18.13293 18.54304 15.54773 13.22721 12.31508 13.16266 14.46879 16.11985 15.48509 14.86392 14.97309 15.37611 15.07204 15.87638 + 10.26267 15.25113 14.67625 17.21563 16.31719 14.77018 14.92522 15.68053 17.32211 18.43587 17.91074 15.57454 13.49049 12.60371 13.12548 14.11297 15.84021 15.45053 14.63433 14.96083 15.49248 13.76896 15.98103 + 10.69819 14.90186 14.28961 17.07143 16.24204 13.46402 14.20674 15.63925 17.09035 18.04039 17.88895 15.37756 12.4007 12.11112 12.55157 12.96375 15.69617 15.59222 14.15425 15.03544 15.54571 13.44852 15.65409 + 9.915021 13.82648 13.51551 16.30905 15.34114 15.36788 15.25857 15.57581 16.88137 17.62993 16.70799 14.8589 12.48502 11.65991 12.48844 12.89608 15.70182 15.3114 14.08729 15.36026 15.73317 12.51652 15.22122 + 8.68051 12.45413 12.77622 15.34519 14.32071 14.90527 13.81296 14.36697 15.78108 17.00771 16.51527 13.94231 11.84495 11.75392 12.35656 13.10109 14.77411 14.72279 13.45488 14.19114 14.58668 12.4133 15.44579 + 10.05589 13.40399 13.02372 15.95843 15.3619 14.07744 14.53119 14.84178 15.96589 16.57776 15.83888 13.69824 11.78194 11.49591 11.9167 13.30375 14.69968 14.48295 12.85517 14.20968 14.40717 12.00698 13.85596 + 11.27062 14.20996 13.00546 15.81915 15.0768 14.00317 14.15812 14.63979 15.93456 16.13581 15.80585 14.0422 10.93639 11.04755 11.28759 13.27676 14.53805 14.24715 12.69541 13.41502 13.21583 11.7954 14.09292 + 11.82292 14.00475 12.70146 14.15521 13.96183 13.86355 13.82776 14.55097 15.977 16.62114 15.52749 14.43003 11.57255 11.82603 11.46633 12.81295 13.52481 13.20844 12.48258 12.9837 12.70388 12.01538 14.10332 + 11.81733 14.02889 12.67105 14.56858 13.83397 13.15577 12.52465 13.75595 15.65288 15.53403 15.14229 13.78594 11.95139 10.92552 12.43795 12.72144 13.77396 13.37051 12.03247 13.05484 13.05454 12.07504 13.45452 + 11.53573 14.69543 13.47587 14.54975 14.09588 12.23716 11.75021 12.82979 16.3925 16.57847 15.83274 15.41968 12.53094 12.0738 12.46284 13.14491 13.65205 13.70883 12.48045 13.69684 14.24071 12.90326 13.78031 + 10.46279 13.28604 12.97831 14.62308 13.95662 12.26015 12.11266 13.03825 15.73407 15.80908 16.49609 15.14229 11.56523 11.61488 11.99993 13.00464 14.1577 13.95174 12.51486 14.32073 14.42474 13.37241 14.48748 + 10.48366 14.08517 13.39815 12.98214 12.39788 11.79398 12.84884 13.57857 15.40684 15.60652 15.99256 14.35739 12.09316 12.1796 13.10014 13.46264 14.51066 14.02861 12.81611 14.63739 14.12812 13.86828 14.78857 + 10.19182 14.69601 13.93462 12.37111 11.73293 10.65019 12.18164 13.14647 14.66128 15.14137 15.29343 13.7568 11.9698 12.07825 12.39925 13.19032 14.63404 14.42319 13.39776 15.18882 14.68679 13.48536 15.13381 + 10.34476 14.25978 13.3268 12.39499 12.02569 10.45536 10.55758 11.70175 15.12028 16.20647 14.50963 12.94513 11.49872 11.71179 12.57724 12.75515 13.61092 13.75198 13.41445 15.13885 14.47829 14.33477 15.76451 + 10.20487 12.92972 12.66008 12.42735 11.86889 10.36294 10.88357 12.17473 14.84048 16.0851 14.19029 12.64169 11.7309 11.68961 12.55493 12.70489 13.73792 13.65674 13.2528 14.73102 13.98869 14.62711 16.16679 + 9.423117 12.70624 12.09342 10.86123 10.24333 9.513165 11.43117 11.95184 14.92405 16.06582 14.44456 13.55055 11.02903 11.31061 12.30381 12.54599 13.94664 13.53971 13.29417 14.64221 13.89266 14.74018 16.82738 + 9.589171 12.47112 11.4502 9.131975 10.2197 10.17758 11.90142 12.39148 15.51737 16.71535 15.28426 13.4031 11.43478 11.36541 12.49403 13.41569 14.58072 13.76381 13.98231 14.93766 14.71383 14.92337 16.24941 + 9.503296 10.60735 9.271545 9.716817 9.667707 10.52781 11.40006 11.39293 14.60591 15.02798 15.03264 13.64719 11.30165 10.74731 12.65038 13.62129 14.64687 13.53882 15.08017 15.38536 14.1648 14.99333 16.10574 + 9.115908 11.43826 10.47298 10.14771 9.880108 9.726262 10.82772 12.05128 14.10969 15.54203 15.91383 13.69349 11.85291 11.131 13.34072 14.18404 15.38566 14.57817 14.72091 15.19623 14.41386 14.31567 15.83257 + 9.310917 10.28504 9.811528 10.01983 10.05451 9.4747 10.45637 11.62435 13.92147 16.01029 15.57332 13.24274 11.89735 11.36156 13.09891 14.07911 15.26106 14.44157 15.20087 15.08729 14.25182 14.66974 15.79354 + 9.030734 10.77806 10.31404 10.89988 11.18181 10.48961 10.15753 11.69851 14.42295 15.29466 14.48458 12.67693 11.36603 10.84135 11.80535 13.1063 15.03863 14.38514 14.50504 14.37171 13.37179 14.37903 15.7146 + 7.50856 11.28577 10.72007 10.24735 10.17675 10.65663 10.4188 11.49671 14.89423 16.14469 14.11847 12.56653 11.28391 10.65832 11.76379 12.46559 14.1188 13.54819 13.30948 13.31488 13.49415 14.57029 15.60327 + 8.540401 11.55971 10.55634 10.50483 10.84564 11.33433 10.85704 11.34962 13.89402 15.64289 14.49759 12.96604 10.80758 9.884405 10.34586 11.19268 13.79956 13.10055 13.12975 13.08347 12.67242 13.66006 14.28579 + 11.08979 14.00895 13.28101 13.3758 13.54885 12.20103 11.48327 11.56215 13.08175 15.66193 14.28371 12.17407 9.616703 9.735795 10.51737 10.66526 12.92028 12.44681 12.94642 12.86102 11.83186 12.5984 13.619 + 13.14398 15.67154 15.34065 16.24163 15.0646 12.54676 11.68441 12.30696 13.41859 15.11965 13.7802 11.35566 9.2933 9.63155 9.780502 10.87477 12.77262 12.19879 12.55715 12.45354 11.55077 12.7023 13.38533 + 14.07658 16.64854 16.01492 17.56435 15.44176 13.57488 11.04171 12.65898 13.55481 14.86006 13.82938 10.95063 9.030316 9.329757 10.07974 11.01514 14.26132 13.92831 12.94692 12.58781 11.56843 13.6175 14.11914 + 14.75746 16.99999 16.77552 18.02952 15.90656 14.6823 12.81055 14.08961 14.8099 15.94903 14.67507 12.65691 10.4475 10.15641 10.20949 12.54788 15.05997 14.94959 15.0851 14.83846 12.45193 15.8906 16.3022 + 15.11706 17.16695 16.8549 17.89547 16.15163 14.86321 13.19364 14.13913 14.60327 15.88921 14.64402 11.80295 9.991564 9.918747 10.29794 12.53781 15.5761 15.41474 14.87424 14.64059 12.25671 15.93182 16.2683 + 15.40835 17.45925 16.58469 16.7639 16.27665 14.75572 13.4018 13.85402 13.12921 15.10079 14.71053 11.99744 9.913205 9.705381 10.4648 12.13035 15.2068 15.025 13.92012 13.05841 12.5278 16.01011 16.19179 + 15.45827 17.28377 16.69241 16.92484 16.34339 14.48242 13.334 13.81861 13.36756 14.88102 14.33365 11.80426 9.697133 9.240011 10.16598 11.92516 14.61208 14.43869 14.29321 13.34631 12.60551 16.59318 16.53483 + 15.13229 16.73378 16.89245 17.1393 17.00265 14.96519 13.72409 14.02927 13.25723 15.83806 14.40103 12.19008 10.30029 9.71996 9.842927 12.35917 14.15221 13.89012 14.0526 13.6017 11.93211 16.53617 16.72011 + 14.57705 15.6379 16.80176 16.86314 16.66628 14.47865 13.58029 14.06467 13.77963 16.02653 14.70159 12.60434 10.41194 10.06278 10.46712 12.41631 14.66149 14.67236 13.84786 12.99362 12.37743 16.0895 16.24062 + 14.77465 16.17302 17.21569 17.31233 15.77169 13.20695 14.42118 14.81845 14.40012 16.4256 15.06712 12.46396 10.4278 10.54279 11.23261 13.11649 15.14829 15.03464 14.55053 13.6049 12.95183 16.86971 16.66895 + 15.05606 16.52065 17.57998 17.69038 16.2915 14.25601 14.84489 15.36414 15.11178 16.8064 15.81776 13.49685 11.06283 10.37466 11.31837 13.62332 15.70944 15.07266 14.53792 14.15806 14.11397 17.4218 17.03832 + 14.91461 16.54216 17.72679 17.76228 16.31701 14.88375 14.68025 15.63748 16.55472 17.25992 17.16825 15.38784 12.14931 11.18112 11.89017 14.01893 16.31654 15.77574 15.18395 14.93204 14.24931 17.65414 17.32909 + 14.06235 15.76193 17.18796 17.04869 16.16309 15.03378 14.50389 15.27548 16.01657 17.05204 16.83701 15.13547 11.94728 10.58079 11.4934 13.36317 15.81689 15.14827 14.4666 14.55218 13.48098 17.22405 16.73607 + 12.20449 13.63824 16.85458 16.60645 16.1426 16.12964 15.33291 15.36466 16.87278 18.04861 17.6068 15.85586 12.63215 11.99263 12.60324 14.04203 16.81243 16.22995 15.30362 15.6595 14.4412 17.11238 17.13072 + 10.72764 13.3548 16.83893 16.19029 15.82427 16.1692 15.66567 15.07302 15.77989 16.54188 16.30075 15.60935 12.34325 10.73788 11.86701 13.85012 16.31892 15.11082 14.34861 14.96774 14.47254 14.20635 15.01912 + 11.60129 14.09942 16.75742 16.20039 15.56324 15.11675 15.08574 14.86573 15.50838 17.15246 16.86691 15.52252 12.93029 10.73168 11.6597 14.13603 16.52929 15.7967 14.49399 14.30547 13.43089 14.71824 14.45458 + 14.02859 15.28391 15.8077 15.34497 15.03183 15.79032 16.02132 15.8215 15.79886 17.51942 17.64467 15.42086 12.91273 10.42257 12.27133 14.28747 16.08209 15.12793 13.71037 14.9558 14.61221 14.93433 14.82792 + 14.18848 15.49555 16.91608 15.82519 14.52658 13.71498 16.10671 15.94508 15.64377 17.88175 17.91087 15.55968 12.45656 10.9743 12.02333 13.80416 15.67876 14.38375 13.71993 15.67794 15.32651 14.47271 14.63666 + 12.46225 13.96751 15.86773 14.64494 14.40544 14.4847 15.3736 16.16685 15.92646 17.85421 18.09699 16.27834 12.37715 10.08867 11.90742 13.48527 15.4419 14.10502 13.62834 14.96597 14.83753 15.32119 15.06888 + 13.05211 14.65883 16.07732 15.72431 14.58461 14.83052 15.30428 15.05263 15.02916 16.23183 15.43935 14.29991 11.75905 11.07148 12.31495 13.43882 14.98901 13.66362 12.9674 14.51913 14.48279 14.95528 14.8023 + 12.55515 14.89801 14.75364 14.68671 14.14907 14.13834 14.59004 13.6544 13.79198 16.03756 16.11797 13.08031 11.24561 10.83997 11.88435 12.2136 13.93883 13.77705 12.87251 14.5708 14.71351 14.24566 14.39286 + 13.83093 15.56555 14.57585 14.22723 13.8579 13.36604 14.29341 13.54445 13.8807 14.93316 14.51684 12.76485 10.79458 10.58632 11.6082 12.35924 13.70661 13.07612 12.48223 12.69072 12.71655 12.41708 13.33185 + 14.18465 15.79808 14.80991 14.02056 12.90899 12.66223 13.70633 13.82998 14.50648 14.96112 15.03471 13.67727 10.52017 10.59638 11.55017 11.89342 12.99354 12.42688 11.95904 12.05783 11.865 12.08287 12.86125 + 13.25803 14.87615 13.40272 12.26935 12.22413 11.50442 12.41747 13.64918 15.23524 15.79496 15.65018 14.92247 10.86561 10.38056 10.77693 10.56645 12.19267 12.05079 11.84969 12.24822 11.36017 11.14598 12.25312 + 12.45111 13.44244 13.22482 12.22398 12.6735 12.62569 12.88445 12.80736 13.84655 14.60308 14.62763 13.62638 10.40659 11.13378 10.61906 9.895057 11.55708 10.91639 10.84196 11.58675 11.38106 11.41171 12.38584 + 11.51846 12.357 13.54436 12.86645 11.85491 11.5113 12.90373 11.86775 12.45533 13.17408 13.00485 11.74634 9.947218 9.551273 9.567058 9.890096 11.33025 11.05918 10.6337 10.56511 10.17946 10.49385 10.70985 + 10.98355 12.91067 13.64736 13.10762 10.84069 10.44838 11.49005 13.12592 12.14138 12.09276 13.07966 12.63638 9.730008 9.848679 9.347866 9.414342 10.63352 10.80758 10.35773 10.48653 10.42719 11.00619 10.87458 + 11.5681 13.21478 13.99549 13.15111 9.779534 10.84289 11.58694 12.34813 12.21469 12.28861 12.12051 10.8032 10.08394 10.18741 9.829264 9.272332 10.70571 10.90198 10.80318 10.46099 11.22602 10.77159 11.26807 + 10.92434 12.3015 13.37657 11.97633 9.846909 10.4243 11.08952 11.22303 10.78325 12.41337 12.66613 11.84448 9.250697 9.51819 9.804947 9.046823 10.62793 10.31114 10.24323 10.33592 10.83164 10.2066 10.32049 + 10.66577 12.14629 11.68034 9.369942 10.3728 9.903213 10.77546 11.68394 11.14858 12.63394 12.94571 11.37593 10.00287 9.558322 9.845166 10.15729 10.41532 9.908718 9.831599 10.41129 10.63024 10.63221 10.3509 + 11.6184 13.30724 11.55282 10.44678 10.41798 10.1706 10.90822 10.41916 10.55029 11.9752 13.67633 11.79162 10.79402 9.887626 10.8025 10.48727 10.37634 10.34983 10.57088 10.24781 10.26391 11.38719 11.21457 + 12.47586 13.6613 11.17755 10.26591 9.585545 8.900165 11.20114 11.92466 11.11244 11.51987 12.53722 10.63915 9.778065 10.18182 10.7475 10.43095 11.06562 10.47551 9.800613 9.590487 10.01961 10.74588 10.42597 + 10.77701 12.82747 11.43204 10.35398 8.763439 9.405526 10.82308 10.63848 11.23412 12.39658 12.69621 11.6574 9.802265 10.72791 10.38412 9.456212 10.21749 10.77777 10.52131 10.53893 10.67069 11.10977 11.42564 + 11.11245 11.89655 11.72092 11.20401 9.289854 9.801051 10.75733 10.49686 11.86391 12.7017 13.00109 11.37016 10.12052 10.20385 9.899943 10.12168 10.17335 10.37608 10.25884 10.2047 10.5204 11.22245 11.59654 + 10.07293 9.634727 11.54807 11.43805 9.092267 9.683016 10.62169 11.24899 11.31559 11.98399 12.95545 12.45842 10.71746 10.80228 11.2789 9.754478 10.40236 10.25889 10.37339 9.958531 10.25048 11.00226 11.04672 + 10.42046 11.45978 11.63636 10.63461 9.173406 8.947865 9.959992 9.868871 11.08009 11.51371 12.75934 12.10706 11.59692 10.57697 11.32946 10.17161 10.1469 10.40671 10.2813 10.1093 10.52484 11.39623 11.14704 + 10.24291 11.15639 10.16661 9.884758 9.216879 9.206462 10.319 10.26303 10.83201 12.79486 13.33239 11.75389 10.45811 9.76089 10.24667 9.601921 10.60552 10.51551 10.36004 10.27134 10.3252 11.17595 10.70015 + 9.422491 10.00307 9.304786 9.541505 9.374505 9.497077 9.545082 9.764844 10.62842 12.44954 12.87034 11.195 9.428076 10.17063 10.55802 9.774949 10.74514 10.18642 10.23282 10.14036 10.41611 10.48228 10.65022 + 9.431662 9.925019 10.80831 9.614099 8.896067 8.509177 8.498697 8.813649 10.72018 11.46818 11.79037 10.94821 10.24577 10.29312 10.4467 10.298 11.07519 10.74677 10.3395 10.43149 10.75678 12.64705 11.43539 + 9.448807 10.96071 9.576197 7.308518 8.883255 8.301652 8.766844 8.846759 10.22622 11.76619 12.58748 11.67644 10.72528 9.9915 10.21584 10.17676 11.38863 11.19318 9.839796 10.4516 11.10404 13.23044 11.87121 + 10.62994 11.5706 10.67056 9.265289 10.66641 8.995152 7.84528 9.58221 9.973509 10.98804 12.24823 11.57158 10.72447 10.14804 9.541183 9.675903 11.06965 10.92531 10.45405 11.09323 10.41595 11.13436 11.58708 + 10.39545 11.44841 10.55975 9.705544 10.74701 9.747647 8.344221 10.04484 10.6118 11.2215 12.51557 12.40113 10.53294 10.54167 10.73098 10.17531 11.36208 11.10819 10.5466 10.93015 10.72956 11.21366 11.42109 + 9.808684 10.54995 8.585596 8.609066 9.104267 8.886292 8.315665 9.341417 10.22613 11.00258 12.79302 12.32948 11.03078 10.42751 10.86653 10.40495 11.54998 10.99841 10.25156 10.56426 10.5004 11.59432 11.25886 + 9.783687 9.554473 9.224267 8.305874 9.829804 8.624431 9.106644 9.878937 9.975676 11.34404 12.81888 12.35782 11.02464 10.09095 10.79956 10.69735 11.30436 10.86825 10.91094 10.57113 10.4626 11.75406 11.67169 + 9.964293 8.91133 9.597994 8.38109 10.30375 10.12096 9.371438 9.138732 10.23402 11.95144 12.71362 11.4016 10.57952 10.13566 10.54746 10.2636 10.74369 10.67116 10.78272 10.88782 11.01974 11.17345 11.2694 + 7.987907 8.382757 9.251793 8.551911 8.960312 9.169497 9.091488 10.20918 11.97596 10.86922 12.52002 12.28877 10.51484 10.44818 10.56632 10.83528 10.84797 10.92687 10.48957 10.72594 10.87492 11.48538 11.44997 + 9.208866 8.503493 9.972482 9.071673 9.462955 8.664878 7.662143 9.897245 10.64185 10.91716 11.13872 12.12932 11.36929 11.34245 11.2402 10.83909 11.03287 10.97415 10.68303 10.55697 10.5056 11.69601 11.68266 + 9.830456 7.644547 9.789823 9.708093 10.68528 10.30543 9.51989 9.725322 10.94882 11.60964 13.0219 12.9686 12.24573 11.09353 11.58634 11.25884 10.88388 10.70734 11.0613 10.88753 10.72593 12.06754 11.55765 + 10.1434 9.600281 9.03609 9.28277 9.389798 9.782507 9.522714 9.155346 10.51925 11.83723 12.88527 13.05917 12.5973 11.04044 12.4058 11.76693 11.41435 11.29793 11.33523 11.57119 11.21824 12.67894 11.60467 + 9.044415 9.35461 8.125829 8.155436 10.21073 9.420408 8.485256 9.519516 10.80159 11.03508 12.98993 12.86469 12.11976 11.60614 11.22908 11.30737 11.26812 11.07872 11.49184 12.23885 12.01657 12.81706 11.95831 + 9.557627 10.25238 8.452591 8.784152 10.9992 9.823544 9.510536 10.38744 11.27521 11.65287 13.02484 12.76013 11.33446 11.90731 11.69084 11.35221 11.25088 11.1325 11.48025 11.96735 11.96839 12.37707 11.87469 + 10.23095 9.161502 8.99103 8.923839 9.805343 9.837078 10.10092 9.621623 10.84666 11.88772 13.02984 13.09626 11.90776 11.65839 11.98773 11.63274 11.56222 10.86827 11.27272 11.77922 11.91178 12.68476 12.05236 + 8.874165 7.809851 8.695865 8.223797 8.763299 9.566321 8.770155 9.008782 11.19149 11.83618 13.52786 13.19089 11.91928 11.96163 12.16576 11.49836 11.79749 10.94192 10.88142 11.00608 11.66361 12.51995 11.84705 + 8.437733 8.480018 7.988172 8.590461 9.420288 9.875575 9.504238 9.388609 10.90206 11.65753 13.35867 13.6816 12.48646 11.95356 12.16133 11.43572 11.42155 11.1403 10.60003 11.26259 11.62654 12.52154 11.82845 + 9.964341 8.923758 9.201259 9.687395 9.499485 9.23505 8.127786 8.023572 10.40248 11.75716 12.92915 12.92148 11.44932 11.59385 12.10262 10.90831 11.27934 11.05236 10.57544 10.54616 11.69068 12.66987 12.08684 + 7.982019 9.21278 8.003357 9.466326 10.96768 9.979166 8.679527 8.800684 10.64961 10.21235 12.66046 12.89555 12.06681 11.04834 11.27791 11.41866 11.11113 10.78568 10.56767 10.6112 11.04461 12.21314 11.62118 + 8.391383 9.194236 9.299546 9.597569 11.07862 9.571204 8.833894 8.325615 10.67207 11.36724 11.90812 12.3979 11.69843 11.26144 10.98187 10.62434 10.55542 10.79755 10.96708 11.02939 11.2887 11.80884 11.33321 + 8.614913 7.849565 7.212549 9.800451 10.48496 9.617368 9.147942 9.296861 10.13177 11.20514 12.3896 11.95667 11.57815 10.64794 11.444 10.93266 11.42423 10.72211 10.74878 10.75023 10.98787 11.26347 11.04169 + 7.535953 8.379319 8.465982 9.019888 8.474906 8.644684 9.380523 9.011086 9.468113 10.66582 11.96134 11.67335 10.88397 10.53693 10.82633 10.25402 10.21263 10.32749 10.5247 10.19471 11.01541 11.35801 10.77586 + 8.953902 8.443554 8.80369 8.623836 9.60961 8.834076 8.999572 8.835788 10.4686 10.42089 11.60229 11.5832 11.33114 10.05566 11.09636 10.20237 10.258 10.62062 10.48857 10.14489 11.40099 11.07088 10.64445 + 8.500578 8.544858 7.815175 8.512371 8.136365 8.380095 9.461661 9.8258 9.200838 10.49927 11.48638 11.7742 10.49608 9.742468 9.315075 9.044184 9.661458 9.323888 9.979736 10.51669 10.50003 10.75289 10.55279 + 8.140522 7.9291 8.467335 7.948473 7.84909 8.878713 9.228608 9.341762 9.541382 9.544453 9.793461 9.858119 10.06971 9.451279 8.51177 8.683918 9.586095 9.493937 10.0905 10.45376 10.50862 10.45298 10.89592 + 9.174277 7.910554 8.41324 7.574174 8.196404 8.136746 8.121965 7.858237 8.164356 9.198856 10.01476 9.891054 9.341989 8.451241 8.975142 8.96706 9.390165 9.745036 9.87119 9.820464 10.01453 10.3652 10.31961 + 9.053761 8.623909 7.898996 7.378081 7.484929 8.12253 7.869719 8.111196 7.660993 7.883986 8.894523 9.96628 9.412325 8.602212 8.978284 9.126224 9.584894 9.770082 10.27369 10.15531 10.25294 10.89211 10.43277 + 8.431073 9.066086 7.605909 6.630337 6.98281 6.810944 7.623994 7.17003 7.13573 8.053357 9.209491 9.415495 8.662474 9.053435 9.397181 9.446578 9.86334 10.01845 10.17869 10.7758 10.44624 10.38814 10.5821 + 8.942445 8.941487 8.016459 8.513492 8.322972 7.758252 7.450797 7.878129 7.665907 7.39168 7.762891 8.652268 8.399451 8.6668 9.206373 9.121785 10.34451 9.926603 10.24554 10.46929 10.76244 10.86812 10.72856 + 8.17054 7.23271 7.703678 7.791962 8.005906 6.999223 7.472554 7.710637 7.925411 7.891777 8.577125 8.739526 8.736339 9.344995 9.341995 9.167021 10.40602 9.640493 9.765063 10.79863 10.77817 10.97881 10.41767 + 8.539558 8.259498 8.565295 7.196165 6.610144 8.112316 7.271636 6.927933 7.946772 8.102273 7.875247 8.079875 9.375752 11.33052 10.81717 10.21815 10.39465 10.33572 9.731151 10.2445 10.49189 11.12053 10.76395 + 8.240433 8.050691 8.147851 7.085478 6.498564 7.444286 7.85869 7.59498 7.437051 8.215886 8.160721 8.345738 8.091083 9.35317 9.591409 9.448403 10.31442 11.06631 10.24245 10.9984 10.90544 11.08032 10.89513 + 8.550308 7.967917 8.127562 7.298366 7.333465 6.49415 7.352107 7.673339 7.976416 7.147206 8.484519 8.401263 8.720249 9.223616 9.384628 9.444779 9.571202 10.1814 10.25545 10.58296 10.57897 10.69769 10.3299 + 8.480454 8.143271 8.400046 8.316236 8.42107 7.541131 8.236753 8.256838 7.837097 7.3845 8.376999 8.782026 8.372799 9.166592 9.061806 8.605547 9.607065 10.09919 10.09029 10.41691 10.74461 10.34597 10.42431 + 8.515889 7.59104 8.670294 8.427706 8.82935 8.922324 7.844193 8.359896 10.19205 11.45637 11.92006 11.58537 10.71724 11.57984 12.44317 12.37348 11.76033 10.8328 10.71005 12.17016 13.12123 13.49667 12.32615 + 9.425822 7.528139 8.268925 8.60403 9.334135 8.938853 8.31205 8.903502 10.90029 12.15107 12.53318 12.27021 11.24565 12.047 13.05301 12.96288 12.37509 11.36883 10.95156 12.79793 14.03581 15.59215 14.59917 + 9.623832 8.175732 8.02983 8.535868 7.534457 7.092595 7.973546 8.616755 9.133872 9.538013 9.353437 10.20192 10.09133 10.06388 10.93718 11.69838 11.60221 10.81748 11.46689 14.67081 16.11157 18.09854 18.4955 + 9.071504 7.593831 8.569519 7.444993 7.027435 7.670381 7.727194 8.79417 8.78412 10.26749 10.49481 10.5346 10.10987 10.96909 11.81418 12.57517 12.30537 11.48952 13.16938 15.3521 18.07163 19.78831 20.41618 + 9.247075 8.342739 8.020856 8.513025 8.168929 8.344195 8.860204 9.17792 10.17791 11.50909 11.07768 11.59347 11.83874 13.10125 13.83476 13.61449 13.87037 13.02653 13.97317 17.72324 19.60029 21.56919 21.07852 + 9.474851 6.999008 7.357038 8.650279 9.284972 10.27271 10.72347 10.36143 11.41015 11.70805 12.40401 12.9837 12.64802 14.57075 15.13742 14.90884 14.86531 14.43093 15.03153 18.73455 20.89188 22.41504 21.75938 + 8.43823 7.602589 7.820417 9.932999 10.68121 10.14239 10.38401 10.35759 12.41399 12.78729 13.28866 13.30149 12.69712 15.16579 15.84278 16.40749 16.29351 14.39652 16.20181 19.23029 21.44838 22.89708 22.22457 + 8.946985 7.907045 8.086035 9.623978 11.20953 10.96355 11.34051 11.00923 13.56718 13.85 13.94107 14.30479 14.27669 15.13896 16.49326 16.82891 16.4699 15.615 17.10016 20.28425 22.26842 23.02636 22.56798 + 8.171475 8.090663 8.552567 10.50998 10.79045 10.79585 11.77593 11.28996 13.5619 14.10327 14.95813 15.71215 14.54693 15.72432 17.80629 18.37472 18.3487 16.05388 17.43175 20.30505 22.645 23.84378 23.11084 + 8.994973 8.401255 10.09553 11.87671 11.69541 11.35841 11.40016 11.24762 13.69226 14.48686 14.93769 14.94588 14.56451 15.99824 18.65324 18.06892 17.89767 16.18208 18.38502 20.50726 22.87932 22.78703 22.46937 + 9.782323 8.487134 9.374578 10.02132 10.83674 10.82025 10.9053 12.09562 13.35448 14.63213 14.8919 14.47755 14.00885 15.77607 18.01674 17.6033 18.13421 16.40895 17.83689 19.94169 22.52357 22.9064 22.88938 + 9.201106 9.515572 10.08597 10.27731 11.7706 10.57605 11.69659 11.87735 13.37034 14.23273 14.85306 14.77176 14.40004 15.35916 18.42156 17.62954 17.38562 16.92805 18.14824 19.61706 22.00475 23.03317 22.16275 + 8.748121 9.011187 9.970596 11.7954 12.21095 11.81142 11.55084 12.17591 13.77476 14.28944 14.6072 13.23592 13.31399 15.84934 19.25628 18.41424 18.67715 16.80241 18.52868 20.36193 21.57055 22.12268 21.53455 + 8.204464 8.748878 10.92591 11.5593 13.19048 12.10626 12.02502 12.05263 13.87249 14.59625 14.2399 13.71816 14.30343 15.58732 18.69723 18.77998 18.86568 17.82364 18.05045 20.36054 21.73694 21.81034 20.88315 + 9.566998 9.260836 10.80363 11.55462 12.66976 12.26979 12.27326 11.70452 12.91361 13.86102 14.35423 14.02273 14.13222 14.11232 18.20366 18.85984 18.12046 16.65557 17.61575 19.08671 20.27447 20.7323 19.79643 + 9.615409 8.908094 10.52764 12.07648 12.35761 11.91719 11.31676 10.78619 11.90151 13.13435 13.57572 13.40028 13.16485 14.1586 17.97005 18.6574 17.49142 16.61602 16.97221 18.26481 19.8641 19.66534 19.13474 + 9.518407 13.66414 14.68301 12.44051 12.49297 11.79643 11.65911 11.69031 11.55598 11.38682 13.41629 12.76745 13.40397 14.54726 16.66532 17.59948 16.87245 15.5036 16.39759 17.45155 18.24678 18.04825 17.68169 + 9.886844 16.85537 18.44436 16.27383 15.36497 13.84907 13.35042 12.87622 12.51681 12.60914 13.06418 12.81159 12.38205 13.68456 16.01586 16.22343 16.41093 15.50471 16.12335 16.51148 17.60962 16.92897 15.91486 + 9.932881 17.91137 19.72267 16.92243 17.54066 16.3813 13.78773 13.66247 14.68949 11.97803 13.91343 13.337 12.36077 13.84169 16.9629 16.03707 15.96878 15.15771 15.55823 16.98711 16.99094 16.69534 16.27666 + 9.659884 18.09613 19.96937 17.05172 18.13224 17.0855 14.13896 14.20781 15.18947 12.32284 14.15654 13.44278 11.52995 14.65633 17.3638 16.08185 14.93075 14.58424 15.63039 16.85744 16.92874 16.18911 15.86921 + 9.225732 17.84486 19.66064 16.73664 18.33948 17.20544 14.32049 13.99798 14.7793 14.12439 13.80436 13.0112 10.64079 14.43213 16.94347 15.76767 14.88731 14.56431 14.75913 16.57955 16.82982 14.99926 14.78576 + 9.978578 17.50287 18.95299 15.45618 18.21201 17.02547 14.4027 13.69167 14.05373 14.97102 13.77975 12.47722 10.86374 13.84392 16.04429 14.79358 15.0554 14.68087 14.3245 15.75972 15.80098 14.99877 15.23887 + 10.18868 17.52852 18.87184 15.18826 17.86486 16.54828 14.55269 13.6402 14.14156 15.5371 13.91196 12.7452 11.54375 13.17193 15.15623 14.38001 14.19828 14.53728 13.81415 15.57458 15.68111 14.43799 15.17661 + 9.751181 17.77567 19.34327 16.0554 17.61001 16.27066 14.56316 13.73765 14.17065 15.73401 13.81508 12.20863 11.4907 13.34967 15.23476 13.96594 13.74054 13.87504 13.52333 15.54135 15.94359 14.1128 15.21993 + 10.12562 17.83921 19.52574 16.31928 17.54741 16.23771 14.63482 13.75617 14.15524 15.65129 13.92926 12.40173 12.0656 13.88922 14.18397 13.18738 13.58043 13.53881 13.6731 15.04371 15.07353 14.68031 15.49483 + 9.599173 17.72381 19.33587 16.07591 17.93183 16.65643 14.42071 13.79618 14.27678 15.20349 13.67884 12.52839 12.27971 14.40655 13.7573 12.9882 12.78122 13.05482 13.01771 15.88482 15.94137 15.41255 15.99297 + 9.698954 17.42312 18.87054 15.56586 18.05615 16.68462 13.77028 13.44723 13.88304 14.32237 13.28011 12.27115 12.59856 13.77862 13.29578 12.70767 12.83421 13.53693 13.18715 15.76992 15.76956 15.14107 15.93729 + 10.26758 17.18085 18.16345 14.96107 18.03324 16.52345 12.76308 12.70064 12.66801 12.16031 13.20089 12.79833 12.22538 12.70561 13.22355 12.84058 12.97821 13.38026 12.87051 16.21716 16.48619 14.9863 15.6656 + 10.44387 17.23746 17.66788 14.44783 17.53398 15.96145 11.02331 12.6539 12.60111 13.22309 12.45506 12.53511 12.75447 13.26548 13.35413 13.15652 13.2005 13.69604 12.86835 15.36887 16.235 16.85772 16.54977 + 10.23759 17.50456 18.4933 14.91491 16.87596 15.31868 10.46777 12.26849 12.64224 12.68833 12.15624 12.53137 13.16832 14.12793 14.15696 13.49824 13.72296 13.93223 13.8926 16.50182 18.04177 18.58524 18.28993 + 10.35166 17.05918 18.34675 14.85144 15.89987 14.52373 9.76105 11.89735 12.64335 14.01029 13.73979 13.24587 13.72216 15.26234 15.57124 15.82822 14.74431 15.00797 14.97392 17.71632 19.5425 20.54453 20.59761 + 9.555297 15.74934 17.18219 13.77729 15.08703 13.69022 10.26886 10.90417 12.99767 13.61335 14.09484 13.58124 14.1276 15.82747 16.31124 16.64211 16.18265 15.21884 15.42664 17.76999 19.3903 20.87875 20.63521 + 8.862854 14.02321 15.96503 13.04325 13.75009 12.35207 10.97646 11.18398 12.65906 13.14713 13.12646 13.15454 14.30518 15.27275 15.80141 16.52305 15.9915 14.97509 15.27901 17.70121 19.40024 21.01748 20.90414 + 9.332595 14.84705 16.37164 13.3482 13.17087 10.29789 10.88544 11.37841 12.42703 13.47049 13.44906 13.32345 14.28644 15.11956 16.00913 15.9466 15.03316 14.63348 14.81898 18.33994 19.95979 22.53777 21.45701 + 9.877868 15.61059 16.83839 13.17729 12.35922 10.87731 12.04013 11.68683 13.13918 13.59089 14.2367 13.87884 13.71417 14.67861 15.89329 16.04236 15.43196 14.25506 15.13684 17.87797 19.84326 21.79107 21.3449 + 9.140958 14.76068 16.10624 13.06766 13.47845 11.71019 11.03197 11.56545 12.67004 13.27332 13.428 13.15621 14.76991 15.18839 16.24062 16.5626 15.80795 14.79566 15.80218 18.18081 20.55774 22.59585 22.16014 + 9.849629 12.1764 13.81905 12.20043 12.96303 11.37443 10.69466 11.47991 12.80477 12.91667 12.75835 13.21933 15.38656 15.95259 16.823 16.35283 16.43909 15.31986 16.49224 18.66559 20.4817 22.71685 21.85016 + 9.36202 14.08019 15.09082 12.18999 12.97359 12.29903 11.47363 11.54493 12.6398 12.84276 13.85428 13.64815 15.08565 15.69742 16.96827 16.94289 16.80222 15.64644 16.48269 19.1488 21.81447 23.17466 22.23106 + 9.57612 15.02501 16.06492 12.43449 13.88631 12.50848 11.44948 10.40349 11.57291 13.3126 14.31746 13.71188 14.76625 16.03081 16.07044 15.89003 16.94098 15.98808 16.14021 18.78211 21.02096 21.56885 20.88732 + 11.78685 15.01811 15.52112 13.93588 14.43564 12.86158 11.35952 11.50686 11.3272 13.30817 13.81913 13.40519 15.05978 15.84919 15.35929 13.89001 15.52159 15.23993 15.40555 17.11906 18.97794 19.44685 18.4641 + 13.22307 17.17885 17.15026 17.71776 17.11022 14.76405 13.44761 13.67636 13.50036 13.58129 13.95018 13.70605 14.88567 15.03857 14.84337 14.45563 14.86374 14.4649 14.85144 16.43289 16.89828 16.35405 16.94752 + 13.76669 17.1444 16.05253 18.63818 17.65204 16.25583 13.92566 13.3862 14.08959 14.32102 14.93346 14.31664 14.22204 15.10196 14.79939 14.6737 15.79121 14.93165 14.95335 16.65422 16.83254 16.26995 16.42411 + 14.16293 17.56638 16.68997 18.26259 16.92739 16.86658 14.25883 13.70589 14.65646 14.7077 15.98879 14.10393 13.49225 14.60994 14.55858 14.16977 16.02258 15.63895 14.65991 16.49418 17.11003 16.32096 16.05037 + 15.02538 17.72275 16.8508 18.08271 16.43288 16.42471 14.93453 14.1509 15.1513 14.99477 16.14239 14.24235 14.14056 14.526 13.32078 13.45539 15.79795 15.33149 14.69157 15.69744 16.36747 15.60381 15.84035 + 15.73365 18.03275 17.27561 18.75753 16.95327 15.80555 14.91612 15.18357 15.67709 14.97079 15.72672 15.15915 14.04085 14.47075 13.372 12.99742 14.7936 14.90177 14.24704 15.20238 16.2678 14.74167 16.11823 + 16.26338 18.46109 17.27797 17.99683 16.66476 16.05012 15.40509 15.53155 15.96098 15.33267 16.30002 15.72512 14.53671 14.58817 13.3534 12.64955 14.37179 14.83991 14.59077 15.26721 16.07784 14.28749 15.199 + 16.74382 18.91121 17.16111 18.04957 17.40871 16.48565 15.41961 15.17963 15.49974 15.08093 16.65548 15.9269 13.91849 13.88327 12.97235 12.65223 14.07203 14.75737 14.22784 14.64774 15.34663 14.63228 16.0888 + 16.98529 19.11541 16.87011 16.74349 16.9392 15.88544 15.29093 14.62053 14.88953 15.09566 16.51639 15.45968 13.03472 13.23992 12.823 11.87619 13.33451 14.86192 14.20521 15.69702 15.84917 14.75232 16.39235 + 17.02896 19.19595 17.16109 16.8834 16.3556 15.42284 14.74861 14.76104 14.92473 14.9596 16.6881 15.93081 13.33428 12.97397 11.86678 11.63746 13.04319 14.28844 13.94617 15.04595 15.0869 13.90257 15.89565 + 16.85907 18.78141 16.70892 17.00507 15.92624 15.45061 14.55362 14.95892 14.77704 14.90913 16.98108 16.19264 12.85906 12.48413 11.65127 11.22398 12.58972 13.57485 13.65335 14.72739 15.04537 13.98265 15.01211 + 16.64772 18.64282 16.71573 17.18554 14.0683 13.95587 14.57919 14.46328 14.58978 14.59518 17.19131 16.57361 11.92534 12.44241 11.72602 10.9928 12.40186 12.90819 13.48149 13.89237 14.56885 13.63314 15.65915 + 16.43158 18.50433 16.55654 16.99913 14.52069 14.72103 15.24015 14.21969 14.87307 14.52989 16.81562 16.34734 11.70553 12.3317 12.12857 10.71785 11.98174 13.78292 13.32322 13.64274 14.45671 12.9734 15.85995 + 16.15336 18.23414 16.24944 17.09164 15.74857 15.23684 15.1064 14.90766 14.93522 14.25292 15.3692 15.24385 11.05891 11.63416 11.56629 10.73565 11.83266 13.19534 12.7056 12.56191 13.70245 13.0052 15.80045 + 15.78317 18.05012 16.20395 16.93727 15.87394 15.19709 14.3524 15.32856 14.63064 14.19885 14.98944 14.75296 10.62751 12.19092 12.06983 10.93399 11.87565 13.48435 13.07779 12.09982 12.47317 12.27248 14.84082 + 15.39456 17.87456 16.5168 17.58305 15.61139 14.72246 13.21522 14.96642 14.20902 13.41669 14.09352 13.92773 10.64034 11.88319 11.45076 10.29098 11.03321 12.29812 12.70397 11.7358 12.26939 12.86226 14.78897 + 15.02351 17.78964 16.85471 18.13364 15.47449 12.54772 11.64264 14.01794 14.02666 13.12667 13.50438 13.3572 10.43241 11.16833 10.74877 10.2707 11.00853 12.42801 11.92629 11.09674 11.43357 12.86431 14.27416 + 15.09622 17.92495 16.85561 18.0988 15.42922 13.02023 12.68088 13.53072 14.48343 13.28728 12.15022 11.93546 9.953141 10.79692 10.91492 10.17909 10.60862 11.80252 11.56975 11.04416 11.2531 12.42208 13.60621 + 15.60607 18.24389 16.80309 17.81159 15.3917 13.49877 12.40576 13.14706 13.09449 12.85986 11.56458 11.51797 9.652337 9.949935 10.32372 9.620278 10.69048 12.02814 11.59302 11.66032 11.30074 12.12424 13.24895 + 15.90996 18.41689 16.64116 16.99631 14.64567 13.13194 12.07542 12.5822 11.69349 12.01927 12.62355 12.76301 9.990061 10.90189 10.44079 10.43505 10.66998 11.15739 10.76031 11.42792 10.89405 11.56491 12.52887 + 16.00483 18.30446 16.08208 15.86133 13.48314 11.61676 10.97823 11.11799 11.98649 11.92625 11.69026 11.50517 9.732758 11.60136 12.52013 10.93729 10.51151 10.81287 10.82617 11.56538 11.44386 11.92824 12.41918 + 15.85966 18.15599 15.9375 14.95248 13.4534 12.87702 10.83218 10.35821 11.16184 9.718279 11.04042 10.5775 9.815519 11.36835 11.88853 10.33835 10.50751 11.11677 11.1463 10.79816 10.42655 11.12749 11.29204 + 15.60883 17.95237 15.71562 14.06708 12.83226 12.50489 11.20979 11.6847 10.72093 10.36459 9.917531 9.80342 9.078652 10.03732 10.6124 10.40085 10.80684 10.88086 10.69822 11.10227 10.46698 10.97048 11.10912 + 15.2283 17.69786 15.57806 13.4353 12.19316 11.6246 11.0224 10.72823 9.161061 9.050728 9.18773 8.855824 9.341613 10.0488 10.13517 9.546819 9.585426 10.50744 10.39803 10.67031 10.51961 11.0685 11.14912 + 14.64353 17.16451 15.15834 12.35796 12.72608 12.63046 11.68167 12.3668 14.25992 15.93695 17.47775 17.61803 15.56757 12.9737 13.57319 14.56981 13.7044 12.71877 12.86225 13.4201 14.1629 15.60515 15.65097 + 14.06131 16.47077 14.28449 12.84858 13.9689 13.82744 13.50231 13.78073 15.74885 17.04282 18.63243 18.85933 16.36653 13.78124 14.21553 15.24145 14.55391 13.56051 13.44235 13.90322 15.24372 16.40675 16.67416 + 13.27166 15.83467 13.93871 14.37551 15.34901 13.98736 12.92254 13.76627 16.36158 17.10549 18.30305 19.29653 16.39378 14.40754 14.97054 15.40539 15.09013 14.31383 14.41104 14.81105 16.28816 17.46544 17.82826 + 12.96865 15.35536 13.58534 12.4107 13.17324 13.02235 12.97369 12.78875 14.50413 17.08331 17.24843 18.6091 16.95518 13.8684 14.65208 15.11388 14.85909 14.55639 14.21002 14.85613 16.15392 16.62638 16.38885 + 12.74014 14.99901 13.14317 12.02542 13.41206 14.03033 13.80731 13.07016 15.74668 17.29949 18.08332 19.69819 16.80057 14.75249 15.27074 15.78106 15.3902 15.52286 15.18476 16.46467 17.64916 18.49447 18.44848 + 12.97496 15.42951 13.52378 12.25876 12.9795 12.56979 12.22692 13.57497 16.76153 17.23584 17.87868 19.12806 16.46191 14.3858 15.09691 16.4803 16.39127 15.58957 15.17072 17.00169 18.0875 17.41795 17.79514 + 12.85048 15.10298 13.23063 12.87181 13.15208 14.49708 13.07669 14.13431 17.66776 18.05823 18.7889 19.8481 17.92514 14.92354 15.70432 16.74818 16.99346 15.81199 15.74879 17.21499 17.70545 17.515 17.36108 + 12.53143 14.44646 12.04487 12.66221 12.77981 14.32154 14.07838 15.03848 17.27874 19.03686 20.9606 21.08079 18.90958 15.76664 16.3242 16.48548 17.68536 17.00244 15.70976 17.18387 17.96568 17.45182 17.34422 + 12.27433 14.13071 11.95814 11.10963 12.29782 13.32947 14.22352 14.91252 17.05256 19.26613 20.56975 21.0718 19.55671 16.45315 16.53867 17.16694 17.57012 16.58561 15.94327 18.1118 18.44273 17.04756 17.29078 + 11.13274 13.31547 11.17836 10.36571 11.99675 13.38614 12.98195 13.65712 17.52398 18.83635 20.82496 21.25018 19.02944 15.45844 17.22033 16.9855 17.61625 16.53855 16.01951 17.28067 17.80919 16.29823 16.60528 + 11.49348 12.72149 11.09698 10.74121 11.50064 13.47943 13.28319 14.12894 16.37674 18.3519 20.4639 21.47652 19.33566 15.77035 17.06349 16.64114 18.07568 16.64302 15.36201 16.04336 16.91956 15.94561 15.99434 + 9.608139 11.75429 10.06571 11.10138 12.11786 11.58483 13.1205 14.21301 17.56386 19.13147 20.32322 20.12503 18.29022 15.28772 16.86212 17.37056 17.82328 16.0193 14.99997 15.78904 16.12305 14.55896 16.01875 + 10.37425 13.20676 13.2479 12.19929 12.48866 11.74895 13.30715 14.54824 16.49951 18.31167 18.70988 19.54097 18.35619 15.11479 16.51697 15.98994 17.09819 15.56539 14.59282 15.14828 15.75255 14.43601 15.72609 + 12.24577 13.50046 14.6557 13.99299 13.82843 14.16929 14.48501 15.5354 17.66883 19.51937 19.39577 20.05754 18.37926 15.92839 17.23025 16.90665 17.33165 15.74956 14.90289 15.95183 16.37263 14.70161 16.83718 + 11.82463 14.14506 14.91792 15.10521 13.43633 14.76357 14.50471 16.30964 18.37582 20.10591 19.70662 20.12249 18.50193 16.44523 17.84676 17.22989 18.06538 15.9933 14.78116 15.97121 16.63473 14.1447 16.62147 + 11.49515 12.57675 14.99955 15.12591 14.04319 14.90118 15.1428 16.90608 19.3396 19.58758 19.89336 20.47232 19.38027 16.83281 17.80051 16.78543 17.68006 16.1482 15.12499 16.29321 17.28958 14.39812 16.74356 + 12.83119 13.36858 15.33085 15.8993 14.98862 15.06884 16.27656 17.09787 19.89 19.45495 19.66687 20.41065 20.05285 16.93578 17.84101 17.22516 16.6539 15.47889 14.51853 15.41234 16.16337 13.92638 16.21105 + 12.24501 13.81182 15.54418 15.71802 14.7434 15.25031 16.42093 16.59528 18.99483 18.75741 18.65719 19.56692 19.45428 16.5445 17.94703 16.85806 17.52571 15.87006 14.62513 16.25237 16.75192 14.53815 16.44307 + 12.43977 14.4055 15.44666 14.61817 14.49417 15.49514 16.47301 15.8417 18.29481 18.40584 18.14786 18.99505 18.48756 16.02132 17.57674 16.21739 17.56367 15.96092 14.12129 15.69186 16.08254 13.29479 15.69123 + 13.40359 14.56592 14.56405 14.75467 14.80557 15.61075 16.30825 16.00495 17.7576 17.7054 18.44081 18.78086 17.91715 15.75736 16.79029 16.09669 16.95103 15.45958 14.6285 16.45296 17.08261 14.81537 16.62719 + 13.40314 14.79066 14.44038 14.9208 15.28192 15.93543 16.12896 15.63424 17.53443 16.71537 17.66586 18.26663 18.14948 15.38054 15.57821 15.0981 16.37489 14.9254 14.11771 16.22453 16.63408 13.88445 16.03982 + 13.27263 15.37152 14.98211 15.65071 16.10147 16.25443 16.39878 15.22288 16.07312 15.48051 16.95177 17.88365 17.64783 15.38212 14.85438 14.25418 15.50375 13.87315 13.85102 15.71543 15.58055 13.48126 13.54171 + 12.79769 14.03458 15.15382 15.77783 16.13641 15.98903 15.71088 14.83081 15.42676 14.42686 16.35059 17.19747 15.89601 14.84456 14.84353 13.56014 14.43848 14.02768 13.56937 15.50516 15.01935 13.35548 13.45835 + 12.93903 13.22154 14.53004 14.98958 15.29645 14.57587 14.04077 13.26272 15.32759 15.32236 15.08416 15.42689 14.78734 13.71587 13.79163 12.75518 14.19596 13.34965 13.19663 14.03743 14.96614 16.49541 15.33635 + 12.45864 14.61374 13.87632 13.62215 13.72294 14.31611 14.38086 14.30659 15.43989 15.61096 14.15577 14.35514 14.81355 13.64131 13.45614 12.72456 14.13968 12.8555 13.59385 14.17748 16.39845 18.38371 17.80732 + 12.33578 14.00891 13.07828 13.71424 14.10664 14.0687 13.13889 13.63885 14.8914 14.61784 13.90929 15.45194 14.73162 13.03892 13.2657 13.5637 13.76148 13.25706 15.10444 16.29706 16.97831 19.44946 19.79165 + 11.96159 13.51957 13.01035 13.54761 13.69153 14.00353 13.68937 12.58661 13.48017 14.13214 13.91707 15.31068 14.23771 12.71703 12.92456 13.6957 14.43063 13.71029 15.22686 17.15446 18.45062 20.47192 20.89673 + 12.05161 13.9109 13.16452 12.97099 13.18609 13.13105 12.99765 11.58859 13.5218 14.01596 14.89017 16.47881 15.28746 13.67678 14.92654 14.96245 15.16147 15.0592 16.54627 18.17285 20.02958 21.51884 20.96085 + 11.84209 13.52904 12.77278 13.65398 13.20718 12.63755 11.65749 11.51693 13.74348 13.71783 15.14928 15.87488 15.38048 14.01578 15.41916 16.25989 16.82 15.85239 17.44685 18.49073 20.68714 23.03419 22.3119 + 10.61903 12.43421 12.6958 13.1518 12.79633 12.09934 11.18174 12.15249 13.5683 12.78554 14.49859 16.1356 16.38138 15.60392 15.1943 16.6934 17.43444 17.15856 17.69735 18.73776 20.3603 23.0533 22.83157 + 11.10656 11.3087 12.01439 12.55888 12.73079 12.43724 11.43508 11.91604 11.70938 13.99057 15.63961 17.28322 16.47677 15.20305 15.66617 17.61813 17.6751 17.60305 17.77451 19.25667 19.94949 21.90983 21.98059 + 10.16949 12.0564 11.52991 9.989189 11.37004 11.68872 11.52673 12.63663 12.73647 14.62583 15.9687 17.945 17.5506 15.1612 15.45209 17.22151 17.94404 18.35554 18.20267 19.54291 20.5292 21.7872 21.39606 + 10.79198 11.45736 9.874234 11.29701 11.26837 11.21837 10.89179 11.62866 12.76508 14.6835 16.18573 17.36658 16.85448 15.94918 15.41981 17.08667 18.88033 18.45577 17.89176 18.7529 19.93383 20.91602 20.71407 + 10.99965 11.83611 10.76372 12.36669 12.88359 12.50686 12.02554 11.77562 12.96449 14.7419 17.49727 19.05647 17.76691 16.14889 15.8502 16.94702 18.54008 18.61212 17.60375 18.40122 18.75871 20.56727 20.2013 + 10.71721 12.24653 11.40098 12.01936 13.33127 11.90686 10.65947 11.82579 13.32248 15.28793 17.01124 18.64284 17.72797 16.53176 16.11108 16.70494 17.7008 16.87293 16.90321 17.01193 17.9865 19.62047 18.54438 + 10.84808 11.77401 10.30343 12.64884 13.14566 11.23923 10.88098 13.11721 13.34063 16.31784 16.83382 18.21345 17.3839 15.27081 15.50685 15.6567 16.72981 16.33526 16.45064 16.3113 16.49539 17.15864 16.46489 + 9.56905 11.07326 11.29717 12.00945 12.56924 11.74636 11.67797 12.27109 12.33903 15.01359 17.29026 17.98109 16.23312 14.9431 14.57544 15.20214 16.10517 16.19224 15.99478 15.25868 15.40402 16.06674 15.44316 + 10.508 10.89142 10.47173 10.95241 11.76593 10.98585 10.76927 12.52917 13.36483 14.31004 15.60877 16.93384 15.8426 14.30149 13.70551 14.91785 15.92855 15.53096 15.40199 15.04334 15.08857 15.01525 14.25574 + 10.63981 10.66823 10.20522 11.10935 11.52312 11.02348 10.33216 11.91914 13.66731 13.93949 16.71332 17.01327 15.03499 14.47763 14.38019 14.41362 15.83647 15.67047 14.47045 14.31423 14.19904 14.82268 14.1559 + 8.488654 10.10538 10.92675 10.09366 10.85918 11.26827 12.20304 11.80998 13.27558 13.73623 16.86435 16.49012 14.37312 13.21352 13.43559 13.28338 14.71591 15.0856 14.91768 13.89271 13.95088 14.00356 13.01124 + 10.81898 13.143 12.69162 12.18221 12.55161 11.64523 12.4468 13.02303 11.64384 13.77602 16.63419 16.27282 14.54465 12.69009 12.62936 13.17467 13.86224 14.07909 14.24895 13.57493 13.15678 13.56058 14.07112 + 11.59634 16.15282 16.04291 14.96902 14.3159 12.56915 13.37283 13.76863 13.54054 15.07096 17.31351 15.84202 14.1527 12.01037 12.44869 12.54331 13.90306 14.87695 13.81047 14.15678 13.85537 13.21027 14.43797 + 11.50468 16.01534 15.65023 16.86644 16.7308 13.15539 13.75249 14.19167 14.84136 15.6804 16.669 15.56741 13.27599 12.18581 12.46388 13.30746 14.70786 14.89385 13.59378 14.1329 13.90083 13.44039 14.82801 + 10.83374 15.32171 15.06138 17.48699 17.51079 13.80905 13.93069 14.59176 15.34084 16.82994 18.43996 15.90578 13.45436 11.4224 12.79343 13.04898 15.73146 15.33158 13.21905 14.24352 13.77445 13.27233 15.71018 + 10.87577 15.47127 14.70888 17.73984 17.70155 15.23704 14.3281 14.20854 15.22783 16.9904 18.81393 15.66493 12.64094 11.61629 12.53687 12.72079 15.53799 15.56939 13.56948 13.97123 13.99972 13.84164 15.74528 + 9.678106 15.093 14.73196 18.04266 17.9735 15.98976 14.84349 14.29395 15.38192 17.14681 18.48132 15.55414 11.81447 11.31875 12.51214 13.46786 15.07734 14.72639 12.89217 14.18221 13.942 14.46083 16.30935 + 9.27702 15.11397 14.6864 18.26455 18.06617 16.64905 15.23202 14.50276 15.79894 17.31784 17.91948 15.71456 11.84832 11.10479 12.36307 13.02193 14.84241 13.94248 12.61262 14.14687 13.61714 14.61513 16.65529 + 10.31116 15.20001 14.41779 18.20655 17.87181 17.37104 15.80053 14.73345 16.33781 17.26945 17.61073 15.76432 12.14948 11.87968 12.84734 13.35572 15.99964 15.05299 12.98151 13.59093 13.31608 14.26525 16.48788 + 11.03995 15.58457 14.74849 18.04535 17.62146 17.83399 16.13437 15.02326 16.80089 17.59974 17.02293 15.01341 11.93478 12.57936 13.6127 14.46719 15.84169 14.35661 12.21926 13.44742 13.43839 15.56678 17.01775 + 10.68538 15.81025 15.13098 18.21277 17.8306 18.10699 16.28154 15.16807 17.16661 18.57889 16.92452 14.87336 11.62055 12.73409 14.09998 15.07829 15.77258 14.38338 12.46635 13.38107 13.42031 15.66041 16.70012 + 10.80705 16.10119 15.46497 18.4098 18.0212 17.97135 16.10877 15.19762 17.24214 18.58634 16.91249 15.42679 11.88585 13.91432 14.45943 15.74949 15.78372 14.54293 11.42183 13.62915 13.34823 14.55129 16.14689 + 11.94579 16.89884 16.24403 18.55092 17.98724 17.20735 15.26665 14.65565 17.00868 18.47542 17.43419 16.03572 12.83943 14.0368 13.85004 14.82996 15.17481 14.47794 11.56922 13.58228 13.62983 13.59302 13.86895 + 12.38524 17.37505 16.7696 18.47446 17.26857 15.96833 14.24874 13.03042 16.26422 17.79273 17.16697 15.42565 13.5957 14.48988 15.57542 16.0727 14.58922 13.24106 11.54757 13.28529 14.40883 13.49071 12.73336 + 13.03429 17.5047 16.87468 18.99148 17.70904 16.97621 14.13228 12.62222 14.45247 16.32981 16.61537 14.76507 12.27121 13.29012 13.69145 14.77818 13.90872 12.32405 11.65774 13.06149 13.20633 12.79723 14.08691 + 13.543 17.20046 16.71364 19.24344 17.89848 16.23823 13.61446 12.58731 13.79848 15.94572 15.83083 13.94334 12.33336 12.76893 13.26038 13.66663 13.53549 12.52763 10.97694 12.18569 12.12396 12.52927 14.61442 + 13.93316 16.19917 16.60253 18.37887 16.34868 15.3344 13.60281 12.46623 14.00873 15.9596 15.67228 13.47866 13.02688 12.05685 12.97747 13.6599 13.39636 12.42592 11.40474 12.42729 12.39029 12.35651 14.67778 + 14.61915 17.17112 17.5472 19.37409 17.49985 15.90717 13.63423 11.95899 12.93315 15.14544 15.01936 13.25283 12.0639 11.61034 12.99201 13.5629 12.46684 11.77172 11.48846 12.21882 12.39871 12.28264 13.6378 + 15.01957 17.45677 17.19109 18.36874 17.45291 15.49117 13.40853 11.98515 13.43848 14.47075 13.50971 13.02251 11.71136 11.68848 13.16979 13.33672 12.58453 12.35258 10.77152 11.58895 12.66962 12.02104 13.51065 + 14.3445 16.08383 16.46618 18.37986 17.49754 15.51561 12.724 11.01192 12.56261 14.75061 13.70792 13.23755 11.97928 11.47003 12.88496 13.19709 12.51916 12.02072 11.23445 11.98222 12.57755 12.58092 13.76349 + 14.65777 17.34103 16.21595 17.87756 17.01974 14.35497 12.22902 10.17611 12.75461 14.43687 13.74576 11.96353 11.00994 10.55103 11.22951 12.06966 11.58648 11.32696 10.70369 11.09274 11.97977 11.15652 12.0545 + 13.84403 16.75669 15.79734 15.90669 15.87204 12.81713 11.09628 9.869988 11.99412 13.88495 12.05193 12.04093 9.865374 9.98888 10.54978 11.08329 11.51721 11.287 10.19415 10.19129 11.11317 10.82287 11.26695 + 12.03434 15.45859 15.11167 15.11641 15.16317 14.43024 11.65586 9.923259 11.36602 12.3641 11.81006 10.42863 9.54241 9.423545 10.06809 10.60886 9.986245 10.09022 9.895988 9.939384 10.39964 10.69043 10.78549 + 11.62159 13.6024 13.63344 15.00115 13.6637 13.22205 10.87602 8.768591 9.799749 12.06331 11.48621 10.03431 9.139547 9.069712 9.670283 10.33705 9.896729 9.732963 9.743416 9.657762 10.36899 10.26934 10.40027 + 11.81183 14.29564 13.63866 13.6298 13.18893 11.65243 10.08644 8.713807 10.15905 11.12224 10.93487 10.20999 9.452074 8.578758 9.197603 9.436418 9.835726 10.35768 10.15316 9.921681 10.65349 10.78003 10.5952 + 12.90228 14.67107 13.85628 14.29541 14.35086 11.63753 8.860591 8.425612 9.22795 10.41009 10.2974 10.03016 9.485574 8.96593 9.532566 10.04701 10.0559 10.14437 9.809213 10.09447 10.73098 10.48613 10.97839 + 12.14247 14.62703 13.12694 13.76217 13.40734 11.91112 10.03432 10.69592 11.79923 14.96772 14.89136 11.78498 11.03141 11.00658 12.59778 13.80232 13.4921 12.70364 11.11213 11.89696 12.66712 11.61696 12.02989 + 12.4993 14.9535 13.76636 14.01113 13.60918 11.75265 9.318426 8.455474 10.17039 14.04918 14.17533 10.41443 9.469222 8.986806 10.21098 11.43141 11.99639 11.92311 10.10373 10.33753 11.20988 10.83258 10.75896 + 12.68394 14.34959 12.56896 14.07434 13.22602 10.90166 8.476089 7.972132 8.819757 12.4768 12.05638 10.18155 9.379935 9.701678 9.932637 10.54168 10.334 10.5734 9.954249 10.09657 10.31382 10.49024 10.26939 + 11.75025 13.98052 12.16752 14.10251 13.03628 9.846658 8.836266 7.344621 8.59577 10.93273 10.1303 9.196149 9.388488 9.020345 10.06814 10.79366 10.47544 10.58243 10.03372 10.03065 10.42077 10.64656 10.34247 + 11.83129 14.04893 12.96955 13.20662 12.82525 9.696637 7.323474 8.177329 8.925125 10.40487 10.10953 8.585592 8.994603 8.708897 9.25738 9.843696 9.578411 9.801521 10.00724 10.09079 10.59092 10.64287 10.58762 + 9.790665 12.15129 12.64895 13.58438 12.95563 9.711924 8.575097 9.001645 8.701345 10.52208 10.09897 8.517282 8.199652 8.714253 9.041263 10.04511 10.11496 10.00863 9.805107 10.16271 11.0758 11.04546 10.75644 + 9.414765 12.83946 11.98675 12.726 12.46979 9.267152 9.039246 8.176429 8.053612 10.21454 10.41292 8.622193 7.66354 8.369621 8.642668 9.53128 9.865145 9.638438 9.991666 10.25773 10.73875 10.72115 10.65728 + 8.779566 11.93363 11.50436 10.50424 9.622196 9.267383 8.582248 8.53771 7.890744 10.04505 10.20443 8.095118 8.612964 8.879345 8.707826 9.227075 9.176577 8.984758 10.03803 10.03335 10.5386 10.95927 10.46486 + 10.31262 11.88174 11.99282 11.90945 9.594206 8.671169 8.318475 8.181697 8.13483 10.15049 10.25244 7.071458 7.442567 8.785149 9.691864 9.679538 9.605824 9.961757 10.42259 10.17275 10.75009 11.18037 10.72504 + 9.364248 11.96104 11.57661 12.01562 10.75383 6.945975 7.367255 7.736284 7.312432 8.969963 9.153383 7.523694 7.927206 8.369026 8.890183 8.625024 9.480546 9.502405 9.561119 10.14811 10.62848 10.7046 10.59589 + 8.967705 11.99061 11.26416 11.1752 9.580898 7.045003 7.880908 7.853495 8.063289 8.442639 8.374674 7.542927 8.712921 9.363231 8.787829 8.940651 8.762001 9.656484 9.560316 9.75022 9.998157 10.96855 10.83991 + 10.79417 10.95528 10.71563 9.979272 8.763993 8.042848 7.088778 6.67021 7.448594 8.206177 8.038567 8.22692 8.547086 7.783141 9.548368 9.043281 9.180702 10.15911 10.00978 9.834736 10.7707 10.82731 10.66534 + 9.814768 12.13082 11.35585 9.269568 8.184406 7.729397 6.804678 6.910729 7.282489 8.309008 8.415974 8.394214 7.598199 8.050271 7.802004 8.228464 9.248132 9.948934 9.981988 9.834879 10.65781 10.51871 10.32499 + 9.652328 11.7325 10.80005 9.37675 9.013214 7.384077 7.177258 6.372046 7.152434 7.877509 7.752526 8.609852 8.207765 8.032439 8.76918 8.827532 10.00151 9.213638 9.988755 9.774078 9.915665 9.921049 10.41844 + 9.466437 10.99616 10.88723 9.492371 8.961466 7.342728 7.358507 7.339148 7.301462 8.448383 7.55255 8.734881 8.417077 8.13668 8.47903 9.036981 9.332474 9.148084 9.903509 9.827729 9.972055 10.26808 10.0221 + 9.64337 12.05854 10.97252 10.21088 9.235108 7.101156 7.432653 8.052295 7.081014 6.580639 7.278504 8.679576 8.280871 7.73062 8.75071 8.532309 9.329696 9.757581 9.649004 9.204338 10.25986 10.47111 10.64369 + 8.506092 11.0128 10.68274 8.38584 7.542353 7.152045 7.326688 7.308694 7.642912 8.45325 8.044881 7.742783 7.756063 7.661537 8.275199 9.033102 9.546831 10.0107 9.767799 9.575422 10.45731 10.67947 10.68756 + 9.190603 9.530713 10.03561 9.930932 8.509491 7.016098 7.502091 7.892929 8.24372 8.307619 7.979042 8.022539 7.607509 8.970244 9.02056 9.152427 9.395686 9.654662 10.00138 9.774302 10.25611 10.34001 10.50237 + 8.055989 10.48079 9.946203 8.668516 8.405702 6.663228 7.840029 7.953751 7.417573 8.407804 8.318707 8.09545 8.268252 8.237886 8.408285 9.147687 9.502143 9.359609 9.642401 10.35548 10.85097 10.35253 10.09162 + 8.523983 10.58812 10.45586 9.346948 8.423094 6.955203 7.860735 7.061844 7.640428 8.098751 8.684567 8.348521 8.667695 8.787177 8.56147 9.256539 9.863892 9.601056 9.600217 10.26275 10.53992 10.67695 10.53019 + 8.54944 10.105 9.919378 8.700562 8.344156 7.651311 7.920049 8.247942 7.364244 7.392271 7.95518 8.640728 8.450232 9.633104 9.684301 9.891527 10.32047 10.18789 10.04646 9.441429 9.973019 10.92726 11.09868 + 8.736779 10.67164 10.37507 8.660881 7.410948 6.964188 8.062383 8.657798 8.175787 8.124825 8.552548 8.639585 9.223927 9.4434 9.095827 9.018662 9.108647 9.592525 9.690062 9.847681 10.15555 10.88235 11.25451 + 9.102138 10.24407 9.305552 7.972584 7.585355 7.130199 8.330059 8.346169 7.620663 7.047201 7.893063 7.923952 8.201685 8.679209 8.079769 8.701505 9.398625 9.830337 10.10372 10.45054 10.39745 10.80141 11.24109 + 8.334327 8.800347 7.70179 9.206788 7.814823 6.755373 8.229139 8.560562 8.269526 8.002664 8.831103 8.463894 8.141541 9.049789 8.658106 9.396982 9.033927 9.765074 9.622846 9.758422 10.27184 10.49305 10.98647 + 8.128156 10.12106 8.910188 8.762326 7.666012 6.949401 7.950629 8.1798 7.218674 8.2833 9.230454 8.431417 8.010346 8.432215 9.385073 9.408096 9.264348 9.842328 9.402944 10.16326 10.44512 10.27258 10.61046 + 9.777776 10.17425 9.162596 8.756527 9.402295 7.245045 6.706331 7.813528 7.5786 6.985806 8.648697 8.302122 8.295655 9.284019 9.676419 9.26071 9.179568 9.636398 10.1599 10.62567 10.66345 10.83598 11.00543 + 9.4869 9.121305 8.684687 8.700015 9.641527 9.05888 7.269274 8.791707 8.11694 7.627497 7.894124 8.112581 8.470985 9.387035 9.151163 9.710186 10.16911 10.16346 9.604074 9.987885 10.31005 10.77668 10.24039 + 7.866471 9.883156 9.715327 8.677911 9.516367 8.34246 6.843951 7.838072 7.583541 7.852625 8.79549 7.970304 7.762091 8.846987 8.563057 9.384929 9.697865 10.01375 9.721039 9.735113 10.16057 10.63224 10.43368 + 9.080318 8.246053 9.041588 9.417509 9.518696 7.989542 8.403717 7.463982 7.206106 7.981693 8.578013 8.107899 8.514518 7.873508 8.147607 8.765822 9.033931 9.63969 10.04347 10.20652 10.35496 10.39911 10.52451 + 9.13128 9.074238 9.046019 9.162777 9.203651 7.817907 8.81809 9.218652 8.689803 8.523691 8.246085 7.754849 8.768758 8.798193 9.144502 9.340219 8.860093 9.865606 10.48086 10.25486 10.56614 10.47177 10.82067 + 7.529797 9.080559 9.025809 9.092778 9.069881 7.946015 8.707859 8.578739 7.658888 7.688912 8.116105 8.22648 8.638034 8.394612 8.661798 9.266599 9.497275 10.0152 10.51752 10.32173 10.39726 10.61129 10.75329 + 8.053345 7.806293 9.592606 9.250229 10.12409 9.191865 7.827196 8.112508 8.535282 8.097424 9.000211 8.186003 8.92979 8.464402 8.670289 9.216187 8.820874 9.527074 9.87499 10.41622 10.59681 10.51637 10.55027 + 8.95764 9.454929 9.582647 10.45938 9.56032 9.433331 8.428452 8.183547 8.032114 8.346304 9.071006 7.965348 8.02034 8.698916 8.684159 9.147419 9.093694 9.894665 9.954333 9.885933 10.35833 10.71119 10.45288 + 8.644167 9.48673 9.193418 10.94477 10.83592 10.44026 9.28124 8.387064 8.084641 8.072067 8.342614 7.222877 7.512965 8.233858 8.808452 9.225642 9.137754 9.547808 9.455416 9.747941 9.971579 10.64146 10.5402 + 9.362679 9.369581 9.729918 10.51496 11.36854 10.06961 9.509526 8.469991 7.580379 7.402191 8.035908 8.038517 7.526035 8.179871 9.229591 9.114322 9.371479 8.994488 10.0342 9.992566 10.37911 10.48729 10.1093 + 9.234426 10.02822 10.1721 10.36807 11.38841 10.48724 9.894856 8.55321 7.932958 7.556772 6.919079 7.997473 8.420939 8.136166 8.576433 8.605513 9.379736 9.246395 9.551528 10.12443 10.13093 10.29004 10.01479 + 7.140229 7.340988 9.690434 11.22617 10.54758 9.907132 10.23349 7.846205 7.38694 7.756484 8.138117 7.949685 8.286037 7.875541 8.682808 9.680047 8.736238 9.250605 9.806664 9.929686 10.29157 10.88262 10.53922 + 7.609503 8.446361 7.927704 10.19232 9.981958 9.750368 10.16796 8.132822 7.723164 7.520811 7.855199 7.349501 7.666749 8.55197 8.498571 9.580915 9.49983 9.968874 9.624427 10.19383 9.79729 10.48853 10.77697 + 8.643137 8.622834 9.379179 10.04107 10.14056 9.3327 9.441696 7.66965 6.918215 7.325087 8.433827 7.403569 7.932473 9.355262 8.961336 9.433534 8.987287 9.442863 9.373944 9.75194 9.910201 10.3459 10.44656 + 8.102217 8.064889 10.64028 12.49552 11.73663 10.07672 9.110008 8.321954 7.095238 7.711002 7.663853 7.130478 7.74688 9.022202 9.092591 9.239534 9.148391 9.078291 9.648328 9.942706 10.50384 10.56971 10.62924 + 9.490426 8.373809 10.40654 12.21494 12.46647 10.44266 9.246642 8.188566 7.077143 7.664156 7.372887 8.266142 8.489851 8.568101 8.872865 9.148156 8.987501 9.957211 10.15845 9.909985 10.00002 10.26888 11.01089 + 8.798372 9.025386 11.31425 11.42679 10.40138 9.216152 9.422606 8.502447 7.214077 7.507916 7.581383 7.426453 7.74972 8.678537 8.401515 9.35175 9.522068 9.689368 10.34969 10.18144 10.10829 10.22423 10.66045 + 8.333779 8.557695 11.21921 11.96504 10.46627 9.176018 9.10099 8.930181 6.847103 7.599282 7.893191 7.544654 8.840031 8.585423 8.405005 8.922948 9.007273 9.288807 9.946635 10.77755 10.62705 10.41732 10.66157 + 7.559142 9.412998 10.48524 11.38948 11.17182 9.945296 9.195613 7.687301 7.509073 7.597322 8.275542 8.369865 7.823867 8.430854 8.52591 8.722355 9.220226 9.689714 9.526666 9.805052 10.34926 10.81544 10.53098 + 11.4918 14.00084 16.17197 16.42617 15.349 12.41796 11.39773 11.66957 13.16477 16.12451 15.81399 11.20098 8.846268 9.76712 11.6804 12.1915 12.09149 11.27532 10.66243 11.10545 11.89396 11.18614 11.62189 + 12.7754 14.8082 17.40473 16.74525 14.93741 12.71457 10.89088 11.37673 13.37231 16.26893 15.81663 11.01917 8.918041 9.566416 11.83768 12.05284 12.66729 11.85449 10.60257 11.00357 11.39586 10.96889 11.1296 + 13.36541 15.34315 17.2086 17.66689 14.65784 13.48884 12.4741 12.45936 13.42722 15.72825 15.79719 14.43064 12.889 10.51247 12.3019 12.30175 12.62188 12.04293 10.42985 10.74694 10.95862 12.90817 13.67789 + 14.24038 16.24807 17.4501 18.67464 18.25082 16.41788 13.84389 13.58693 15.07749 17.34456 17.16127 16.20167 15.06416 11.77578 12.49449 13.45164 13.06607 12.11281 10.48501 10.73691 11.01208 15.49132 16.34476 + 15.46261 17.19522 17.5746 18.0107 18.14651 16.75021 13.80587 13.41014 14.9592 17.26956 16.178 14.19134 11.93522 11.6239 12.82757 14.12765 13.70803 12.50571 10.75355 11.29876 11.34688 16.21528 16.64844 + 15.85424 17.58728 17.14469 17.19608 18.15673 16.2019 13.98389 14.04934 14.00954 16.88185 15.97725 14.16334 13.0995 11.42474 11.70505 13.47377 14.31889 12.8265 11.54771 11.79184 11.55733 14.441 14.84616 + 16.01069 17.67813 17.21562 17.56873 18.24154 16.43555 14.16117 14.16953 13.69155 17.32711 16.4162 13.46104 12.36254 11.61799 11.27409 13.07141 14.62038 12.76868 11.54521 12.79095 12.39311 14.58929 14.84247 + 16.09941 17.7363 16.53284 17.27621 18.18447 16.58593 14.33624 14.35762 14.19332 17.44104 17.00833 13.70702 12.45344 12.21988 13.11712 14.56761 16.01712 13.74598 12.13099 13.26468 13.10818 15.27417 15.56255 + 16.42318 17.98415 16.44273 16.57448 17.62833 16.28909 14.36828 14.6948 13.78254 16.22694 15.95521 14.12572 12.26701 11.85083 12.46605 14.29742 16.13456 13.84185 12.26186 12.63923 12.99921 15.56506 15.71164 + 16.66626 18.41392 16.23549 16.69583 17.69269 16.16858 13.91554 14.21553 13.17823 15.73793 16.4865 15.50647 12.3832 11.67269 11.71129 12.98511 15.19916 14.09333 12.14127 13.53028 13.66361 16.01434 15.8486 + 16.93131 18.80218 16.81364 17.33029 16.89452 15.53996 14.12277 13.81145 13.03909 15.09264 16.55081 16.00311 12.3552 12.25566 11.77334 12.40888 14.75922 13.7299 12.90318 13.40209 14.23598 16.61812 16.00201 + 17.09422 18.93463 16.77671 17.12045 16.87137 15.12399 13.50143 13.57805 12.80646 15.09097 16.1608 15.57011 12.32053 11.78571 11.45637 11.75474 14.11037 13.6446 12.81923 13.51655 14.85688 16.60715 15.62787 + 17.18843 19.15834 16.90851 16.13819 16.45988 14.99436 12.40748 12.04965 12.14001 13.26226 14.0558 13.51968 12.57948 11.99215 11.86336 12.04673 13.09016 13.15625 12.4888 12.85295 14.979 16.59832 15.41977 + 17.2978 19.31523 17.34639 17.72629 15.35329 13.78927 12.61048 11.38221 11.57769 13.06238 13.21393 12.3947 11.35336 11.29097 10.76642 10.99077 12.29214 12.08838 12.20228 12.01544 11.86961 12.86051 13.13075 + 17.29455 19.39194 17.52913 18.08251 14.94142 11.73378 12.26912 13.0758 11.84843 11.48248 13.48376 13.39672 11.70031 11.98227 11.31891 10.61537 11.5765 11.5006 12.25064 12.40025 11.37915 12.90368 12.65543 + 17.11082 19.30302 17.25127 17.65386 14.90019 12.53856 11.45692 13.26181 11.62685 11.53579 13.36939 12.93143 11.07778 11.12064 10.86599 10.39632 11.41168 11.49042 11.78741 12.00982 11.57957 12.68554 12.28857 + 16.81596 19.11267 17.10374 17.62917 15.10644 12.49786 11.83172 13.11271 12.08539 11.51897 12.27075 12.25029 10.05081 10.51726 10.23621 9.723547 11.47403 11.38655 11.75697 12.38226 11.68046 12.32908 12.25521 + 16.18891 18.7452 17.12043 17.90645 15.35898 12.87751 11.93357 11.34936 12.12841 12.00346 12.70253 13.15777 10.02708 9.598401 9.508228 9.663599 10.49346 10.55344 11.21704 12.04108 11.25043 12.10459 11.84318 + 15.3587 18.25852 17.01021 17.94506 15.36013 11.68553 10.90639 9.600526 11.48932 11.83768 11.86593 12.23622 10.37516 10.22231 9.242025 9.690022 10.79908 10.51446 10.66708 11.09983 11.20814 11.95468 11.32153 + 14.94686 18.0086 16.66558 16.91915 14.43537 11.78186 10.37191 10.1009 10.64833 11.51232 11.21707 11.44729 10.38132 10.89793 11.71739 11.39077 10.99349 11.08029 10.52239 10.70206 11.1781 11.64449 11.60586 + 15.2814 17.80077 15.7858 15.0733 13.19273 10.99025 11.4507 10.23576 11.88874 11.69319 11.04233 10.65287 11.20542 12.47354 12.96547 12.31134 12.59687 12.5441 11.05464 11.68961 12.18429 12.52163 12.24349 + 15.48732 17.81838 15.57828 14.95755 13.17332 11.15086 11.35037 10.27524 11.15464 11.83677 10.82353 10.86964 10.84648 12.2185 12.01063 11.35811 12.14788 12.13265 10.27622 11.16301 10.85313 11.33077 11.19722 + 15.64028 18.04706 15.90875 13.46693 12.71794 10.47495 10.41679 10.41669 11.51304 10.97092 10.52732 10.51946 10.18956 11.28483 11.5248 11.06633 10.79301 11.08132 10.48834 11.23098 10.90977 10.93761 11.2342 + 15.691 18.08693 15.95903 14.5647 13.08687 11.96817 11.98348 10.27445 10.82906 10.65066 10.7676 10.49903 10.69828 10.99068 11.62179 10.48239 10.64531 10.73122 10.30917 10.84842 11.01107 11.19445 10.96024 + 15.70235 17.87411 15.54562 14.17106 13.73759 13.39945 12.94871 11.86754 12.32136 13.34113 14.04813 13.64429 12.8817 14.03526 13.78847 14.31763 14.08296 12.28475 12.26945 13.41342 15.16624 15.82314 14.65862 + 15.111 17.38759 15.23328 14.86325 16.06344 16.10236 14.34899 14.72656 14.66246 16.20999 16.94175 17.2274 15.76645 16.78901 16.12683 16.99647 16.62846 13.99079 13.86968 16.12244 18.25901 19.34782 17.66724 + 15.03301 16.61184 14.17075 13.25705 14.54141 14.69707 13.71418 15.49278 15.08241 16.18828 17.16152 16.65724 15.34151 13.99803 13.97429 15.01542 15.35275 14.87416 14.55297 15.45949 16.31717 18.42344 16.47798 + 13.45951 15.78569 13.98534 13.04344 13.92377 14.24774 14.06853 15.00025 15.36809 16.57527 17.38427 17.02029 15.19632 14.64439 14.65536 14.64023 15.68649 15.49167 14.9104 15.35289 16.33175 18.0865 16.37584 + 13.07347 14.7915 12.67954 13.23848 14.1819 13.9683 13.21752 14.69234 17.90232 17.24359 17.5149 18.04125 15.55333 15.03565 14.85524 15.23376 15.60953 15.83141 15.17968 15.23778 16.42048 17.88067 16.92698 + 12.37712 14.9033 13.8624 13.76913 13.30324 14.3478 14.02929 14.99968 18.80645 18.39549 18.51047 18.57759 16.0035 14.5608 15.19788 16.24825 16.87722 16.25792 15.09623 15.11478 16.32289 17.68389 16.08194 + 12.66646 14.60857 12.63233 12.64944 13.4228 13.81045 14.2454 15.89087 17.83408 17.56272 18.75677 18.45625 15.79576 15.1664 15.52465 16.30447 17.33408 16.53073 14.91176 15.41308 16.24126 17.18274 15.97926 + 12.81794 14.79919 12.64581 13.73917 14.27735 12.86728 13.65656 16.11627 17.94633 17.98828 18.37813 18.78796 17.11118 16.00847 15.83047 16.21775 16.80949 15.5775 14.92074 15.60607 15.80383 16.84433 15.66324 + 12.5034 15.02809 13.34704 12.59922 13.16282 13.18943 13.6498 16.22042 17.74181 18.11487 19.01717 18.76182 16.68096 15.37317 16.47843 15.88386 16.60799 16.23045 15.78561 15.60193 15.58282 16.25681 16.40265 + 13.06095 14.47213 11.57626 11.60358 12.57563 13.76851 13.97735 14.38274 16.31401 17.55055 18.43916 18.5317 17.04531 14.99704 16.53685 17.02856 17.58887 16.26225 14.9763 14.45201 15.51912 15.21459 16.6817 + 12.86505 15.85786 14.75419 13.01475 12.67307 14.4433 15.20655 15.15495 16.09785 16.51936 17.95182 18.31379 16.75537 15.01732 15.75735 16.82045 17.44093 15.66828 14.33217 14.62619 15.22149 15.17155 17.20671 + 13.12523 16.5502 15.50594 15.34845 14.73641 15.80987 16.79601 17.06586 17.48354 16.89506 16.9989 17.87918 16.51353 15.33819 15.52597 17.10384 16.88856 15.24374 15.05034 15.51818 15.27853 14.60615 17.90415 + 12.69545 15.62294 14.66864 16.31116 15.64141 15.63712 16.38996 17.50281 17.90165 17.66326 17.61484 17.62272 16.00488 15.10813 14.94744 17.00407 17.49522 15.62474 15.2027 15.69592 15.58376 14.26855 17.33854 + 11.70221 15.91556 15.21819 16.73549 15.93421 15.34525 15.80453 16.35826 17.22446 17.98482 17.83851 17.86388 16.83107 16.10304 15.82976 17.13237 17.91541 15.26026 15.10075 15.98048 15.72246 14.22937 16.43557 + 12.58039 16.54533 15.48762 17.14302 16.20825 15.26482 15.79737 16.80904 17.53083 17.92554 17.57588 16.92835 16.21835 16.24897 16.26789 16.09962 16.68681 15.19278 14.3501 15.73407 15.31177 14.58012 16.44425 + 12.52427 16.68682 15.6768 17.41134 16.48487 16.26741 15.93352 16.79063 17.23722 17.75588 17.59963 16.55783 16.45605 16.19305 16.34012 15.8233 16.01214 14.49679 14.05411 15.83327 15.75738 14.70327 16.81463 + 13.08901 16.92737 15.88609 17.48892 16.60913 16.92618 15.98914 16.84229 16.96335 17.23575 17.33563 17.23502 16.5829 16.31644 16.85165 16.5601 16.59091 14.8695 14.04865 15.1961 15.04456 15.03072 16.76081 + 13.25131 16.82976 15.65168 17.33111 16.53403 16.99053 16.30228 16.67911 16.8145 17.26553 17.52997 17.40855 16.6225 16.19843 16.2693 16.43582 16.03738 13.90187 14.50136 15.9589 15.88366 15.52198 16.96512 + 12.86011 16.4959 15.32254 16.57291 15.98928 16.51817 16.59031 17.21095 17.32273 17.24012 17.26693 17.4594 16.63605 16.95958 17.0414 16.83618 16.73441 14.66106 14.54188 15.98279 15.59871 15.42995 16.82753 + 12.3734 16.38073 15.23618 15.71347 15.76168 16.80319 16.83652 17.01589 17.01722 16.75942 16.97372 17.74806 16.4648 16.73439 16.26514 16.33158 16.27448 13.83779 14.71891 15.37935 14.90931 15.09158 16.92881 + 13.16311 16.98702 15.90418 16.86047 16.45071 17.14736 16.50004 16.52925 16.95103 16.78541 16.71283 17.1481 15.68781 16.3924 15.7757 16.42943 16.24413 13.86384 14.62436 15.48191 14.93738 14.84517 16.21951 + 13.59746 17.23912 16.12656 17.50044 16.93601 17.43536 16.78477 16.41955 16.75596 16.41606 17.25539 17.49482 16.25328 16.44511 15.88677 16.52536 16.53255 14.46775 14.81169 15.79123 14.8385 15.43922 17.17949 + 13.25004 16.94229 15.93826 17.73337 17.23859 17.89079 17.34496 15.97857 15.19893 15.15988 16.91029 17.25496 16.62859 16.25416 15.48432 15.56355 16.21918 14.83444 15.0622 15.81797 15.64522 15.32866 16.89268 + 12.62537 16.47641 15.74364 17.85862 17.47602 18.16114 17.55453 15.95657 15.11439 15.08639 16.68707 16.74309 16.72464 16.83375 15.94381 16.12422 16.87457 15.30209 14.94832 16.63556 16.4691 15.57759 17.3871 + 12.6226 16.10576 15.56736 18.04713 17.56757 18.11768 17.59097 16.34696 15.375 14.14986 15.13968 15.70977 16.85783 17.35108 16.21252 16.49694 16.90446 14.97466 14.87337 16.36794 16.10093 15.90252 17.58858 + 12.7855 15.88645 15.67985 18.15505 17.37622 17.52381 17.42296 16.19477 15.50058 13.98604 15.38529 15.37528 15.93515 16.47197 15.3381 15.97862 16.40454 14.95582 15.0605 16.63037 15.63746 16.15078 17.13511 + 12.65207 15.56413 15.72229 18.15676 17.02139 16.67873 16.7427 15.08276 14.19359 12.79751 14.48611 15.64405 16.11738 15.6327 14.42156 14.5413 15.50612 14.09361 14.9137 16.91826 15.45331 16.1494 17.52712 + 12.56314 15.1539 15.81251 18.0403 17.20735 16.9832 15.43454 13.55827 13.10696 12.59839 13.23814 15.90523 16.60976 15.61129 13.46397 13.59857 14.55115 13.29045 14.68942 16.51844 14.84454 16.06714 16.90926 + 12.64222 15.16426 16.14207 18.01224 17.03122 16.82287 13.88338 12.87623 12.53724 12.11878 13.98522 15.42566 15.64351 14.8041 13.28969 13.65548 14.46269 13.32662 13.92385 14.84129 13.31076 15.09256 15.82777 + 12.85059 15.56986 16.29726 18.16373 16.31842 15.27977 12.30446 12.48871 12.05114 12.02475 13.32861 15.53581 15.44006 14.6188 12.19517 12.34837 13.52474 12.41385 13.52724 14.1898 12.92852 15.22741 15.49917 + 12.59761 14.4621 15.45572 17.18511 15.81542 15.78824 11.84854 11.87338 12.32981 11.94361 12.86972 14.26315 14.89518 14.27585 11.97713 12.49144 13.58669 12.65414 13.09633 13.75735 14.88413 16.18767 15.3166 + 12.64882 14.81147 14.45962 16.38583 15.72507 15.59489 12.376 11.95343 12.09104 11.86625 12.24266 13.68499 13.91463 13.24626 10.7595 12.1026 13.03325 11.85887 12.62869 13.85928 16.20368 18.33456 16.91249 + 12.12053 15.05175 14.22981 15.73134 14.97451 14.68129 13.12028 11.97819 11.38219 11.20992 11.37042 12.24603 13.25563 13.08652 10.43595 10.82252 11.63596 11.33452 11.86574 13.24061 15.52648 17.4119 16.81245 + 11.19065 14.21162 13.51477 14.70132 14.9847 15.25536 14.19143 12.48769 11.34493 9.814653 9.99059 11.53341 12.29802 11.784 10.16933 10.75036 11.20462 10.74964 11.48954 12.01296 13.41964 14.80476 14.38404 + 10.00999 12.74599 12.14843 14.51654 15.13391 15.2609 13.72731 11.66748 10.16199 9.022615 10.54656 11.04408 11.06597 10.65407 9.941639 9.674333 10.40516 10.81487 11.25098 11.6855 11.23007 11.83496 12.85696 + 10.08466 11.83495 11.54785 14.59242 13.85901 13.03223 12.44154 11.23707 9.762304 8.823195 10.68114 10.62345 10.76976 10.03955 9.436696 9.586202 11.22563 10.83237 11.0967 10.70838 10.57485 11.49634 11.70702 + 10.48889 12.83749 11.55844 14.30776 13.98957 13.29756 10.27051 11.19239 10.73191 8.282329 9.798191 11.28903 11.10856 10.43637 9.679453 9.696969 10.23166 10.5042 10.2436 10.84797 10.9094 11.14272 11.04821 + 10.19536 11.74172 11.33944 13.41399 13.06223 13.24977 10.40681 9.719469 9.504123 8.071562 9.28103 10.37499 11.08919 10.83884 9.125082 9.426393 10.12565 10.30615 10.62199 11.02502 10.98999 11.49767 10.76202 + 10.88223 12.977 11.56636 10.88618 12.75476 12.96493 10.24409 9.20118 8.650577 7.399164 8.780226 9.993423 11.50119 11.16004 9.309609 9.911741 10.38707 9.787494 10.5507 10.78142 10.8794 11.07239 10.47661 + 10.47173 13.69682 12.45944 12.35382 12.58801 12.46847 10.00025 10.27305 11.53972 12.61611 13.00516 13.0168 12.24968 12.74772 13.46355 13.35037 12.67452 11.07662 10.77348 12.34726 13.52226 13.54476 12.45269 + 10.39999 12.38218 11.96567 12.83998 11.78783 11.14596 10.65086 9.983682 11.39105 12.32884 12.81081 12.60661 11.70481 12.39304 13.20282 13.14799 12.67365 11.12111 11.64005 15.3785 17.26889 19.2809 18.58731 + 10.06194 11.97701 11.10652 11.85843 11.02539 11.2265 10.7828 9.873035 10.32476 11.25525 11.96012 12.71968 11.64478 11.76205 12.47315 13.18736 12.99789 12.38262 13.63724 17.6046 20.06792 21.4036 21.43807 + 9.509731 11.85916 11.10777 12.50954 12.18235 11.80091 11.27237 10.29496 12.2601 12.32322 13.42 14.12483 13.16052 13.71877 13.45849 13.22503 14.22825 13.49225 15.37626 19.22064 21.55962 22.73142 22.24018 + 9.15207 11.07175 10.86126 11.87928 12.69756 12.46886 11.5245 13.08445 13.88625 14.80505 14.99481 15.52319 15.05282 15.02273 14.87423 15.29251 15.91438 14.93134 16.80274 21.40077 22.54545 22.58663 22.29738 + 8.860111 10.74111 10.50416 12.93807 12.55079 13.06175 12.17259 13.51095 14.48125 15.87022 17.08365 15.86352 15.00874 14.95488 15.34727 15.18754 16.02795 15.03839 16.93264 19.53366 21.6056 21.50261 21.28786 + 10.75877 10.37344 10.58075 12.34408 12.94353 11.96778 11.4975 12.68404 14.95128 16.74927 16.77153 15.63198 13.98707 14.3226 14.68699 15.35497 16.36192 15.49951 15.98009 17.65331 18.19219 18.41393 18.1715 + 9.39485 10.52738 11.42019 12.21228 12.45682 12.18025 11.33037 12.44518 14.51794 15.84477 14.62877 14.42839 14.07113 13.2896 13.65752 13.82688 15.6779 15.75582 15.67209 17.08607 16.55664 17.27306 16.92216 + 9.381274 11.83695 11.8863 11.62455 11.99966 11.92766 12.16977 12.76743 14.2169 15.01731 14.82383 13.0397 13.42383 13.10484 13.42112 13.71131 14.73178 14.64882 14.79978 16.09834 16.16719 17.4647 16.77292 + 9.585428 10.993 10.5035 11.81598 11.44083 12.43314 11.64416 12.2522 14.10823 14.41961 14.19406 12.61582 11.76546 12.10949 13.28017 13.21444 14.49621 14.27315 14.40105 16.25966 16.55149 17.44991 16.81313 + 8.175888 11.18484 11.35472 11.47145 12.36835 12.95294 11.74024 12.37499 14.70968 14.42316 13.73902 12.62927 11.59597 12.07641 12.50259 12.79706 14.06515 14.19124 14.13676 15.15194 15.65369 18.23908 17.15416 + 9.260625 10.70815 9.263671 9.806908 11.83224 12.31308 11.73443 13.4353 14.60034 15.05972 13.83386 12.88395 11.57649 12.02801 12.20291 12.59455 14.31687 14.47969 14.6405 15.52516 15.67438 18.1055 17.65921 + 9.911335 10.50611 10.12131 9.937845 12.0217 12.06643 12.41577 13.58587 15.64432 14.32141 13.08726 12.30006 11.95351 12.71829 11.26942 12.65187 14.17917 13.53116 13.70112 15.10717 14.98607 17.59751 17.46946 + 9.024209 8.987809 9.160165 10.86254 12.75719 12.29259 12.99271 14.01397 14.93609 15.38431 14.07591 12.15879 11.33199 11.99755 11.29723 12.28741 13.99432 13.90781 13.2847 14.09958 14.27385 16.84444 16.68974 + 11.9299 13.47678 12.837 11.34953 12.98505 12.79702 14.93977 14.99091 14.8044 15.23901 13.70815 12.30987 11.19355 11.14724 11.14456 11.97139 13.38016 13.39131 13.10051 13.16111 13.63137 15.1045 15.48153 + 14.41228 16.11685 15.7402 15.5474 13.80078 14.53132 14.65797 14.65964 15.91533 16.35481 13.96598 12.8188 11.46816 10.90168 10.61743 11.47446 13.77556 13.64553 13.89567 13.91599 13.57935 15.20967 15.69138 + 15.08783 16.8548 16.49383 16.41818 14.09665 15.30241 14.7049 14.89885 15.83918 18.0921 16.22671 14.06109 11.65885 11.18969 11.55042 12.64634 15.04636 14.6538 14.17054 14.18222 15.13279 16.13375 16.41827 + 15.16109 16.7801 16.56729 16.43837 15.12475 14.8846 14.26196 15.39288 16.01123 17.1432 17.07575 15.71479 12.39699 11.93664 11.86322 12.98023 15.49663 15.14287 14.6057 14.86261 15.40321 16.85805 17.07797 + 15.09084 16.57223 16.80362 16.58635 15.20792 15.10697 14.90998 15.40153 15.35094 16.88487 17.96318 16.37918 12.55137 12.20782 12.30409 12.03328 14.67583 15.03111 14.56669 14.42755 15.211 17.10543 17.10053 + 14.69408 15.81541 16.46612 16.37843 15.2229 14.59921 13.61355 14.3778 14.58977 16.18752 17.5792 16.62926 12.41473 12.08434 12.35257 11.9434 14.27981 14.79067 13.80497 13.96159 14.25573 17.45439 16.78282 + 14.43095 15.41959 16.21408 16.07892 15.18807 14.0085 13.96235 14.37799 14.08463 15.0561 16.641 15.33981 12.0121 10.58257 10.67117 11.07191 13.45955 14.30978 13.5234 13.39615 13.00758 15.30398 14.59562 + 14.58677 15.82187 15.58251 15.65558 15.2996 14.34471 13.48909 13.53928 12.62957 13.79965 15.50717 14.88582 12.17444 11.02395 10.55875 10.28314 11.87372 12.80804 12.80521 12.87114 12.06493 14.00245 13.72964 + 14.95683 16.3266 15.16857 15.4292 15.51012 13.59986 12.23133 12.66695 12.21721 13.14255 14.3418 13.26337 11.4309 11.01019 10.59134 10.42654 11.62912 13.19194 13.29006 13.23644 11.81969 14.27526 13.76118 + 15.59626 17.08241 15.06971 15.65379 14.82292 13.31317 11.43343 11.9617 11.85537 12.2777 14.29009 13.45866 10.72894 10.13381 9.537953 9.800446 11.53536 12.31185 12.60432 11.92848 11.34388 12.84455 12.54369 + 16.04304 17.82648 15.79309 16.24393 14.73321 13.42411 10.97739 10.73002 11.65459 12.07827 13.2604 12.44436 10.10683 9.841578 9.451722 9.291868 11.41494 11.8923 11.88242 11.91761 11.27107 12.20158 12.1325 + 16.25625 18.22469 16.04192 16.12708 14.96282 13.00054 10.65593 11.17855 11.14046 12.55776 12.52015 11.42063 9.433226 9.00628 9.585645 9.290247 10.70464 11.49628 11.68974 12.07785 11.17581 11.06459 11.13168 + 16.04482 18.14673 15.86384 14.91284 13.05532 12.45239 11.72008 11.51588 11.29592 11.78518 12.2973 11.38977 10.29393 9.548064 9.722668 10.09043 10.84775 11.8718 11.26131 11.56782 11.02544 11.18756 11.03338 + 15.26615 17.28764 15.16505 14.44016 13.28143 12.07429 10.97578 11.15899 11.50891 11.01097 11.61723 11.36335 10.16722 9.822009 9.901525 10.20638 10.18853 11.82158 11.44402 10.68624 10.50383 11.11971 11.41882 + 13.81127 16.00517 14.23292 13.67491 13.21358 11.73995 9.486867 10.56567 9.862735 10.49043 11.29869 10.67811 9.464268 9.29777 9.709767 10.42091 10.48922 10.93209 10.42687 11.04964 12.2851 12.72577 12.39185 + 12.14262 14.94287 14.0802 14.32626 12.80348 10.66512 9.237948 9.739904 9.596913 10.61011 11.65724 10.63011 9.505305 9.886621 10.47523 11.0215 10.59563 10.78076 11.00128 13.60528 15.06756 16.77889 16.86555 + 10.83472 14.31258 12.90632 12.77348 12.20279 9.816229 9.277019 10.18015 9.096459 9.997322 11.51482 10.87203 9.44985 10.83187 12.01145 12.17475 12.17965 11.82202 12.18132 14.90107 17.46739 18.73794 18.04218 + 11.36189 14.46365 13.13914 12.11007 11.7593 10.0019 9.75862 10.77737 11.03628 12.26316 12.78038 11.30242 11.24927 12.86973 13.40784 13.56777 13.70109 13.02316 12.83176 16.09006 18.6455 20.18859 19.64919 + 12.72338 15.11341 13.32158 12.74039 11.63489 10.73177 10.17774 10.56085 11.74206 12.8467 13.64448 12.64196 13.06981 14.0199 13.50293 14.09397 14.45456 13.70243 13.05322 16.6385 19.08248 21.01362 20.21127 + 14.20404 15.91786 14.92538 15.12413 14.77285 12.89441 12.79587 11.85586 12.40155 12.80069 14.29893 14.05416 12.61579 13.57712 13.58947 13.30546 13.65021 12.84343 13.35256 14.62488 16.85373 18.83813 18.01679 + 14.53132 17.33943 16.26635 18.11593 17.92229 16.41659 14.97751 13.63034 14.93866 15.25947 16.20634 15.82948 14.33713 12.11738 13.05697 13.88322 14.07832 13.04026 13.09391 14.61522 14.58644 16.06195 17.62827 + 14.11968 16.69542 15.12335 18.32276 17.78468 17.74669 15.92803 14.50374 15.56971 16.23568 16.50482 16.08389 14.88408 13.72153 14.5031 14.91234 14.72964 13.03544 12.99891 14.99354 14.95278 15.26584 17.54221 + 12.58309 15.06906 15.59264 18.20675 17.21118 17.89225 16.83617 15.57529 15.21058 16.55922 16.91265 16.39316 15.46596 14.28004 14.31382 15.09121 15.5357 13.50103 13.16001 15.68369 15.05554 15.30483 17.25786 + 13.38149 16.1832 16.11864 18.42098 17.48438 17.89621 18.30592 16.22846 16.11395 16.84072 17.24339 16.6131 15.43338 14.83396 15.42686 15.86161 16.32101 15.09858 13.3338 15.44106 14.9978 14.34465 16.55215 + 14.37599 16.83687 16.94507 18.2267 16.84422 18.06699 18.55002 15.54701 16.76327 16.83081 17.27568 17.00946 16.32395 15.44895 15.63621 15.85781 16.74874 15.47261 13.73446 15.28013 15.02808 14.89976 16.14604 + 15.05994 16.78429 17.38232 18.71122 17.29902 17.89909 18.18792 17.06817 16.19571 16.4189 16.93696 17.02257 16.01795 15.9466 15.9529 16.66254 17.07906 14.79625 13.80007 15.45906 15.62278 14.89583 16.3634 + 15.31985 17.11125 16.90094 17.50673 18.12416 17.26594 18.61826 17.81363 16.92988 17.33131 17.22307 17.6853 17.16475 17.8327 17.79674 18.01369 18.75657 16.41342 14.83692 16.64419 17.08493 16.10439 17.74908 + 14.81287 16.67113 17.24438 17.58853 16.56671 17.4409 19.14317 17.1272 17.22141 17.37194 17.30178 17.35553 16.81259 17.59592 17.2289 17.99676 18.54756 16.97488 15.1711 17.01239 17.41453 16.61493 18.02877 + 14.10214 16.48185 16.70473 17.83863 17.09863 17.92168 18.60074 17.03748 17.01916 17.1662 17.45386 16.9503 17.22705 17.88758 17.25076 18.06163 18.82708 17.06891 15.6639 17.32082 17.86867 16.99368 18.4935 + 14.47095 16.27239 17.20447 16.68737 16.69925 16.92639 17.55458 16.4129 16.37072 16.70506 17.13801 16.74328 16.66209 17.66596 17.03108 17.52262 18.5179 16.57609 15.3233 16.59836 16.57953 15.76227 17.69633 + 13.24856 14.56392 16.16074 15.96923 16.11824 17.0615 17.37887 16.89696 16.49023 16.93359 17.04477 16.61666 17.3206 18.46787 17.4531 17.96162 19.10358 16.9934 15.63334 17.35444 17.27749 16.49334 18.51469 + 13.37477 14.40732 15.3166 16.12179 16.0549 17.9857 18.24229 15.97747 16.51573 16.80781 17.66976 16.77187 17.07391 18.37435 17.8941 17.99025 18.43793 16.58463 15.94918 17.33995 17.58286 16.71625 18.26147 + 13.93172 15.95009 16.12278 16.62806 16.77155 17.70332 18.30991 16.70022 16.12438 16.63647 16.96805 16.56441 16.83017 17.72108 17.19194 17.83681 18.34489 16.32563 15.5139 17.0459 17.14361 16.61393 17.9541 + 13.97243 15.71532 14.24013 15.94024 16.42779 17.24181 18.20842 16.16203 15.17454 15.77178 16.21501 15.67723 16.35604 17.39831 16.76721 17.22853 17.88738 15.95963 14.72727 16.41531 16.48671 16.12189 17.57236 + 13.12301 15.36403 14.92359 14.51013 15.03061 17.25054 18.02694 15.68099 14.72595 15.05695 15.51794 15.62031 15.82822 17.21599 16.45444 16.81317 17.53438 15.40422 14.59688 15.75735 15.82233 15.50435 17.19834 + 13.63734 15.75846 15.76891 16.33092 16.02224 15.02408 15.51878 13.95916 13.93933 15.34064 15.0723 15.51362 15.4393 16.63021 16.81165 16.50006 17.1815 15.69489 14.01058 16.13823 15.96146 15.71183 17.02876 + 13.19862 15.13811 14.20608 14.87641 13.86195 15.69343 16.0471 14.37471 12.70754 13.07089 13.74677 13.72397 14.30151 15.42236 14.87322 14.77012 16.19817 14.61831 14.36353 14.7163 14.1343 13.27196 14.94497 + 13.07108 14.96432 15.33887 15.41621 16.32788 16.2543 15.70077 13.64809 12.23586 13.97429 14.36621 14.99106 14.89284 15.73454 15.09936 16.08811 17.21342 14.54043 14.93736 16.18698 15.30752 15.68343 17.1031 + 12.17307 13.8663 14.74691 13.82833 15.29623 15.13898 14.94032 14.15431 13.22405 12.60576 13.50053 13.70859 14.2374 14.95605 14.1026 13.79868 15.32834 13.637 13.26627 13.85343 12.49579 13.00945 15.18009 + 12.25888 13.0473 13.98215 15.20883 14.53955 14.94806 15.02145 12.94323 12.06552 12.47472 12.65622 12.89004 14.31748 15.0515 13.45358 13.49286 14.73266 13.38384 12.97834 13.98633 13.04967 14.18903 15.84389 + 12.96655 13.67219 15.57411 16.78977 16.06032 13.93955 14.09687 13.42214 11.74005 12.39577 12.6212 13.11872 14.73195 14.7253 13.47528 13.54747 14.39114 12.98527 13.10725 14.80631 13.07693 14.86841 16.53499 + 10.92069 13.71753 13.87495 14.55451 14.22817 13.57006 13.76763 12.60664 11.17306 11.62393 12.25004 11.81037 13.68605 13.56421 12.86382 12.15489 13.24436 12.0221 12.38628 13.08033 11.34459 12.62064 14.02351 + 11.5769 13.79373 14.03928 14.87669 13.80563 13.71551 14.04329 12.57617 11.19479 11.37623 10.92707 11.98935 12.46576 12.69549 12.09219 11.78906 13.35041 11.86954 12.23488 13.13238 10.95979 13.09149 14.30729 + 10.74847 13.18716 13.24313 12.67642 13.39273 12.77279 12.68126 11.46781 10.00143 9.96587 10.43531 11.69773 12.84946 12.46179 11.33073 10.75771 12.40113 11.34042 11.7729 12.49863 11.20993 11.8419 11.45071 + 11.98419 13.92745 12.27599 12.76547 12.93638 12.34464 12.64864 11.34802 10.23944 9.272176 10.22678 11.26323 11.94163 12.36338 11.0064 10.31246 12.27957 11.23496 11.376 12.09842 11.01261 11.91821 11.30618 + 11.78683 13.45012 12.74603 13.96315 13.49791 12.03139 12.34809 11.16278 9.914504 8.632698 10.02429 10.49186 10.53503 11.25449 10.37139 10.6025 11.64441 10.73072 11.01634 10.47035 9.727706 10.35247 10.77614 + 11.52162 12.46663 11.89697 14.03308 13.64052 11.73958 11.48232 9.956855 8.571227 8.986975 9.7626 10.39963 10.45375 10.46915 10.78598 10.67382 11.57074 10.30212 9.981796 10.63711 10.12906 10.43168 10.83299 + 10.47112 11.29303 12.18044 11.88793 10.8442 10.59727 11.06464 9.595164 9.016017 8.599607 8.99171 9.042683 10.83571 10.81611 9.935513 10.24435 10.53577 9.991421 10.32891 10.49404 10.43093 10.59912 10.33619 + 11.11114 12.00806 12.1118 11.56301 11.28773 11.11582 11.11947 10.14109 9.354194 9.394133 8.459903 9.571765 10.62552 10.94563 10.39587 10.17176 11.07636 10.36478 10.18448 10.5289 10.58135 11.55 12.22885 + 9.4698 10.58114 11.28397 11.78697 11.88663 11.19909 11.94986 8.947301 8.886659 9.0145 8.525748 9.001356 10.4408 10.03337 9.662758 9.838831 10.64479 9.835432 9.941095 11.35219 12.8765 13.6802 13.69769 + 9.431818 10.37749 9.402466 11.65605 12.08712 11.54609 11.73875 8.867339 9.922234 10.61318 10.76134 10.87708 10.16173 10.49702 11.13492 10.97119 10.87446 9.942475 10.69347 12.76756 14.78555 15.63049 15.3683 + 9.377582 10.94667 11.15134 12.46202 11.73515 10.88063 11.25175 9.65536 11.14065 11.88232 11.94413 11.89391 10.90223 11.40995 12.1747 11.62114 11.59762 10.78957 11.37593 13.46099 15.81433 17.16356 17.15998 + 9.576265 11.13453 10.96931 10.33049 10.23858 10.44758 10.76839 8.92027 9.525447 10.34433 9.90531 9.858282 9.904203 11.16824 11.88748 11.96853 11.37809 11.49845 11.76391 14.43392 16.65162 18.26472 17.6829 + 9.068971 10.9832 11.37302 11.22971 9.851135 9.574883 9.735991 9.078069 9.105554 10.11883 10.55576 10.29943 9.432137 11.80125 12.00973 12.56134 12.2724 12.0964 12.37772 14.91978 17.71165 19.49631 18.86863 + 10.06087 11.30585 10.13232 9.214253 8.846772 9.325168 10.23292 9.699574 10.61134 11.65377 12.32304 11.8669 11.56203 13.31346 13.75598 14.85218 14.10346 13.62769 13.95514 16.67099 18.7434 19.90597 20.01846 + 9.883128 9.034005 10.26573 9.922016 9.431784 8.751758 10.03959 10.56669 12.11162 13.17491 13.19539 13.8256 12.93738 14.20389 14.85687 14.53677 14.83226 13.86686 14.76633 17.12251 20.07998 22.08923 21.37822 + 9.735471 10.76163 10.26859 10.09679 10.99103 9.163989 9.649745 10.54053 11.75659 12.85315 12.67314 13.1372 12.42263 13.90682 15.30728 15.41667 14.59862 14.48736 15.16387 17.94337 20.98712 23.08864 22.34081 + 8.208311 9.269901 9.024371 9.993098 11.19902 9.208381 9.769848 11.40966 12.96586 14.02102 14.22982 14.19959 13.32056 14.34479 16.31928 16.57144 15.62925 14.52523 16.18148 18.67118 20.88604 23.1573 22.48557 + 8.409505 9.858494 9.497688 10.31458 11.88834 9.982258 10.32621 11.68756 12.89914 13.39427 14.21135 14.64743 13.3156 14.29278 16.14828 15.96886 15.35177 15.5271 16.91822 18.72905 21.57679 23.61708 23.15364 + 8.934703 9.573559 9.441955 8.765581 10.14542 9.618201 10.5309 11.58863 12.7027 13.85705 14.36015 14.13195 13.7818 15.45178 16.22048 15.6483 15.75696 15.26135 16.86555 19.28024 22.11215 24.40104 23.93007 + 8.684306 8.866581 8.434036 8.029984 10.91321 11.22698 10.23968 11.33583 12.85784 13.39227 14.42832 14.13936 13.58225 16.27074 17.07727 16.51017 16.3993 16.14433 16.99274 19.69513 23.2365 24.59908 24.04222 + 8.643711 9.807123 9.50042 9.324292 10.83774 11.15303 10.39372 11.22418 12.95454 13.35421 14.3774 13.54205 13.72393 17.05115 17.68932 16.12386 15.83425 16.01268 17.58204 19.77008 23.01275 24.67944 24.14307 + 7.688036 8.535404 9.236469 10.83574 11.49044 11.28016 11.46384 12.16683 13.50681 13.8899 13.76011 13.80902 13.72299 16.50299 18.20104 16.61069 16.52741 16.1986 18.36386 20.11685 22.81937 23.6178 23.35131 + 10.17826 8.205004 9.347319 12.3267 13.34488 11.22051 10.90597 11.83232 13.47991 13.05177 12.89349 13.7592 13.9114 16.77988 18.02056 16.96051 16.41222 16.26488 18.08109 20.25217 22.95943 23.70821 22.32704 + 9.040493 8.760096 8.527176 9.89751 10.56365 9.972799 10.10701 10.67076 12.86245 12.45882 13.2768 14.06905 14.12293 17.41031 18.83172 16.48821 16.42317 16.09177 17.95219 20.02211 23.01787 23.78878 22.42188 + 9.399467 7.837672 9.216712 10.6783 10.54392 10.52287 11.50509 11.89538 12.42534 13.73793 12.68215 13.53249 13.51577 16.23136 18.68464 17.29062 16.49525 15.83475 18.22473 19.69581 22.15342 22.9642 22.44792 + 8.776668 9.244227 9.925127 11.38309 10.78001 10.8051 10.342 11.05655 12.77748 14.84761 13.69246 13.08996 13.35411 16.14378 18.69108 17.32467 17.7679 16.45478 17.57494 19.5618 22.46428 22.97581 21.49464 + 8.894381 9.427493 10.64883 11.46896 10.78124 9.074279 10.21656 11.47114 12.82468 12.99811 12.95543 12.60641 13.26145 15.72201 18.2295 17.42356 17.95378 16.7246 17.54635 19.24829 21.3367 21.933 20.77688 + 9.042042 8.76036 10.59839 11.72806 12.2252 10.01876 10.65936 11.28481 12.38915 12.18661 11.73761 12.19487 12.95884 15.87654 18.47887 17.35869 17.52493 16.28156 16.84913 18.45013 20.72539 20.79898 19.75169 + 10.06297 12.90782 12.88049 10.60552 11.71332 10.51397 9.21656 10.82334 11.41065 12.40258 13.10792 13.42447 12.83565 15.32679 18.56764 17.4046 16.69835 15.57237 16.41321 17.4268 18.71982 19.50741 18.1189 + 9.921656 16.52995 17.53824 15.70275 15.32331 12.92085 12.47987 12.10413 12.42868 12.15174 12.5522 11.8612 12.07436 13.91121 17.06873 16.3721 16.04488 15.49017 15.58386 17.01062 17.89955 17.60539 17.31772 + 11.36264 17.33499 18.40477 17.00244 18.4658 15.7809 13.04894 11.71813 12.67283 13.29064 13.457 12.057 11.66851 13.66247 17.68314 16.57116 15.98984 14.92666 16.06848 17.17213 17.39293 17.66684 17.4516 + 10.62282 17.60542 18.32822 17.09484 19.33393 16.77328 12.53772 11.13757 13.03852 14.02408 14.38111 13.17555 12.76845 14.38874 17.52058 16.74355 16.38338 15.24556 15.39419 16.26055 16.64132 16.97384 16.89183 + 10.47606 17.70844 18.43419 17.68979 19.75669 16.95199 11.87117 12.01979 13.45656 14.36295 14.81179 13.49354 12.68675 14.77314 17.4999 16.20375 15.68843 15.2202 15.67017 16.32603 16.47589 16.68805 16.65318 + 10.98051 17.72518 18.46542 18.05853 19.93608 16.77472 12.27509 12.2058 13.27803 14.52329 15.10997 13.82026 12.10452 13.67547 16.55763 15.52405 15.14251 14.49046 15.37576 16.78892 16.64076 16.92625 17.4085 + 10.61574 17.7157 18.246 18.44892 20.22108 17.01719 13.5045 12.65141 12.83893 14.40987 15.02312 13.29914 13.55334 15.01744 16.19461 15.84118 15.6518 14.68441 15.11373 16.25138 16.23415 16.90338 17.4352 + 10.69256 17.79112 18.42277 18.3324 20.11359 16.95714 13.75263 13.08895 13.11321 14.44533 15.22537 13.40903 13.27475 15.41946 15.46931 15.14482 15.65731 14.71926 15.28069 17.00951 16.92454 17.32482 17.49486 + 10.73899 17.75406 18.27556 17.87709 19.47082 15.97545 13.59863 13.1574 13.07014 14.04729 14.62672 13.32558 12.45246 15.42138 14.76762 14.0249 15.21964 14.52955 15.10038 17.08111 17.13165 16.41658 17.86931 + 9.618335 17.47857 17.98661 17.55681 18.80152 14.7733 13.48202 12.65518 13.07832 13.56103 13.67241 12.99241 12.99369 14.52666 14.21892 14.50008 15.0451 14.01138 14.70819 17.09094 17.17188 17.34347 17.56815 + 11.57962 16.64433 17.44956 16.3053 18.07066 14.92957 13.12261 12.80251 13.23727 13.17543 12.1275 12.36365 13.38163 14.66714 14.47845 14.50121 14.2356 14.29019 15.07313 17.368 19.52579 21.40561 20.27804 + 10.79007 16.8456 17.36958 16.39471 18.20171 15.12339 12.79474 10.63306 11.83869 12.54484 13.22725 12.38338 12.43016 14.38861 14.98121 15.43519 15.47331 14.8543 16.05373 18.43741 20.38091 22.39174 21.13035 + 11.29912 15.8077 16.54896 16.36229 18.221 15.09686 11.11965 9.979053 10.83024 13.19693 13.55953 12.65395 12.45233 12.89222 15.0179 15.60445 14.92871 14.3497 15.49676 18.35275 19.81606 22.24131 21.26899 + 10.58634 15.52423 16.11585 16.42515 18.17402 15.00347 10.48176 11.49412 11.44849 12.50072 12.81663 12.37796 12.68344 12.88461 13.50673 14.09901 14.95052 14.7693 14.78594 17.34875 19.04901 21.56851 20.89043 + 9.614183 15.8431 16.38121 15.86494 17.58311 14.49032 11.02957 10.22538 9.527282 10.68686 12.11254 12.43469 12.31795 13.20986 13.51692 13.65216 14.22145 14.17002 14.99944 16.96408 18.17498 20.48696 20.18502 + 10.00105 14.93148 15.57334 14.18313 15.84909 13.41543 10.91846 10.40649 10.04232 11.3954 11.08972 10.65496 11.28233 12.84103 13.64318 13.3043 13.51652 13.92885 14.5559 16.84107 18.5327 20.81325 20.21984 + 8.364077 14.47285 15.08788 13.55744 15.35808 12.38914 10.11354 10.69198 10.48146 11.39112 12.41379 12.30688 11.5294 12.61159 13.42383 14.04588 13.40064 13.34902 14.46458 16.70078 18.35919 20.76412 19.943 + 9.641496 14.35918 14.95244 14.19986 15.70295 12.1898 10.18897 9.93488 11.01549 11.42438 12.44854 12.86371 11.5565 13.17326 13.65934 14.53895 13.90649 12.75882 14.03429 16.0668 18.27451 20.19135 19.50024 + 8.998137 15.16441 15.34586 14.19052 15.65328 11.88099 10.49521 10.64151 11.44318 12.29878 12.59886 12.93051 11.39418 13.67889 14.56925 14.55365 14.10461 13.24354 14.07761 16.63885 18.53308 20.30708 20.31402 + 8.946667 14.58632 14.90333 13.99691 15.40372 11.7403 9.425845 11.23817 12.30968 13.13296 12.68324 12.09499 11.59824 14.54168 14.32594 15.0352 14.37218 13.71023 14.06014 17.93824 19.09838 21.4241 20.9504 + 9.447927 13.22877 13.59622 13.29706 14.72807 10.7798 10.31542 10.73058 12.23221 13.26059 12.40936 13.92871 12.75949 13.78177 15.05717 15.43973 15.04269 14.58284 15.24181 18.27596 20.08396 22.0071 21.56488 + 8.942842 12.3533 12.72897 12.85406 14.50646 11.68498 10.16205 11.14519 12.01001 13.16905 12.63423 12.60056 13.09376 15.80599 15.64569 15.43857 15.37898 14.46924 16.22836 18.90742 20.43498 22.41726 21.382 + 9.982429 12.81441 13.19554 12.47804 14.03025 11.90199 10.44281 10.78242 11.68254 11.92076 12.58015 12.23102 12.68594 15.57787 14.6662 15.05085 15.23528 13.82845 15.80674 17.82709 19.04893 21.38214 19.97395 + 9.869902 15.98693 17.0225 15.82257 16.53093 14.39392 13.55346 13.0189 13.5896 13.15744 13.18752 12.97133 12.9559 14.33525 13.73748 13.04741 14.4363 13.70424 15.57391 16.99634 17.09068 17.86176 18.46799 + 11.20318 16.74047 17.93852 17.55423 19.5529 17.38312 15.2714 13.70905 14.90142 15.34691 15.5448 12.94791 14.09873 15.03901 14.75121 14.84058 15.57433 14.77669 15.42783 17.23933 17.08564 16.54724 18.42886 + 10.00581 16.99308 17.64376 17.35759 19.84209 17.72609 16.06901 13.94531 14.6718 16.30286 16.95507 13.571 14.54512 15.59432 15.28288 16.09251 16.91068 14.48281 15.62211 16.89838 16.95857 16.07769 17.91624 + 10.26451 17.10342 17.68718 17.12966 18.80752 16.72883 17.11706 14.18921 15.08757 17.02866 17.63015 14.70868 14.18901 15.36524 15.08402 16.53765 17.53717 14.94885 15.30448 16.46144 16.25202 15.7747 17.48356 + 10.57615 17.0614 17.78706 16.76842 18.19138 17.44588 18.12214 14.26881 15.37736 17.35711 17.82368 16.12888 14.66693 15.406 15.11084 16.10291 17.21349 14.85879 14.25072 15.92479 15.79147 15.51069 17.19426 + 9.48652 16.911 17.18489 17.25456 18.75069 18.27182 18.70464 15.1519 15.75929 18.05139 18.79077 18.19505 14.61217 15.21042 14.50809 16.6024 17.5759 14.97376 14.62691 15.54537 15.83502 14.67196 16.36763 + 9.985225 16.74782 17.24112 17.25887 18.27095 18.51624 18.83493 16.13771 15.24101 18.14103 19.13589 18.64982 14.49468 13.72041 14.16209 16.20668 16.41984 14.58272 14.20643 15.07785 16.00739 15.01148 16.37612 + 8.453218 16.44852 16.53209 17.24354 18.39434 18.03302 18.01833 17.08058 14.58579 18.43371 19.00238 18.1741 14.07615 12.95393 12.84746 15.36702 15.92542 14.33508 13.597 14.46982 16.11521 14.52893 17.01237 + 9.352406 16.0076 16.35685 16.47454 16.98188 17.873 17.68334 17.51781 14.67671 18.76287 18.72811 17.72148 13.38931 12.69698 13.39213 14.65827 15.30858 15.00858 14.27974 14.66115 15.79502 13.98777 16.22205 + 9.672524 14.51215 14.49281 17.57202 18.71115 18.5533 18.56325 18.01528 15.20035 18.96259 18.58512 17.13366 13.41415 12.05879 12.61457 14.21013 14.71272 14.4392 14.22963 14.40962 15.35258 14.32724 15.84399 + 9.294844 14.85708 15.12689 17.73894 18.71831 18.47003 18.26656 17.68312 15.53754 18.16326 17.79104 15.80158 12.8884 11.75445 11.60362 14.12353 14.61159 13.81479 13.50152 14.23705 15.36493 14.26479 16.47873 + 8.768968 15.45139 15.69153 17.49653 18.18467 18.7153 18.61305 16.95576 17.30786 17.01988 16.78725 15.96744 13.20623 11.91497 10.71408 13.16159 14.11679 14.18742 13.99787 14.10843 14.59204 14.09456 16.28277 + 9.966001 15.72716 15.85344 17.40161 18.01343 18.25241 18.0155 17.06878 17.53317 16.64179 16.41474 15.78998 13.04946 11.22962 10.81054 12.68965 14.08202 14.16896 13.95166 14.16778 15.26385 14.41844 15.19306 + 9.675585 15.72316 15.94752 16.87626 17.34341 17.19278 16.94996 16.84417 17.60019 16.79139 15.83696 14.38576 11.87001 11.4011 11.60792 12.10766 13.4803 13.23835 12.92072 14.22253 15.03658 14.08519 14.59369 + 8.843268 15.32752 15.28943 16.05486 16.22001 15.98866 16.2473 16.98972 17.01772 16.9006 16.29029 14.78596 10.99794 11.25592 11.78223 12.48373 13.76172 13.57825 13.22475 14.14124 14.77772 14.18768 15.47867 + 9.988932 15.02293 15.06712 16.10529 16.68101 14.5116 15.2082 16.47553 16.51361 17.52498 17.05329 14.73698 11.47603 11.26132 11.55777 12.60618 14.0904 13.70418 12.92093 14.22556 15.54817 14.19895 15.33703 + 9.373691 14.60107 14.44204 16.04573 16.79593 15.65233 15.8361 15.7082 15.76369 17.70542 17.72066 15.61394 12.20694 11.29502 12.29862 12.74661 13.96791 13.84649 13.18555 14.58438 16.68427 15.04027 15.47512 + 9.678563 14.24788 13.43199 15.21713 15.649 16.42124 16.40302 16.3937 15.09498 16.95411 17.4481 16.14875 12.54013 12.54267 13.3262 13.59261 15.50308 14.9336 13.64636 14.634 16.40599 14.55039 15.61549 + 10.3574 15.14911 14.75568 15.57308 15.29968 16.94623 16.488 16.12799 15.32639 15.1618 16.76408 16.33082 12.41711 12.65482 13.66632 13.70024 15.7187 15.12583 13.7085 15.76237 17.63751 14.65858 15.68508 + 10.7973 15.52072 14.91968 15.44418 16.11236 16.58336 16.3113 15.46747 14.99532 15.4524 15.88347 15.21543 12.29164 12.56826 12.42722 12.49476 14.77974 14.30123 13.07562 15.28318 17.01124 14.17749 15.07545 + 11.72055 14.70813 14.33016 15.86267 16.10855 16.00652 15.79218 14.71058 14.24063 14.49434 15.89563 14.62785 13.76968 14.33625 13.71839 14.10913 14.64376 14.01509 13.78574 15.50584 16.63034 17.31616 17.19594 + 11.63814 14.6362 14.03121 15.15585 15.78361 15.6864 15.34269 14.2795 14.29758 15.06682 15.55843 14.9841 14.52794 14.38037 14.58176 15.49519 16.01623 14.98994 16.1685 17.89346 19.66196 20.41212 19.85152 + 11.20878 14.61073 14.74267 14.05825 15.03689 14.27688 13.934 13.7751 13.63184 13.97793 14.57368 14.39714 14.21094 14.06395 14.52638 15.53573 16.57571 15.51742 17.78471 19.37989 21.206 22.15632 21.33591 + 10.45609 14.74396 14.32149 13.18418 13.62141 14.69138 14.50593 13.22618 13.50317 13.10417 13.68227 13.81558 14.411 13.72738 14.54855 15.41036 16.20938 15.58582 17.08364 18.51379 20.73615 22.85728 22.03742 + 9.892098 14.23401 13.93373 13.37699 13.63826 14.14518 13.86748 12.95281 12.58174 13.15587 13.58239 13.93001 14.0541 14.45245 14.81557 15.24402 15.24497 14.92806 16.91828 19.23318 21.00042 22.89181 22.22411 + 8.341251 13.11608 13.08356 12.63929 12.80791 12.68776 12.75128 13.05065 11.75436 13.81135 13.41625 12.83436 13.37474 14.62833 15.19703 15.31099 14.71062 15.49001 16.62827 18.99271 20.98364 22.86999 22.26387 + 9.033696 14.0476 13.55966 12.04009 12.19411 12.87305 12.72984 12.89095 12.6282 13.35929 13.01105 12.84826 12.64545 13.73565 15.17793 15.06093 14.961 14.88946 16.90281 18.75511 20.67654 22.07957 22.50922 + 9.733017 14.11259 13.47146 12.15287 12.6395 12.34159 11.76064 12.4338 12.91527 13.87755 13.5646 12.60468 13.0273 14.35512 15.41535 15.23291 15.34092 14.8519 15.97584 18.7154 21.41322 22.42959 23.02157 + 8.697401 12.64109 12.03506 13.12382 13.84305 11.54991 11.58626 11.05973 11.39041 14.03995 14.19523 13.01843 13.23257 14.71688 15.60102 14.75217 15.33405 14.82154 16.59491 18.86729 21.02257 22.58431 22.67589 + 9.467981 13.12758 12.64267 12.87043 13.40577 11.28999 10.91053 11.14885 11.37754 13.09841 14.32014 13.18549 12.73418 14.28728 14.77119 14.96639 15.80654 15.12319 16.99688 18.39054 20.01874 22.73198 22.52024 + 9.764517 13.51877 13.10358 11.6141 12.21243 11.77503 11.65425 10.68032 11.29402 14.13506 14.52542 13.75776 13.12655 14.90901 14.66903 15.17769 14.88138 14.35127 15.96097 17.97906 20.40209 22.40177 22.05331 + 9.448538 12.1722 12.48105 11.88218 12.70931 12.26048 11.73737 10.74498 12.15391 13.1719 13.41782 12.89102 12.99866 15.54638 15.04468 15.65555 15.56007 14.52773 15.27511 18.04018 19.91089 21.79332 21.80087 + 8.763973 11.93478 11.62999 11.1273 12.46282 11.85779 11.41145 11.12057 12.67596 13.37468 12.94005 12.73368 12.64572 15.58685 15.55944 15.38471 14.74936 14.22819 16.26686 18.11139 19.70222 21.42123 21.45517 + 8.306178 9.252882 9.844025 11.26888 10.83866 11.36586 11.08982 10.34481 11.93284 12.10324 12.52144 12.75002 12.61329 14.85645 14.61 14.17808 15.05804 14.43231 15.56323 17.80058 18.97718 20.20973 19.62204 + 11.66475 14.36481 14.23808 12.98364 11.47848 11.98761 11.70588 10.32386 11.46336 12.05531 11.33844 11.47684 12.1066 15.10926 14.7728 13.86291 14.54506 14.13791 14.81665 16.32619 17.66183 18.56561 18.54115 + 13.551 15.17671 16.76833 15.87209 15.30873 11.94541 10.92486 11.23132 11.48584 13.04966 12.27409 11.97255 11.65486 14.969 14.62882 13.83866 13.70533 13.39387 13.99928 15.66928 16.7587 16.72407 16.5293 + 12.76456 14.3368 17.05488 16.533 16.53849 12.9081 12.13053 12.54419 11.06146 11.80947 11.34655 11.66301 11.78405 14.4737 14.33242 13.79723 14.23168 13.66543 14.59762 15.88466 16.25202 16.19663 16.058 + 12.61326 13.91244 16.62031 16.31223 16.49494 13.073 12.46359 13.13346 11.08299 12.0898 12.36925 12.15002 11.55262 14.73402 14.74845 14.4159 15.61065 14.59098 14.15156 15.8146 16.68856 15.90823 15.70445 + 13.72736 14.60473 16.47353 16.42584 16.23803 13.49946 13.32173 13.55856 11.47504 12.57557 13.47919 12.9309 12.37103 15.21231 15.2276 15.20738 16.28225 14.82661 15.0314 16.40727 17.3156 15.99237 15.84188 + 13.94386 14.66504 15.96983 16.09722 16.08472 13.28472 14.21239 13.74801 11.81877 13.22909 13.79301 13.41157 12.9921 15.82657 15.1773 15.28221 16.49038 15.39782 15.09806 16.5119 17.39903 16.71843 16.71772 + 13.7535 15.06458 15.29338 15.41305 15.38942 12.72157 14.62464 13.94845 13.23048 13.06216 13.54 12.74474 13.10539 14.58909 14.21166 14.60993 15.12524 14.18825 14.24555 15.87136 16.5764 16.25047 16.18505 + 12.87529 15.11237 17.02908 16.62773 14.56104 13.15497 14.62326 14.26014 13.4457 13.14097 14.58538 14.2613 13.35599 14.02586 13.7997 13.72621 14.95759 14.69201 13.92311 15.1955 15.75672 15.51821 15.26852 + 14.88954 16.34912 15.96387 16.39929 15.98874 13.18963 13.59016 13.90227 13.35802 13.87966 14.67649 14.61434 13.03115 13.09564 12.67227 13.00849 14.46988 13.8509 13.29925 14.3982 14.9851 14.69154 15.44168 + 15.86816 17.34939 15.38919 15.75551 14.90487 13.54091 13.4477 14.09079 13.59264 14.21146 13.69315 13.91447 12.34339 11.63899 11.57346 11.78274 13.74251 13.4482 12.77586 13.67141 13.67339 14.87321 15.2977 + 16.05614 17.80696 15.5341 15.78276 14.98103 13.54131 13.31379 14.18915 14.42894 15.16783 13.61487 12.74171 12.90643 12.58465 11.50915 11.18896 13.20965 13.26229 12.49681 12.70356 12.91538 14.117 14.82414 + 16.10782 18.11083 15.80454 15.79372 14.83904 13.20489 12.75853 14.28803 15.24095 14.56751 12.98957 12.72844 12.02183 12.00667 11.41799 10.49253 12.19255 12.55818 12.08304 12.07552 12.59875 13.70636 14.76297 + 16.48818 18.47473 16.28432 16.31223 13.50066 12.83804 13.33812 14.4014 15.45115 14.3461 12.77997 12.5514 11.41195 11.27457 9.940119 10.18195 11.79267 12.34199 12.40519 12.08422 12.70067 13.04217 14.32282 + 16.58727 18.6493 16.57899 16.56668 13.67641 12.70696 13.48661 14.16076 15.01744 13.59957 12.72013 12.734 11.13864 11.15946 10.10025 10.58426 12.08072 12.54692 12.42924 12.06971 13.08699 12.87339 13.88818 + 16.46552 18.60275 16.49226 16.2148 14.75385 13.87186 13.3091 13.94653 14.61146 13.24284 12.09616 11.93655 11.40253 11.15538 10.07787 9.789737 11.60745 12.03494 11.88888 12.21645 12.83724 12.63594 13.60312 + 16.42601 18.49523 16.10097 14.80393 15.19385 14.14109 13.04128 13.45862 14.21167 13.62841 11.52437 10.68034 10.83395 10.6881 10.08846 10.43773 10.89225 11.42747 11.60774 13.2441 13.97224 11.69935 13.44734 + 16.38114 18.33183 15.98755 14.96587 15.34151 13.83746 12.48781 12.56362 13.59895 13.62195 11.67679 11.84699 11.38903 10.70972 10.37174 10.57339 10.79502 11.32389 11.35826 13.23451 14.09176 12.10806 13.03413 + 16.22431 17.94065 15.84532 15.77651 16.14402 14.11528 12.80109 13.16647 14.27707 13.8602 11.68355 11.39642 10.84387 10.61396 9.958416 9.830719 10.69155 11.12258 11.26303 13.12325 13.99851 11.67061 12.9628 + 15.79015 17.19271 15.68581 15.83383 16.8037 14.45622 12.3988 12.65228 14.56971 13.79517 10.82631 9.563471 10.30857 9.767759 10.45248 9.569944 10.59113 11.10918 11.09264 12.86746 13.68986 11.89357 12.99938 + 15.2913 16.56188 15.66566 15.6369 15.88488 12.91912 13.74727 13.40825 14.74673 12.99693 11.53082 10.84703 10.13508 9.678087 9.518613 9.16087 10.43609 11.18994 10.68452 11.71982 12.54992 12.5922 13.53928 + 14.92816 16.64891 16.45783 16.25064 16.19631 13.19242 13.77824 14.43863 15.26204 15.19201 12.83485 11.38921 10.91256 11.21886 10.82799 12.13972 13.95731 12.54356 12.07864 12.44756 12.12163 12.97568 14.7286 + 15.13246 17.03524 15.97898 15.40096 15.36011 13.36627 13.54038 14.25134 15.57904 16.03234 13.77775 12.25592 10.30315 10.69148 10.83694 12.56628 14.37519 12.44555 12.39819 13.07718 11.56385 13.12282 15.2996 + 15.5982 17.27533 16.06111 15.55091 15.21003 14.51325 13.98331 14.05154 14.17753 16.04241 15.2899 13.87621 11.14674 10.69581 11.96811 14.34262 14.9851 13.41596 13.65708 14.32451 13.39169 12.8552 14.58668 + 14.91011 16.69463 15.57334 15.01008 15.36094 14.74225 14.26171 13.92481 13.91756 15.95652 16.69785 16.57439 12.48547 11.33714 12.08421 15.43829 15.81007 13.38737 13.30834 14.67949 14.26769 13.08782 14.67955 + 13.62063 15.99206 15.72027 15.10223 15.1442 15.15948 14.64559 13.86851 12.91738 14.75704 17.01463 17.44593 14.92344 12.40641 12.71938 16.50565 16.63255 13.53405 12.98962 15.20941 15.12311 13.42216 15.25566 + 15.30581 16.69621 15.66549 15.66445 16.12411 15.10698 15.31674 14.56899 12.28834 15.10705 16.23727 16.72542 15.70731 13.46484 13.77255 16.57919 16.63644 13.61368 13.20484 14.98691 15.30538 13.48375 14.71632 + 14.74377 15.90853 16.02791 15.53424 15.54271 15.17513 15.70076 15.01335 12.41409 14.9216 15.6982 15.6553 14.80186 13.63735 14.12234 16.54076 16.64301 13.9333 13.65155 15.33424 15.71972 14.00131 14.723 + 13.63359 14.52747 16.50115 15.59644 14.78498 14.94671 15.83353 15.04419 12.83702 15.15406 14.95185 15.14444 14.53343 14.07447 14.4541 16.43644 16.78634 13.96131 13.85571 15.59888 16.54558 14.7505 15.17269 + 15.09095 15.96606 16.31398 15.20485 14.33777 14.76441 15.66189 15.22405 12.65838 15.33522 14.93109 15.00384 14.89501 14.88041 14.65054 16.52218 17.02337 14.22087 14.82588 15.54361 17.17436 15.60863 15.80521 + 15.26671 15.98887 16.00072 15.11115 14.80698 14.81987 15.41057 15.06448 12.76331 14.64497 15.39146 15.59635 15.41956 14.94571 14.81527 16.34526 16.81958 14.88231 15.31733 15.54397 16.68404 16.08439 16.50137 + 14.82031 15.1955 15.81392 14.74509 13.80763 14.37639 15.23381 14.08953 13.05277 14.46634 15.04908 15.01031 14.62417 15.87493 14.96298 16.19891 16.81858 14.21854 14.53428 15.09545 15.81948 15.23545 15.83264 + 14.47235 14.64184 15.65243 14.61598 13.88489 14.16747 15.15573 13.50578 13.0122 14.29219 15.03921 14.0275 13.43212 15.84878 14.55854 14.92103 15.28403 13.08439 14.17978 15.17877 15.71674 13.99384 15.05782 + 14.84271 15.37902 15.59052 14.53613 13.88661 14.49238 15.42805 13.71516 12.43119 13.77503 14.90729 14.78802 14.2214 15.8298 14.60928 14.95287 15.55999 13.44495 13.74132 15.10681 16.23884 14.13648 15.53918 + 14.90855 15.54294 15.92132 14.83505 13.52632 14.82017 15.56321 12.84901 12.36878 12.84481 13.59268 13.83251 13.89308 14.76446 13.99949 14.81193 15.35496 13.92693 14.23314 14.60406 16.01696 13.7629 15.32229 + 14.34874 14.65815 15.8946 14.89865 13.93546 14.51131 15.38126 12.69744 12.18602 11.85635 12.55572 13.3946 13.59089 14.50925 13.44721 14.08821 15.0949 13.18603 13.76213 14.69819 15.71466 14.58852 16.02038 + 14.12023 14.95996 14.94988 14.08591 14.26389 15.05177 15.42382 14.23856 13.6525 13.4122 13.92378 13.58581 13.71874 15.37159 13.65612 14.78279 15.35144 12.51747 13.10743 13.96306 14.74565 13.60848 15.42061 + 13.03794 14.3534 14.61717 14.4276 14.20311 14.88333 16.29688 13.85629 12.45 12.66146 13.211 13.02482 13.61957 15.25426 13.65302 14.40839 15.28184 12.64547 12.91868 13.65031 15.02586 13.60051 14.85588 + 12.80224 14.75209 15.02113 14.23392 13.57626 14.24956 14.97642 13.44714 11.19146 11.87919 12.94502 13.08048 12.71222 14.35021 13.33305 13.61649 14.14324 12.44998 12.97652 14.02602 14.98486 13.33818 14.75948 + 13.16971 14.54832 13.68839 12.53332 12.31186 13.85297 14.5408 12.63638 10.70129 10.50308 11.22596 12.15875 12.87752 14.50729 13.75705 13.03189 14.20643 12.62912 13.04198 13.98892 14.39815 13.00242 14.93295 + 12.32784 14.45602 13.87575 12.9689 12.90031 12.28457 12.79731 12.50595 11.64002 10.49457 12.00499 11.84997 12.20587 13.69985 12.74907 13.07555 13.99215 12.42866 12.85618 13.70903 14.67477 12.98654 15.42268 + 13.97398 15.76731 14.26718 13.93614 13.3635 12.53315 12.47679 12.46972 10.95234 10.91325 11.5195 11.66877 12.05166 13.99423 12.40961 12.80348 13.87326 12.39891 12.30221 12.87925 14.37371 12.68297 14.16082 + 14.184 16.03344 14.21303 12.96472 13.494 13.50742 12.40183 12.13428 11.0977 10.09598 11.73288 11.88649 11.97245 12.51878 11.91088 12.78705 13.84648 12.43722 11.65642 12.11694 12.9002 12.40637 14.5552 + 13.45738 15.55 14.00745 12.82178 12.33664 11.91138 12.54709 12.3248 11.18794 10.89101 11.58366 11.65439 12.35607 12.53853 11.86051 12.31624 13.99491 12.18095 11.57812 11.95029 13.21074 12.14984 13.58227 + 12.75044 14.95871 13.36009 13.20988 12.31619 11.93608 11.93395 12.31846 11.38457 11.1864 11.68532 11.97781 12.34169 12.93438 11.78984 12.08069 13.22225 11.86906 11.43046 11.13731 12.37698 12.51735 13.13258 + 12.4284 14.15335 13.07597 11.76668 11.4075 11.61571 12.59232 11.93633 12.10711 12.10692 12.07862 13.06988 12.64771 14.07678 12.7958 11.8246 12.44421 11.69291 11.27304 11.0924 11.61102 12.44975 12.95033 + 11.18342 11.99406 12.91778 11.29505 11.66648 10.58673 12.03916 12.36362 11.94302 11.53715 12.30084 12.70467 12.66107 14.14579 13.0996 11.72703 12.5057 11.78472 11.09719 10.43786 12.19886 12.96147 12.51465 + 11.16282 12.16246 10.93769 9.637576 10.93914 11.07357 12.48322 11.72473 10.95556 11.30609 12.062 12.24674 12.28014 13.23953 12.19423 12.05279 12.69395 11.68082 11.26663 10.09986 10.75675 11.19461 11.49739 + 10.68674 13.24407 11.97083 9.004447 9.364768 10.10863 12.20102 11.69279 10.02772 10.04208 11.35098 11.3541 12.00796 12.02115 10.81907 10.48873 11.81506 11.11288 11.23438 10.76176 10.97295 11.27559 11.05051 + 11.25764 13.04875 10.96754 9.594095 9.950509 9.515109 10.90454 10.44351 10.30407 10.58162 11.61821 10.79663 11.97438 12.49545 10.3045 10.45207 10.77822 10.23204 10.59221 10.55611 10.73 11.25474 10.92693 + 10.77957 12.84101 10.96046 9.825205 9.921305 10.27295 11.00374 9.069146 9.143576 9.619534 9.886018 9.683996 11.43353 11.68437 10.21345 9.418591 10.17027 9.919155 9.729475 10.12781 10.13701 10.20216 10.49461 + 10.50037 12.81704 10.93899 8.919902 9.181169 9.454815 9.864502 9.160638 7.950092 8.281847 9.608268 9.700049 10.10044 10.43497 10.07498 9.374721 10.09255 9.838331 9.777655 9.972161 10.5668 10.3991 10.44382 + 10.9499 12.69608 10.32951 8.873781 9.134046 8.758868 9.037214 8.199131 7.569058 8.374478 9.34644 9.717125 9.732412 10.43906 8.821301 8.579359 9.148021 9.602486 9.728423 9.711402 10.63859 10.64856 10.91956 + 11.27755 12.95559 10.74122 9.436187 9.256186 9.484769 9.586822 8.388662 7.160058 8.068262 9.397726 9.698923 10.2531 10.30162 9.136081 8.90623 9.838286 9.443312 9.586123 9.845777 10.52771 11.16902 11.16297 + 10.61487 12.45117 10.35181 8.28381 7.78183 7.990805 8.725731 8.746444 7.518696 7.472842 8.455659 9.625546 9.859873 9.179219 8.927357 9.205382 9.615867 10.14538 10.18613 10.31581 10.64848 10.60155 10.51831 + 9.637716 11.20578 9.314525 7.651236 7.868614 8.413736 9.356231 8.070017 8.155 7.390232 8.749864 9.116447 9.567814 9.369207 9.694729 9.147233 9.482315 9.444982 9.887435 9.599484 9.862085 10.45017 10.60415 + 8.626204 9.187364 9.029099 8.493851 7.209723 7.690259 8.042856 7.316092 8.150468 8.128954 8.491919 8.446475 8.681947 8.747696 8.789898 9.233255 10.31805 9.660691 9.486577 10.23518 9.970778 9.988548 10.34961 + 9.442098 8.689657 9.283001 7.998808 6.22693 6.962261 9.189577 8.19746 7.75057 8.493724 8.455694 7.799927 8.001998 8.729837 9.923102 9.574437 9.835016 9.547566 9.595923 10.27687 9.859653 10.14931 10.31981 + 9.97291 9.826776 8.408665 7.496465 8.021371 7.480401 6.859789 7.656764 8.673873 8.172565 8.807829 9.007799 9.039057 8.638908 9.110216 9.078871 9.454023 9.512172 9.644451 9.953197 10.47481 10.57586 11.22771 + 7.733074 9.88445 8.777633 8.313414 8.081938 7.271777 8.92068 8.634503 8.78035 8.908507 9.615075 9.58618 10.19903 9.804263 9.953383 9.936666 10.38816 9.741985 10.35782 10.95726 11.52999 11.21175 11.48313 + 10.96227 9.154578 8.698281 7.998504 7.728884 6.602579 8.022117 8.025263 9.123106 8.844633 8.908731 10.21477 9.655914 9.417415 9.496919 9.789172 10.42569 10.3659 11.02518 10.92264 11.54033 11.66203 11.41841 + 10.86337 9.16935 9.55076 7.872849 7.942523 7.244263 7.779666 7.115378 7.89739 8.183571 8.867866 9.697963 9.289954 9.11062 9.085766 9.426685 9.012211 9.846148 10.90698 10.7715 10.9265 11.21198 11.22182 + 9.851903 10.36412 8.908376 7.846486 7.46843 7.405447 7.65377 8.196727 7.064144 8.249885 8.761197 8.942713 9.204334 8.628345 8.864152 9.710718 9.490798 9.545791 10.44929 10.69282 10.93337 10.86275 10.97815 + 11.25423 10.87261 8.889456 7.461558 7.015344 7.351716 8.382879 8.503271 7.68911 7.91639 8.643186 8.87805 9.065163 9.099637 9.386837 9.786633 10.39724 10.21951 10.45584 10.46524 10.56583 10.76281 10.16936 + 10.68273 9.817769 8.26171 8.016673 8.054502 7.516357 7.65291 7.820787 7.519141 7.720293 7.444949 8.414156 9.215623 8.999539 9.341202 10.16718 9.897247 10.21318 10.05819 10.82438 10.51383 10.53982 10.3831 + 9.478124 9.167519 9.010949 7.99378 7.74503 6.204545 7.584774 7.112559 7.285814 7.478474 7.668393 7.974492 8.957026 8.854042 8.923244 10.00307 9.395614 9.709485 9.681889 10.5162 10.42807 10.61794 10.64966 + 10.47888 7.862177 7.167226 8.245425 7.75247 7.6353 7.317435 8.184895 7.887283 7.203204 8.485103 8.665626 8.602202 8.789666 8.851316 9.74954 9.710799 9.547979 9.842075 10.54527 10.60706 10.56509 10.56258 + 9.801606 8.885911 7.033187 7.478241 6.67696 7.042121 7.39953 7.7513 7.696868 7.563337 8.205177 8.162902 8.607606 8.607259 8.436271 9.256256 9.444992 9.138235 9.183046 10.3544 10.70144 10.78459 10.73416 + 8.729084 9.680941 8.473826 7.128935 7.117252 7.535285 7.976354 8.395122 7.388021 7.665706 7.663038 7.935491 7.918374 8.014401 9.072487 9.747068 9.442183 10.02906 9.621786 10.21271 10.62509 10.38278 10.59681 + 9.071483 8.072448 8.148285 8.208888 6.865083 7.357923 7.7726 7.642717 7.373379 7.314355 6.811155 8.184822 8.202291 9.007961 8.424119 9.344726 9.500482 9.494846 9.845454 10.21647 10.59387 10.59069 10.30458 + 9.551182 8.782715 9.017637 8.455041 7.292755 6.371716 8.139261 7.807406 6.868361 7.754928 8.373298 7.639658 8.648994 8.402566 9.127618 9.492344 9.512679 9.582137 10.01061 10.36339 10.5303 10.40906 10.77627 + 10.07956 9.123581 9.239129 7.188252 7.983877 7.36659 7.689083 7.349831 6.549315 7.351971 7.765708 8.071753 8.22062 8.234403 9.252606 9.165942 9.141379 9.528788 10.10328 10.09754 10.46661 10.03632 10.45256 + 10.45638 9.177458 8.172346 6.487576 7.374524 7.649885 7.573339 6.959404 7.260113 6.734559 7.447418 8.466086 8.382314 8.260194 8.807273 9.042309 9.807338 9.552331 9.757251 10.22166 10.39291 10.50788 10.47725 + 11.13613 7.758188 7.694408 7.91339 6.591579 7.690708 7.883243 6.817697 6.937893 6.617546 7.995504 8.199288 8.606889 7.930028 8.27558 9.028001 9.202659 9.807508 10.00867 10.30622 10.30117 10.22799 10.23392 + 10.84375 8.658377 8.964039 7.577753 5.997756 6.243629 6.59042 7.667848 7.77693 7.160565 7.672915 8.214157 7.767068 8.187228 8.741798 9.008192 8.761507 9.775722 9.991219 10.50324 10.35022 10.56752 10.42405 + 9.856415 8.33345 7.864082 7.394323 7.037837 7.429994 7.053414 8.148975 7.734139 7.73136 8.126728 8.250671 8.107525 8.775521 8.947971 9.013912 8.709566 9.952392 10.0177 10.55204 10.14417 10.48263 10.89007 + 11.22424 8.785028 8.384821 6.571542 6.668182 6.510378 7.012306 7.705905 6.736544 7.154219 8.193804 7.920104 8.426934 8.557131 8.854219 9.46376 10.04807 9.964184 9.701237 9.969363 10.31233 9.983346 10.42036 + 11.32489 8.361799 9.032561 7.834023 7.204043 6.074617 7.471241 8.117975 7.885279 7.726513 8.305443 8.50788 8.930935 8.875918 8.786529 9.071368 10.33387 9.977633 10.02416 10.06347 10.81268 11.20751 10.80103 + 10.06941 6.52937 7.571665 6.465108 6.881132 6.903685 7.100048 7.664837 8.100976 8.205462 8.043177 8.448032 8.847051 8.371434 9.149493 9.756526 10.0323 9.265886 10.12252 10.04926 10.18163 10.70782 10.76523 + 10.31685 7.024517 5.869543 5.841137 6.383105 6.215681 7.949264 7.746029 7.835628 7.861153 8.296052 8.204115 8.655869 8.276096 8.929706 8.994547 9.447945 9.700706 10.37251 10.27933 10.33522 10.72122 10.48557 + 10.91509 7.91675 8.244367 6.124669 6.732698 7.492036 8.363312 8.124249 8.108838 7.358902 8.053522 7.411808 8.716305 8.342316 8.457804 9.005593 9.336573 10.05767 9.578779 10.344 10.4169 10.55184 10.60104 + 10.32075 8.261191 8.136519 6.961864 6.799195 7.198459 7.713956 6.972926 6.764237 7.75519 7.804876 7.912869 8.563591 8.987835 9.309792 9.610885 9.492855 9.925476 10.05713 10.52021 10.62411 10.47692 10.59566 + 9.86818 8.572285 8.530177 7.359343 7.294422 6.582515 6.642591 7.496963 7.95584 7.202435 7.878167 8.503516 8.365258 9.081302 8.992274 9.197975 9.750833 9.722472 9.760623 9.966175 10.59453 10.34588 10.6256 + 10.25583 7.347171 7.843901 6.244213 6.5353 6.617674 7.064937 7.198507 6.530531 7.619411 7.706642 8.672579 8.665023 9.01842 9.258142 9.454097 9.65053 9.569846 10.16275 10.25629 10.61747 10.79843 11.0936 + 11.3455 8.169881 7.368921 6.081739 7.016907 7.807951 8.699952 7.736558 6.748681 7.378449 7.852139 8.727378 9.049452 8.352005 9.397895 9.694369 9.896957 9.87398 9.838742 10.29402 10.58788 9.819412 10.6098 + 11.90842 7.299352 8.247597 6.929464 5.668571 7.252095 8.041783 7.685021 7.479499 7.446598 7.486227 8.122455 8.321239 8.863303 8.986836 9.896532 10.01282 9.700945 10.13044 10.36466 10.79011 10.65473 10.96276 + 11.22572 8.534163 7.996068 7.321532 6.95424 7.306089 8.242614 7.205853 7.210618 7.631306 8.128415 8.210221 7.745347 8.572201 9.164312 9.454391 9.143291 9.996038 9.919705 10.61216 10.94615 11.0497 10.50996 + 11.99271 8.205185 9.120809 8.732939 7.727026 7.459247 9.017488 8.611053 9.431357 8.641321 9.48832 9.588237 9.180689 8.96218 9.460557 9.78753 10.30156 10.65017 10.35131 10.94515 12.2452 13.12846 12.19351 + 11.79253 9.627811 9.291315 7.524522 6.52378 7.294258 8.705289 7.135509 8.226054 8.742827 9.064022 9.066143 8.709431 8.971881 9.728841 9.269897 9.861171 10.09128 10.07978 10.35271 10.13663 11.0843 11.13849 + 10.56259 9.232968 9.15976 6.620336 6.150416 6.181613 7.583303 6.586105 7.54056 7.118359 8.163677 8.156444 8.354664 8.431437 9.365588 9.699803 9.425529 9.986162 10.02214 9.757886 9.986296 10.37123 11.12805 + 11.46303 8.064131 8.81135 8.263533 7.772588 6.787446 7.045297 7.507244 7.852684 7.8141 8.464418 8.278731 8.368163 9.374079 9.125239 9.165322 8.79129 9.501587 10.15753 9.792738 10.41069 10.7875 10.81474 + 11.05755 8.402949 8.103877 8.311771 7.382164 7.518039 8.082945 8.166703 8.587493 8.333583 7.051155 8.128522 9.163286 9.241158 9.282046 9.011143 9.606009 9.214875 9.92196 10.35358 10.19762 11.04288 11.07783 + 9.634427 8.981845 9.008856 8.496973 8.026294 6.744306 7.501451 7.233029 7.99301 7.752292 7.717514 8.286538 9.62907 9.19305 8.897845 9.250588 9.401032 9.651338 10.04432 10.55263 10.60681 10.55907 10.44911 + 9.16023 9.718575 9.712869 9.499995 9.118845 7.099794 7.596916 7.821012 7.377513 7.772183 8.825283 8.444467 8.374529 8.278049 8.336656 9.146471 9.616967 9.900914 9.985411 10.23762 10.56904 10.3051 10.82687 + 10.26259 9.707577 7.891645 7.938838 8.196815 7.030812 7.729892 8.539984 7.097323 7.639617 8.26931 8.103879 8.820785 8.756143 8.088627 7.633537 8.861978 9.411267 9.507934 9.617286 10.103 10.32123 10.60248 + 9.416736 8.067968 8.121611 8.702229 8.153371 7.398215 8.101689 7.075943 7.48716 7.682926 7.930077 7.562144 7.981254 8.482229 8.007603 8.850947 9.587449 9.971848 10.00796 10.0423 10.69032 11.02298 10.9979 + 9.875791 9.180859 8.33131 7.329909 7.138772 6.531456 7.820087 7.730562 7.006549 7.355982 8.221857 7.397998 8.619684 9.434539 8.325085 8.88515 9.217641 10.11225 10.50192 10.39947 10.4549 10.84156 10.37869 + 10.21343 8.826467 8.089176 7.33913 7.855656 7.318372 7.243741 7.606412 7.226522 7.431902 7.899468 8.143455 8.827127 9.14143 8.887341 8.847593 9.56572 9.84055 9.684552 9.931477 10.32066 10.90385 10.82047 + 8.685722 8.634503 8.177417 7.393768 7.107471 7.263133 7.5967 7.938039 6.885909 7.359814 8.428015 8.861872 8.920212 7.885601 8.544594 9.326226 9.538568 9.941797 10.37305 10.73129 10.24279 10.99198 10.71185 + 9.49738 9.815642 8.553341 7.461448 7.640052 7.98072 7.311526 8.038465 7.255682 6.560006 7.371539 7.967708 8.035154 7.652845 8.489419 9.47836 9.636602 9.799182 10.27001 10.54407 10.1862 10.5361 11.08353 + 9.237267 8.263541 7.987866 7.640958 7.269582 6.937474 6.849837 7.717149 7.656352 7.173209 7.225511 7.958437 8.102967 8.547636 8.357112 8.845057 9.423195 9.327521 10.10193 10.10455 10.16159 10.10588 10.53935 + 8.52638 7.134833 7.512567 7.138206 6.746409 7.367229 7.365469 6.383105 7.514528 7.68226 8.600569 8.164186 8.062187 8.582131 9.225581 9.787975 9.365478 9.480648 9.960615 9.841322 9.842931 10.30676 10.41945 + 9.151896 6.975066 6.058979 7.529419 6.584132 6.413368 7.757835 7.395633 7.860129 7.49466 8.109066 7.873742 8.698033 9.225484 9.379223 9.214903 9.393662 9.46548 9.963161 10.11975 10.1148 10.09052 10.40652 + 9.582273 6.791395 7.215298 7.381511 7.378876 7.854954 7.890674 7.242115 7.359837 7.425533 8.024413 7.492979 8.248519 8.686938 8.807583 9.178555 9.128061 9.372928 9.666212 9.78712 9.796471 10.31979 10.85505 ] diff --git a/audio/tests/features/testdata/pitch_feat.ark b/audio/tests/features/testdata/pitch_feat.ark new file mode 100644 index 00000000..ee7d4c7f Binary files /dev/null and b/audio/tests/features/testdata/pitch_feat.ark differ diff --git a/audio/tests/features/testdata/pitch_feat_txt.ark b/audio/tests/features/testdata/pitch_feat_txt.ark new file mode 100644 index 00000000..da72c588 --- /dev/null +++ b/audio/tests/features/testdata/pitch_feat_txt.ark @@ -0,0 +1,942 @@ +test_wav [ + 0.4300044 238.1164 + 0.7310953 238.1164 + 0.0589752 238.1164 + 0.3706925 238.1164 + 0.6353879 238.1164 + 0.4168843 238.1164 + 0.7615743 238.1164 + 0.7359886 238.1164 + 0.5104555 238.1164 + 0.843815 238.1164 + 0.574707 238.1164 + 0.8757079 238.1164 + 0.8545787 238.1164 + 0.5284878 238.1164 + 0.8398617 238.1164 + 0.8405749 238.1164 + 0.7291093 238.1164 + 0.3530312 238.1164 + 0.8516902 238.1164 + 0.8366287 238.1164 + 0.7860549 238.1164 + 0.7996263 238.1164 + 0.8769377 238.1164 + 0.8062987 238.1164 + 0.5502667 238.1164 + 0.8050084 236.9318 + 0.8435217 235.753 + 0.6781067 234.5801 + 0.6275977 233.4131 + 0.8354951 232.2518 + 0.7898548 231.0963 + 0.6786529 229.9466 + 0.5784115 228.8026 + 0.8078744 227.6642 + 0.7860623 226.5316 + 0.3529067 225.4046 + 0.7398534 224.2832 + 0.7554479 223.1673 + 0.3688865 222.057 + 0.431939 220.9523 + -0.2559481 219.853 + 0.5161331 218.7592 + 0.736354 217.6709 + 0.2649688 216.5879 + 0.6187224 215.5104 + 0.8040497 214.4382 + 0.4176693 213.3714 + 0.7362868 212.3098 + 0.6412426 211.2535 + 0.01994592 210.2025 + -0.09901931 209.1568 + 0.4139394 208.1162 + 0.7458671 207.0808 + 0.7015585 206.0505 + 0.8989595 206.0505 + 0.9356874 209.1568 + 0.9370709 212.3098 + 0.9640602 216.5879 + 0.9851464 217.6709 + 0.9874667 217.6709 + 0.9662011 215.5104 + 0.9561557 211.2535 + 0.9835509 209.1568 + 0.9764188 209.1568 + 0.8779365 208.1162 + 0.8911879 207.0808 + 0.8716732 205.0254 + 0.8663442 197.9909 + 0.9105747 191.1978 + 0.9614732 191.1978 + 0.9704162 187.4211 + 0.9690547 186.4887 + 0.9596871 187.4211 + 0.9392474 190.2465 + 0.8951484 192.1537 + 0.8852764 190.2465 + 0.9345272 185.5609 + 0.9304817 182.8051 + 0.9600235 180.0902 + 0.9829449 178.3027 + 0.9876611 178.3027 + 0.9889374 178.3027 + 0.9911457 178.3027 + 0.9835688 176.533 + 0.9755108 175.6547 + 0.9868198 174.7808 + 0.9932452 175.6547 + 0.9902206 175.6547 + 0.9920143 176.533 + 0.9922135 175.6547 + 0.9892406 174.7808 + 0.9888865 172.185 + 0.9796383 172.185 + 0.9825094 170.476 + 0.9640273 170.476 + 0.9416605 173.046 + 0.9690976 173.9112 + 0.9527848 173.9112 + 0.8625391 173.046 + 0.8571138 173.9112 + 0.826855 174.7808 + 0.8046249 176.533 + 0.6064064 178.3027 + 0.4831207 180.9906 + 0.4654697 183.7191 + 0.6392145 186.4887 + 0.6342434 190.2465 + 0.8626602 194.0801 + 0.953752 194.0801 + 0.987371 191.1978 + 0.9915444 188.3582 + 0.9920763 186.4887 + 0.9898383 184.6377 + 0.9908906 181.8956 + 0.9892344 180.9906 + 0.9779232 179.1942 + 0.962887 175.6547 + 0.9623674 170.476 + 0.9719465 171.3284 + 0.9843823 173.046 + 0.9776363 173.9112 + 0.9711902 173.9112 + 0.9477384 172.185 + 0.9629893 172.185 + 0.9716213 173.9112 + 0.9675733 176.533 + 0.9643332 178.3027 + 0.9592766 180.0902 + 0.8798139 181.8956 + 0.7133937 185.5609 + 0.558998 190.2465 + 0.3460312 196.0257 + 0.645723 201.9805 + 0.538826 208.1162 + 0.6076745 216.5879 + 0.5921855 228.8026 + 0.8826846 238.1164 + 0.9501736 242.9146 + 0.9898381 245.3498 + 0.9941772 245.3498 + 0.9901065 246.5766 + 0.9880084 247.8095 + 0.9941741 249.0485 + 0.9959649 249.0485 + 0.9930359 250.2938 + 0.9856881 252.8029 + 0.9906433 252.8029 + 0.9973371 252.8029 + 0.9980655 252.8029 + 0.9958057 251.5452 + 0.9909865 250.2938 + 0.990723 249.0485 + 0.987911 249.0485 + 0.9759061 251.5452 + 0.9722236 251.5452 + 0.9578422 251.5452 + 0.936386 250.2938 + 0.9094891 245.3498 + 0.8420637 235.753 + 0.6358631 218.7592 + 0.757064 198.9809 + 0.8944787 192.1537 + 0.9415626 188.3582 + 0.9400396 183.7191 + 0.9019431 180.9906 + 0.904547 175.6547 + 0.8742625 173.046 + 0.7475201 169.6279 + 0.5156456 164.6269 + 0.4781345 161.3751 + 0.4000205 149.7427 + 0.4614965 147.5188 + 0.4422437 141.7487 + 0.3527509 136.2042 + 0.191848 130.2255 + 0.3072545 128.2915 + 0.5506754 127.0181 + 0.6923887 129.5776 + 0.6101584 132.8496 + 0.3040284 138.2575 + 0.1897903 155.8383 + 0.4685728 164.6269 + 0.5444003 164.6269 + 0.5138596 162.9929 + 0.5802024 160.5723 + 0.2090085 160.5723 + 0.2416739 162.9929 + 0.2459603 168.784 + 0.6345571 176.533 + 0.5914032 184.6377 + 0.4447052 193.1145 + 0.2762254 201.9805 + 0.2842087 212.3098 + -0.1974148 224.2832 + 0.5095772 238.1164 + 0.7442543 252.8029 + 0.8915138 252.8029 + 0.9569594 247.8095 + 0.9625007 242.9146 + 0.9194686 235.753 + 0.8994824 227.6642 + 0.9381443 218.7592 + 0.7226841 219.853 + 0.6949252 223.1673 + 0.6777956 222.057 + 0.7978759 214.4382 + 0.8507771 209.1568 + 0.7713854 211.2535 + 0.6789038 211.2535 + 0.7500904 206.0505 + 0.7494768 204.0054 + 0.7971382 206.0505 + 0.8222839 206.0505 + 0.7602305 200.9756 + 0.6428912 197.0059 + 0.6536841 193.1145 + 0.7034875 188.3582 + 0.5804744 181.8956 + 0.4417492 173.046 + 0.3494109 161.3751 + 0.1981726 148.2564 + 0.6261529 140.3417 + 0.7587391 136.8852 + 0.3861219 134.8523 + 0.2585415 138.2575 + 0.4469885 141.7487 + 0.7737626 140.3417 + 0.7246874 138.2575 + 0.6511324 136.8852 + 0.4254677 136.8852 + 0.1780608 141.7487 + 0.4341104 146.7849 + 0.2834992 149.7427 + 0.4845652 151.2439 + 0.4879717 151.2439 + 0.5601908 152.0001 + 0.7019184 152.0001 + 0.8482625 152.0001 + 0.8672082 152.0001 + 0.8626106 151.2439 + 0.8626055 149.7427 + 0.9013379 148.2564 + 0.8793075 146.7849 + 0.8914734 144.605 + 0.8311929 141.7487 + 0.6839114 139.6435 + 0.5378032 136.8852 + 0.3579432 131.531 + 0.3721773 123.8897 + 0.259927 118.4515 + 0.4204291 116.1118 + 0.7305987 117.2759 + 0.6386622 122.6601 + 0.4521356 127.0181 + 0.1688575 132.1886 + 0.2404094 136.8852 + 0.161655 139.6435 + 0.361738 140.3417 + -0.02500387 138.2575 + 0.4358978 136.2042 + 0.4791997 134.8523 + 0.5491226 134.1814 + 0.6218376 133.5138 + 0.566164 133.5138 + 0.6004029 134.1814 + 0.4282176 134.8523 + 0.2462277 135.5266 + 0.468562 136.8852 + 0.1709644 137.5696 + -0.1866998 138.2575 + -0.2322609 138.9488 + -0.3413201 138.9488 + -0.5628413 138.9488 + -0.3278477 138.2575 + -0.1193225 138.9488 + 0.04384596 140.3417 + 0.04935479 142.4574 + 0.1841608 144.605 + 0.5726393 147.5188 + 0.6960948 151.2439 + 0.7003101 153.5239 + 0.7147154 155.8383 + 0.7900128 158.9785 + 0.7915136 160.5723 + 0.8635668 162.9929 + 0.9153162 167.1087 + 0.9632365 168.784 + 0.9837555 173.046 + 0.9895447 174.7808 + 0.9936979 178.3027 + 0.9939244 180.0902 + 0.9943298 180.9906 + 0.9935455 183.7191 + 0.9959602 184.6377 + 0.9956325 184.6377 + 0.9592334 185.5609 + 0.8768551 189.3 + 0.7307228 193.1145 + 0.511133 192.1537 + 0.6857247 188.3582 + 0.9158598 184.6377 + 0.9108561 186.4887 + 0.9116812 187.4211 + 0.9223366 187.4211 + 0.8974369 188.3582 + 0.8092315 189.3 + 0.6424754 190.2465 + 0.415496 193.1145 + -0.09486372 194.0801 + 0.06201403 196.0257 + 0.7022306 199.9758 + 0.8596367 206.0505 + 0.8891434 212.3098 + 0.8837855 220.9523 + 0.7532349 229.9466 + 0.8273478 235.753 + 0.8926229 240.5036 + 0.9618158 242.9146 + 0.9802947 242.9146 + 0.9757999 241.7061 + 0.9556377 236.9318 + 0.9495205 228.8026 + 0.8714783 222.057 + 0.6913882 217.6709 + 0.5996734 214.4382 + 0.5818065 196.0257 + 0.7346321 182.8051 + 0.8720678 184.6377 + 0.8043494 181.8956 + 0.7913815 184.6377 + 0.8019897 179.1942 + 0.8272967 177.4156 + 0.917188 173.9112 + 0.948779 178.3027 + 0.9491397 179.1942 + 0.9660939 181.8956 + 0.948925 181.8956 + 0.9438759 183.7191 + 0.9082419 182.8051 + 0.8157918 182.8051 + 0.7726267 183.7191 + 0.7925529 184.6377 + 0.82323 185.5609 + 0.7710455 186.4887 + 0.7245523 187.4211 + 0.6725792 188.3582 + 0.6098945 190.2465 + 0.6053364 192.1537 + 0.5669799 194.0801 + 0.6425812 196.0257 + 0.5920788 198.9809 + 0.5982969 201.9805 + 0.5845767 206.0505 + 0.8673239 210.2025 + 0.8958703 213.3714 + 0.9322492 215.5104 + 0.9763456 216.5879 + 0.9871499 217.6709 + 0.9847117 216.5879 + 0.9803717 215.5104 + 0.9864718 214.4382 + 0.9891353 213.3714 + 0.9886542 212.3098 + 0.9887235 211.2535 + 0.9895412 211.2535 + 0.987739 210.2025 + 0.9813522 211.2535 + 0.979372 210.2025 + 0.9715059 211.2535 + 0.9659958 212.3098 + 0.9582934 213.3714 + 0.9457313 214.4382 + 0.9001306 214.4382 + 0.8375491 214.4382 + 0.8580287 213.3714 + 0.8090529 212.3098 + 0.7204515 211.2535 + 0.727868 211.2535 + 0.8134795 211.2535 + 0.7847017 212.3098 + 0.855688 212.3098 + 0.9308017 212.3098 + 0.8832355 211.2535 + 0.7976366 210.2025 + 0.6125828 208.1162 + 0.7335693 206.0505 + 0.5974885 204.0054 + 0.5784881 201.9805 + 0.626056 199.9758 + 0.3227086 197.9909 + 0.4882276 196.0257 + 0.5797763 194.0801 + 0.6834005 191.1978 + 0.8976591 190.2465 + 0.9618267 188.3582 + 0.9768698 185.5609 + 0.9630268 181.8956 + 0.951674 178.3027 + 0.9476838 173.9112 + 0.9517156 172.185 + 0.9504529 169.6279 + 0.9870636 169.6279 + 0.9741296 168.784 + 0.9508372 168.784 + 0.90883 165.4501 + 0.8581914 161.3751 + 0.8267851 156.6175 + 0.6312259 150.4914 + 0.546525 146.7849 + 0.5260749 146.7849 + 0.4342186 153.5239 + 0.492891 160.5723 + 0.6401276 166.2773 + 0.7607003 168.784 + 0.8006893 169.6279 + 0.754485 169.6279 + 0.3563844 168.784 + 0.2301813 168.784 + 0.5213931 168.784 + 0.4302804 169.6279 + 0.203999 170.476 + 0.5803608 172.185 + 0.799207 173.9112 + 0.7838959 175.6547 + 0.6272278 177.4156 + 0.5649745 179.1942 + 0.1334038 180.9906 + 0.4665532 182.8051 + 0.7017906 184.6377 + 0.574991 186.4887 + 0.1776394 188.3582 + 0.7058933 190.2465 + 0.7285945 192.1537 + 0.5696192 194.0801 + 0.5714518 196.0257 + 0.8047431 198.9809 + 0.7406042 200.9756 + 0.3201705 202.9904 + 0.7420282 205.0254 + 0.8154832 207.0808 + 0.7317356 209.1568 + 0.3067544 211.2535 + 0.8014479 213.3714 + 0.8102676 215.5104 + 0.4439816 217.6709 + 0.8234195 219.853 + 0.7885534 222.057 + 0.4245847 224.2832 + 0.00418177 226.5316 + 0.3035149 228.8026 + 0.6538261 231.0963 + 0.847946 233.4131 + 0.6219971 235.753 + 0.858582 236.9318 + 0.8284138 239.307 + 0.4044586 240.5036 + 0.7807371 241.7061 + 0.6421613 242.9146 + 0.4366452 244.1292 + 0.8172922 245.3498 + 0.7077252 246.5766 + 0.7137164 247.8095 + 0.8416377 249.0485 + 0.8084357 250.2938 + 0.6429872 251.5452 + 0.8479958 252.8029 + 0.8376269 254.067 + 0.5148344 255.3373 + 0.8253111 256.614 + 0.792549 257.8971 + 0.7535735 259.1866 + 0.08307214 260.4825 + 0.7227954 261.7849 + 0.7564813 264.4093 + 0.4621202 265.7313 + 0.4633192 267.06 + 0.7247673 268.3953 + 0.7581604 269.7372 + 0.5511292 271.0859 + 0.9282034 272.4414 + 0.9706463 271.0859 + 0.9854098 273.8036 + 0.9971125 273.8036 + 0.9954729 272.4414 + 0.9888761 269.7372 + 0.9950762 267.06 + 0.9968371 269.7372 + 0.9980098 269.7372 + 0.997749 268.3953 + 0.9915248 265.7313 + 0.9653835 259.1866 + 0.9663866 256.614 + 0.9707376 259.1866 + 0.9852746 263.0938 + 0.982106 265.7313 + 0.9469596 267.06 + 0.9675582 264.4093 + 0.9636477 261.7849 + 0.9427549 257.8971 + 0.7895892 251.5452 + 0.8654758 245.3498 + 0.5468963 235.753 + 0.683558 220.9523 + 0.8124123 211.2535 + 0.9160304 205.0254 + 0.9279389 197.0059 + 0.9523526 191.1978 + 0.9704132 186.4887 + 0.9692958 185.5609 + 0.9680378 184.6377 + 0.9765167 184.6377 + 0.9860514 182.8051 + 0.9883636 182.8051 + 0.9909548 181.8956 + 0.991558 183.7191 + 0.9909708 185.5609 + 0.9903755 187.4211 + 0.9908676 189.3 + 0.9932029 191.1978 + 0.9957952 191.1978 + 0.9942914 191.1978 + 0.9921359 189.3 + 0.9943052 187.4211 + 0.9959483 186.4887 + 0.995445 188.3582 + 0.9905357 190.2465 + 0.9810765 189.3 + 0.9172173 189.3 + 0.8372061 189.3 + 0.7548154 189.3 + 0.7888815 189.3 + 0.7481033 187.4211 + 0.598231 181.8956 + 0.4594265 180.9906 + 0.3907863 181.8956 + 0.3352165 180.9906 + 0.1176405 178.3027 + 0.07078327 173.046 + -0.04527154 169.6279 + -0.1348021 168.784 + 0.04466751 167.1087 + 0.09953013 164.6269 + 0.0682964 162.182 + 0.06978174 163.8079 + 0.1322864 165.4501 + 0.2013361 169.6279 + 0.2920707 174.7808 + 0.3333177 176.533 + 0.3332107 176.533 + 0.3530797 177.4156 + 0.4650808 179.1942 + 0.5486825 180.9906 + 0.4580497 182.8051 + 0.4908407 184.6377 + 0.4697383 186.4887 + 0.3304503 188.3582 + 0.3914385 190.2465 + 0.6257187 192.1537 + 0.3618582 195.0505 + 0.1043633 197.9909 + 0.3943349 200.9756 + 0.5306126 204.0054 + 0.1373097 207.0808 + 0.2010625 210.2025 + 0.3670651 213.3714 + 0.3145425 216.5879 + 0.8130425 219.853 + 0.8798357 222.057 + 0.9403205 223.1673 + 0.97297 224.2832 + 0.9836287 223.1673 + 0.9911686 222.057 + 0.9915301 220.9523 + 0.9894016 219.853 + 0.9908847 218.7592 + 0.9930059 217.6709 + 0.9904228 217.6709 + 0.962741 213.3714 + 0.9670218 209.1568 + 0.9779282 206.0505 + 0.9113222 202.9904 + 0.863717 196.0257 + 0.7813085 193.1145 + 0.7102375 197.0059 + 0.6673803 201.9805 + 0.7775867 202.9904 + 0.8043374 204.0054 + 0.7297218 200.9756 + 0.5714095 197.0059 + 0.5821126 194.0801 + 0.7140544 193.1145 + 0.7262678 194.0801 + 0.7389845 195.0505 + 0.7598057 196.0257 + 0.7466297 197.9909 + 0.6394933 199.9758 + 0.6129577 201.9805 + 0.672642 202.9904 + 0.715472 202.9904 + 0.7394825 202.9904 + 0.5446303 202.9904 + 0.7562882 202.9904 + 0.7478679 202.9904 + 0.3738182 201.9805 + 0.7470279 200.9756 + 0.7631992 199.9758 + 0.4866134 198.9809 + 0.6727687 197.9909 + 0.6740197 197.0059 + 0.5121869 196.0257 + 0.5960711 195.0505 + 0.4775652 194.0801 + 0.7727789 193.1145 + 0.7569727 192.1537 + 0.3645771 190.2465 + 0.7480979 188.3582 + 0.669458 186.4887 + 0.06009803 184.6377 + -0.2068706 182.8051 + 0.2833839 180.9906 + 0.6422815 179.1942 + 0.3581112 177.4156 + 0.2500266 175.6547 + 0.3498747 173.9112 + 0.569603 172.185 + 0.097353 170.476 + 0.3730714 168.784 + -0.1027659 167.1087 + -0.1343261 165.4501 + -0.1674749 163.8079 + -0.09346908 162.182 + 0.02017644 160.5723 + 0.01829195 158.9785 + 0.2345988 157.4006 + 0.254218 155.8383 + 0.4619125 154.2915 + 0.2792292 165.4501 + 0.6047359 176.533 + 0.7835823 178.3027 + 0.8670148 175.6547 + 0.9359789 173.9112 + 0.9631585 175.6547 + 0.9587292 176.533 + 0.9695755 176.533 + 0.9835575 179.1942 + 0.9900097 179.1942 + 0.9886937 180.0902 + 0.9895495 180.9906 + 0.9944302 183.7191 + 0.9966992 183.7191 + 0.9946688 186.4887 + 0.992237 189.3 + 0.9917749 191.1978 + 0.9863276 192.1537 + 0.9785607 192.1537 + 0.9806378 190.2465 + 0.9924863 189.3 + 0.99017 188.3582 + 0.9820646 187.4211 + 0.9470521 188.3582 + 0.8216711 187.4211 + 0.7153458 190.2465 + 0.7442878 193.1145 + 0.5942695 196.0257 + 0.5665525 197.0059 + 0.535006 195.0505 + 0.6266476 193.1145 + 0.6059493 194.0801 + 0.6425897 198.9809 + 0.8118222 206.0505 + 0.8551767 210.2025 + 0.8889339 211.2535 + 0.947816 211.2535 + 0.9787855 209.1568 + 0.988611 208.1162 + 0.987321 207.0808 + 0.9843316 205.0254 + 0.9737096 204.0054 + 0.9765185 202.9904 + 0.9856598 202.9904 + 0.9898718 204.0054 + 0.9886413 204.0054 + 0.989678 202.9904 + 0.9851701 200.9756 + 0.9817263 198.9809 + 0.9766667 196.0257 + 0.9717003 194.0801 + 0.9652438 193.1145 + 0.9332103 193.1145 + 0.9138572 194.0801 + 0.8846416 194.0801 + 0.9482771 195.0505 + 0.9305538 196.0257 + 0.8390872 197.0059 + 0.7701216 197.9909 + 0.7264634 197.9909 + 0.7708728 197.9909 + 0.8309863 197.9909 + 0.8339165 197.9909 + 0.723191 197.0059 + 0.7247626 196.0257 + 0.608819 195.0505 + 0.3213559 194.0801 + 0.2234745 193.1145 + -0.02573975 191.1978 + 0.05725723 189.3 + 0.218053 187.4211 + 0.4777128 185.5609 + 0.5337029 182.8051 + 0.2318052 180.0902 + 0.4889631 177.4156 + 0.08109105 174.7808 + 0.7427355 172.185 + 0.8433576 171.3284 + 0.938632 170.476 + 0.9607551 168.784 + 0.9642593 167.1087 + 0.963613 166.2773 + 0.9651926 167.1087 + 0.9591027 168.784 + 0.9754831 172.185 + 0.9820764 176.533 + 0.9875088 180.0902 + 0.9851621 181.8956 + 0.9825414 183.7191 + 0.9723955 185.5609 + 0.9567259 187.4211 + 0.8835074 189.3 + 0.8628154 192.1537 + 0.9157982 195.0505 + 0.5938084 198.9809 + 0.6943321 209.1568 + 0.7714629 212.3098 + 0.8662375 211.2535 + 0.849728 205.0254 + 0.7945137 196.0257 + 0.7933522 188.3582 + 0.6368725 178.3027 + 0.5897154 167.1087 + 0.3229582 158.1876 + 0.2969382 144.605 + 0.3351896 141.7487 + 0.384491 146.0546 + 0.04096958 151.2439 + 0.1369363 172.185 + 0.3727793 180.9906 + 0.4194036 183.7191 + 0.4396896 185.5609 + 0.5275242 185.5609 + 0.2498598 186.4887 + 0.05898202 190.2465 + 0.04901373 195.0505 + 0.1100158 197.9909 + 0.2187118 198.9809 + 0.4847157 197.9909 + 0.4972816 197.9909 + 0.5150168 198.9809 + 0.5341532 200.9756 + 0.2631531 202.9904 + 0.1344986 205.0254 + 0.1769232 207.0808 + 0.2019505 209.1568 + 0.3217678 211.2535 + 0.366561 213.3714 + 0.3891162 215.5104 + 0.3456501 217.6709 + 0.3461981 219.853 + 0.1349857 222.057 + 0.06558777 224.2832 + 0.397542 226.5316 + 0.697022 228.8026 + 0.4396819 231.0963 + 0.7819827 233.4131 + 0.7121504 235.753 + 0.2208821 238.1164 + 0.7816582 240.5036 + 0.7002975 242.9146 + 0.03593514 245.3498 + 0.1999688 247.8095 + 0.6519101 249.0485 + 0.5185443 251.5452 + 0.9164662 254.067 + 0.9069665 255.3373 + 0.9549389 254.067 + 0.9885621 252.8029 + 0.9925307 251.5452 + 0.9942389 249.0485 + 0.996495 249.0485 + 0.9955549 247.8095 + 0.9936098 246.5766 + 0.980476 245.3498 + 0.9671 246.5766 + 0.9642795 249.0485 + 0.9722587 249.0485 + 0.974653 249.0485 + 0.9627596 247.8095 + 0.9594576 247.8095 + 0.9352374 247.8095 + 0.9516878 246.5766 + 0.9676836 245.3498 + 0.9551129 246.5766 + 0.9023392 249.0485 + 0.8472683 251.5452 + 0.8856258 254.067 + 0.8884159 255.3373 + 0.9254211 255.3373 + 0.9612991 254.067 + 0.9673759 250.2938 + 0.9728466 245.3498 + 0.967782 242.9146 + 0.9654288 240.5036 + 0.9444144 238.1164 + 0.9269778 236.9318 + 0.9488637 236.9318 + 0.9771202 236.9318 + 0.9830479 235.753 + 0.97499 234.5801 + 0.968623 233.4131 + 0.9521769 233.4131 + 0.9390221 233.4131 + 0.9339334 233.4131 + 0.887956 232.2518 + 0.9046763 231.0963 + 0.8827981 229.9466 + 0.8236388 231.0963 + 0.7853005 231.0963 + 0.8529194 229.9466 + 0.8421693 227.6642 + 0.880672 224.2832 + 0.8143209 219.853 + 0.8765387 215.5104 + 0.8224545 210.2025 + 0.5476995 204.0054 + 0.3984698 197.0059 + 0.2524756 189.3 + 0.0114817 180.9906 + 0.2040667 172.185 + -0.1669366 163.8079 + 0.504205 154.2915 + 0.7180874 151.2439 + 0.8632782 151.2439 + 0.8973259 150.4914 + 0.9185986 151.2439 + 0.7587776 154.2915 + 0.7147576 159.7734 + 0.7589291 165.4501 + 0.8840488 171.3284 + 0.972356 175.6547 + 0.9816653 179.1942 + 0.988443 180.9906 + 0.9923041 181.8956 + 0.9943824 182.8051 + 0.9964477 183.7191 + 0.9936554 181.8956 + 0.9887792 180.0902 + 0.9771134 175.6547 + 0.9618319 170.476 + 0.9328524 167.9442 + 0.819974 168.784 + 0.8450117 170.476 + 0.8293109 171.3284 + 0.6963592 171.3284 + 0.6338254 164.6269 + 0.7285098 158.9785 + 0.7664092 154.2915 + 0.8064316 152.0001 + 0.9278697 152.0001 + 0.9533199 151.2439 + 0.9601526 149.7427 + 0.9562845 148.9977 + 0.963026 149.7427 + 0.9602929 149.7427 + 0.8744306 150.4914 + 0.5927675 154.2915 + 0.3564559 159.7734 + 0.2405773 164.6269 + 0.2860079 169.6279 + 0.6529107 173.9112 + 0.835753 176.533 + 0.8849658 179.1942 + 0.875807 180.9906 + 0.823069 182.8051 + 0.6626108 184.6377 + 0.2836408 187.4211 + 0.6051244 190.2465 + 0.7253854 193.1145 + 0.765985 196.0257 + 0.8194041 198.9809 + 0.6263421 201.9805 + 0.8017131 205.0254 + 0.682602 209.1568 + 0.5036187 213.3714 + 0.5814967 218.7592 + 0.814868 224.2832 + 0.8269848 229.9466 + 0.7358219 235.753 + 0.4268066 241.7061 + 0.8835183 247.8095 + 0.8267587 254.067 + 0.5491355 259.1866 + 0.8746379 264.4093 + 0.8389229 269.7372 + 0.6826822 275.1726 + 0.9028191 280.7175 + 0.8286572 286.3741 + 0.4525082 292.1447 + 0.7583002 298.0316 + 0.9073849 304.037 + 0.9051184 310.1635 + 0.64346 316.4135 + 0.9253378 322.7894 + 0.9132795 329.2938 + 0.6598362 334.2579 + 0.9356085 339.2969 + 0.9236958 344.4118 + 0.8228285 349.6039 + 0.9376769 354.8742 + 0.9356694 360.224 + 0.9184375 365.6544 + 0.9058462 371.1667 + 0.9012623 374.8877 + 0.9611984 378.6459 + 0.9567629 382.4419 + 0.7675866 384.3541 + 0.9645271 386.2758 + 0.9546855 388.2072 + 0.7844603 388.2072 + 0.9640375 388.2072 + 0.9452955 388.2072 + 0.5753929 388.2072 + 0.394645 388.2072 + 0.5464906 388.2072 + 0.7876784 388.2072 + 0.7982122 388.2072 + 0.5932955 388.2072 + 0.4936025 388.2072 + 0.7250561 388.2072 + 0.6559195 388.2072 + 0.7656435 388.2072 + 0.9420093 388.2072 + 0.7749707 388.2072 ] diff --git a/audio/tests/features/testdata/test.wav b/audio/tests/features/testdata/test.wav new file mode 100644 index 00000000..6fdfee3c Binary files /dev/null and b/audio/tests/features/testdata/test.wav differ diff --git a/audio/tools/setup_helpers/__init__.py b/audio/tools/setup_helpers/__init__.py new file mode 100644 index 00000000..5d375081 --- /dev/null +++ b/audio/tools/setup_helpers/__init__.py @@ -0,0 +1 @@ +from .extension import * diff --git a/audio/tools/setup_helpers/extension.py b/audio/tools/setup_helpers/extension.py new file mode 100644 index 00000000..9b0aca4b --- /dev/null +++ b/audio/tools/setup_helpers/extension.py @@ -0,0 +1,152 @@ +import os +import platform +import subprocess +from pathlib import Path + +import distutils.sysconfig +from setuptools import Extension +from setuptools.command.build_ext import build_ext + +__all__ = [ + "get_ext_modules", + "CMakeBuild", +] + +_THIS_DIR = Path(__file__).parent.resolve() +_ROOT_DIR = _THIS_DIR.parent.parent.resolve() +_PADDLESPEECH_DIR = _ROOT_DIR / "paddleaudio" + + +def _get_build(var, default=False): + if var not in os.environ: + return default + + val = os.environ.get(var, "0") + trues = ["1", "true", "TRUE", "on", "ON", "yes", "YES"] + falses = ["0", "false", "FALSE", "off", "OFF", "no", "NO"] + if val in trues: + return True + if val not in falses: + print(f"WARNING: Unexpected environment variable value `{var}={val}`. " + f"Expected one of {trues + falses}") + return False + + +_BUILD_SOX = False if platform.system() == "Windows" else _get_build( + "BUILD_SOX", True) +_BUILD_MAD = _get_build("BUILD_MAD", False) +_BUILD_KALDI = False if platform.system() == "Windows" else _get_build( + "BUILD_KALDI", True) +_PADDLESPEECH_CUDA_ARCH_LIST = os.environ.get("PADDLESPEECH_CUDA_ARCH_LIST", + None) + +def get_ext_modules(): + if platform.system() == "Windows": + return [] + modules = [ + Extension(name="paddleaudio.lib.libpaddleaudio", sources=[]), + Extension(name="paddleaudio._paddleaudio", sources=[]), + ] + return modules + + +# Based off of +# https://github.com/pybind/cmake_example/blob/580c5fd29d4651db99d8874714b07c0c49a53f8a/setup.py +class CMakeBuild(build_ext): + def run(self): + try: + subprocess.check_output(["cmake", "--version"]) + except OSError: + raise RuntimeError("CMake is not available.") from None + super().run() + + def build_extension(self, ext): + # Since two library files (libpaddleaudio and _paddleaudio) need to be + # recognized by setuptools, we instantiate `Extension` twice. (see `get_ext_modules`) + # This leads to the situation where this `build_extension` method is called twice. + # However, the following `cmake` command will build all of them at the same time, + # so, we do not need to perform `cmake` twice. + # Therefore we call `cmake` only for `paddleaudio._paddleaudio`. + if ext.name != "paddleaudio._paddleaudio": + return + + extdir = os.path.abspath( + os.path.dirname(self.get_ext_fullpath(ext.name))) + + # required for auto-detection of auxiliary "native" libs + if not extdir.endswith(os.path.sep): + extdir += os.path.sep + + cfg = "Debug" if self.debug else "Release" + + cmake_args = [ + f"-DCMAKE_BUILD_TYPE={cfg}", + # f"-DCMAKE_PREFIX_PATH={torch.utils.cmake_prefix_path}", + f"-DCMAKE_INSTALL_PREFIX={extdir}", + "-DCMAKE_VERBOSE_MAKEFILE=ON", + f"-DPYTHON_INCLUDE_DIR={distutils.sysconfig.get_python_inc()}", + #f"-DPYTHON_LIBRARY={distutils.sysconfig.get_config_var('LIBDIR')}", + f"-DBUILD_SOX:BOOL={'ON' if _BUILD_SOX else 'OFF'}", + f"-DBUILD_MAD:BOOL={'ON' if _BUILD_MAD else 'OFF'}", + f"-DBUILD_KALDI:BOOL={'ON' if _BUILD_KALDI else 'OFF'}", + # f"-DBUILD_RNNT:BOOL={'ON' if _BUILD_RNNT else 'OFF'}", + # f"-DBUILD_CTC_DECODER:BOOL={'ON' if _BUILD_CTC_DECODER else 'OFF'}", + "-DBUILD_PADDLEAUDIO_PYTHON_EXTENSION:BOOL=ON", + # f"-DUSE_ROCM:BOOL={'ON' if _USE_ROCM else 'OFF'}", + # f"-DUSE_CUDA:BOOL={'ON' if _USE_CUDA else 'OFF'}", + # f"-DUSE_OPENMP:BOOL={'ON' if _USE_OPENMP else 'OFF'}", + # f"-DUSE_FFMPEG:BOOL={'ON' if _USE_FFMPEG else 'OFF'}", + ] + build_args = ["--target", "install"] + # Pass CUDA architecture to cmake + if _PADDLESPEECH_CUDA_ARCH_LIST is not None: + # Convert MAJOR.MINOR[+PTX] list to new style one + # defined at https://cmake.org/cmake/help/latest/prop_tgt/CUDA_ARCHITECTURES.html + _arches = _PADDLESPEECH_CUDA_ARCH_LIST.replace(".", "").replace( + " ", ";").split(";") + _arches = [ + arch[:-4] if arch.endswith("+PTX") else f"{arch}-real" + for arch in _arches + ] + cmake_args += [f"-DCMAKE_CUDA_ARCHITECTURES={';'.join(_arches)}"] + + # Default to Ninja + if "CMAKE_GENERATOR" not in os.environ or platform.system() == "Windows": + cmake_args += ["-GNinja"] + + if platform.system() == "Windows": + import sys + + python_version = sys.version_info + cmake_args += [ + "-DCMAKE_C_COMPILER=cl", + "-DCMAKE_CXX_COMPILER=cl", + f"-DPYTHON_VERSION={python_version.major}.{python_version.minor}", + ] + + # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level + # across all generators. + if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: + # self.parallel is a Python 3 only way to set parallel jobs by hand + # using -j in the build_ext call, not supported by pip or PyPA-build. + if hasattr(self, "parallel") and self.parallel: + # CMake 3.12+ only. + build_args += ["-j{}".format(self.parallel)] + + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + + print( + f"cmake {_ROOT_DIR} {' '.join(cmake_args)}, cwd={self.build_temp}") + subprocess.check_call( + ["cmake", str(_ROOT_DIR)] + cmake_args, cwd=self.build_temp) + print(f"cmake --build . {' '.join(build_args)}, cwd={self.build_temp}") + subprocess.check_call( + ["cmake", "--build", "."] + build_args, cwd=self.build_temp) + + def get_ext_filename(self, fullname): + ext_filename = super().get_ext_filename(fullname) + ext_filename_parts = ext_filename.split(".") + without_abi = ext_filename_parts[:-2] + ext_filename_parts[-1:] + ext_filename = ".".join(without_abi) + return ext_filename diff --git a/docs/source/api/paddlespeech.audio.backends.rst b/docs/source/api/paddlespeech.audio.backends.rst deleted file mode 100644 index e8917897..00000000 --- a/docs/source/api/paddlespeech.audio.backends.rst +++ /dev/null @@ -1,16 +0,0 @@ -paddlespeech.audio.backends package -=================================== - -.. automodule:: paddlespeech.audio.backends - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - paddlespeech.audio.backends.soundfile_backend - paddlespeech.audio.backends.sox_backend diff --git a/docs/source/api/paddlespeech.audio.backends.soundfile_backend.rst b/docs/source/api/paddlespeech.audio.backends.soundfile_backend.rst deleted file mode 100644 index 5c4ef388..00000000 --- a/docs/source/api/paddlespeech.audio.backends.soundfile_backend.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.backends.soundfile\_backend module -===================================================== - -.. automodule:: paddlespeech.audio.backends.soundfile_backend - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.backends.sox_backend.rst b/docs/source/api/paddlespeech.audio.backends.sox_backend.rst deleted file mode 100644 index a99c49de..00000000 --- a/docs/source/api/paddlespeech.audio.backends.sox_backend.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.backends.sox\_backend module -=============================================== - -.. automodule:: paddlespeech.audio.backends.sox_backend - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.compliance.kaldi.rst b/docs/source/api/paddlespeech.audio.compliance.kaldi.rst deleted file mode 100644 index f1459cf1..00000000 --- a/docs/source/api/paddlespeech.audio.compliance.kaldi.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.compliance.kaldi module -========================================== - -.. automodule:: paddlespeech.audio.compliance.kaldi - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.compliance.rst b/docs/source/api/paddlespeech.audio.compliance.rst deleted file mode 100644 index 515d25e9..00000000 --- a/docs/source/api/paddlespeech.audio.compliance.rst +++ /dev/null @@ -1,16 +0,0 @@ -paddlespeech.audio.compliance package -===================================== - -.. automodule:: paddlespeech.audio.compliance - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - paddlespeech.audio.compliance.kaldi - paddlespeech.audio.compliance.librosa diff --git a/docs/source/api/paddlespeech.audio.datasets.dataset.rst b/docs/source/api/paddlespeech.audio.datasets.dataset.rst deleted file mode 100644 index 41243fb7..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.dataset.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.datasets.dataset module -========================================== - -.. automodule:: paddlespeech.audio.datasets.dataset - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.hey_snips.rst b/docs/source/api/paddlespeech.audio.datasets.hey_snips.rst deleted file mode 100644 index ce08b700..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.hey_snips.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.datasets.hey\_snips module -============================================= - -.. automodule:: paddlespeech.audio.datasets.hey_snips - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.rirs_noises.rst b/docs/source/api/paddlespeech.audio.datasets.rirs_noises.rst deleted file mode 100644 index 3015ba9e..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.rirs_noises.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.datasets.rirs\_noises module -=============================================== - -.. automodule:: paddlespeech.audio.datasets.rirs_noises - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.rst b/docs/source/api/paddlespeech.audio.datasets.rst deleted file mode 100644 index bfc313a7..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.rst +++ /dev/null @@ -1,22 +0,0 @@ -paddlespeech.audio.datasets package -=================================== - -.. automodule:: paddlespeech.audio.datasets - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - paddlespeech.audio.datasets.dataset - paddlespeech.audio.datasets.esc50 - paddlespeech.audio.datasets.gtzan - paddlespeech.audio.datasets.hey_snips - paddlespeech.audio.datasets.rirs_noises - paddlespeech.audio.datasets.tess - paddlespeech.audio.datasets.urban_sound - paddlespeech.audio.datasets.voxceleb diff --git a/docs/source/api/paddlespeech.audio.datasets.tess.rst b/docs/source/api/paddlespeech.audio.datasets.tess.rst deleted file mode 100644 index d845e6d6..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.tess.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.datasets.tess module -======================================= - -.. automodule:: paddlespeech.audio.datasets.tess - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.urban_sound.rst b/docs/source/api/paddlespeech.audio.datasets.urban_sound.rst deleted file mode 100644 index 4efa060a..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.urban_sound.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.datasets.urban\_sound module -=============================================== - -.. automodule:: paddlespeech.audio.datasets.urban_sound - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.voxceleb.rst b/docs/source/api/paddlespeech.audio.datasets.voxceleb.rst deleted file mode 100644 index 179053dc..00000000 --- a/docs/source/api/paddlespeech.audio.datasets.voxceleb.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.datasets.voxceleb module -=========================================== - -.. automodule:: paddlespeech.audio.datasets.voxceleb - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.functional.functional.rst b/docs/source/api/paddlespeech.audio.functional.functional.rst deleted file mode 100644 index 80cc5a5a..00000000 --- a/docs/source/api/paddlespeech.audio.functional.functional.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.functional.functional module -=============================================== - -.. automodule:: paddlespeech.audio.functional.functional - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.functional.rst b/docs/source/api/paddlespeech.audio.functional.rst deleted file mode 100644 index 4e979dd9..00000000 --- a/docs/source/api/paddlespeech.audio.functional.rst +++ /dev/null @@ -1,16 +0,0 @@ -paddlespeech.audio.functional package -===================================== - -.. automodule:: paddlespeech.audio.functional - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - paddlespeech.audio.functional.functional - paddlespeech.audio.functional.window diff --git a/docs/source/api/paddlespeech.audio.functional.window.rst b/docs/source/api/paddlespeech.audio.functional.window.rst deleted file mode 100644 index 34776275..00000000 --- a/docs/source/api/paddlespeech.audio.functional.window.rst +++ /dev/null @@ -1,7 +0,0 @@ -paddlespeech.audio.functional.window module -=========================================== - -.. automodule:: paddlespeech.audio.functional.window - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.metric.rst b/docs/source/api/paddlespeech.audio.metric.rst deleted file mode 100644 index a6d411dd..00000000 --- a/docs/source/api/paddlespeech.audio.metric.rst +++ /dev/null @@ -1,15 +0,0 @@ -paddlespeech.audio.metric package -================================= - -.. automodule:: paddlespeech.audio.metric - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - paddlespeech.audio.metric.eer diff --git a/docs/source/api/paddlespeech.audio.rst b/docs/source/api/paddlespeech.audio.rst index 4ed7e467..368ffda9 100644 --- a/docs/source/api/paddlespeech.audio.rst +++ b/docs/source/api/paddlespeech.audio.rst @@ -12,12 +12,10 @@ Subpackages .. toctree:: :maxdepth: 4 - paddlespeech.audio.backends - paddlespeech.audio.compliance - paddlespeech.audio.datasets paddlespeech.audio.features paddlespeech.audio.functional paddlespeech.audio.io + paddlespeech.audio.kaldi paddlespeech.audio.metric paddlespeech.audio.sox_effects paddlespeech.audio.streamdata diff --git a/docs/source/api/paddlespeech.audio.utils.rst b/docs/source/api/paddlespeech.audio.utils.rst index 217afa8f..0f1150ff 100644 --- a/docs/source/api/paddlespeech.audio.utils.rst +++ b/docs/source/api/paddlespeech.audio.utils.rst @@ -18,5 +18,6 @@ Submodules paddlespeech.audio.utils.error paddlespeech.audio.utils.log paddlespeech.audio.utils.numeric + paddlespeech.audio.utils.sox_utils paddlespeech.audio.utils.tensor_utils paddlespeech.audio.utils.time diff --git a/docs/source/api/paddlespeech.cls.exps.panns.rst b/docs/source/api/paddlespeech.cls.exps.panns.rst index 72f30ba6..c50382fb 100644 --- a/docs/source/api/paddlespeech.cls.exps.panns.rst +++ b/docs/source/api/paddlespeech.cls.exps.panns.rst @@ -19,4 +19,3 @@ Submodules .. toctree:: :maxdepth: 4 - diff --git a/docs/source/api/paddlespeech.kws.exps.mdtc.plot_det_curve.rst b/docs/source/api/paddlespeech.kws.exps.mdtc.plot_det_curve.rst new file mode 100644 index 00000000..46a149b0 --- /dev/null +++ b/docs/source/api/paddlespeech.kws.exps.mdtc.plot_det_curve.rst @@ -0,0 +1,7 @@ +paddlespeech.kws.exps.mdtc.plot\_det\_curve module +================================================== + +.. automodule:: paddlespeech.kws.exps.mdtc.plot_det_curve + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.rst b/docs/source/api/paddlespeech.rst index d06cd2c7..70b93ca0 100644 --- a/docs/source/api/paddlespeech.rst +++ b/docs/source/api/paddlespeech.rst @@ -23,3 +23,11 @@ Subpackages paddlespeech.text paddlespeech.utils paddlespeech.vector + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddlespeech.version diff --git a/docs/source/api/paddlespeech.t2s.exps.rst b/docs/source/api/paddlespeech.t2s.exps.rst index 643f97b4..58bbccb2 100644 --- a/docs/source/api/paddlespeech.t2s.exps.rst +++ b/docs/source/api/paddlespeech.t2s.exps.rst @@ -34,6 +34,7 @@ Submodules paddlespeech.t2s.exps.ort_predict paddlespeech.t2s.exps.ort_predict_e2e paddlespeech.t2s.exps.ort_predict_streaming + paddlespeech.t2s.exps.stream_play_tts paddlespeech.t2s.exps.syn_utils paddlespeech.t2s.exps.synthesize paddlespeech.t2s.exps.synthesize_e2e diff --git a/docs/source/api/paddlespeech.t2s.exps.stream_play_tts.rst b/docs/source/api/paddlespeech.t2s.exps.stream_play_tts.rst new file mode 100644 index 00000000..cb22dde0 --- /dev/null +++ b/docs/source/api/paddlespeech.t2s.exps.stream_play_tts.rst @@ -0,0 +1,7 @@ +paddlespeech.t2s.exps.stream\_play\_tts module +============================================== + +.. automodule:: paddlespeech.t2s.exps.stream_play_tts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.core.rst b/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.core.rst new file mode 100644 index 00000000..7aaba795 --- /dev/null +++ b/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.core.rst @@ -0,0 +1,7 @@ +paddlespeech.t2s.models.vits.monotonic\_align.core module +========================================================= + +.. automodule:: paddlespeech.t2s.models.vits.monotonic_align.core + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.rst b/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.rst new file mode 100644 index 00000000..25c819a7 --- /dev/null +++ b/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.rst @@ -0,0 +1,16 @@ +paddlespeech.t2s.models.vits.monotonic\_align package +===================================================== + +.. automodule:: paddlespeech.t2s.models.vits.monotonic_align + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddlespeech.t2s.models.vits.monotonic_align.core + paddlespeech.t2s.models.vits.monotonic_align.setup diff --git a/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.setup.rst b/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.setup.rst new file mode 100644 index 00000000..a93c3b8b --- /dev/null +++ b/docs/source/api/paddlespeech.t2s.models.vits.monotonic_align.setup.rst @@ -0,0 +1,7 @@ +paddlespeech.t2s.models.vits.monotonic\_align.setup module +========================================================== + +.. automodule:: paddlespeech.t2s.models.vits.monotonic_align.setup + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.version.rst b/docs/source/api/paddlespeech.version.rst new file mode 100644 index 00000000..707c5f88 --- /dev/null +++ b/docs/source/api/paddlespeech.version.rst @@ -0,0 +1,7 @@ +paddlespeech.version module +=========================== + +.. automodule:: paddlespeech.version + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/modules.rst b/docs/source/audio_api/modules.rst new file mode 100644 index 00000000..f4d1fda6 --- /dev/null +++ b/docs/source/audio_api/modules.rst @@ -0,0 +1,7 @@ +audio +===== + +.. toctree:: + :maxdepth: 4 + + paddleaudio diff --git a/docs/source/audio_api/paddleaudio.backends.common.rst b/docs/source/audio_api/paddleaudio.backends.common.rst new file mode 100644 index 00000000..c936645e --- /dev/null +++ b/docs/source/audio_api/paddleaudio.backends.common.rst @@ -0,0 +1,7 @@ +paddleaudio.backends.common module +================================== + +.. automodule:: paddleaudio.backends.common + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.sox_effects.rst b/docs/source/audio_api/paddleaudio.backends.no_backend.rst similarity index 51% rename from docs/source/api/paddlespeech.audio.sox_effects.rst rename to docs/source/audio_api/paddleaudio.backends.no_backend.rst index 75f991a1..bf01dab2 100644 --- a/docs/source/api/paddlespeech.audio.sox_effects.rst +++ b/docs/source/audio_api/paddleaudio.backends.no_backend.rst @@ -1,7 +1,7 @@ -paddlespeech.audio.sox\_effects package +paddleaudio.backends.no\_backend module ======================================= -.. automodule:: paddlespeech.audio.sox_effects +.. automodule:: paddleaudio.backends.no_backend :members: :undoc-members: :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.backends.rst b/docs/source/audio_api/paddleaudio.backends.rst new file mode 100644 index 00000000..79907dd2 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.backends.rst @@ -0,0 +1,19 @@ +paddleaudio.backends package +============================ + +.. automodule:: paddleaudio.backends + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.backends.common + paddleaudio.backends.no_backend + paddleaudio.backends.soundfile_backend + paddleaudio.backends.sox_io_backend + paddleaudio.backends.utils diff --git a/docs/source/audio_api/paddleaudio.backends.soundfile_backend.rst b/docs/source/audio_api/paddleaudio.backends.soundfile_backend.rst new file mode 100644 index 00000000..6146373c --- /dev/null +++ b/docs/source/audio_api/paddleaudio.backends.soundfile_backend.rst @@ -0,0 +1,7 @@ +paddleaudio.backends.soundfile\_backend module +============================================== + +.. automodule:: paddleaudio.backends.soundfile_backend + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.compliance.librosa.rst b/docs/source/audio_api/paddleaudio.backends.sox_io_backend.rst similarity index 50% rename from docs/source/api/paddlespeech.audio.compliance.librosa.rst rename to docs/source/audio_api/paddleaudio.backends.sox_io_backend.rst index 85271bee..04972706 100644 --- a/docs/source/api/paddlespeech.audio.compliance.librosa.rst +++ b/docs/source/audio_api/paddleaudio.backends.sox_io_backend.rst @@ -1,7 +1,7 @@ -paddlespeech.audio.compliance.librosa module +paddleaudio.backends.sox\_io\_backend module ============================================ -.. automodule:: paddlespeech.audio.compliance.librosa +.. automodule:: paddleaudio.backends.sox_io_backend :members: :undoc-members: :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.backends.utils.rst b/docs/source/audio_api/paddleaudio.backends.utils.rst new file mode 100644 index 00000000..c4cd5e1e --- /dev/null +++ b/docs/source/audio_api/paddleaudio.backends.utils.rst @@ -0,0 +1,7 @@ +paddleaudio.backends.utils module +================================= + +.. automodule:: paddleaudio.backends.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.compliance.kaldi.rst b/docs/source/audio_api/paddleaudio.compliance.kaldi.rst new file mode 100644 index 00000000..81bb7d64 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.compliance.kaldi.rst @@ -0,0 +1,7 @@ +paddleaudio.compliance.kaldi module +=================================== + +.. automodule:: paddleaudio.compliance.kaldi + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.compliance.librosa.rst b/docs/source/audio_api/paddleaudio.compliance.librosa.rst new file mode 100644 index 00000000..553e4d3a --- /dev/null +++ b/docs/source/audio_api/paddleaudio.compliance.librosa.rst @@ -0,0 +1,7 @@ +paddleaudio.compliance.librosa module +===================================== + +.. automodule:: paddleaudio.compliance.librosa + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.compliance.rst b/docs/source/audio_api/paddleaudio.compliance.rst new file mode 100644 index 00000000..137599bb --- /dev/null +++ b/docs/source/audio_api/paddleaudio.compliance.rst @@ -0,0 +1,16 @@ +paddleaudio.compliance package +============================== + +.. automodule:: paddleaudio.compliance + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.compliance.kaldi + paddleaudio.compliance.librosa diff --git a/docs/source/audio_api/paddleaudio.datasets.dataset.rst b/docs/source/audio_api/paddleaudio.datasets.dataset.rst new file mode 100644 index 00000000..ebf4ea18 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.datasets.dataset.rst @@ -0,0 +1,7 @@ +paddleaudio.datasets.dataset module +=================================== + +.. automodule:: paddleaudio.datasets.dataset + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.datasets.esc50.rst b/docs/source/audio_api/paddleaudio.datasets.esc50.rst new file mode 100644 index 00000000..2730fb91 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.datasets.esc50.rst @@ -0,0 +1,7 @@ +paddleaudio.datasets.esc50 module +================================= + +.. automodule:: paddleaudio.datasets.esc50 + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.datasets.gtzan.rst b/docs/source/audio_api/paddleaudio.datasets.gtzan.rst new file mode 100644 index 00000000..da3600cb --- /dev/null +++ b/docs/source/audio_api/paddleaudio.datasets.gtzan.rst @@ -0,0 +1,7 @@ +paddleaudio.datasets.gtzan module +================================= + +.. automodule:: paddleaudio.datasets.gtzan + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.datasets.hey_snips.rst b/docs/source/audio_api/paddleaudio.datasets.hey_snips.rst new file mode 100644 index 00000000..29da9fa8 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.datasets.hey_snips.rst @@ -0,0 +1,7 @@ +paddleaudio.datasets.hey\_snips module +====================================== + +.. automodule:: paddleaudio.datasets.hey_snips + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.gtzan.rst b/docs/source/audio_api/paddleaudio.datasets.rirs_noises.rst similarity index 51% rename from docs/source/api/paddlespeech.audio.datasets.gtzan.rst rename to docs/source/audio_api/paddleaudio.datasets.rirs_noises.rst index 47252e8d..26f52346 100644 --- a/docs/source/api/paddlespeech.audio.datasets.gtzan.rst +++ b/docs/source/audio_api/paddleaudio.datasets.rirs_noises.rst @@ -1,7 +1,7 @@ -paddlespeech.audio.datasets.gtzan module +paddleaudio.datasets.rirs\_noises module ======================================== -.. automodule:: paddlespeech.audio.datasets.gtzan +.. automodule:: paddleaudio.datasets.rirs_noises :members: :undoc-members: :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.datasets.rst b/docs/source/audio_api/paddleaudio.datasets.rst new file mode 100644 index 00000000..7a0b6f3f --- /dev/null +++ b/docs/source/audio_api/paddleaudio.datasets.rst @@ -0,0 +1,22 @@ +paddleaudio.datasets package +============================ + +.. automodule:: paddleaudio.datasets + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.datasets.dataset + paddleaudio.datasets.esc50 + paddleaudio.datasets.gtzan + paddleaudio.datasets.hey_snips + paddleaudio.datasets.rirs_noises + paddleaudio.datasets.tess + paddleaudio.datasets.urban_sound + paddleaudio.datasets.voxceleb diff --git a/docs/source/audio_api/paddleaudio.datasets.tess.rst b/docs/source/audio_api/paddleaudio.datasets.tess.rst new file mode 100644 index 00000000..7a4ad62a --- /dev/null +++ b/docs/source/audio_api/paddleaudio.datasets.tess.rst @@ -0,0 +1,7 @@ +paddleaudio.datasets.tess module +================================ + +.. automodule:: paddleaudio.datasets.tess + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.datasets.esc50.rst b/docs/source/audio_api/paddleaudio.datasets.urban_sound.rst similarity index 51% rename from docs/source/api/paddlespeech.audio.datasets.esc50.rst rename to docs/source/audio_api/paddleaudio.datasets.urban_sound.rst index 80e4a418..ee4ad47e 100644 --- a/docs/source/api/paddlespeech.audio.datasets.esc50.rst +++ b/docs/source/audio_api/paddleaudio.datasets.urban_sound.rst @@ -1,7 +1,7 @@ -paddlespeech.audio.datasets.esc50 module +paddleaudio.datasets.urban\_sound module ======================================== -.. automodule:: paddlespeech.audio.datasets.esc50 +.. automodule:: paddleaudio.datasets.urban_sound :members: :undoc-members: :show-inheritance: diff --git a/docs/source/api/paddlespeech.audio.metric.eer.rst b/docs/source/audio_api/paddleaudio.datasets.voxceleb.rst similarity index 52% rename from docs/source/api/paddlespeech.audio.metric.eer.rst rename to docs/source/audio_api/paddleaudio.datasets.voxceleb.rst index bbe88122..b8f90366 100644 --- a/docs/source/api/paddlespeech.audio.metric.eer.rst +++ b/docs/source/audio_api/paddleaudio.datasets.voxceleb.rst @@ -1,7 +1,7 @@ -paddlespeech.audio.metric.eer module +paddleaudio.datasets.voxceleb module ==================================== -.. automodule:: paddlespeech.audio.metric.eer +.. automodule:: paddleaudio.datasets.voxceleb :members: :undoc-members: :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.features.layers.rst b/docs/source/audio_api/paddleaudio.features.layers.rst new file mode 100644 index 00000000..90833e0a --- /dev/null +++ b/docs/source/audio_api/paddleaudio.features.layers.rst @@ -0,0 +1,7 @@ +paddleaudio.features.layers module +================================== + +.. automodule:: paddleaudio.features.layers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.features.rst b/docs/source/audio_api/paddleaudio.features.rst new file mode 100644 index 00000000..86ecb5c9 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.features.rst @@ -0,0 +1,15 @@ +paddleaudio.features package +============================ + +.. automodule:: paddleaudio.features + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.features.layers diff --git a/docs/source/audio_api/paddleaudio.functional.functional.rst b/docs/source/audio_api/paddleaudio.functional.functional.rst new file mode 100644 index 00000000..d1f72052 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.functional.functional.rst @@ -0,0 +1,7 @@ +paddleaudio.functional.functional module +======================================== + +.. automodule:: paddleaudio.functional.functional + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.functional.rst b/docs/source/audio_api/paddleaudio.functional.rst new file mode 100644 index 00000000..be76de79 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.functional.rst @@ -0,0 +1,16 @@ +paddleaudio.functional package +============================== + +.. automodule:: paddleaudio.functional + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.functional.functional + paddleaudio.functional.window diff --git a/docs/source/audio_api/paddleaudio.functional.window.rst b/docs/source/audio_api/paddleaudio.functional.window.rst new file mode 100644 index 00000000..46d89f3f --- /dev/null +++ b/docs/source/audio_api/paddleaudio.functional.window.rst @@ -0,0 +1,7 @@ +paddleaudio.functional.window module +==================================== + +.. automodule:: paddleaudio.functional.window + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.kaldi.kaldi.rst b/docs/source/audio_api/paddleaudio.kaldi.kaldi.rst new file mode 100644 index 00000000..90b07661 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.kaldi.kaldi.rst @@ -0,0 +1,7 @@ +paddleaudio.kaldi.kaldi module +============================== + +.. automodule:: paddleaudio.kaldi.kaldi + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.kaldi.rst b/docs/source/audio_api/paddleaudio.kaldi.rst new file mode 100644 index 00000000..c61b4366 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.kaldi.rst @@ -0,0 +1,15 @@ +paddleaudio.kaldi package +========================= + +.. automodule:: paddleaudio.kaldi + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.kaldi.kaldi diff --git a/docs/source/audio_api/paddleaudio.metric.eer.rst b/docs/source/audio_api/paddleaudio.metric.eer.rst new file mode 100644 index 00000000..e4b4f5f3 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.metric.eer.rst @@ -0,0 +1,7 @@ +paddleaudio.metric.eer module +============================= + +.. automodule:: paddleaudio.metric.eer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.metric.rst b/docs/source/audio_api/paddleaudio.metric.rst new file mode 100644 index 00000000..0074f0b5 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.metric.rst @@ -0,0 +1,15 @@ +paddleaudio.metric package +========================== + +.. automodule:: paddleaudio.metric + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.metric.eer diff --git a/docs/source/audio_api/paddleaudio.rst b/docs/source/audio_api/paddleaudio.rst new file mode 100644 index 00000000..1f3b2a1c --- /dev/null +++ b/docs/source/audio_api/paddleaudio.rst @@ -0,0 +1,23 @@ +paddleaudio package +=================== + +.. automodule:: paddleaudio + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.backends + paddleaudio.compliance + paddleaudio.datasets + paddleaudio.features + paddleaudio.functional + paddleaudio.kaldi + paddleaudio.metric + paddleaudio.sox_effects + paddleaudio.utils diff --git a/docs/source/audio_api/paddleaudio.sox_effects.rst b/docs/source/audio_api/paddleaudio.sox_effects.rst new file mode 100644 index 00000000..16979dd7 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.sox_effects.rst @@ -0,0 +1,15 @@ +paddleaudio.sox\_effects package +================================ + +.. automodule:: paddleaudio.sox_effects + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.sox_effects.sox_effects diff --git a/docs/source/audio_api/paddleaudio.sox_effects.sox_effects.rst b/docs/source/audio_api/paddleaudio.sox_effects.sox_effects.rst new file mode 100644 index 00000000..d9616d2e --- /dev/null +++ b/docs/source/audio_api/paddleaudio.sox_effects.sox_effects.rst @@ -0,0 +1,7 @@ +paddleaudio.sox\_effects.sox\_effects module +============================================ + +.. automodule:: paddleaudio.sox_effects.sox_effects + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.download.rst b/docs/source/audio_api/paddleaudio.utils.download.rst new file mode 100644 index 00000000..43ff441a --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.download.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.download module +================================= + +.. automodule:: paddleaudio.utils.download + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.env.rst b/docs/source/audio_api/paddleaudio.utils.env.rst new file mode 100644 index 00000000..eb398712 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.env.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.env module +============================ + +.. automodule:: paddleaudio.utils.env + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.error.rst b/docs/source/audio_api/paddleaudio.utils.error.rst new file mode 100644 index 00000000..0965835a --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.error.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.error module +============================== + +.. automodule:: paddleaudio.utils.error + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.log.rst b/docs/source/audio_api/paddleaudio.utils.log.rst new file mode 100644 index 00000000..ccd6c8c2 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.log.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.log module +============================ + +.. automodule:: paddleaudio.utils.log + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.numeric.rst b/docs/source/audio_api/paddleaudio.utils.numeric.rst new file mode 100644 index 00000000..dc8bd5a5 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.numeric.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.numeric module +================================ + +.. automodule:: paddleaudio.utils.numeric + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.rst b/docs/source/audio_api/paddleaudio.utils.rst new file mode 100644 index 00000000..71ebe88e --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.rst @@ -0,0 +1,22 @@ +paddleaudio.utils package +========================= + +.. automodule:: paddleaudio.utils + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + paddleaudio.utils.download + paddleaudio.utils.env + paddleaudio.utils.error + paddleaudio.utils.log + paddleaudio.utils.numeric + paddleaudio.utils.sox_utils + paddleaudio.utils.tensor_utils + paddleaudio.utils.time diff --git a/docs/source/audio_api/paddleaudio.utils.sox_utils.rst b/docs/source/audio_api/paddleaudio.utils.sox_utils.rst new file mode 100644 index 00000000..66a150ee --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.sox_utils.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.sox\_utils module +=================================== + +.. automodule:: paddleaudio.utils.sox_utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.tensor_utils.rst b/docs/source/audio_api/paddleaudio.utils.tensor_utils.rst new file mode 100644 index 00000000..b4bdc8e4 --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.tensor_utils.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.tensor\_utils module +====================================== + +.. automodule:: paddleaudio.utils.tensor_utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/audio_api/paddleaudio.utils.time.rst b/docs/source/audio_api/paddleaudio.utils.time.rst new file mode 100644 index 00000000..e57c595b --- /dev/null +++ b/docs/source/audio_api/paddleaudio.utils.time.rst @@ -0,0 +1,7 @@ +paddleaudio.utils.time module +============================= + +.. automodule:: paddleaudio.utils.time + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/cls/custom_dataset.md b/docs/source/cls/custom_dataset.md index b7c06cd7..7482d5ed 100644 --- a/docs/source/cls/custom_dataset.md +++ b/docs/source/cls/custom_dataset.md @@ -14,7 +14,7 @@ Assuming you have some wave files that stored in your own directory. You should Here is an example to build your custom dataset in `custom_dataset.py`: ```python -from paddlespeech.audio.datasets.dataset import AudioClassificationDataset +from paddleaudio.datasets.dataset import AudioClassificationDataset class CustomDataset(AudioClassificationDataset): meta_file = '/PATH/TO/META_FILE.txt' @@ -48,7 +48,7 @@ class CustomDataset(AudioClassificationDataset): Then you can build dataset and data loader from `CustomDataset`: ```python import paddle -from paddlespeech.audio.features import LogMelSpectrogram +from paddleaudio.features import LogMelSpectrogram from custom_dataset import CustomDataset diff --git a/docs/source/conf.py b/docs/source/conf.py index cd9b1807..d7d4d201 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,6 +26,8 @@ import sys import recommonmark.parser import sphinx_rtd_theme sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath('../../audio')) + autodoc_mock_imports = ["soundfile", "librosa"] diff --git a/docs/source/index.rst b/docs/source/index.rst index 8540d3fc..48bba3bb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -70,6 +70,7 @@ Contents :maxdepth: 2 :caption: API Reference + paddleaudio paddlespeech.audio paddlespeech.cli paddlespeech.cls diff --git a/docs/source/install.md b/docs/source/install.md index aa3d311c..61133dfa 100644 --- a/docs/source/install.md +++ b/docs/source/install.md @@ -63,8 +63,8 @@ pip install paddlespeech -i https://pypi.tuna.tsinghua.edu.cn/simple ``` You can also specify the version of paddlepaddle or install the develop version. ```bash -# install 2.3.1 version. Note, 2.3.1 is just an example, please follow the minimum dependency of paddlepaddle for your selection -pip install paddlepaddle==2.3.1 -i https://mirror.baidu.com/pypi/simple +# install 2.4.0 version. Note, 2.4.0 is just an example, please follow the minimum dependency of paddlepaddle for your selection +pip install paddlepaddle==2.4.0 -i https://mirror.baidu.com/pypi/simple # install develop version pip install paddlepaddle==0.0.0 -f https://www.paddlepaddle.org.cn/whl/linux/cpu-mkl/develop.html ``` @@ -124,9 +124,9 @@ conda install -y -c gcc_linux-64=8.4.0 gxx_linux-64=8.4.0 ``` (Hip: Do not use the last script if you want to install by **Hard** way): ### Install PaddlePaddle -You can choose the `PaddlePaddle` version based on your system. For example, for CUDA 10.2, CuDNN7.6 install paddlepaddle-gpu 2.4rc: +You can choose the `PaddlePaddle` version based on your system. For example, for CUDA 10.2, CuDNN7.6 install paddlepaddle-gpu 2.4: ```bash -# Note, 2.4rc is just an example, please follow the minimum dependency of paddlepaddle for your selection +# Note, 2.4 is just an example, please follow the minimum dependency of paddlepaddle for your selection python3 -m pip install paddlepaddle-gpu==2.4.0rc0 -i https://mirror.baidu.com/pypi/simple ``` You can also install the develop version of paddlepaddle. For example, for CUDA 10.2, CuDNN7.6 install paddlepaddle-gpu develop: @@ -188,10 +188,10 @@ conda activate tools/venv conda install -y -c conda-forge sox libsndfile swig bzip2 libflac bc ``` ### Install PaddlePaddle -Make sure you have GPU and the paddlepaddle version is right. For example, for CUDA 10.2, CuDNN7.6 install paddle 2.4rc: +Make sure you have GPU and the paddlepaddle version is right. For example, for CUDA 10.2, CuDNN7.6 install paddle 2.4: ```bash -# Note, 2.4rc is just an example, please follow the minimum dependency of paddlepaddle for your selection -python3 -m pip install paddlepaddle-gpu==2.4.0rc0 -i https://mirror.baidu.com/pypi/simple +# Note, 2.4 is just an example, please follow the minimum dependency of paddlepaddle for your selection +python3 -m pip install paddlepaddle-gpu==2.4.0 -i https://mirror.baidu.com/pypi/simple ``` You can also install the develop version of paddlepaddle. For example, for CUDA 10.2, CuDNN7.6 install paddlepaddle-gpu develop: ```bash diff --git a/examples/esc50/cls0/conf/panns.yaml b/examples/esc50/cls0/conf/panns.yaml index 1f0323f0..a0668b27 100644 --- a/examples/esc50/cls0/conf/panns.yaml +++ b/examples/esc50/cls0/conf/panns.yaml @@ -1,5 +1,5 @@ data: - dataset: 'paddlespeech.audio.datasets:ESC50' + dataset: 'paddle.audio.datasets:ESC50' num_classes: 50 train: mode: 'train' @@ -33,4 +33,4 @@ training: predicting: audio_file: '/audio/dog.wav' top_k: 10 - checkpoint: './checkpoint/epoch_50/model.pdparams' \ No newline at end of file + checkpoint: './checkpoint/epoch_50/model.pdparams' diff --git a/examples/hey_snips/kws0/conf/mdtc.yaml b/examples/hey_snips/kws0/conf/mdtc.yaml index 54d05947..857d36d4 100644 --- a/examples/hey_snips/kws0/conf/mdtc.yaml +++ b/examples/hey_snips/kws0/conf/mdtc.yaml @@ -2,7 +2,7 @@ ########################################### # Data # ########################################### -dataset: 'paddlespeech.audio.datasets:HeySnips' +dataset: 'paddleaudio.datasets:HeySnips' data_dir: '../tests/hey_snips_research_6k_en_train_eval_clean_ter' ############################################ diff --git a/examples/tess/README.md b/examples/tess/README.md new file mode 100644 index 00000000..0439841c --- /dev/null +++ b/examples/tess/README.md @@ -0,0 +1,34 @@ +# 背景 + +TESS音频情绪分类任务。 +从而校验和测试 paddle.audio 的feature, backend等相关模块。 + +本实验采用了PaddleSpeech提供了PANNs的CNN14的预训练模型进行finetune: +- CNN14: 该模型主要包含12个卷积层和2个全连接层,模型参数的数量为 79.6M,embbedding维度是 2048。 + +`PANNs`([PANNs: Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition](https://arxiv.org/pdf/1912.10211.pdf))是基于Audioset数据集训练的声音分类/识别的模型。经过预训练后,模型可以用于提取音频的embbedding。本示例将使用`PANNs`的预训练模型Finetune完成声音分类的任务。 + +## 数据集 + +[TESS: Toronto emotional speech set](https://tspace.library.utoronto.ca/handle/1807/24487) 是一个包含有 200 个目标词的时长为 2 ~ 3 秒的音频,七种情绪的数据集。由两个女演员录制(24岁和64岁),其中情绪分别是愤怒,恶心,害怕,高兴,惊喜,伤心,平淡。 + +## 模型指标 + +根据 `TESS` 提供的fold信息,对数据集进行 5-fold 的 fine-tune 训练和评估,dev准确率如下: + +|Model|feat_type|Acc| note | +|--|--|--| -- | +|CNN14| mfcc | 0.9929 |3 epoch | +|CNN14| logmelspectrogram | 0.9983 | 3 epoch | +|CNN14| spectrogram| 0.95 | 11 epoch | +|CNN14| melspectrogram| 0.9375 | 17 epoch | + +### 模型训练 + +启动训练: +```shell +$ CUDA_VISIBLE_DEVICES=0 ./run.sh 1 conf/panns_mfcc.yaml +$ CUDA_VISIBLE_DEVICES=0 ./run.sh 1 conf/panns_logmelspectrogram.yaml +$ CUDA_VISIBLE_DEVICES=0 ./run.sh 1 conf/panns_melspectrogram.yaml +$ CUDA_VISIBLE_DEVICES=0 ./run.sh 1 conf/panns_pectrogram.yaml +``` diff --git a/examples/tess/cls0/conf/panns_logmelspectrogram.yaml b/examples/tess/cls0/conf/panns_logmelspectrogram.yaml new file mode 100644 index 00000000..c48e517e --- /dev/null +++ b/examples/tess/cls0/conf/panns_logmelspectrogram.yaml @@ -0,0 +1,32 @@ +data: + dataset: 'paddle.audio.datasets:TESS' + num_classes: 7 + train: + mode: 'train' + split: 1 + feat_type: 'logmelspectrogram' + dev: + mode: 'dev' + split: 1 + feat_type: 'logmelspectrogram' + +model: + backbone: 'paddlespeech.cls.models:cnn14' + +feature: + n_fft: 1024 + hop_length: 320 + window: 'hann' + win_length: 1024 + f_min: 50.0 + f_max: 14000.0 + n_mels: 64 + +training: + epochs: 5 + learning_rate: 0.0005 + num_workers: 2 + batch_size: 128 + checkpoint_dir: './checkpoint_logmelspectrogram' + save_freq: 1 + log_freq: 1 diff --git a/examples/tess/cls0/conf/panns_melspectrogram.yaml b/examples/tess/cls0/conf/panns_melspectrogram.yaml new file mode 100644 index 00000000..66aa4a71 --- /dev/null +++ b/examples/tess/cls0/conf/panns_melspectrogram.yaml @@ -0,0 +1,32 @@ +data: + dataset: 'paddle.audio.datasets:TESS' + num_classes: 7 + train: + mode: 'train' + split: 1 + feat_type: 'melspectrogram' + dev: + mode: 'dev' + split: 1 + feat_type: 'melspectrogram' + +model: + backbone: 'paddlespeech.cls.models:cnn14' + +feature: + n_fft: 1024 + hop_length: 320 + window: 'hann' + win_length: 1024 + f_min: 50.0 + f_max: 14000.0 + n_mels: 64 + +training: + epochs: 10 + learning_rate: 0.0005 + num_workers: 2 + batch_size: 128 + checkpoint_dir: './checkpoint_melspectrogram' + save_freq: 1 + log_freq: 1 diff --git a/examples/tess/cls0/conf/panns_mfcc.yaml b/examples/tess/cls0/conf/panns_mfcc.yaml new file mode 100644 index 00000000..6800e3ab --- /dev/null +++ b/examples/tess/cls0/conf/panns_mfcc.yaml @@ -0,0 +1,33 @@ +data: + dataset: 'paddle.audio.datasets:TESS' + num_classes: 7 + train: + mode: 'train' + split: 1 + feat_type: 'mfcc' + dev: + mode: 'dev' + split: 1 + feat_type: 'mfcc' + +model: + backbone: 'paddlespeech.cls.models:cnn14' + +feature: + n_fft: 1024 + hop_length: 320 + window: 'hann' + win_length: 1024 + f_min: 50.0 + f_max: 14000.0 + n_mfcc: 64 + n_mels: 64 + +training: + epochs: 5 + learning_rate: 0.0005 + num_workers: 2 + batch_size: 128 + checkpoint_dir: './checkpoint_mfcc' + save_freq: 1 + log_freq: 1 diff --git a/examples/tess/cls0/conf/panns_spectrogram.yaml b/examples/tess/cls0/conf/panns_spectrogram.yaml new file mode 100644 index 00000000..8d88f41c --- /dev/null +++ b/examples/tess/cls0/conf/panns_spectrogram.yaml @@ -0,0 +1,28 @@ +data: + dataset: 'paddle.audio.datasets:TESS' + num_classes: 7 + train: + mode: 'train' + split: 1 + feat_type: 'spectrogram' + dev: + mode: 'dev' + split: 1 + feat_type: 'spectrogram' + +model: + backbone: 'paddlespeech.cls.models:cnn14' + +feature: + n_fft: 126 + hop_length: 320 + window: 'hann' + +training: + epochs: 10 + learning_rate: 0.0005 + num_workers: 2 + batch_size: 128 + checkpoint_dir: './checkpoint_spectrogram' + save_freq: 1 + log_freq: 1 diff --git a/examples/tess/cls0/local/train.py b/examples/tess/cls0/local/train.py new file mode 100644 index 00000000..25382d8c --- /dev/null +++ b/examples/tess/cls0/local/train.py @@ -0,0 +1,191 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import os + +import paddle +import yaml +from paddleaudio.utils import logger +from paddleaudio.utils import Timer + +from paddlespeech.cls.models import SoundClassifier +from paddlespeech.utils.dynamic_import import dynamic_import + +# yapf: disable +parser = argparse.ArgumentParser(__doc__) +parser.add_argument("--cfg_path", type=str, required=True) +args = parser.parse_args() +# yapf: enable + + +def _collate_features(batch): + # (feat, label) + # (( n_mels, length), label) + feats = [] + labels = [] + lengths = [] + for sample in batch: + feats.append(paddle.transpose(sample[0], perm=[1, 0])) + lengths.append(sample[0].shape[1]) + labels.append(sample[1]) + + max_length = max(lengths) + for i in range(len(feats)): + feats[i] = paddle.nn.functional.pad( + feats[i], [0, max_length - feats[i].shape[0], 0, 0], + data_format='NLC') + + return paddle.stack(feats), paddle.to_tensor(labels), paddle.to_tensor( + lengths) + + +if __name__ == "__main__": + nranks = paddle.distributed.get_world_size() + if paddle.distributed.get_world_size() > 1: + paddle.distributed.init_parallel_env() + local_rank = paddle.distributed.get_rank() + + args.cfg_path = os.path.abspath(os.path.expanduser(args.cfg_path)) + with open(args.cfg_path, 'r') as f: + config = yaml.safe_load(f) + + model_conf = config['model'] + data_conf = config['data'] + feat_conf = config['feature'] + feat_type = data_conf['train']['feat_type'] + training_conf = config['training'] + + # Dataset + + # set audio backend, make sure paddleaudio >= 1.0.2 installed. + paddle.audio.backends.set_backend('soundfile') + + ds_class = dynamic_import(data_conf['dataset']) + train_ds = ds_class(**data_conf['train'], **feat_conf) + dev_ds = ds_class(**data_conf['dev'], **feat_conf) + train_sampler = paddle.io.DistributedBatchSampler( + train_ds, + batch_size=training_conf['batch_size'], + shuffle=True, + drop_last=False) + train_loader = paddle.io.DataLoader( + train_ds, + batch_sampler=train_sampler, + num_workers=training_conf['num_workers'], + return_list=True, + use_buffer_reader=True, + collate_fn=_collate_features) + + # Model + backbone_class = dynamic_import(model_conf['backbone']) + backbone = backbone_class(pretrained=True, extract_embedding=True) + model = SoundClassifier(backbone, num_class=data_conf['num_classes']) + model = paddle.DataParallel(model) + optimizer = paddle.optimizer.Adam( + learning_rate=training_conf['learning_rate'], + parameters=model.parameters()) + criterion = paddle.nn.loss.CrossEntropyLoss() + + steps_per_epoch = len(train_sampler) + timer = Timer(steps_per_epoch * training_conf['epochs']) + timer.start() + + for epoch in range(1, training_conf['epochs'] + 1): + model.train() + + avg_loss = 0 + num_corrects = 0 + num_samples = 0 + for batch_idx, batch in enumerate(train_loader): + feats, labels, length = batch # feats-->(N, length, n_mels) + + logits = model(feats) + + loss = criterion(logits, labels) + loss.backward() + optimizer.step() + if isinstance(optimizer._learning_rate, + paddle.optimizer.lr.LRScheduler): + optimizer._learning_rate.step() + optimizer.clear_grad() + + # Calculate loss + avg_loss += loss.numpy()[0] + + # Calculate metrics + preds = paddle.argmax(logits, axis=1) + num_corrects += (preds == labels).numpy().sum() + num_samples += feats.shape[0] + + timer.count() + + if (batch_idx + 1 + ) % training_conf['log_freq'] == 0 and local_rank == 0: + lr = optimizer.get_lr() + avg_loss /= training_conf['log_freq'] + avg_acc = num_corrects / num_samples + + print_msg = feat_type + ' Epoch={}/{}, Step={}/{}'.format( + epoch, training_conf['epochs'], batch_idx + 1, + steps_per_epoch) + print_msg += ' loss={:.4f}'.format(avg_loss) + print_msg += ' acc={:.4f}'.format(avg_acc) + print_msg += ' lr={:.6f} step/sec={:.2f} | ETA {}'.format( + lr, timer.timing, timer.eta) + logger.train(print_msg) + + avg_loss = 0 + num_corrects = 0 + num_samples = 0 + + if epoch % training_conf[ + 'save_freq'] == 0 and batch_idx + 1 == steps_per_epoch and local_rank == 0: + dev_sampler = paddle.io.BatchSampler( + dev_ds, + batch_size=training_conf['batch_size'], + shuffle=False, + drop_last=False) + dev_loader = paddle.io.DataLoader( + dev_ds, + batch_sampler=dev_sampler, + num_workers=training_conf['num_workers'], + return_list=True, + use_buffer_reader=True, + collate_fn=_collate_features) + + model.eval() + num_corrects = 0 + num_samples = 0 + with logger.processing('Evaluation on validation dataset'): + for batch_idx, batch in enumerate(dev_loader): + feats, labels, length = batch + logits = model(feats) + + preds = paddle.argmax(logits, axis=1) + num_corrects += (preds == labels).numpy().sum() + num_samples += feats.shape[0] + + print_msg = '[Evaluation result] ' + str(feat_type) + print_msg += ' dev_acc={:.4f}'.format(num_corrects / num_samples) + + logger.eval(print_msg) + + # Save model + save_dir = os.path.join(training_conf['checkpoint_dir'], + 'epoch_{}'.format(epoch)) + logger.info('Saving model checkpoint to {}'.format(save_dir)) + paddle.save(model.state_dict(), + os.path.join(save_dir, 'model.pdparams')) + paddle.save(optimizer.state_dict(), + os.path.join(save_dir, 'model.pdopt')) diff --git a/examples/tess/cls0/local/train.sh b/examples/tess/cls0/local/train.sh new file mode 100755 index 00000000..953c56bf --- /dev/null +++ b/examples/tess/cls0/local/train.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +ngpu=$1 +cfg_path=$2 + +if [ ${ngpu} -gt 0 ]; then + python3 -m paddle.distributed.launch --gpus $CUDA_VISIBLE_DEVICES local/train.py \ + --cfg_path ${cfg_path} +else + python3 local/train.py \ + --cfg_path ${cfg_path} +fi diff --git a/examples/tess/cls0/path.sh b/examples/tess/cls0/path.sh new file mode 100644 index 00000000..3eff28e4 --- /dev/null +++ b/examples/tess/cls0/path.sh @@ -0,0 +1,13 @@ +#!/bin/bash +export MAIN_ROOT=`realpath ${PWD}/../../../` + +export PATH=${MAIN_ROOT}:${MAIN_ROOT}/utils:${PATH} +export LC_ALL=C + +export PYTHONDONTWRITEBYTECODE=1 +# Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C +export PYTHONIOENCODING=UTF-8 +export PYTHONPATH=${MAIN_ROOT}:${PYTHONPATH} + +MODEL=panns +export BIN_DIR=${MAIN_ROOT}/paddlespeech/cls/exps/${MODEL} \ No newline at end of file diff --git a/examples/tess/cls0/run.sh b/examples/tess/cls0/run.sh new file mode 100755 index 00000000..0e407b40 --- /dev/null +++ b/examples/tess/cls0/run.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e +source path.sh + +ngpu=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}') + +stage=$1 +stop_stage=100 + +if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then + cfg_path=$2 + ./local/train.sh ${ngpu} ${cfg_path} || exit -1 + exit 0 +fi + +if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then + cfg_path=$2 + ./local/infer.sh ${cfg_path} || exit -1 + exit 0 +fi + +if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then + ckpt=$2 + output_dir=$3 + ./local/export.sh ${ckpt} ${output_dir} || exit -1 + exit 0 +fi + +if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then + infer_device=$2 + graph_dir=$3 + audio_file=$4 + ./local/static_model_infer.sh ${infer_device} ${graph_dir} ${audio_file} || exit -1 + exit 0 +fi diff --git a/examples/voxceleb/sv0/local/data_prepare.py b/examples/voxceleb/sv0/local/data_prepare.py index e5a5dff7..b4486b6f 100644 --- a/examples/voxceleb/sv0/local/data_prepare.py +++ b/examples/voxceleb/sv0/local/data_prepare.py @@ -14,9 +14,9 @@ import argparse import paddle +from paddleaudio.datasets.voxceleb import VoxCeleb from yacs.config import CfgNode -from paddlespeech.audio.datasets.voxceleb import VoxCeleb from paddlespeech.s2t.utils.log import Log from paddlespeech.vector.io.augment import build_augment_pipeline from paddlespeech.vector.training.seeding import seed_everything diff --git a/examples/voxceleb/sv0/local/make_rirs_noise_csv_dataset_from_json.py b/examples/voxceleb/sv0/local/make_rirs_noise_csv_dataset_from_json.py index 7ad9bd6e..11908fe6 100644 --- a/examples/voxceleb/sv0/local/make_rirs_noise_csv_dataset_from_json.py +++ b/examples/voxceleb/sv0/local/make_rirs_noise_csv_dataset_from_json.py @@ -21,9 +21,9 @@ import os from typing import List import tqdm +from paddleaudio.backends import soundfile_load as load_audio from yacs.config import CfgNode -from paddlespeech.audio import load as load_audio from paddlespeech.s2t.utils.log import Log from paddlespeech.vector.utils.vector_utils import get_chunks diff --git a/examples/voxceleb/sv0/local/make_vox_csv_dataset_from_json.py b/examples/voxceleb/sv0/local/make_vox_csv_dataset_from_json.py index 40adf53d..ebeb598a 100644 --- a/examples/voxceleb/sv0/local/make_vox_csv_dataset_from_json.py +++ b/examples/voxceleb/sv0/local/make_vox_csv_dataset_from_json.py @@ -22,9 +22,9 @@ import os import random import tqdm +from paddleaudio.backends import soundfile_load as load_audio from yacs.config import CfgNode -from paddlespeech.audio import load as load_audio from paddlespeech.s2t.utils.log import Log from paddlespeech.vector.utils.vector_utils import get_chunks diff --git a/paddlespeech/__init__.py b/paddlespeech/__init__.py index b781c4a8..6c7e75c1 100644 --- a/paddlespeech/__init__.py +++ b/paddlespeech/__init__.py @@ -12,5 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. import _locale - _locale._getdefaultlocale = (lambda *args: ['en_US', 'utf8']) diff --git a/paddlespeech/audio/.gitignore b/paddlespeech/audio/.gitignore new file mode 100644 index 00000000..24343e79 --- /dev/null +++ b/paddlespeech/audio/.gitignore @@ -0,0 +1 @@ +fc_patch/ diff --git a/paddlespeech/audio/__init__.py b/paddlespeech/audio/__init__.py index a9195810..a7cf6caa 100644 --- a/paddlespeech/audio/__init__.py +++ b/paddlespeech/audio/__init__.py @@ -11,15 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from . import compliance -from . import datasets -from . import features -from . import functional -from . import io -from . import metric -from . import sox_effects from . import streamdata from . import text from . import transform -from .backends import load -from .backends import save diff --git a/paddlespeech/audio/backends/soundfile_backend.py b/paddlespeech/audio/backends/soundfile_backend.py deleted file mode 100644 index c1155654..00000000 --- a/paddlespeech/audio/backends/soundfile_backend.py +++ /dev/null @@ -1,325 +0,0 @@ -# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import os -import warnings -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import resampy -import soundfile as sf -from scipy.io import wavfile - -from ..utils import ParameterError - -__all__ = [ - 'resample', - 'to_mono', - 'depth_convert', - 'normalize', - 'save', - 'load', -] -NORMALMIZE_TYPES = ['linear', 'gaussian'] -MERGE_TYPES = ['ch0', 'ch1', 'random', 'average'] -RESAMPLE_MODES = ['kaiser_best', 'kaiser_fast'] -EPS = 1e-8 - - -def resample(y: np.ndarray, - src_sr: int, - target_sr: int, - mode: str='kaiser_fast') -> np.ndarray: - """Audio resampling. - - Args: - y (np.ndarray): Input waveform array in 1D or 2D. - src_sr (int): Source sample rate. - target_sr (int): Target sample rate. - mode (str, optional): The resampling filter to use. Defaults to 'kaiser_fast'. - - Returns: - np.ndarray: `y` resampled to `target_sr` - """ - - if mode == 'kaiser_best': - warnings.warn( - f'Using resampy in kaiser_best to {src_sr}=>{target_sr}. This function is pretty slow, \ - we recommend the mode kaiser_fast in large scale audio trainning') - - if not isinstance(y, np.ndarray): - raise ParameterError( - 'Only support numpy np.ndarray, but received y in {type(y)}') - - if mode not in RESAMPLE_MODES: - raise ParameterError(f'resample mode must in {RESAMPLE_MODES}') - - return resampy.resample(y, src_sr, target_sr, filter=mode) - - -def to_mono(y: np.ndarray, merge_type: str='average') -> np.ndarray: - """Convert sterior audio to mono. - - Args: - y (np.ndarray): Input waveform array in 1D or 2D. - merge_type (str, optional): Merge type to generate mono waveform. Defaults to 'average'. - - Returns: - np.ndarray: `y` with mono channel. - """ - - if merge_type not in MERGE_TYPES: - raise ParameterError( - f'Unsupported merge type {merge_type}, available types are {MERGE_TYPES}' - ) - if y.ndim > 2: - raise ParameterError( - f'Unsupported audio array, y.ndim > 2, the shape is {y.shape}') - if y.ndim == 1: # nothing to merge - return y - - if merge_type == 'ch0': - return y[0] - if merge_type == 'ch1': - return y[1] - if merge_type == 'random': - return y[np.random.randint(0, 2)] - - # need to do averaging according to dtype - - if y.dtype == 'float32': - y_out = (y[0] + y[1]) * 0.5 - elif y.dtype == 'int16': - y_out = y.astype('int32') - y_out = (y_out[0] + y_out[1]) // 2 - y_out = np.clip(y_out, np.iinfo(y.dtype).min, - np.iinfo(y.dtype).max).astype(y.dtype) - - elif y.dtype == 'int8': - y_out = y.astype('int16') - y_out = (y_out[0] + y_out[1]) // 2 - y_out = np.clip(y_out, np.iinfo(y.dtype).min, - np.iinfo(y.dtype).max).astype(y.dtype) - else: - raise ParameterError(f'Unsupported dtype: {y.dtype}') - return y_out - - -def _safe_cast(y: np.ndarray, dtype: Union[type, str]) -> np.ndarray: - """Data type casting in a safe way, i.e., prevent overflow or underflow. - - Args: - y (np.ndarray): Input waveform array in 1D or 2D. - dtype (Union[type, str]): Data type of waveform. - - Returns: - np.ndarray: `y` after safe casting. - """ - if 'float' in str(y.dtype): - return np.clip(y, np.finfo(dtype).min, - np.finfo(dtype).max).astype(dtype) - else: - return np.clip(y, np.iinfo(dtype).min, - np.iinfo(dtype).max).astype(dtype) - - -def depth_convert(y: np.ndarray, dtype: Union[type, str]) -> np.ndarray: - """Convert audio array to target dtype safely. This function convert audio waveform to a target dtype, with addition steps of - preventing overflow/underflow and preserving audio range. - - Args: - y (np.ndarray): Input waveform array in 1D or 2D. - dtype (Union[type, str]): Data type of waveform. - - Returns: - np.ndarray: `y` after safe casting. - """ - - SUPPORT_DTYPE = ['int16', 'int8', 'float32', 'float64'] - if y.dtype not in SUPPORT_DTYPE: - raise ParameterError( - 'Unsupported audio dtype, ' - f'y.dtype is {y.dtype}, supported dtypes are {SUPPORT_DTYPE}') - - if dtype not in SUPPORT_DTYPE: - raise ParameterError( - 'Unsupported audio dtype, ' - f'target dtype is {dtype}, supported dtypes are {SUPPORT_DTYPE}') - - if dtype == y.dtype: - return y - - if dtype == 'float64' and y.dtype == 'float32': - return _safe_cast(y, dtype) - if dtype == 'float32' and y.dtype == 'float64': - return _safe_cast(y, dtype) - - if dtype == 'int16' or dtype == 'int8': - if y.dtype in ['float64', 'float32']: - factor = np.iinfo(dtype).max - y = np.clip(y * factor, np.iinfo(dtype).min, - np.iinfo(dtype).max).astype(dtype) - y = y.astype(dtype) - else: - if dtype == 'int16' and y.dtype == 'int8': - factor = np.iinfo('int16').max / np.iinfo('int8').max - EPS - y = y.astype('float32') * factor - y = y.astype('int16') - - else: # dtype == 'int8' and y.dtype=='int16': - y = y.astype('int32') * np.iinfo('int8').max / \ - np.iinfo('int16').max - y = y.astype('int8') - - if dtype in ['float32', 'float64']: - org_dtype = y.dtype - y = y.astype(dtype) / np.iinfo(org_dtype).max - return y - - -def sound_file_load(file: os.PathLike, - offset: Optional[float]=None, - dtype: str='int16', - duration: Optional[int]=None) -> Tuple[np.ndarray, int]: - """Load audio using soundfile library. This function load audio file using libsndfile. - - Args: - file (os.PathLike): File of waveform. - offset (Optional[float], optional): Offset to the start of waveform. Defaults to None. - dtype (str, optional): Data type of waveform. Defaults to 'int16'. - duration (Optional[int], optional): Duration of waveform to read. Defaults to None. - - Returns: - Tuple[np.ndarray, int]: Waveform in ndarray and its samplerate. - """ - with sf.SoundFile(file) as sf_desc: - sr_native = sf_desc.samplerate - if offset: - sf_desc.seek(int(offset * sr_native)) - if duration is not None: - frame_duration = int(duration * sr_native) - else: - frame_duration = -1 - y = sf_desc.read(frames=frame_duration, dtype=dtype, always_2d=False).T - - return y, sf_desc.samplerate - - -def normalize(y: np.ndarray, norm_type: str='linear', - mul_factor: float=1.0) -> np.ndarray: - """Normalize an input audio with additional multiplier. - - Args: - y (np.ndarray): Input waveform array in 1D or 2D. - norm_type (str, optional): Type of normalization. Defaults to 'linear'. - mul_factor (float, optional): Scaling factor. Defaults to 1.0. - - Returns: - np.ndarray: `y` after normalization. - """ - - if norm_type == 'linear': - amax = np.max(np.abs(y)) - factor = 1.0 / (amax + EPS) - y = y * factor * mul_factor - elif norm_type == 'gaussian': - amean = np.mean(y) - astd = np.std(y) - astd = max(astd, EPS) - y = mul_factor * (y - amean) / astd - else: - raise NotImplementedError(f'norm_type should be in {NORMALMIZE_TYPES}') - - return y - - -def save(y: np.ndarray, sr: int, file: os.PathLike) -> None: - """Save audio file to disk. This function saves audio to disk using scipy.io.wavfile, with additional step to convert input waveform to int16. - - Args: - y (np.ndarray): Input waveform array in 1D or 2D. - sr (int): Sample rate. - file (os.PathLike): Path of auido file to save. - """ - if not file.endswith('.wav'): - raise ParameterError( - f'only .wav file supported, but dst file name is: {file}') - - if sr <= 0: - raise ParameterError( - f'Sample rate should be larger than 0, recieved sr = {sr}') - - if y.dtype not in ['int16', 'int8']: - warnings.warn( - f'input data type is {y.dtype}, will convert data to int16 format before saving' - ) - y_out = depth_convert(y, 'int16') - else: - y_out = y - - wavfile.write(file, sr, y_out) - - -def load( - file: os.PathLike, - sr: Optional[int]=None, - mono: bool=True, - merge_type: str='average', # ch0,ch1,random,average - normal: bool=True, - norm_type: str='linear', - norm_mul_factor: float=1.0, - offset: float=0.0, - duration: Optional[int]=None, - dtype: str='float32', - resample_mode: str='kaiser_fast') -> Tuple[np.ndarray, int]: - """Load audio file from disk. This function loads audio from disk using using audio beackend. - - Args: - file (os.PathLike): Path of auido file to load. - sr (Optional[int], optional): Sample rate of loaded waveform. Defaults to None. - mono (bool, optional): Return waveform with mono channel. Defaults to True. - merge_type (str, optional): Merge type of multi-channels waveform. Defaults to 'average'. - normal (bool, optional): Waveform normalization. Defaults to True. - norm_type (str, optional): Type of normalization. Defaults to 'linear'. - norm_mul_factor (float, optional): Scaling factor. Defaults to 1.0. - offset (float, optional): Offset to the start of waveform. Defaults to 0.0. - duration (Optional[int], optional): Duration of waveform to read. Defaults to None. - dtype (str, optional): Data type of waveform. Defaults to 'float32'. - resample_mode (str, optional): The resampling filter to use. Defaults to 'kaiser_fast'. - - Returns: - Tuple[np.ndarray, int]: Waveform in ndarray and its samplerate. - """ - - y, r = sound_file_load(file, offset=offset, dtype=dtype, duration=duration) - - if not ((y.ndim == 1 and len(y) > 0) or (y.ndim == 2 and len(y[0]) > 0)): - raise ParameterError(f'audio file {file} looks empty') - - if mono: - y = to_mono(y, merge_type) - - if sr is not None and sr != r: - y = resample(y, r, sr, mode=resample_mode) - r = sr - - if normal: - y = normalize(y, norm_type, norm_mul_factor) - elif dtype in ['int8', 'int16']: - # still need to do normalization, before depth convertion - y = normalize(y, 'linear', 1.0) - - y = depth_convert(y, dtype) - return y, r diff --git a/paddlespeech/audio/backends/sox_backend.py b/paddlespeech/audio/backends/sox_backend.py deleted file mode 100644 index 97043fd7..00000000 --- a/paddlespeech/audio/backends/sox_backend.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/paddlespeech/audio/streamdata/autodecode.py b/paddlespeech/audio/streamdata/autodecode.py index d7f7937b..2e82226d 100644 --- a/paddlespeech/audio/streamdata/autodecode.py +++ b/paddlespeech/audio/streamdata/autodecode.py @@ -295,7 +295,7 @@ def torch_video(key, data): def paddle_audio(key, data): - """Decode audio using the paddlespeech.audio library. + """Decode audio using the paddleaudio library. :param key: file name extension :param data: data to be decoded @@ -304,13 +304,13 @@ def paddle_audio(key, data): if extension not in ["flac", "mp3", "sox", "wav", "m4a", "ogg", "wma"]: return None - import paddlespeech.audio + import paddleaudio with tempfile.TemporaryDirectory() as dirname: fname = os.path.join(dirname, f"file.{extension}") with open(fname, "wb") as stream: stream.write(data) - return paddlespeech.audio.load(fname) + return paddleaudio.backends.soundfile_load(fname) ################################################################ diff --git a/paddlespeech/audio/streamdata/filters.py b/paddlespeech/audio/streamdata/filters.py index 68d6830b..110b4a30 100644 --- a/paddlespeech/audio/streamdata/filters.py +++ b/paddlespeech/audio/streamdata/filters.py @@ -22,11 +22,11 @@ from fnmatch import fnmatch from functools import reduce import paddle +from paddleaudio import backends +from paddleaudio.compliance import kaldi from . import autodecode from . import utils -from .. import backends -from ..compliance import kaldi from ..transform.cmvn import GlobalCMVN from ..transform.spec_augment import freq_mask from ..transform.spec_augment import time_mask diff --git a/paddlespeech/audio/streamdata/tariterators.py b/paddlespeech/audio/streamdata/tariterators.py index 79b81c0c..3adf4892 100644 --- a/paddlespeech/audio/streamdata/tariterators.py +++ b/paddlespeech/audio/streamdata/tariterators.py @@ -20,7 +20,7 @@ trace = False meta_prefix = "__" meta_suffix = "__" -import paddlespeech +import paddleaudio import paddle import numpy as np @@ -111,7 +111,7 @@ def tar_file_iterator(fileobj, assert pos > 0 prefix, postfix = name[:pos], name[pos + 1:] if postfix == 'wav': - waveform, sample_rate = paddlespeech.audio.load( + waveform, sample_rate = paddleaudio.backends.soundfile_load( stream.extractfile(tarinfo), normal=False) result = dict( fname=prefix, wav=waveform, sample_rate=sample_rate) @@ -163,7 +163,7 @@ def tar_file_and_group_iterator(fileobj, if postfix == 'txt': example['txt'] = file_obj.read().decode('utf8').strip() elif postfix in AUDIO_FORMAT_SETS: - waveform, sample_rate = paddlespeech.audio.load( + waveform, sample_rate = paddleaudio.backends.soundfile_load( file_obj, normal=False) waveform = paddle.to_tensor( np.expand_dims(np.array(waveform), 0), diff --git a/paddlespeech/audio/transform/spectrogram.py b/paddlespeech/audio/transform/spectrogram.py index 84812a2c..f2dab316 100644 --- a/paddlespeech/audio/transform/spectrogram.py +++ b/paddlespeech/audio/transform/spectrogram.py @@ -15,10 +15,9 @@ import librosa import numpy as np import paddle +from paddleaudio.compliance import kaldi from python_speech_features import logfbank -from ..compliance import kaldi - def stft(x, n_fft, diff --git a/paddlespeech/audio/utils/__init__.py b/paddlespeech/audio/utils/__init__.py index f1e5deb0..18c59ff1 100644 --- a/paddlespeech/audio/utils/__init__.py +++ b/paddlespeech/audio/utils/__init__.py @@ -19,5 +19,7 @@ from .download import load_state_dict_from_url from .error import ParameterError from .log import Logger from .log import logger +from .numeric import depth_convert +from .numeric import pcm16to32 from .time import seconds_to_hms from .time import Timer diff --git a/paddlespeech/audio/utils/numeric.py b/paddlespeech/audio/utils/numeric.py index 126cada5..9fe00484 100644 --- a/paddlespeech/audio/utils/numeric.py +++ b/paddlespeech/audio/utils/numeric.py @@ -11,8 +11,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from typing import Union + import numpy as np +__all__ = ["pcm16to32", "depth_convert"] + def pcm16to32(audio: np.ndarray) -> np.ndarray: """pcm int16 to float32 @@ -28,3 +32,76 @@ def pcm16to32(audio: np.ndarray) -> np.ndarray: bits = np.iinfo(np.int16).bits audio = audio / (2**(bits - 1)) return audio + + +def _safe_cast(y: np.ndarray, dtype: Union[type, str]) -> np.ndarray: + """Data type casting in a safe way, i.e., prevent overflow or underflow. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + dtype (Union[type, str]): Data type of waveform. + + Returns: + np.ndarray: `y` after safe casting. + """ + if 'float' in str(y.dtype): + return np.clip(y, np.finfo(dtype).min, + np.finfo(dtype).max).astype(dtype) + else: + return np.clip(y, np.iinfo(dtype).min, + np.iinfo(dtype).max).astype(dtype) + + +def depth_convert(y: np.ndarray, dtype: Union[type, str]) -> np.ndarray: + """Convert audio array to target dtype safely. + This function convert audio waveform to a target dtype, with addition steps of + preventing overflow/underflow and preserving audio range. + + Args: + y (np.ndarray): Input waveform array in 1D or 2D. + dtype (Union[type, str]): Data type of waveform. + + Returns: + np.ndarray: `y` after safe casting. + """ + + SUPPORT_DTYPE = ['int16', 'int8', 'float32', 'float64'] + if y.dtype not in SUPPORT_DTYPE: + raise ParameterError( + 'Unsupported audio dtype, ' + f'y.dtype is {y.dtype}, supported dtypes are {SUPPORT_DTYPE}') + + if dtype not in SUPPORT_DTYPE: + raise ParameterError( + 'Unsupported audio dtype, ' + f'target dtype is {dtype}, supported dtypes are {SUPPORT_DTYPE}') + + if dtype == y.dtype: + return y + + if dtype == 'float64' and y.dtype == 'float32': + return _safe_cast(y, dtype) + if dtype == 'float32' and y.dtype == 'float64': + return _safe_cast(y, dtype) + + if dtype == 'int16' or dtype == 'int8': + if y.dtype in ['float64', 'float32']: + factor = np.iinfo(dtype).max + y = np.clip(y * factor, np.iinfo(dtype).min, + np.iinfo(dtype).max).astype(dtype) + y = y.astype(dtype) + else: + if dtype == 'int16' and y.dtype == 'int8': + factor = np.iinfo('int16').max / np.iinfo('int8').max - EPS + y = y.astype('float32') * factor + y = y.astype('int16') + + else: # dtype == 'int8' and y.dtype=='int16': + y = y.astype('int32') * np.iinfo('int8').max / \ + np.iinfo('int16').max + y = y.astype('int8') + + if dtype in ['float32', 'float64']: + org_dtype = y.dtype + y = y.astype(dtype) / np.iinfo(org_dtype).max + return y diff --git a/paddlespeech/cli/cls/infer.py b/paddlespeech/cli/cls/infer.py index c869e28b..5e2168e3 100644 --- a/paddlespeech/cli/cls/infer.py +++ b/paddlespeech/cli/cls/infer.py @@ -21,12 +21,12 @@ from typing import Union import numpy as np import paddle import yaml +from paddle.audio.features import LogMelSpectrogram +from paddleaudio.backends import soundfile_load as load from ..executor import BaseExecutor from ..log import logger from ..utils import stats_wrapper -from paddlespeech.audio import load -from paddlespeech.audio.features import LogMelSpectrogram __all__ = ['CLSExecutor'] diff --git a/paddlespeech/cli/kws/infer.py b/paddlespeech/cli/kws/infer.py index 111cfd75..ce2f3f46 100644 --- a/paddlespeech/cli/kws/infer.py +++ b/paddlespeech/cli/kws/infer.py @@ -20,12 +20,12 @@ from typing import Union import paddle import yaml +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.compliance.kaldi import fbank as kaldi_fbank from ..executor import BaseExecutor from ..log import logger from ..utils import stats_wrapper -from paddlespeech.audio import load -from paddlespeech.audio.compliance.kaldi import fbank as kaldi_fbank __all__ = ['KWSExecutor'] @@ -139,7 +139,7 @@ class KWSExecutor(BaseExecutor): Input content can be a text(tts), a file(asr, cls) or a streaming(not supported yet). """ assert os.path.isfile(audio_file) - waveform, _ = load(audio_file) + waveform, _ = load_audio(audio_file) if isinstance(audio_file, (str, os.PathLike)): logger.debug("Preprocessing audio_file:" + audio_file) diff --git a/paddlespeech/cli/vector/infer.py b/paddlespeech/cli/vector/infer.py index 11198724..57a78165 100644 --- a/paddlespeech/cli/vector/infer.py +++ b/paddlespeech/cli/vector/infer.py @@ -22,13 +22,13 @@ from typing import Union import paddle import soundfile +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.compliance.librosa import melspectrogram from yacs.config import CfgNode from ..executor import BaseExecutor from ..log import logger from ..utils import stats_wrapper -from paddlespeech.audio.backends import load as load_audio -from paddlespeech.audio.compliance.librosa import melspectrogram from paddlespeech.vector.io.batch import feature_normalize from paddlespeech.vector.modules.sid_model import SpeakerIdetification diff --git a/paddlespeech/cls/exps/panns/deploy/predict.py b/paddlespeech/cls/exps/panns/deploy/predict.py index fe1c93fa..f14b4421 100644 --- a/paddlespeech/cls/exps/panns/deploy/predict.py +++ b/paddlespeech/cls/exps/panns/deploy/predict.py @@ -16,12 +16,11 @@ import os import numpy as np from paddle import inference +from paddle.audio.datasets import ESC50 +from paddle.audio.features import MelSpectrogram +from paddleaudio.backends import soundfile_load as load_audio from scipy.special import softmax -from paddlespeech.audio.backends import load as load_audio -from paddlespeech.audio.datasets import ESC50 -from paddlespeech.audio.features import melspectrogram - # yapf: disable parser = argparse.ArgumentParser() parser.add_argument("--model_dir", type=str, required=True, default="./export", help="The directory to static model.") @@ -42,7 +41,7 @@ def extract_features(files: str, **kwargs): srs = [] max_length = float('-inf') for file in files: - waveform, sr = load_audio(file, sr=None) + waveform, sr = load_audio(file) max_length = max(max_length, len(waveform)) waveforms.append(waveform) srs.append(sr) @@ -54,7 +53,7 @@ def extract_features(files: str, **kwargs): pad_width = max_length - len(waveforms[i]) waveforms[i] = np.pad(waveforms[i], pad_width=(0, pad_width)) - feat = melspectrogram(waveforms[i], sr, **kwargs).transpose() + feat = MelSpectrogram(waveforms[i], sr, **kwargs).transpose() feats.append(feat) return np.stack(feats, axis=0) diff --git a/paddlespeech/cls/exps/panns/export_model.py b/paddlespeech/cls/exps/panns/export_model.py index e62d58f0..63b22981 100644 --- a/paddlespeech/cls/exps/panns/export_model.py +++ b/paddlespeech/cls/exps/panns/export_model.py @@ -15,8 +15,8 @@ import argparse import os import paddle +from paddleaudio.datasets import ESC50 -from paddlespeech.audio.datasets import ESC50 from paddlespeech.cls.models import cnn14 from paddlespeech.cls.models import SoundClassifier diff --git a/paddlespeech/cls/exps/panns/predict.py b/paddlespeech/cls/exps/panns/predict.py index 97759a89..4681e4dc 100644 --- a/paddlespeech/cls/exps/panns/predict.py +++ b/paddlespeech/cls/exps/panns/predict.py @@ -17,12 +17,13 @@ import os import paddle import paddle.nn.functional as F import yaml +from paddle.audio.features import LogMelSpectrogram +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.utils import logger -from paddlespeech.audio.backends import load as load_audio -from paddlespeech.audio.features import LogMelSpectrogram -from paddlespeech.audio.utils import logger from paddlespeech.cls.models import SoundClassifier from paddlespeech.utils.dynamic_import import dynamic_import +#from paddleaudio.features import LogMelSpectrogram # yapf: disable parser = argparse.ArgumentParser(__doc__) diff --git a/paddlespeech/cls/exps/panns/train.py b/paddlespeech/cls/exps/panns/train.py index 13389308..b768919b 100644 --- a/paddlespeech/cls/exps/panns/train.py +++ b/paddlespeech/cls/exps/panns/train.py @@ -16,10 +16,10 @@ import os import paddle import yaml +from paddle.audio.features import LogMelSpectrogram +from paddleaudio.utils import logger +from paddleaudio.utils import Timer -from paddlespeech.audio.features import LogMelSpectrogram -from paddlespeech.audio.utils import logger -from paddlespeech.audio.utils import Timer from paddlespeech.cls.models import SoundClassifier from paddlespeech.utils.dynamic_import import dynamic_import diff --git a/paddlespeech/cls/models/panns/panns.py b/paddlespeech/cls/models/panns/panns.py index 37deae80..6f9af9b5 100644 --- a/paddlespeech/cls/models/panns/panns.py +++ b/paddlespeech/cls/models/panns/panns.py @@ -15,8 +15,8 @@ import os import paddle.nn as nn import paddle.nn.functional as F +from paddleaudio.utils.download import load_state_dict_from_url -from paddlespeech.audio.utils.download import load_state_dict_from_url from paddlespeech.utils.env import MODEL_HOME __all__ = ['CNN14', 'CNN10', 'CNN6', 'cnn14', 'cnn10', 'cnn6'] diff --git a/paddlespeech/kws/exps/mdtc/train.py b/paddlespeech/kws/exps/mdtc/train.py index d5bb5e02..bb727d36 100644 --- a/paddlespeech/kws/exps/mdtc/train.py +++ b/paddlespeech/kws/exps/mdtc/train.py @@ -14,10 +14,10 @@ import os import paddle +from paddleaudio.utils import logger +from paddleaudio.utils import Timer from yacs.config import CfgNode -from paddlespeech.audio.utils import logger -from paddlespeech.audio.utils import Timer from paddlespeech.kws.exps.mdtc.collate import collate_features from paddlespeech.kws.models.loss import max_pooling_loss from paddlespeech.kws.models.mdtc import KWSModel diff --git a/paddlespeech/s2t/frontend/featurizer/audio_featurizer.py b/paddlespeech/s2t/frontend/featurizer/audio_featurizer.py index ac5720fd..22329d5e 100644 --- a/paddlespeech/s2t/frontend/featurizer/audio_featurizer.py +++ b/paddlespeech/s2t/frontend/featurizer/audio_featurizer.py @@ -14,11 +14,10 @@ """Contains the audio featurizer class.""" import numpy as np import paddle +import paddleaudio.compliance.kaldi as kaldi from python_speech_features import delta from python_speech_features import mfcc -import paddlespeech.audio.compliance.kaldi as kaldi - class AudioFeaturizer(): """Audio featurizer, for extracting features from audio contents of diff --git a/paddlespeech/s2t/models/u2_st/u2_st.py b/paddlespeech/s2t/models/u2_st/u2_st.py index 31defbba..016087d6 100644 --- a/paddlespeech/s2t/models/u2_st/u2_st.py +++ b/paddlespeech/s2t/models/u2_st/u2_st.py @@ -24,9 +24,9 @@ from typing import Tuple import paddle from paddle import jit from paddle import nn +from paddleaudio.utils.tensor_utils import add_sos_eos +from paddleaudio.utils.tensor_utils import th_accuracy -from paddlespeech.audio.utils.tensor_utils import add_sos_eos -from paddlespeech.audio.utils.tensor_utils import th_accuracy from paddlespeech.s2t.frontend.utility import IGNORE_ID from paddlespeech.s2t.frontend.utility import load_cmvn from paddlespeech.s2t.modules.cmvn import GlobalCMVN diff --git a/paddlespeech/s2t/modules/fbank.py b/paddlespeech/s2t/modules/fbank.py index 8d76a472..30671c27 100644 --- a/paddlespeech/s2t/modules/fbank.py +++ b/paddlespeech/s2t/modules/fbank.py @@ -1,7 +1,7 @@ import paddle from paddle import nn +from paddleaudio.compliance import kaldi -from paddlespeech.audio.compliance import kaldi from paddlespeech.s2t.utils.log import Log logger = Log(__name__).getlog() diff --git a/paddlespeech/server/engine/vector/python/vector_engine.py b/paddlespeech/server/engine/vector/python/vector_engine.py index 7b8f667d..7d86f3df 100644 --- a/paddlespeech/server/engine/vector/python/vector_engine.py +++ b/paddlespeech/server/engine/vector/python/vector_engine.py @@ -16,9 +16,9 @@ from collections import OrderedDict import numpy as np import paddle +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.compliance.librosa import melspectrogram -from paddlespeech.audio.backends import load as load_audio -from paddlespeech.audio.compliance.librosa import melspectrogram from paddlespeech.cli.log import logger from paddlespeech.cli.vector.infer import VectorExecutor from paddlespeech.server.engine.base_engine import BaseEngine diff --git a/paddlespeech/server/util.py b/paddlespeech/server/util.py index 32546a33..6aa6fd58 100644 --- a/paddlespeech/server/util.py +++ b/paddlespeech/server/util.py @@ -24,11 +24,11 @@ from typing import Any from typing import Dict import paddle +import paddleaudio import requests import yaml from paddle.framework import load -import paddlespeech.audio from .entry import client_commands from .entry import server_commands from paddlespeech.cli import download @@ -289,7 +289,7 @@ def _note_one_stat(cls_name, params={}): if 'audio_file' in params: try: - _, sr = paddlespeech.audio.load(params['audio_file']) + _, sr = paddleaudio.backends.soundfile_load(params['audio_file']) except Exception: sr = -1 diff --git a/paddlespeech/vector/exps/ecapa_tdnn/extract_emb.py b/paddlespeech/vector/exps/ecapa_tdnn/extract_emb.py index cd4538bb..821b1dee 100644 --- a/paddlespeech/vector/exps/ecapa_tdnn/extract_emb.py +++ b/paddlespeech/vector/exps/ecapa_tdnn/extract_emb.py @@ -16,10 +16,10 @@ import os import time import paddle +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.compliance.librosa import melspectrogram from yacs.config import CfgNode -from paddlespeech.audio.backends import load as load_audio -from paddlespeech.audio.compliance.librosa import melspectrogram from paddlespeech.s2t.utils.log import Log from paddlespeech.vector.io.batch import feature_normalize from paddlespeech.vector.models.ecapa_tdnn import EcapaTdnn diff --git a/paddlespeech/vector/exps/ecapa_tdnn/test.py b/paddlespeech/vector/exps/ecapa_tdnn/test.py index 6c87dbe7..f15dbf9b 100644 --- a/paddlespeech/vector/exps/ecapa_tdnn/test.py +++ b/paddlespeech/vector/exps/ecapa_tdnn/test.py @@ -18,10 +18,10 @@ import numpy as np import paddle from paddle.io import BatchSampler from paddle.io import DataLoader +from paddleaudio.metric import compute_eer from tqdm import tqdm from yacs.config import CfgNode -from paddlespeech.audio.metric import compute_eer from paddlespeech.s2t.utils.log import Log from paddlespeech.vector.io.batch import batch_feature_normalize from paddlespeech.vector.io.dataset import CSVDataset diff --git a/paddlespeech/vector/exps/ecapa_tdnn/train.py b/paddlespeech/vector/exps/ecapa_tdnn/train.py index 961b75e2..bf014045 100644 --- a/paddlespeech/vector/exps/ecapa_tdnn/train.py +++ b/paddlespeech/vector/exps/ecapa_tdnn/train.py @@ -20,9 +20,9 @@ import paddle from paddle.io import BatchSampler from paddle.io import DataLoader from paddle.io import DistributedBatchSampler +from paddleaudio.compliance.librosa import melspectrogram from yacs.config import CfgNode -from paddlespeech.audio.compliance.librosa import melspectrogram from paddlespeech.s2t.utils.log import Log from paddlespeech.vector.io.augment import build_augment_pipeline from paddlespeech.vector.io.augment import waveform_augment diff --git a/paddlespeech/vector/exps/ge2e/speaker_verification_dataset.py b/paddlespeech/vector/exps/ge2e/speaker_verification_dataset.py index ae6f6ad9..87b7d59a 100644 --- a/paddlespeech/vector/exps/ge2e/speaker_verification_dataset.py +++ b/paddlespeech/vector/exps/ge2e/speaker_verification_dataset.py @@ -22,7 +22,7 @@ from paddlespeech.vector.exps.ge2e.random_cycle import random_cycle class MultiSpeakerMelDataset(Dataset): - """A 2 layer directory thatn contains mel spectrograms in *.npy format. + """A 2 layer directory that contains mel spectrograms in *.npy format. An Example file structure tree is shown below. We prefer to preprocess raw datasets and organized them like this. diff --git a/paddlespeech/vector/io/dataset.py b/paddlespeech/vector/io/dataset.py index 245b2959..dff8ad9f 100644 --- a/paddlespeech/vector/io/dataset.py +++ b/paddlespeech/vector/io/dataset.py @@ -15,9 +15,9 @@ from dataclasses import dataclass from dataclasses import fields from paddle.io import Dataset +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.compliance.librosa import melspectrogram -from paddlespeech.audio import load as load_audio -from paddlespeech.audio.compliance.librosa import melspectrogram from paddlespeech.s2t.utils.log import Log logger = Log(__name__).getlog() diff --git a/paddlespeech/vector/io/dataset_from_json.py b/paddlespeech/vector/io/dataset_from_json.py index 12e84577..852f39a9 100644 --- a/paddlespeech/vector/io/dataset_from_json.py +++ b/paddlespeech/vector/io/dataset_from_json.py @@ -16,10 +16,9 @@ from dataclasses import dataclass from dataclasses import fields from paddle.io import Dataset - -from paddlespeech.audio import load as load_audio -from paddlespeech.audio.compliance.librosa import melspectrogram -from paddlespeech.audio.compliance.librosa import mfcc +from paddleaudio.backends import soundfile_load as load_audio +from paddleaudio.compliance.librosa import melspectrogram +from paddleaudio.compliance.librosa import mfcc @dataclass diff --git a/setup.py b/setup.py index 5ed216f3..c55bc15b 100644 --- a/setup.py +++ b/setup.py @@ -76,6 +76,7 @@ base = [ "pyyaml", "pybind11", "paddleslim==2.3.4", + "paddleaudio>=1.0.2", ] server = ["fastapi", "uvicorn", "pattern_singleton", "websockets"] diff --git a/speechx/speechx/kaldi/base/kaldi-types.h b/speechx/speechx/kaldi/base/kaldi-types.h index 4fa8f224..c6a3e1ae 100644 --- a/speechx/speechx/kaldi/base/kaldi-types.h +++ b/speechx/speechx/kaldi/base/kaldi-types.h @@ -42,6 +42,8 @@ typedef float BaseFloat; // for discussion on what to do if you need compile kaldi // without OpenFST, see the bottom of this this file +#ifndef COMPILE_WITHOUT_OPENFST + #include namespace kaldi { @@ -55,9 +57,10 @@ namespace kaldi { typedef double double64; } // end namespace kaldi +#else // In a theoretical case you decide compile Kaldi without the OpenFST // comment the previous namespace statement and uncomment the following -/* + namespace kaldi { typedef int8_t int8; typedef int16_t int16; @@ -71,6 +74,6 @@ namespace kaldi { typedef float float32; typedef double double64; } // end namespace kaldi -*/ +#endif #endif // KALDI_BASE_KALDI_TYPES_H_ diff --git a/speechx/speechx/kaldi/feat/feature-plp.h b/speechx/speechx/kaldi/feat/feature-plp.h index 4f156ca1..cce6ee1c 100644 --- a/speechx/speechx/kaldi/feat/feature-plp.h +++ b/speechx/speechx/kaldi/feat/feature-plp.h @@ -27,7 +27,7 @@ #include "feat/feature-functions.h" #include "feat/feature-window.h" #include "feat/mel-computations.h" -#include "itf/options-itf.h" +#include "util/options-itf.h" namespace kaldi { /// @addtogroup feat FeatureExtraction diff --git a/speechx/speechx/kaldi/feat/online-feature-itf.h b/speechx/speechx/kaldi/feat/online-feature-itf.h new file mode 100644 index 00000000..a0211c09 --- /dev/null +++ b/speechx/speechx/kaldi/feat/online-feature-itf.h @@ -0,0 +1,125 @@ +// feat/online-feature-itf.h + +// Copyright 2013 Johns Hopkins University (author: Daniel Povey) + +// See ../../COPYING for clarification regarding multiple authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing permissions and +// limitations under the License. + +#ifndef KALDI_FEAT_ONLINE_FEATURE_ITF_H_ +#define KALDI_FEAT_ONLINE_FEATURE_ITF_H_ 1 +#include "base/kaldi-common.h" +#include "matrix/matrix-lib.h" + +namespace kaldi { +/// @ingroup Interfaces +/// @{ + +/** + OnlineFeatureInterface is an interface for online feature processing (it is + also usable in the offline setting, but currently we're not using it for + that). This is for use in the online2/ directory, and it supersedes the + interface in ../online/online-feat-input.h. We have a slightly different + model that puts more control in the hands of the calling thread, and won't + involve waiting on semaphores in the decoding thread. + + This interface only specifies how the object *outputs* the features. + How it obtains the features, e.g. from a previous object or objects of type + OnlineFeatureInterface, is not specified in the interface and you will + likely define new constructors or methods in the derived type to do that. + + You should appreciate that this interface is designed to allow random + access to features, as long as they are ready. That is, the user + can call GetFrame for any frame less than NumFramesReady(), and when + implementing a child class you must not make assumptions about the + order in which the user makes these calls. +*/ + +class OnlineFeatureInterface { + public: + virtual int32 Dim() const = 0; /// returns the feature dimension. + + /// Returns the total number of frames, since the start of the utterance, that + /// are now available. In an online-decoding context, this will likely + /// increase with time as more data becomes available. + virtual int32 NumFramesReady() const = 0; + + /// Returns true if this is the last frame. Frame indices are zero-based, so the + /// first frame is zero. IsLastFrame(-1) will return false, unless the file + /// is empty (which is a case that I'm not sure all the code will handle, so + /// be careful). This function may return false for some frame if + /// we haven't yet decided to terminate decoding, but later true if we decide + /// to terminate decoding. This function exists mainly to correctly handle + /// end effects in feature extraction, and is not a mechanism to determine how + /// many frames are in the decodable object (as it used to be, and for backward + /// compatibility, still is, in the Decodable interface). + virtual bool IsLastFrame(int32 frame) const = 0; + + /// Gets the feature vector for this frame. Before calling this for a given + /// frame, it is assumed that you called NumFramesReady() and it returned a + /// number greater than "frame". Otherwise this call will likely crash with + /// an assert failure. This function is not declared const, in case there is + /// some kind of caching going on, but most of the time it shouldn't modify + /// the class. + virtual void GetFrame(int32 frame, VectorBase *feat) = 0; + + + /// This is like GetFrame() but for a collection of frames. There is a + /// default implementation that just gets the frames one by one, but it + /// may be overridden for efficiency by child classes (since sometimes + /// it's more efficient to do things in a batch). + virtual void GetFrames(const std::vector &frames, + MatrixBase *feats) { + KALDI_ASSERT(static_cast(frames.size()) == feats->NumRows()); + for (size_t i = 0; i < frames.size(); i++) { + SubVector feat(*feats, i); + GetFrame(frames[i], &feat); + } + } + + + // Returns frame shift in seconds. Helps to estimate duration from frame + // counts. + virtual BaseFloat FrameShiftInSeconds() const = 0; + + /// Virtual destructor. Note: constructors that take another member of + /// type OnlineFeatureInterface are not expected to take ownership of + /// that pointer; the caller needs to keep track of that manually. + virtual ~OnlineFeatureInterface() { } + +}; + + +/// Add a virtual class for "source" features such as MFCC or PLP or pitch +/// features. +class OnlineBaseFeature: public OnlineFeatureInterface { + public: + /// This would be called from the application, when you get more wave data. + /// Note: the sampling_rate is typically only provided so the code can assert + /// that it matches the sampling rate expected in the options. + virtual void AcceptWaveform(BaseFloat sampling_rate, + const VectorBase &waveform) = 0; + + /// InputFinished() tells the class you won't be providing any + /// more waveform. This will help flush out the last few frames + /// of delta or LDA features (it will typically affect the return value + /// of IsLastFrame. + virtual void InputFinished() = 0; +}; + + +/// @} +} // namespace Kaldi + +#endif // KALDI_ITF_ONLINE_FEATURE_ITF_H_ diff --git a/speechx/speechx/kaldi/feat/online-feature.h b/speechx/speechx/kaldi/feat/online-feature.h index f2ebe45b..f9b26ecc 100644 --- a/speechx/speechx/kaldi/feat/online-feature.h +++ b/speechx/speechx/kaldi/feat/online-feature.h @@ -34,7 +34,7 @@ #include "feat/feature-mfcc.h" #include "feat/feature-plp.h" #include "feat/feature-fbank.h" -#include "itf/online-feature-itf.h" +#include "feat/online-feature-itf.h" namespace kaldi { /// @addtogroup onlinefeat OnlineFeatureExtraction diff --git a/speechx/speechx/kaldi/feat/pitch-functions.h b/speechx/speechx/kaldi/feat/pitch-functions.h index 70e85380..9edf6c9f 100644 --- a/speechx/speechx/kaldi/feat/pitch-functions.h +++ b/speechx/speechx/kaldi/feat/pitch-functions.h @@ -31,7 +31,7 @@ #include "base/kaldi-error.h" #include "feat/mel-computations.h" -#include "itf/online-feature-itf.h" +#include "feat/online-feature-itf.h" #include "matrix/matrix-lib.h" #include "util/common-utils.h" diff --git a/speechx/speechx/kaldi/matrix/kaldi-blas.h b/speechx/speechx/kaldi/matrix/kaldi-blas.h index 143781c8..e8a703c0 100644 --- a/speechx/speechx/kaldi/matrix/kaldi-blas.h +++ b/speechx/speechx/kaldi/matrix/kaldi-blas.h @@ -96,6 +96,12 @@ #elif defined(HAVE_OPENBLAS) // getting cblas.h and lapacke.h from /. // putting in "" not <> to search -I before system libraries. + #if defined(_MSC_VER) + #include + #define LAPACK_COMPLEX_CUSTOM + #define lapack_complex_float _Fcomplex + #define lapack_complex_double _Dcomplex + #endif #include "cblas.h" #include "lapacke.h" #undef I diff --git a/tests/unit/audio/features/__init__.py b/tests/unit/audio/features/__init__.py deleted file mode 100644 index 97043fd7..00000000 --- a/tests/unit/audio/features/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/tools/extras/install_openblas.sh b/tools/extras/install_openblas.sh index b1e4d3da..91b6444b 100755 --- a/tools/extras/install_openblas.sh +++ b/tools/extras/install_openblas.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -OPENBLAS_VERSION=0.3.13 +OPENBLAS_VERSION=0.3.10 WGET=${WGET:-wget}