Code Monkey home page Code Monkey logo

soxbindings's Introduction

SoxBindings

Downloads Tests Wheels built

Python bindings for SoX. An attempt to bind a subset of the capabilities of the SoX command line utility but in Python via bindings for speed. This avoids costly exec calls when using augmentations in SoX. This is a work in progress! Help welcome.

soxbindings only supports Unix systems (Linux and OSX), due to how one builds sox. A related library (torchaudio) has similar problems: pytorch/audio#425.

Install from pip

If on MacOS or Linux, just do:

pip install soxbindings

If on Windows, it's not supported but you could install sox from source, and then link libsox and get everything working possibly. If you do and figure out an automated way to do it using cibuildwheel, please put in a PR adding Windows support!

Installation from source

On Unix (Linux, OS X) using Anaconda

  • clone this repository
  • Make a conda environment
  • conda install -c conda-forge sox
  • If on Linux:
    • Option 1: conda install gcc_linux-64 gxx_linux-64
    • Option 2: sudo apt-get install sox libsox-dev
    • Option 3: build and install sox from source (e.g. as in .github/workflows/build_install_sox_centos.sh).
  • pip install -e .

Run the tests to make sure everything works:

pip install -r extra_requirements.txt
python -m pytest .

The tests run a large variety of commands, all pulled from the pysox test cases. SoxBindings output is then compared with pysox output.

Usage

SoxBindings is built to be a drop-in replacement for the sox command line tool, avoiding a costly exec call. Specifically, the way it works is to provide an alternative backend to the excellent library that wraps the command line tool pysox. SoxBindings simply re-implements the build function in pysox Transformer classes.

Note that Combiner classes in pysox are NOT supported.

If you have a script that works with pysox, like so:

import sox
# create transformer
tfm = sox.Transformer()
# trim the audio between 5 and 10.5 seconds.
tfm.trim(5, 10.5)
# apply compression
tfm.compand()
# apply a fade in and fade out
tfm.fade(fade_in_len=1.0, fade_out_len=0.5)
# create an output file.
tfm.build_file('path/to/input_audio.wav', 'path/to/output/audio.aiff')
# or equivalently using the legacy API
tfm.build('path/to/input_audio.wav', 'path/to/output/audio.aiff')
# get the output in-memory as a numpy array
# by default the sample rate will be the same as the input file
array_out = tfm.build_array(input_filepath='path/to/input_audio.wav')
# see the applied effects
tfm.effects_log
> ['trim', 'compand', 'fade']

Then, all you have to do is change the import:

import soxbindings as sox

and everything should work, but be faster because of the direct bindings to libsox!

Multithreading

SoxBindings requires some special care when being used in a multi-threaded program (i.e. a TensorFlow data loader). This issue has more discussion. To use SoxBindings in a multi-threaded program, you must use the SoxBindings context manager: soxbindings.sox_context.

Note below that anything related to SoxBindings is called in the context block with sox.sox_context():.

import numpy as np
import soxbindings as sox

y1 = np.zeros((4000, 1))
y2 = np.zeros((3000, 1))

def do_transform(y):
   tfm = sox.Transformer()
   tfm.vol(0.5)
   y_out = tfm.build_array(input_array=y, sample_rate_in=1000)
   return y_out

# multithread
pool = ThreadPool(2)
with sox.sox_context():
   multi_thread = pool.map(do_transform, [y1, y2]) 
   for a1, a2 in zip(single_thread, multi_thread):
      assert np.allclose(a1, a2)

The other option is to wrap your program into a function, and then decorate the function:

import numpy as np
import soxbindings as sox

@sox.sox_context()
def run():
   y1 = np.zeros((4000, 1))
   y2 = np.zeros((3000, 1))

   def do_transform(y):
      tfm = sox.Transformer()
      tfm.vol(0.5)
      y_out = tfm.build_array(input_array=y, sample_rate_in=1000)
      return y_out

   # multithread
   pool = ThreadPool(2)
   multi_thread = pool.map(do_transform, [y1, y2]) 
   for a1, a2 in zip(single_thread, multi_thread):
      assert np.allclose(a1, a2)

If your program is single-threaded, no changes are needed. SoxBindings checks to see if SoX has been initialized already before initializing again.

Deploying to PyPI

The Github action workflow "Build wheels" gets run every time there is a commit to master. When it's done, the wheels for OSX and Linux are created and place in an artifact. For example:

https://github.com/pseeth/soxbindings/actions/runs/169544837

Download the artifact zip, then do the following steps from the root of the soxbindings repo:

