Source code for pyfasst.audioObject

"""AudioObject

The audioObject module provides a class for input/output of audio
WAV files.

Originally meant to wrap scikits.audiolab, yet allowing to load the
scipy.io.wavfile if audiolab is missing.

Unfortunately it got awfully complicated in time, and a clean up is
necessary. Notably, there are problems with scaling, and some issues
related to the type of the file from audiolab. 

Jean-Louis Durrieu, 2012 - 2013
"""


import numpy as np
import warnings

from tools.utils import *

"""
# functions to read and write audio files
#     note that if audiolab is available, there are going to be
#     more available audio formats to read/write.
"""
try:
    import scikits.audiolab as al
    """
    # import marcel # just to make it read with scipy
    """
    
    def wavread(filename, first=0, last=None):
        sndfile = al.pysndfile.Sndfile(filename, mode='r')
        if last is None:
            last = sndfile.nframes
        
        sndfile.seek(first)
        fs = sndfile.samplerate
        data = sndfile.read_frames(nframes=last-first, )
        # Note: read_frame(nframes,dtype=np.int16) is broken! probably... 
        if sndfile.encoding == 'pcm16':
            # convert back to signed int16
            data = np.int16(data * 2.**15)
        sndfile.close()
        return fs, data, sndfile.encoding
    
    def wavwrite(filename, rate, data,
                 formattype='wav',
                 formatenc='pcm16',
                 formatend='file'):
        if formattype not in al.pysndfile.available_file_formats():
            raise AttributeError(formattype+' not available in sndfile.')
        if formatenc not in al.pysndfile.available_encodings(formattype):
            formatenc = al.pysndfile.available_encodings(formattype)[0]
        format = al.pysndfile.Format(type=formattype,
                                     encoding=formatenc,
                                     endianness=formatend)
        sndfile = al.pysndfile.Sndfile(filename=filename,
                                       mode='w',
                                       samplerate=rate,
                                       format=format,
                                       channels=data.shape[1]
                                       )
        sndfile.write_frames(np.int16(data))
        sndfile.close()
        return 0
    
    print "Reading and Writing WAV files with audiolab"
except ImportError:
    print "Using scipy.io.wavfile"
    import scipy.io.wavfile as wav
    
    def wavread(filename, first=0, last=None):
        fs, data = wav.read(filename)
        data = data[first:last]
        encoding = data.dtype
        
        return fs, data, encoding
    
    def wavwrite(filename, rate, data,
                 formattype='wav',
                 formatenc='int16',
                 formatend='file'):
        if formatenc not in ('int16', 'int32', 'int8'):
            if np.abs(data).max()>2**15:
                formatenc = 'int32'
            elif np.abs(data).max()>2**7:
                formatenc = 'int16'
            else:
                formatenc = 'int8'
            print "Changing encoding to", formatenc
        data_ = np.array(data, dtype=formatenc)
        # print data_.dtype
        wav.write(filename, rate, data_)
        return 0

[docs]class AudioObject(object): """A wrapper for the wrapper by D. Cournapeau. Or in case it is not installed, it falls back on :py:mod:`scipy.io.wavfile`. """ def __init__(self, filename, mode='rw'): """AudioObject initialization """ self.filename = filename self.mode = mode def _read(self): if 'r' not in self.mode: raise ValueError("Not in read mode.") self._samplerate, self._data, self._encoding = ( wavread(self.filename)) if len(self._data.shape)==2: self._nframes, self._channels = self._data.shape else: self._nframes = self._data.size self._channels = 1 # rescaling the data array self._maxdata = np.maximum( 1.1 * np.abs(self._data).max(), 1e-10) self._data = self._data / self._maxdata # self._encoding = def _write(self): if 'w' not in self.mode: raise ValueError("Not in write mode.") if 'w' in self.mode and not hasattr(self, '_samplerate') \ and not hasattr(self, '_data'): raise AttributeError("Should set sample rate and have data "+\ "in write mode.") ##print "Setting encoding to pcm16, converting data too..." ##self._encoding = 'pcm16' ##self._data = np.int16(self._maxdata * self._data) ##self._maxdata = 1 wavwrite(filename=self.filename, rate=self._samplerate, data=self._maxdata * self._data, formatenc=self._encoding) def _set_data(self, data): s = data.shape if s[0] < s[1] and s[1] > 2: print "Data shape is strangely ordered: transposing input data." self._data = np.array(data.T, order='C') else: self._data = np.array(data, order='C') self._maxdata = 1.1 * np.abs(self._data).max() self._encoding = self._data.dtype.name self._data = self._data / self._maxdata def _get_data(self): if not hasattr(self, '_data'): self._read() return self._data def _del_data(self): if hasattr(self, 'data'): del self._data data = property(_get_data, _set_data, _del_data) def _get_samplerate(self): if not hasattr(self, '_samplerate') and 'r' in self.mode: self._read() return self._samplerate def _set_samplerate(self, samplerate): if 'r' in self.mode: warnings.warn("Changing the sampling rate in read mode") self._samplerate = int(samplerate) samplerate = property(_get_samplerate, _set_samplerate) fs = samplerate # just an alias, for ease of use @property def channels(self): if not hasattr(self, '_channels'): self._read() return self._channels @property def nframes(self): if not hasattr(self, '_nframes'): self._read() return self._nframes