Skip to content

Commit

Permalink
Use Transformer in-memory with stdin/stdout (#102)
Browse files Browse the repository at this point in the history
* added in-memory build_array for sox transformer

* adding pysoundfile to travis

* upping coverage and adding docstrings

* merging build_array into build, handling cases for both inputs and outputs to be either arrays or filepaths.

* add numpy to docs requirements

* increase test coverage

Co-authored-by: Rachel Bittner <rmb456@nyu.edu>
  • Loading branch information
pseeth and rabitt committed May 21, 2020
1 parent 99de814 commit bdb1058
Show file tree
Hide file tree
Showing 9 changed files with 683 additions and 131 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
tests/data/output.wav
tests/data/output_alt.wav
*.DS_Store

# Byte-compiled / optimized / DLL files
Expand Down Expand Up @@ -63,3 +64,5 @@ target/

#Ipython Notebook
.ipynb_checkpoints

**/noise.prof
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ addons:
# command to install dependencies
install:
- pip install coveralls
- pip install pysoundfile
- pip install -e .

# command to run tests
Expand Down
3 changes: 2 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
numpydoc>=0.5
numpydoc>=0.5
numpy >= 1.9.0
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
keywords='audio effects SoX',
license='BSD-3-Clause',
install_requires=[
'numpy >= 1.9.0',
],
extras_require={
'tests': [
'pytest',
'pytest-cov',
'pytest-pep8',
'pysoundfile >= 0.9.0',
],
'docs': [
'sphinx==1.2.3', # autodoc was broken in 1.3.1
Expand Down
51 changes: 41 additions & 10 deletions sox/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import subprocess
from subprocess import CalledProcessError
import numpy as np

from . import NO_SOX

Expand All @@ -14,19 +15,31 @@
]


def sox(args):
def sox(args, src_array=None, decode_out_with_utf=True):
'''Pass an argument list to SoX.
Parameters
----------
args : iterable
Argument list for SoX. The first item can, but does not
need to, be 'sox'.
src_array : np.ndarray, or None
If src_array is not None, then we make sure it's a numpy
array and pass it into stdin.
decode_out_with_utf : bool, default=True
Whether or not sox is outputting a bytestring that should be
decoded with utf-8.
Returns:
--------
status : bool
True on success.
out : str, np.ndarray, or None
Returns a np.ndarray if src_array was an np.ndarray.
Returns the stdout produced by sox if src_array is None.
Otherwise, returns None if there's an error.
err : str, or None
Returns stderr as a string.
'''
if args[0].lower() != "sox":
Expand All @@ -37,15 +50,33 @@ def sox(args):
try:
logger.info("Executing: %s", ' '.join(args))

process_handle = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

out, err = process_handle.communicate()
out = out.decode("utf-8")
err = err.decode("utf-8")

status = process_handle.returncode
if src_array is None:
process_handle = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

out, err = process_handle.communicate()
if decode_out_with_utf:
out = out.decode("utf-8")
err = err.decode("utf-8")

status = process_handle.returncode
elif isinstance(src_array, np.ndarray):
process_handle = subprocess.Popen(
args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# We do order "F" for Fortran formatting of the numpy array, which is
# sox expects. When we reshape stdout later, we need to use the same
# order, otherwise tests fail.
out, err = process_handle.communicate(src_array.T.tobytes(order='F'))
err = err.decode("utf-8")
status = process_handle.returncode
else:
raise TypeError("src_array must be an np.ndarray!")

return status, out, err

except OSError as error_msg:
Expand Down
10 changes: 6 additions & 4 deletions sox/file_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def bitdepth(input_filepath):
Number of bits per sample.
Returns None if not applicable.
'''

validate_input_file(input_filepath)
output = soxi(input_filepath, 'b')
if output == '0':
Expand All @@ -49,7 +49,7 @@ def bitrate(input_filepath):
Bit rate, expressed in bytes per second.
Returns None if not applicable.
'''

validate_input_file(input_filepath)
output = soxi(input_filepath, 'B')
# The characters below stand for kilo, Mega, Giga, etc.
Expand Down Expand Up @@ -291,10 +291,12 @@ def validate_output_file(output_filepath):
The output filepath.
'''
if output_filepath == '-n':
return

nowrite_conditions = [
bool(os.path.dirname(output_filepath)) or\
not os.access(os.getcwd(), os.W_OK),
bool(os.path.dirname(output_filepath)) or
not os.access(os.getcwd(), os.W_OK),
not os.access(os.path.dirname(output_filepath), os.W_OK)]

if all(nowrite_conditions):
Expand Down
Loading

0 comments on commit bdb1058

Please sign in to comment.