diff --git a/.circleci/unittest/linux/scripts/install.sh b/.circleci/unittest/linux/scripts/install.sh index 487e92d638..d2502aa2d8 100755 --- a/.circleci/unittest/linux/scripts/install.sh +++ b/.circleci/unittest/linux/scripts/install.sh @@ -71,7 +71,7 @@ fi # Note: installing librosa via pip fail because it will try to compile numba. ( set -x - conda install -y -c conda-forge ${NUMBA_DEV_CHANNEL} 'librosa==0.10.0' parameterized 'requests>=2.20' + conda install -y -c conda-forge ${NUMBA_DEV_CHANNEL} sox libvorbis 'librosa==0.10.0' parameterized 'requests>=2.20' pip install kaldi-io SoundFile coverage pytest pytest-cov 'scipy==1.7.3' transformers expecttest unidecode inflect Pillow sentencepiece pytorch-lightning 'protobuf<4.21.0' demucs tinytag pyroomacoustics flashlight-text git+https://github.com/kpu/kenlm ) # Install fairseq diff --git a/.circleci/unittest/windows/scripts/install.sh b/.circleci/unittest/windows/scripts/install.sh index a1f9243fd3..88a48eb5af 100644 --- a/.circleci/unittest/windows/scripts/install.sh +++ b/.circleci/unittest/windows/scripts/install.sh @@ -67,7 +67,7 @@ case "$(python --version)" in esac # Note: installing librosa via pip fail because it will try to compile numba. ( - conda install -y -c conda-forge ${NUMBA_DEV_CHANNEL} 'librosa==0.10.0' parameterized 'requests>=2.20' + conda install -y -c conda-forge ${NUMBA_DEV_CHANNEL} sox libvorbis 'librosa==0.10.0' parameterized 'requests>=2.20' # Need to disable shell check since this'll fail out if SENTENCEPIECE_DEPENDENCY is empty # shellcheck disable=SC2086 pip install \ diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 8f1f99f9c3..3d7213c787 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -119,7 +119,7 @@ jobs: pip --quiet install git+https://github.com/kpu/kenlm/ flashlight-text # Install build tools - conda install --quiet -y -c conda-forge pandoc doxygen pysoundfile + conda install --quiet -y -c conda-forge sox pandoc doxygen pysoundfile pip install --quiet -r docs/requirements.txt -r docs/requirements-tutorials.txt # Build docs diff --git a/.github/workflows/unittest-linux-cpu.yml b/.github/workflows/unittest-linux-cpu.yml index 1403c175dc..193095a7c5 100644 --- a/.github/workflows/unittest-linux-cpu.yml +++ b/.github/workflows/unittest-linux-cpu.yml @@ -50,6 +50,8 @@ jobs: export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_AUDIO_OUT_DEVICE=true export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MACOS=true + export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_DECODER=true + export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_ENCODER=true echo '::endgroup::' set -euxo pipefail diff --git a/.github/workflows/unittest-linux-gpu.yml b/.github/workflows/unittest-linux-gpu.yml index b6bb10daf6..53064ca7ee 100644 --- a/.github/workflows/unittest-linux-gpu.yml +++ b/.github/workflows/unittest-linux-gpu.yml @@ -60,7 +60,7 @@ jobs: USE_FFMPEG=1 python3 -m pip install -v -e . --no-use-pep517 # Install test tools - conda install -y --quiet -c conda-forge -c numba/label/dev 'librosa==0.10.0' parameterized 'requests>=2.20' + conda install -y --quiet -c conda-forge -c numba/label/dev sox libvorbis 'librosa==0.10.0' parameterized 'requests>=2.20' python3 -m pip install --quiet kaldi-io SoundFile coverage pytest pytest-cov 'scipy==1.7.3' transformers expecttest unidecode inflect Pillow sentencepiece pytorch-lightning 'protobuf<4.21.0' demucs tinytag flashlight-text git+https://github.com/kpu/kenlm/ python3 -m pip install --quiet git+https://github.com/pytorch/fairseq.git@e47a4c8 diff --git a/.github/workflows/unittest-macos-cpu.yml b/.github/workflows/unittest-macos-cpu.yml index 962d8949c1..e7f2460ed6 100644 --- a/.github/workflows/unittest-macos-cpu.yml +++ b/.github/workflows/unittest-macos-cpu.yml @@ -49,6 +49,8 @@ jobs: export TORCHAUDIO_TEST_ALLOW_SKIP_IF_ON_PYTHON_310=true export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_MOD_sentencepiece=true export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_AUDIO_OUT_DEVICE=true + export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_DECODER=true + export TORCHAUDIO_TEST_ALLOW_SKIP_IF_NO_SOX_ENCODER=true echo '::endgroup::' set -euxo pipefail diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..a2f59ecec4 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,13 @@ +[pytest] +addopts = + # show tests that (f)ailed, (E)rror, or (X)passed in the summary + -rfEX + # Make tracebacks shorter + --tb=native + # enable all warnings + -Wd + --ignore=test/test_datasets_download.py + --ignore-glob=test/test_prototype_*.py +testpaths = + test +xfail_strict = True diff --git a/setup.py b/setup.py index f55a2c3f01..37490eb9ae 100644 --- a/setup.py +++ b/setup.py @@ -104,18 +104,6 @@ def _parse_url(path): yield url -def _parse_sources(): - third_party_dir = ROOT_DIR / "third_party" - libs = ["sox"] - archive_dir = third_party_dir / "archives" - archive_dir.mkdir(exist_ok=True) - for lib in libs: - cmake_file = third_party_dir / lib / "CMakeLists.txt" - for url in _parse_url(cmake_file): - path = archive_dir / os.path.basename(url) - yield path, url - - def _fetch_archives(src): for dest, url in src: if not dest.exists(): @@ -123,12 +111,6 @@ def _fetch_archives(src): torch.hub.download_url_to_file(url, dest, progress=False) -def _fetch_third_party_libraries(): - _init_submodule() - if os.name != "nt": - _fetch_archives(_parse_sources()) - - def _main(): sha = _run_cmd(["git", "rev-parse", "HEAD"]) branch = _run_cmd(["git", "rev-parse", "--abbrev-ref", "HEAD"]) @@ -142,7 +124,7 @@ def _main(): print("-- Building version", version) _make_version_file(version, sha) - _fetch_third_party_libraries() + _init_submodule() with open("README.md") as f: long_description = f.read() diff --git a/test/torchaudio_unittest/backend/dispatcher/sox/info_test.py b/test/torchaudio_unittest/backend/dispatcher/sox/info_test.py index 7d87e375ee..87d13fe5bc 100644 --- a/test/torchaudio_unittest/backend/dispatcher/sox/info_test.py +++ b/test/torchaudio_unittest/backend/dispatcher/sox/info_test.py @@ -15,6 +15,7 @@ skipIfNoExec, skipIfNoModule, skipIfNoSox, + skipIfNoSoxDecoder, sox_utils, TempDirMixin, ) @@ -178,6 +179,7 @@ def test_amb(self, dtype, sample_rate, num_channels): assert info.bits_per_sample == bits_per_sample assert info.encoding == get_encoding("amb", dtype) + @skipIfNoSoxDecoder("amr_nb") def test_amr_nb(self): """`self._info` can check amr-nb file correctly""" duration = 1 @@ -256,7 +258,7 @@ def test_htk(self): assert info.encoding == "PCM_S" -@skipIfNoSox +@skipIfNoSoxDecoder("opus") class TestInfoOpus(PytorchTestCase): _info = partial(get_info_func(), backend="sox") diff --git a/test/torchaudio_unittest/backend/dispatcher/sox/load_test.py b/test/torchaudio_unittest/backend/dispatcher/sox/load_test.py index 20bc808f4b..fafe76df36 100644 --- a/test/torchaudio_unittest/backend/dispatcher/sox/load_test.py +++ b/test/torchaudio_unittest/backend/dispatcher/sox/load_test.py @@ -14,6 +14,7 @@ save_wav, skipIfNoExec, skipIfNoSox, + skipIfNoSoxDecoder, sox_utils, TempDirMixin, ) @@ -238,6 +239,7 @@ def test_vorbis_large(self, sample_rate, num_channels, quality_level): ), name_func=name_func, ) + @skipIfNoSoxDecoder("opus") def test_opus(self, bitrate, num_channels, compression_level): """`sox_io_backend.load` can load opus file correctly.""" ops_path = get_asset_path("io", f"{bitrate}_{compression_level}_{num_channels}ch.opus") @@ -282,6 +284,7 @@ def test_amb(self, dtype, sample_rate, num_channels, normalize): "amb", sample_rate, num_channels, bit_depth=bit_depth, duration=1, encoding=encoding, normalize=normalize ) + @skipIfNoSoxDecoder("amr_nb") def test_amr_nb(self): """`sox_io_backend.load` can load amr_nb format correctly.""" self.assert_format("amr-nb", sample_rate=8000, num_channels=1, bit_depth=32, duration=1) diff --git a/test/torchaudio_unittest/backend/dispatcher/sox/save_test.py b/test/torchaudio_unittest/backend/dispatcher/sox/save_test.py index eec476b6d2..afa63f69a1 100644 --- a/test/torchaudio_unittest/backend/dispatcher/sox/save_test.py +++ b/test/torchaudio_unittest/backend/dispatcher/sox/save_test.py @@ -13,6 +13,7 @@ save_wav, skipIfNoExec, skipIfNoSox, + skipIfNoSoxEncoder, sox_utils, TempDirMixin, TorchaudioTestCase, @@ -253,6 +254,7 @@ def test_save_amb(self, enc_params): encoding, bits_per_sample = enc_params self.assert_save_consistency("amb", encoding=encoding, bits_per_sample=bits_per_sample, test_mode="path") + @skipIfNoSoxEncoder("amr_nb") def test_save_amr_nb(self): self.assert_save_consistency("amr-nb", num_channels=1, test_mode="path") @@ -269,12 +271,18 @@ def test_save_gsm(self): ("flac",), ("vorbis",), ("sph", "PCM_S", 16), - ("amr-nb",), ("amb", "PCM_S", 16), ], name_func=name_func, ) def test_save_large(self, format, encoding=None, bits_per_sample=None): + self._test_save_large(format, encoding, bits_per_sample) + + @skipIfNoSoxEncoder("amr_nb") + def test_save_large_amr_nb(self): + self._test_save_large("amr_nb") + + def _test_save_large(self, format, encoding=None, bits_per_sample=None): """`self._save` can save large files.""" sample_rate = 8000 one_hour = 60 * 60 * sample_rate diff --git a/test/torchaudio_unittest/backend/sox_io/info_test.py b/test/torchaudio_unittest/backend/sox_io/info_test.py index eea0313314..67782091cc 100644 --- a/test/torchaudio_unittest/backend/sox_io/info_test.py +++ b/test/torchaudio_unittest/backend/sox_io/info_test.py @@ -10,6 +10,7 @@ save_wav, skipIfNoExec, skipIfNoSox, + skipIfNoSoxDecoder, sox_utils, TempDirMixin, ) @@ -196,6 +197,7 @@ def test_amb(self, dtype, sample_rate, num_channels): assert info.bits_per_sample == bits_per_sample assert info.encoding == get_encoding("amb", dtype) + @skipIfNoSoxDecoder("amr_nb") def test_amr_nb(self): """`sox_io_backend.info` can check amr-nb file correctly""" duration = 1 diff --git a/test/torchaudio_unittest/backend/sox_io/load_test.py b/test/torchaudio_unittest/backend/sox_io/load_test.py index 6740ac446d..35caebc028 100644 --- a/test/torchaudio_unittest/backend/sox_io/load_test.py +++ b/test/torchaudio_unittest/backend/sox_io/load_test.py @@ -18,6 +18,7 @@ skipIfNoExec, skipIfNoModule, skipIfNoSox, + skipIfNoSoxDecoder, sox_utils, TempDirMixin, ) @@ -244,6 +245,7 @@ def test_vorbis_large(self, sample_rate, num_channels, quality_level): ), name_func=name_func, ) + @skipIfNoSoxDecoder("opus") def test_opus(self, bitrate, num_channels, compression_level): """`sox_io_backend.load` can load opus file correctly.""" ops_path = get_asset_path("io", f"{bitrate}_{compression_level}_{num_channels}ch.opus") @@ -288,6 +290,7 @@ def test_amb(self, dtype, sample_rate, num_channels, normalize): "amb", sample_rate, num_channels, bit_depth=bit_depth, duration=1, encoding=encoding, normalize=normalize ) + @skipIfNoSoxDecoder("amr_nb") def test_amr_nb(self): """`sox_io_backend.load` can load amr_nb format correctly.""" self.assert_format("amr-nb", sample_rate=8000, num_channels=1, bit_depth=32, duration=1) diff --git a/test/torchaudio_unittest/backend/sox_io/save_test.py b/test/torchaudio_unittest/backend/sox_io/save_test.py index 75656d6ed6..83c188cf3d 100644 --- a/test/torchaudio_unittest/backend/sox_io/save_test.py +++ b/test/torchaudio_unittest/backend/sox_io/save_test.py @@ -12,6 +12,7 @@ save_wav, skipIfNoExec, skipIfNoSox, + skipIfNoSoxEncoder, sox_utils, TempDirMixin, TorchaudioTestCase, @@ -266,6 +267,7 @@ def test_save_amb(self, enc_params): 7, ], ) + @skipIfNoSoxEncoder("amr-nb") def test_save_amr_nb(self, bit_rate): self.assert_save_consistency("amr-nb", compression=bit_rate, num_channels=1) @@ -282,12 +284,18 @@ def test_save_gsm(self): ("flac",), ("vorbis",), ("sph", "PCM_S", 16), - ("amr-nb",), ("amb", "PCM_S", 16), ], name_func=name_func, ) def test_save_large(self, format, encoding=None, bits_per_sample=None): + self._test_save_large(format, encoding, bits_per_sample) + + @skipIfNoSoxEncoder + def test_save_large_amr_nb(self): + self.test_save_large("amr_nb") + + def _test_save_large(self, format, encoding=None, bits_per_sample=None): """`sox_io_backend.save` can save large files.""" sample_rate = 8000 one_hour = 60 * 60 * sample_rate diff --git a/test/torchaudio_unittest/common_utils/__init__.py b/test/torchaudio_unittest/common_utils/__init__.py index 1bff73a907..065f4e6fef 100644 --- a/test/torchaudio_unittest/common_utils/__init__.py +++ b/test/torchaudio_unittest/common_utils/__init__.py @@ -19,6 +19,8 @@ skipIfNoQengine, skipIfNoRIR, skipIfNoSox, + skipIfNoSoxDecoder, + skipIfNoSoxEncoder, skipIfPy310, skipIfRocm, TempDirMixin, diff --git a/test/torchaudio_unittest/common_utils/case_utils.py b/test/torchaudio_unittest/common_utils/case_utils.py index b5adfcb3b1..7d2d2d6858 100644 --- a/test/torchaudio_unittest/common_utils/case_utils.py +++ b/test/torchaudio_unittest/common_utils/case_utils.py @@ -234,6 +234,24 @@ def skipIfNoModule(module, display_name=None): reason="Sox features are not available.", key="NO_SOX", ) + + +def skipIfNoSoxDecoder(ext): + return _skipIf( + not torchaudio._extension._SOX_INITIALIZED or ext not in torchaudio.utils.sox_utils.list_read_formats(), + f'sox does not handle "{ext}" for read.', + key=f"NO_SOX_DECODER", + ) + + +def skipIfNoSoxEncoder(ext): + return _skipIf( + not torchaudio._extension._SOX_INITIALIZED or ext not in torchaudio.utils.sox_utils.list_write_formats(), + f'sox does not handle "{ext}" for read.', + key=f"NO_SOX_ENCODER", + ) + + skipIfNoKaldi = _skipIf( not torchaudio._extension._IS_KALDI_AVAILABLE, reason="Kaldi features are not available.", diff --git a/test/torchaudio_unittest/sox_effect/dataset_test.py b/test/torchaudio_unittest/sox_effect/dataset_test.py index ba3b6edf8e..4e99fad9cf 100644 --- a/test/torchaudio_unittest/sox_effect/dataset_test.py +++ b/test/torchaudio_unittest/sox_effect/dataset_test.py @@ -94,7 +94,7 @@ def test_apply_effects_file(self): loader = torch.utils.data.DataLoader( dataset, batch_size=32, - num_workers=16, + num_workers=4, worker_init_fn=init_random_seed, ) for batch in loader: @@ -115,7 +115,7 @@ def test_apply_effects_tensor(self): loader = torch.utils.data.DataLoader( dataset, batch_size=32, - num_workers=16, + num_workers=4, worker_init_fn=init_random_seed, ) for batch in loader: diff --git a/third_party/sox/CMakeLists.txt b/third_party/sox/CMakeLists.txt index b043362925..4fd0aa7376 100644 --- a/third_party/sox/CMakeLists.txt +++ b/third_party/sox/CMakeLists.txt @@ -1,212 +1,18 @@ -find_package(PkgConfig REQUIRED) +include(FetchContent) -include(ExternalProject) - -set(INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../install) -set(ARCHIVE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../archives) -set(patch_dir ${PROJECT_SOURCE_DIR}/third_party/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}" -) - -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-mad - --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 - ) - -ExternalProject_Add(sox - PREFIX ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${sox_depends} - DOWNLOAD_DIR ${ARCHIVE_DIR} +FetchContent_Declare( + sox URL https://downloads.sourceforge.net/project/sox/sox/14.4.2/sox-14.4.2.tar.bz2 URL_HASH SHA256=81a6956d4330e75b5827316e44ae381e6f1e8928003c6aa45896da9041ea149c - PATCH_COMMAND 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 -) + PATCH_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + ) +# FetchContent_MakeAvailable will parse the downloaded content and setup the targets. +# We want to only download and not build, so we run Populate manually. +if(NOT sox_POPULATED) + FetchContent_Populate(sox) +endif() add_library(libsox INTERFACE) -add_dependencies(libsox sox) -target_include_directories(libsox INTERFACE ${INSTALL_DIR}/include) -target_link_libraries(libsox INTERFACE ${SOX_LIBRARIES}) +target_include_directories(libsox INTERFACE ${sox_SOURCE_DIR}/src) diff --git a/torchaudio/_extension/__init__.py b/torchaudio/_extension/__init__.py index f65b982228..7cc62e49fe 100644 --- a/torchaudio/_extension/__init__.py +++ b/torchaudio/_extension/__init__.py @@ -4,7 +4,15 @@ from torchaudio._internal.module_utils import fail_with_message, is_module_available, no_op -from .utils import _check_cuda_version, _fail_since_no_ffmpeg, _init_dll_path, _init_ffmpeg, _init_sox, _load_lib +from .utils import ( + _check_cuda_version, + _fail_since_no_ffmpeg, + _fail_since_no_sox, + _init_dll_path, + _init_ffmpeg, + _init_sox, + _load_lib, +) _LG = logging.getLogger(__name__) @@ -51,15 +59,14 @@ _IS_ALIGN_AVAILABLE = torchaudio.lib._torchaudio.is_align_available() -# Similar to libtorchaudio, sox-related features should be importable when present. -# -# Note: This will be change in the future when sox is dynamically linked. -# At that point, this initialization should handle the case where -# sox integration is built but libsox is not found. +# Initialize libsox-related features _SOX_INITIALIZED = False if is_module_available("torchaudio.lib._torchaudio_sox"): - _init_sox() - _SOX_INITIALIZED = True + try: + _init_sox() + _SOX_INITIALIZED = True + except Exception: + _LG.debug("Failed to initialize libsox bindings", exc_info=True) # Initialize FFmpeg-related features @@ -84,14 +91,7 @@ "requires kaldi extension, but TorchAudio is not compiled with it. Please build TorchAudio with kaldi support." ) ) -fail_if_no_sox = ( - no_op - if _SOX_INITIALIZED - else fail_with_message( - "requires sox extension, but TorchAudio is not compiled with it. Please build TorchAudio with libsox support." - ) -) - +fail_if_no_sox = no_op if _SOX_INITIALIZED else _fail_since_no_sox fail_if_no_ffmpeg = no_op if _FFMPEG_INITIALIZED else _fail_since_no_ffmpeg fail_if_no_rir = ( diff --git a/torchaudio/_extension/utils.py b/torchaudio/_extension/utils.py index 30ef2e4a35..f7d24e23c5 100644 --- a/torchaudio/_extension/utils.py +++ b/torchaudio/_extension/utils.py @@ -67,12 +67,8 @@ def _init_sox(): _load_lib("libtorchaudio_sox") import torchaudio.lib._torchaudio_sox # noqa - torchaudio.lib._torchaudio_sox.set_verbosity(0) - - import atexit - - torch.ops.torchaudio.sox_effects_initialize_sox_effects() - atexit.register(torch.ops.torchaudio.sox_effects_shutdown_sox_effects) + # Dry-run + torchaudio.lib._torchaudio_sox.list_effects() def _init_ffmpeg(): @@ -124,6 +120,25 @@ def _check_cuda_version(): return version +def _fail_since_no_sox(func): + @wraps(func) + def wrapped(*_args, **_kwargs): + try: + # Note: + # We run _init_sox again just to show users the stacktrace. + # _init_ffmpeg would not succeed here. + _init_sox() + except Exception as err: + raise RuntimeError( + f"{func.__name__} requires libsox extension which is not available. " + "Please refer to the stacktrace above for how to resolve this." + ) from err + # This should not happen in normal execution, but just in case. + return func(*_args, **_kwargs) + + return wrapped + + def _fail_since_no_ffmpeg(func): @wraps(func) def wrapped(*_args, **_kwargs): diff --git a/torchaudio/csrc/sox/CMakeLists.txt b/torchaudio/csrc/sox/CMakeLists.txt index 3391a4fc37..59dbbeefdb 100644 --- a/torchaudio/csrc/sox/CMakeLists.txt +++ b/torchaudio/csrc/sox/CMakeLists.txt @@ -1,5 +1,6 @@ set( sources + libsox.cpp io.cpp utils.cpp effects.cpp diff --git a/torchaudio/csrc/sox/effects.cpp b/torchaudio/csrc/sox/effects.cpp index a159663a10..6897c1e309 100644 --- a/torchaudio/csrc/sox/effects.cpp +++ b/torchaudio/csrc/sox/effects.cpp @@ -1,49 +1,10 @@ #include #include #include +#include #include namespace torchaudio::sox { -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: - TORCH_CHECK( - sox_init() == SOX_SUCCESS, "Failed to initialize sox effects."); - SOX_RESOURCE_STATE = Initialized; - break; - case Initialized: - break; - case ShutDown: - TORCH_CHECK( - false, "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: - TORCH_CHECK(false, "SoX Effects is not initialized. Cannot shutdown."); - case Initialized: - TORCH_CHECK( - sox_quit() == SOX_SUCCESS, "Failed to initialize sox effects."); - SOX_RESOURCE_STATE = ShutDown; - break; - case ShutDown: - break; - } -} auto apply_effects_tensor( torch::Tensor waveform, @@ -91,7 +52,7 @@ auto apply_effects_file( const c10::optional& format) -> c10::optional> { // Open input file - SoxFormat sf(sox_open_read( + SoxFormat sf(lsx().sox_open_read( path.c_str(), /*signal=*/nullptr, /*encoding=*/nullptr, @@ -129,7 +90,6 @@ auto apply_effects_file( dtype, normalize.value_or(true), channels_first_); - return std::tuple( tensor, chain.getOutputSampleRate()); } @@ -137,13 +97,8 @@ auto apply_effects_file( namespace { TORCH_LIBRARY_FRAGMENT(torchaudio, m) { - m.def( - "torchaudio::sox_effects_initialize_sox_effects", - &initialize_sox_effects); - m.def("torchaudio::sox_effects_shutdown_sox_effects", &shutdown_sox_effects); m.def("torchaudio::sox_effects_apply_effects_tensor", &apply_effects_tensor); m.def("torchaudio::sox_effects_apply_effects_file", &apply_effects_file); } - } // namespace } // namespace torchaudio::sox diff --git a/torchaudio/csrc/sox/effects_chain.cpp b/torchaudio/csrc/sox/effects_chain.cpp index 81dddada28..c5d6cc27af 100644 --- a/torchaudio/csrc/sox/effects_chain.cpp +++ b/torchaudio/csrc/sox/effects_chain.cpp @@ -1,11 +1,11 @@ #include +#include #include #include "c10/util/Exception.h" using namespace torch::indexing; namespace torchaudio::sox { - namespace { /// helper classes for passing the location of input tensor and output buffer @@ -112,12 +112,12 @@ int file_output_flow( *osamp = 0; if (*isamp) { auto sf = static_cast(effp->priv)->sf; - if (sox_write(sf, ibuf, *isamp) != *isamp) { + if (lsx().sox_write(sf, ibuf, *isamp) != *isamp) { TORCH_CHECK( !sf->sox_errno, sf->sox_errstr, " ", - sox_strerror(sf->sox_errno), + lsx().sox_strerror(sf->sox_errno), " ", sf->filename); return SOX_EOF; @@ -197,18 +197,18 @@ SoxEffectsChain::SoxEffectsChain( in_sig_(), interm_sig_(), out_sig_(), - sec_(sox_create_effects_chain(&in_enc_, &out_enc_)) { + sec_(lsx().sox_create_effects_chain(&in_enc_, &out_enc_)) { TORCH_CHECK(sec_, "Failed to create effect chain."); } SoxEffectsChain::~SoxEffectsChain() { if (sec_ != nullptr) { - sox_delete_effects_chain(sec_); + lsx().sox_delete_effects_chain(sec_); } } void SoxEffectsChain::run() { - sox_flow_effects(sec_, NULL, NULL); + lsx().sox_flow_effects(sec_, NULL, NULL); } void SoxEffectsChain::addInputTensor( @@ -217,44 +217,44 @@ void SoxEffectsChain::addInputTensor( 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())); + SoxEffect e(lsx().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; TORCH_CHECK( - sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, + lsx().sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, "Internal Error: Failed to add effect: input_tensor"); } void SoxEffectsChain::addOutputBuffer( std::vector* output_buffer) { - SoxEffect e(sox_create_effect(get_tensor_output_handler())); + SoxEffect e(lsx().sox_create_effect(get_tensor_output_handler())); static_cast(e->priv)->buffer = output_buffer; TORCH_CHECK( - sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, + lsx().sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, "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"))); + SoxEffect e(lsx().sox_create_effect(lsx().sox_find_effect("input"))); char* opts[] = {(char*)sf}; - sox_effect_options(e, 1, opts); + lsx().sox_effect_options(e, 1, opts); TORCH_CHECK( - sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, + lsx().sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, "Internal Error: Failed to add effect: input ", sf->filename); } void SoxEffectsChain::addOutputFile(sox_format_t* sf) { out_sig_ = sf->signal; - SoxEffect e(sox_create_effect(get_file_output_handler())); + SoxEffect e(lsx().sox_create_effect(get_file_output_handler())); static_cast(e->priv)->sf = sf; TORCH_CHECK( - sox_add_effect(sec_, e, &interm_sig_, &out_sig_) == SOX_SUCCESS, + lsx().sox_add_effect(sec_, e, &interm_sig_, &out_sig_) == SOX_SUCCESS, "Internal Error: Failed to add effect: output ", sf->filename); } @@ -266,12 +266,12 @@ void SoxEffectsChain::addEffect(const std::vector effect) { TORCH_CHECK( UNSUPPORTED_EFFECTS.find(name) == UNSUPPORTED_EFFECTS.end(), "Unsupported effect: ", - name) + name); - auto returned_effect = sox_find_effect(name.c_str()); + auto returned_effect = lsx().sox_find_effect(name.c_str()); TORCH_CHECK(returned_effect, "Unsupported effect: ", name) - SoxEffect e(sox_create_effect(returned_effect)); + SoxEffect e(lsx().sox_create_effect(returned_effect)); const auto num_options = num_args - 1; std::vector opts; @@ -279,12 +279,12 @@ void SoxEffectsChain::addEffect(const std::vector effect) { opts.push_back((char*)effect[i].c_str()); } TORCH_CHECK( - sox_effect_options(e, num_options, num_options ? opts.data() : nullptr) == - SOX_SUCCESS, + lsx().sox_effect_options( + e, num_options, num_options ? opts.data() : nullptr) == SOX_SUCCESS, "Invalid effect option: ", c10::Join(" ", effect)) TORCH_CHECK( - sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, + lsx().sox_add_effect(sec_, e, &interm_sig_, &in_sig_) == SOX_SUCCESS, "Internal Error: Failed to add effect: \"", c10::Join(" ", effect), "\""); diff --git a/torchaudio/csrc/sox/io.cpp b/torchaudio/csrc/sox/io.cpp index b8aac89372..197c3c2bee 100644 --- a/torchaudio/csrc/sox/io.cpp +++ b/torchaudio/csrc/sox/io.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -11,7 +12,7 @@ namespace torchaudio::sox { c10::optional get_info_file( const std::string& path, const c10::optional& format) { - SoxFormat sf(sox_open_read( + SoxFormat sf(lsx().sox_open_read( path.c_str(), /*signal=*/nullptr, /*encoding=*/nullptr, @@ -107,7 +108,7 @@ void save_audio_file( const auto encoding_info = get_encodinginfo_for_save( filetype, tensor.dtype(), compression, encoding, bits_per_sample); - SoxFormat sf(sox_open_write( + SoxFormat sf(lsx().sox_open_write( path.c_str(), &signal_info, &encoding_info, diff --git a/torchaudio/csrc/sox/libsox.cpp b/torchaudio/csrc/sox/libsox.cpp new file mode 100644 index 0000000000..6c00ed2c29 --- /dev/null +++ b/torchaudio/csrc/sox/libsox.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +#include + +#include + +namespace torchaudio::sox { +namespace { + +// Handle to the dlopen-ed libsox +class LSXImpl { + at::DynamicLibrary handle; + + public: + LSX lsx; + + LSXImpl(const char* name) : handle(name) { + // check version: we only support 14.4.2 + { + auto version = ((const char* (*)(void))handle.sym("sox_version"))(); + TORCH_CHECK( + strcmp(version, "14.4.2") == 0, + "Need libsox 14.4.2, but found ", + version); + } + + // Register fanction pointers on public-facing interface +#define set_func(NAME) this->lsx.NAME = (decltype(LSX::NAME))handle.sym(#NAME) + set_func(sox_add_effect); + set_func(sox_close); + set_func(sox_create_effect); + set_func(sox_create_effects_chain); + set_func(sox_delete_effect); + set_func(sox_delete_effects_chain); + set_func(sox_effect_options); + set_func(sox_find_effect); + set_func(sox_flow_effects); + set_func(sox_get_effect_fns); + set_func(sox_get_format_fns); + set_func(sox_get_globals); + set_func(sox_open_read); + set_func(sox_open_write); + set_func(sox_strerror); + set_func(sox_write); +#undef set_func + + // Init sox effect plugins + auto fn = (int (*)())handle.sym("sox_init"); + TORCH_CHECK(SOX_SUCCESS == fn(), "Failed to initialize sox effects."); + } + + ~LSXImpl() { + auto fn = (int (*)())handle.sym("sox_quit"); + if (SOX_SUCCESS != fn()) { + TORCH_WARN("Failed to release sox effect plugins."); + } + } +}; + +static std::unique_ptr libsox; + +} // namespace + +// Fetch lsx +#if defined(_WIN32) +#define EXT ".lib" +#elif defined(__APPLE__) +#define EXT ".dylib" +#else +#define EXT ".so" +#endif +LSX& lsx() { + static c10::once_flag init_flag; + c10::call_once(init_flag, [](){ + libsox.reset(new LSXImpl("libsox" EXT)); + auto config = libsox->lsx.sox_get_globals(); + config->verbosity = 0; + config->use_threads = sox_false; + }); + static LSX& ret = libsox->lsx; + return ret; +} +#undef EXT + +} // namespace torchaudio::sox diff --git a/torchaudio/csrc/sox/libsox.h b/torchaudio/csrc/sox/libsox.h new file mode 100644 index 0000000000..f1ffcc2026 --- /dev/null +++ b/torchaudio/csrc/sox/libsox.h @@ -0,0 +1,60 @@ +#pragma once +#include + +namespace torchaudio::sox { + +// Interface to provide handle to libsox library. +struct LSX { + int (*sox_add_effect)( + sox_effects_chain_t* chain, + sox_effect_t* effp, + sox_signalinfo_t* in, + sox_signalinfo_t const* out); + int (*sox_close)(sox_format_t* ft); + + sox_effect_t* (*sox_create_effect)(sox_effect_handler_t const* eh); + + sox_effects_chain_t* (*sox_create_effects_chain)( + sox_encodinginfo_t const* in_enc, + sox_encodinginfo_t const* out_enc); + + void (*sox_delete_effect)(sox_effect_t* effp); + void (*sox_delete_effects_chain)(sox_effects_chain_t* ecp); + + int (*sox_effect_options)(sox_effect_t* effp, int argc, char* const argv[]); + + const sox_effect_handler_t* (*sox_find_effect)(char const* name); + + int (*sox_flow_effects)( + sox_effects_chain_t* chain, + int (*callback)(sox_bool all_done, void* client_data), + void* client_data); + + const sox_effect_fn_t* (*sox_get_effect_fns)(void); + + const sox_format_tab_t* (*sox_get_format_fns)(void); + + sox_globals_t* (*sox_get_globals)(void); + + sox_format_t* (*sox_open_read)( + char const* path, + sox_signalinfo_t const* signal, + sox_encodinginfo_t const* encoding, + char const* filetype); + + sox_format_t* (*sox_open_write)( + char const* path, + sox_signalinfo_t const* signal, + sox_encodinginfo_t const* encoding, + char const* filetype, + sox_oob_t const* oob, + sox_bool (*overwrite_permitted)(char const* filename)); + + const char* (*sox_strerror)(int sox_errno); + + size_t (*sox_write)(sox_format_t* ft, const sox_sample_t* buf, size_t len); +}; + +LSX& lsx(); + +} // namespace torchaudio::sox diff --git a/torchaudio/csrc/sox/utils.cpp b/torchaudio/csrc/sox/utils.cpp index 5b662bd6ff..eeb806bc84 100644 --- a/torchaudio/csrc/sox/utils.cpp +++ b/torchaudio/csrc/sox/utils.cpp @@ -1,33 +1,34 @@ #include #include +#include #include #include namespace torchaudio::sox { void set_seed(const int64_t seed) { - sox_get_globals()->ranqd1 = static_cast(seed); + lsx().sox_get_globals()->ranqd1 = static_cast(seed); } void set_verbosity(const int64_t verbosity) { - sox_get_globals()->verbosity = static_cast(verbosity); + lsx().sox_get_globals()->verbosity = static_cast(verbosity); } void set_use_threads(const bool use_threads) { - sox_get_globals()->use_threads = static_cast(use_threads); + lsx().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); + lsx().sox_get_globals()->bufsiz = static_cast(buffer_size); } int64_t get_buffer_size() { - return sox_get_globals()->bufsiz; + return lsx().sox_get_globals()->bufsiz; } std::vector> list_effects() { std::vector> effects; - for (const sox_effect_fn_t* fns = sox_get_effect_fns(); *fns; ++fns) { + for (const sox_effect_fn_t* fns = lsx().sox_get_effect_fns(); *fns; ++fns) { const sox_effect_handler_t* handler = (*fns)(); if (handler && handler->name) { if (UNSUPPORTED_EFFECTS.find(handler->name) == @@ -43,7 +44,8 @@ std::vector> list_effects() { std::vector list_write_formats() { std::vector formats; - for (const sox_format_tab_t* fns = sox_get_format_fns(); fns->fn; ++fns) { + for (const sox_format_tab_t* fns = lsx().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) @@ -55,7 +57,8 @@ std::vector list_write_formats() { std::vector list_read_formats() { std::vector formats; - for (const sox_format_tab_t* fns = sox_get_format_fns(); fns->fn; ++fns) { + for (const sox_format_tab_t* fns = lsx().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) @@ -79,7 +82,7 @@ SoxFormat::operator sox_format_t*() const noexcept { void SoxFormat::close() { if (fd_ != nullptr) { - sox_close(fd_); + lsx().sox_close(fd_); fd_ = nullptr; } } @@ -490,5 +493,4 @@ sox_encodinginfo_t get_encodinginfo_for_save( /*reverse_bits=*/sox_option_default, /*opposite_endian=*/sox_false}; } - } // namespace torchaudio::sox