I use SoX in an application. The application uses it to apply various operations on audiofiles, such as trimming.
This works fine:
from subprocess import Popen, PIPE
kwargs = {'stdin': PIPE, 'stdout': PIPE, 'stderr': PIPE}
pipe = Popen(['sox','-t','mp3','-', 'test.mp3','trim','0','15'], **kwargs)
output, errors = pipe.communicate(input=open('test.mp3','rb').read())
if errors:
raise RuntimeError(errors)
This will cause problems on large files hower, since read()
loads the complete file to memory; which is slow and may cause the pipes' buffer to overflow. A workaround exists:
from subprocess import Popen, PIPE
import tempfile
import uuid
import shutil
import os
kwargs = {'stdin': PIPE, 'stdout': PIPE, 'stderr': PIPE}
tmp = os.path.join(tempfile.gettempdir(), uuid.uuid1().hex + '.mp3')
pipe = Popen(['sox','test.mp3', tmp,'trim','0','15'], **kwargs)
output, errors = pipe.communicate()
if errors:
raise RuntimeError(errors)
shutil.copy2(tmp, 'test.mp3')
os.remove(tmp)
So the question stands as follows: Are there any alternatives to this approach, aside from writing a Python extension to the Sox C API?
A Python wrapper for SoX already exists: sox. Maybe the simplest solution is to switch to use that instead of invoking external SoX command line utilities through subprocess
.
The following achieves what you want in your example using the sox
package (see documentation), and should work on Linux and macOS on Python 2.7, 3.4 and 3.5 (it might also work on Windows but I haven't been able to test because I don't have access to a Windows box):
>>> import sox
>>> transformer = sox.Transformer() # create transformer
>>> transformer.trim(0, 15) # trim the audio between 0 and 15 seconds
>>> transformer.build('test.mp3', 'out.mp3') # create the output file
Note: this answer used to mention the no longer maintained pysox
package. Thanks to @erik for the tip.