unzip [/path/to/artifact.zip]
# clear out dist
rm -rf dist/
# create source distribution
python setup.py sdist
cp -r [/path/to/artifact]/* dist/

The dist folder should look something like:

dist
├── soxbindings-0.0.1-cp35-cp35m-macosx_10_9_x86_64.whl
├── soxbindings-0.0.1-cp35-cp35m-manylinux2010_i686.whl
├── soxbindings-0.0.1-cp35-cp35m-manylinux2010_x86_64.whl
├── soxbindings-0.0.1-cp36-cp36m-macosx_10_9_x86_64.whl
├── soxbindings-0.0.1-cp36-cp36m-manylinux2010_i686.whl
├── soxbindings-0.0.1-cp36-cp36m-manylinux2010_x86_64.whl
├── soxbindings-0.0.1-cp37-cp37m-macosx_10_9_x86_64.whl
├── soxbindings-0.0.1-cp37-cp37m-manylinux2010_i686.whl
├── soxbindings-0.0.1-cp37-cp37m-manylinux2010_x86_64.whl
├── soxbindings-0.0.1-cp38-cp38-macosx_10_9_x86_64.whl
├── soxbindings-0.0.1-cp38-cp38-manylinux2010_i686.whl
├── soxbindings-0.0.1-cp38-cp38-manylinux2010_x86_64.whl
├── soxbindings-0.0.1-pp27-pypy_73-macosx_10_9_x86_64.whl
├── soxbindings-0.0.1-pp27-pypy_73-manylinux2010_x86_64.whl
├── soxbindings-0.0.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl
├── soxbindings-0.0.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl
└── soxbindings-0.0.1.tar.gz

Upload it to the test server first (requires a version bump):

twine upload --repository testpypi dist/*

Make sure you can pip install it on both Linux and OSX:

pip install -U --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple -U soxbindings

Use the demo script included in this repo to try it out. Finally, upload it to the regular PyPi server:

twine upload dist/*

License

soxbindings is under an MIT license.

soxbindings's People

Contributors

mpariente avatar pseeth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

soxbindings's Issues

mcompand not functional

Hi,
what is an issue with this mcompand command:

tfm.mcompand(
n_bands=3,
crossover_frequencies=[6500, 8000],
attack_time=[0.001, 0.001, 0.001],
decay_time=[0.020, 0.020, 0.020],
soft_knee_db=[None, 2.0, None],
tf_points=[
[(-40, -40), (0, 0)],
[(-40, -40), (-30, -38), (-20, -36), (0, -34)],
[(-40, -40), (0, 0)]],
gain = [0,0,0]
)
I get an error :
mcompand: mcompand accepts only an odd number of arguments:rgc mcompand quoted_compand_args [crossover_freq quoted_compand_args [...]]

In fact, I get this error even if I do

tfm.mcompand()

speed effect is to slow

image

def do_transform(y):
    tfm = sox.Transformer()
    tfm.speed(0.9)
    y_out = tfm.build_array(input_array=y, sample_rate_in=1000)
    return y_out

how to increase the speed

Support more audio formats.

More audio formats should be supported. I'm not sure all formats are currently supported due to what is available on CentOS. Should also make a more exhaustive list of what formats are supported exactly.

To add more formats, we would have to install more codec libraries and build against them when compiling LibSoX from source.

Windows support

Currently can't figure out how to support Windows. I think we can compile SoX from source in Windows in cibuildwheel and then build against it. Not having a Windows machine myself, help is welcome!

soxbindings fails when multithreading

soxbinding works great in one thread, but it looks like it consistently fails when multithreading. Minimal example below. Note that any effect (.vol, .compand, .trim, etc) triggers the same error. Running this with command line sox (replacing import soxbindings as sox with import sox) works fine.

from multiprocessing.dummy import Pool as ThreadPool
import numpy as np
import soxbindings as sox

y1 = np.zeros((4000, 1))
y2 = np.zeros((3000, 1))


def do_transform(y):
    tfm = sox.Transformer()
    tfm.vol(0.5)
    y_out = tfm.build_array(input_array=y, sample_rate_in=1000)
    return y_out


# single thread
print("running single thread")
for y in [y1, y2]:
    res = do_transform(y)
    print(res.shape)

# multithread
print("running multi thread")
pool = ThreadPool(2)
results = pool.map(do_transform, [y1, y2])

Output:

running single thread
(4000, 1)
(3000, 1)
running multi thread
Assertion failed: (fft_len == -1), function init_fft_cache, file effects_i_dsp.c, line 170.
Abort trap: 6

SoxBindings doesn't release GIL.

Following discussion in #4, SoxBindings "works" in multithreading in that it doesn't fail, but it doesn't let you actually use multi-threading. We can fix that by releasing the GIL in the C extension.

building issues on macOS

On macOS, /usr/local/include and /usr/local/lib are not automatically searched so pip install sox bindings fails.

I have fixed this by git cloning the soxbindings repo and making the following changes to the setup.py file:

% git diff setup.py
diff --git a/setup.py b/setup.py
index 3ee9d8c..8b2c894 100644
--- a/setup.py
+++ b/setup.py
@@ -27,6 +27,10 @@ ext_modules = [
         include_dirs=[
             # Path to pybind11 headers
             get_pybind_include(),
+            "/usr/local/include",
+        ],
+        library_dirs=[
+            "/usr/local/lib",
         ],
         language='c++'
     ),

file_info support

pysox has metadata parsing abilities using file_info. Can this be interfaced from soxbindings as well?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.