{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Reading and Writing Audio Files with the `soundfile` module\n", "\n", "[back to overview page](index.ipynb)\n", "\n", "There are many libraries for handling audio files with Python (see [overview page](index.ipynb)), but the best one is probably the [soundfile](http://github.com/bastibe/SoundFile) module.\n", "\n", "Full documentation including installation instructions is available at http://pysoundfile.readthedocs.org/.\n", "\n", "Advantages: \n", "\n", "* supports many file formats (thanks to libsndfile)\n", " * WAV, OGG, FLAC and many more\n", " * see [bottom of this notebook](#Available-Formats) for full list of supported formats\n", "* supports 24-bit PCM and 32-bit floating point WAV files\n", "* WAVEX support\n", "* can read parts of audio files\n", "* automatic type conversion and normalization\n", "* works in CPython 2.x and 3.x and in PyPy as well\n", "* provides audio data as NumPy arrays by default, but it can also work with plain Python buffer objects if NumPy is not available\n", "\n", "Disadvantages:\n", "\n", "* no MP3 support\n", "\n", "Installation:\n", "\n", " python3 -m pip install soundfile" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reading\n", "\n", "This is the quickest way to load a WAV file into a NumPy array (using [soundfile.read()](http://pysoundfile.readthedocs.org/#soundfile.read)):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import soundfile as sf\n", "sig, samplerate = sf.read('data/test_wav_pcm16.wav')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's all. Easy, isn't it?\n", "\n", "But let's have a closer look ...\n", "\n", "The test file is not a very typical file, because it only has 15 frames but it has 7 channels:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sig.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "samplerate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check the contents of the file by plotting thw audio waveform:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(sig);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looking good!\n", "\n", "In most cases [soundfile.read()](http://pysoundfile.readthedocs.org/#soundfile.read) is all you need, but for some advanced use cases, you might want to use a [soundfile.SoundFile](http://pysoundfile.readthedocs.org/#soundfile.SoundFile) object instead:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = sf.SoundFile('data/test_wav_pcm16.wav')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len(f), f.channels, f.samplerate" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f.format, f.subtype, f.endian" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test = f.read()\n", "test.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(test);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "(test == sig).all()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, you get the same data as with `sf.read()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# TODO: read mono file\n", "# mono data is by default returned as one-dimensional NumPy array,\n", "# this can be changed with always_2d=True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "24-bit files work:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sig, samplerate = sf.read('data/test_wav_pcm24.wav')\n", "plt.plot(sig);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "WAVEX is supported:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sig, samplerate = sf.read('data/test_wavex_pcm16.wav')\n", "plt.plot(sig);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sig, samplerate = sf.read('data/test_wavex_pcm24.wav')\n", "plt.plot(sig);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "32-bit float files work:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sig, samplerate = sf.read('data/test_wav_float32.wav')\n", "plt.plot(sig);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sig, samplerate = sf.read('data/test_wavex_float32.wav')\n", "plt.plot(sig);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Writing\n", "\n", "Writing audio data to a file (using [soundfile.write()](http://pysoundfile.readthedocs.org/#soundfile.write)) is as simple as reading from a file:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sf.write('my_pcm16_file.wav', sig, samplerate)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check if this file has really been written:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!sndfile-info my_pcm16_file.wav" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that by default, WAV files are written as 16-bit fixed point data (a.k.a. `'PCM_16'`).\n", "You can find the default setting for each file format with [soundfile.default_subtype()](http://pysoundfile.readthedocs.org/#soundfile.default_subtype):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sf.default_subtype('WAV')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to save your file with a better quality setting (especially if you want to do further processing later), you can, for example, use the 32-bit floating point format:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sf.write('my_float_file.wav', sig, samplerate, subtype='FLOAT')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check if this worked:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!sndfile-info my_float_file.wav" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can get all available subtypes for a given format with [soundfile.available_subtypes()](http://pysoundfile.readthedocs.org/#soundfile.available_subtypes):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sf.available_subtypes('WAV')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Available Formats\n", "\n", "You can get all available formats with [soundfile.available_formats()](http://pysoundfile.readthedocs.org/#soundfile.available_formats):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sf.available_formats()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and all available subtypes with [soundfile.available_subtypes()](http://pysoundfile.readthedocs.org/#soundfile.available_subtypes):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sf.available_subtypes()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Version Info" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"PySoundFile version:\", sf.__version__)\n", "\n", "import sys\n", "print(\"Python version:\", sys.version)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", " \n", " \"CC0\"\n", " \n", "
\n", " To the extent possible under law,\n", " the person who associated CC0\n", " with this work has waived all copyright and related or neighboring\n", " rights to this work.\n", "

" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 4 }