-
Notifications
You must be signed in to change notification settings - Fork 633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor backend and not rely on global variables on switching #698
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import unittest | ||
|
||
import torchaudio | ||
from torchaudio._internal.module_utils import is_module_available | ||
|
||
|
||
class BackendSwitch: | ||
"""Test set/get_audio_backend works""" | ||
backend = None | ||
backend_module = None | ||
|
||
def test_switch(self): | ||
torchaudio.set_audio_backend(self.backend) | ||
if self.backend is None: | ||
assert torchaudio.get_audio_backend() is None | ||
else: | ||
assert torchaudio.get_audio_backend() == self.backend | ||
assert torchaudio.load == self.backend_module.load | ||
assert torchaudio.load_wav == self.backend_module.load_wav | ||
assert torchaudio.save == self.backend_module.save | ||
assert torchaudio.info == self.backend_module.info | ||
|
||
|
||
class TestBackendSwitch_NoBackend(BackendSwitch, unittest.TestCase): | ||
backend = None | ||
backend_module = torchaudio.backend.no_backend | ||
|
||
|
||
@unittest.skipIf( | ||
not is_module_available('torchaudio._torchaudio'), | ||
'torchaudio C++ extension not available') | ||
class TestBackendSwitch_SoX(BackendSwitch, unittest.TestCase): | ||
backend = 'sox' | ||
backend_module = torchaudio.backend.sox_backend | ||
|
||
|
||
@unittest.skipIf(not is_module_available('soundfile'), '"soundfile" not available') | ||
class TestBackendSwitch_soundfile(BackendSwitch, unittest.TestCase): | ||
backend = 'soundfile' | ||
backend_module = torchaudio.backend.soundfile_backend |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
from typing import Any, Optional, Tuple | ||
from typing import Any, Optional | ||
|
||
|
||
class SignalInfo: | ||
|
@@ -29,3 +29,115 @@ def __init__(self, | |
self.reverse_nibbles = reverse_nibbles | ||
self.reverse_bits = reverse_bits | ||
self.opposite_endian = opposite_endian | ||
|
||
|
||
_LOAD_DOCSTRING = r"""Loads an audio file from disk into a tensor | ||
|
||
Args: | ||
filepath: Path to audio file | ||
|
||
out: An optional output tensor to use instead of creating one. (Default: ``None``) | ||
|
||
normalization: Optional normalization. | ||
If boolean `True`, then output is divided by `1 << 31`. | ||
Assuming the input is signed 32-bit audio, this normalizes to `[-1, 1]`. | ||
If `float`, then output is divided by that number. | ||
If `Callable`, then the output is passed as a paramete to the given function, | ||
then the output is divided by the result. (Default: ``True``) | ||
|
||
channels_first: Set channels first or length first in result. (Default: ``True``) | ||
|
||
num_frames: Number of frames to load. 0 to load everything after the offset. | ||
(Default: ``0``) | ||
|
||
offset: Number of frames from the start of the file to begin data loading. | ||
(Default: ``0``) | ||
|
||
signalinfo: A sox_signalinfo_t type, which could be helpful if the | ||
audio type cannot be automatically determined. (Default: ``None``) | ||
|
||
encodinginfo: A sox_encodinginfo_t type, which could be set if the | ||
audio type cannot be automatically determined. (Default: ``None``) | ||
|
||
filetype: A filetype or extension to be set if sox cannot determine it | ||
automatically. (Default: ``None``) | ||
|
||
Returns: | ||
(Tensor, int): An output tensor of size `[C x L]` or `[L x C]` where | ||
L is the number of audio frames and | ||
C is the number of channels. | ||
An integer which is the sample rate of the audio (as listed in the metadata of the file) | ||
|
||
Example | ||
>>> data, sample_rate = torchaudio.load('foo.mp3') | ||
>>> print(data.size()) | ||
torch.Size([2, 278756]) | ||
>>> print(sample_rate) | ||
44100 | ||
>>> data_vol_normalized, _ = torchaudio.load('foo.mp3', normalization=lambda x: torch.abs(x).max()) | ||
>>> print(data_vol_normalized.abs().max()) | ||
1. | ||
""" | ||
|
||
|
||
_LOAD_WAV_DOCSTRING = r""" Loads a wave file. | ||
|
||
It assumes that the wav file uses 16 bit per sample that needs normalization by | ||
shifting the input right by 16 bits. | ||
|
||
Args: | ||
filepath: Path to audio file | ||
|
||
Returns: | ||
(Tensor, int): An output tensor of size `[C x L]` or `[L x C]` where L is the number | ||
of audio frames and C is the number of channels. An integer which is the sample rate of the | ||
audio (as listed in the metadata of the file) | ||
""" | ||
|
||
_SAVE_DOCSTRING = r"""Saves a Tensor on file as an audio file | ||
|
||
Args: | ||
filepath: Path to audio file | ||
src: An input 2D tensor of shape `[C x L]` or `[L x C]` where L is | ||
the number of audio frames, C is the number of channels | ||
sample_rate: An integer which is the sample rate of the | ||
audio (as listed in the metadata of the file) | ||
precision Bit precision (Default: ``16``) | ||
channels_first (bool, optional): Set channels first or length first in result. ( | ||
Default: ``True``) | ||
""" | ||
|
||
|
||
_INFO_DOCSTRING = r"""Gets metadata from an audio file without loading the signal. | ||
|
||
Args: | ||
filepath: Path to audio file | ||
|
||
Returns: | ||
(sox_signalinfo_t, sox_encodinginfo_t): A si (sox_signalinfo_t) signal | ||
info as a python object. An ei (sox_encodinginfo_t) encoding info | ||
|
||
Example | ||
>>> si, ei = torchaudio.info('foo.wav') | ||
>>> rate, channels, encoding = si.rate, si.channels, ei.encoding | ||
""" | ||
|
||
|
||
def _impl_load(func): | ||
setattr(func, '__doc__', _LOAD_DOCSTRING) | ||
return func | ||
|
||
|
||
def _impl_load_wav(func): | ||
setattr(func, '__doc__', _LOAD_WAV_DOCSTRING) | ||
return func | ||
|
||
|
||
def _impl_save(func): | ||
setattr(func, '__doc__', _SAVE_DOCSTRING) | ||
return func | ||
|
||
|
||
def _impl_info(func): | ||
setattr(func, '__doc__', _INFO_DOCSTRING) | ||
return func | ||
Comment on lines
+126
to
+143
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: how about calling them
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from pathlib import Path | ||
from typing import Any, Callable, Optional, Tuple, Union | ||
|
||
from torch import Tensor | ||
|
||
from . import common | ||
from .common import SignalInfo, EncodingInfo | ||
|
||
|
||
@common._impl_load | ||
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, | ||
signalinfo: Optional[SignalInfo] = None, | ||
encodinginfo: Optional[EncodingInfo] = None, | ||
filetype: Optional[str] = None) -> Tuple[Tensor, int]: | ||
raise RuntimeError('No audio I/O backend is available.') | ||
|
||
|
||
@common._impl_load_wav | ||
def load_wav(filepath: Union[str, Path], **kwargs: Any) -> Tuple[Tensor, int]: | ||
raise RuntimeError('No audio I/O backend is available.') | ||
|
||
|
||
@common._impl_save | ||
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.') | ||
|
||
|
||
@common._impl_info | ||
def info(filepath: str) -> Tuple[SignalInfo, EncodingInfo]: | ||
raise RuntimeError('No audio I/O backend is available.') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #715
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this fixes #715 completely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. This is a temporary fix. #719 gives the principled fix which fully utilizes
no_backend
from this PR.