8

I want to use Python to access a wav-file and write its content in a form which allows me to analyze it (let's say arrays).

  1. I heard that "audiolab" is a suitable tool for that (it transforms numpy arrays into wav and vica versa).
  2. I have installed the "audiolab" but I had a problem with the version of numpy (I could not "from numpy.testing import Tester"). I had 1.1.1. version of numpy.
  3. I have installed a newer version on numpy (1.4.0). But then I got a new set of errors:

    Traceback (most recent call last): File "test.py", line 7, in import scikits.audiolab File "/usr/lib/python2.5/site-packages/scikits/audiolab/init.py", line 25, in from pysndfile import formatinfo, sndfile File "/usr/lib/python2.5/site-packages/scikits/audiolab/pysndfile/init.py", line 1, in from _sndfile import Sndfile, Format, available_file_formats, available_encodings File "numpy.pxd", line 30, in scikits.audiolab.pysndfile._sndfile (scikits/audiolab/pysndfile/_sndfile.c:9632) ValueError: numpy.dtype does not appear to be the correct type object

  4. I gave up to use audiolab and thought that I can use "wave" package to read in a wav-file. I asked a question about that but people recommended to use scipy instead. OK, I decided to focus on scipy (I have 0.6.0. version).

  5. But when I tried to do the following:

    from scipy.io import wavfile
    x = wavfile.read('/usr/share/sounds/purple/receive.wav')

I get the following:

Traceback (most recent call last):
  File "test3.py", line 4, in <module>
    from scipy.io import wavfile
  File "/usr/lib/python2.5/site-packages/scipy/io/__init__.py", line 23, in <module>
    from numpy.testing import NumpyTest
ImportError: cannot import name NumpyTest
  1. So, I gave up to use scipy. Can I use just wave package? I do not need much. I just need to have content of wav-file in human readable format and than I will figure out what to do with that.
Roman
  • 97,757
  • 149
  • 317
  • 426
  • 1
    How exactly were you installing audiolab? – gruszczy Jan 14 '10 at 10:40
  • How is this different from your previous questions on the exact same topic? – S.Lott Jan 14 '10 at 12:00
  • audiolab is great. Try to get that working. Make sure you have installed the packages libsndfile and setuptools. Did you follow Sec. 2.4 in the manual? – Steve Tjoa Jan 15 '10 at 19:21
  • Did you get a newer version of Scipy when you upgraded your version of Numpy? I use wave for reading in wave files like James Roth suggested below, but if you want to use Scipy you should check to see if your version of Scipy is up to date. From the error messages that you are getting I am guessing that it is not. – Justin Peel Apr 08 '10 at 18:26
  • Have you seen this? http://stackoverflow.com/questions/2060628/how-to-read-wav-file-in-python/5281240#5281240 Time stamp is (more) recent, March 2011. – Ellie Kesselman Oct 07 '11 at 07:39
  • [pydub](http://pydub.com/) is another alternative for reading in wave files. – machow Aug 03 '13 at 15:02
  • how to deal with stereo sounds ? 2 arrays that have 1-dimension ? or one single 2-dimensional array ? – Basj Nov 12 '13 at 11:09

8 Answers8

12

Have you tried the wave module? It has fewer dependencies:

http://docs.python.org/library/wave.html

def everyOther (v, offset=0):
   return [v[i] for i in range(offset, len(v), 2)]

def wavLoad (fname):
   wav = wave.open (fname, "r")
   (nchannels, sampwidth, framerate, nframes, comptype, compname) = wav.getparams ()
   frames = wav.readframes (nframes * nchannels)
   out = struct.unpack_from ("%dh" % nframes * nchannels, frames)

   # Convert 2 channles to numpy arrays
   if nchannels == 2:
       left = array (list (everyOther (out, 0)))
       right = array (list  (everyOther (out, 1)))
   else:
       left = array (out)
       right = left
James Roth
  • 1
  • 1
  • 3
  • 8
    Instead of everyOther, use out[0::2] and out[1::2]. – treat your mods well Oct 15 '10 at 18:34
  • 1
    Combine this with external conversion tools to open other formats. http://www.assembla.com/code/freesound/git/nodes/freesound/utils/audioprocessing/processing.py?rev=acda3b2a572b62efe9c468d7508012f0b638d10e – endolith Dec 31 '10 at 02:37
6

I wrote a simple wrapper over the wave module in the std lib. it's called pydub and it has a method for reading samples from the audio data as ints.

>>> from pydub import AudioSegment
>>> song = AudioSegment.from_wav("your_song.wav")
<pydub.audio_segment.AudioSegment at 0x1068868d0>

>>> # This song is stereo
>>> song.channels
2

>>> # get the 5000th "frame" in the song
>>> frame = song.get_frame(5000)

>>> sample_left, sample_right = frame[:2], frame[2:]
>>> def sample_to_int(sample): 
        return int(sample.encode("hex"), 16)

>>> sample_to_int(sample_left)
8448

>>> sample_to_int(sample_right)
9984

Hopefully this helps

Jiaaro
  • 67,024
  • 38
  • 154
  • 182
5

This is good enough for me

import numpy as np
x = np.fromfile(open('song.wav'),np.int16)[24:]

It ignores the first 24 values, because that's not audio, it the header.

Also, if the file was stereo, your channels will have alternating indexes, So I usually just reduce it to mono with Audacity first.

ayke
  • 1,366
  • 10
  • 13
Nathan
  • 5,747
  • 9
  • 43
  • 54
  • 1
    This works if you know the file format (channel count, sample rate) and know there's no weird stuff in the file (like multiple data blocks - see https://ccrma.stanford.edu/courses/422/projects/WaveFormat/). – ayke Jan 18 '14 at 01:59
4

You can also use the wave module along with the numpy.fromstring() function to convert it to an array

import wave
import numpy

fp = wave.open('test.wav')
nchan = fp.getnchannels()
N = fp.getnframes()
dstr = fp.readframes(N*nchan)
data = numpy.fromstring(dstr, numpy.int16)
data = numpy.reshape(data, (-1,nchan))
2

After trying so many things that does not work I used the decode library from Use (Python) Gstreamer to decode audio (to PCM data) and build a function to parse the raw pcm data into a scipy array.

It's nice and can open any audio file that gstreamer can open: http://gist.github.com/592776 (see Test and the end of the file for usage info)

Community
  • 1
  • 1
Dominik
  • 1
  • 1
1

audiolab is the best way, but it doesn't work in every environment and the developer's not working on it. I'm still using Python 2.5 so I can use it.

Did you install libsndfile?

endolith
  • 21,410
  • 30
  • 114
  • 183
1

audiolab seems to be not maintained anymore, you should try PySoundFile.

Installation is simple:

pip install PySoundFile --user

And reading a sound file as well:

import soundfile as sf
x, fs = sf.read('/usr/share/sounds/purple/receive.wav')

Have a look at this overview about different Python libraries for handling sound files.

Matthias
  • 3,777
  • 2
  • 24
  • 42
0

pydub provides an even easier solution without any dependencies needing to be installed (for wav files). I'm currently using this method in production without any issues.

from pydub import AudioSegment
awesome_song = AudioSegment.from_wav('awesome_song.wav')
print('Duration in seconds is {}'.format(awesome_song.duration_seconds))
TimmyGee
  • 183
  • 4