Skip to content

Commit

Permalink
Merge a26e607 into 6d30e92
Browse files Browse the repository at this point in the history
  • Loading branch information
bmcfee committed Oct 2, 2016
2 parents 6d30e92 + a26e607 commit 37d098f
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 44 deletions.
53 changes: 11 additions & 42 deletions librosa/core/spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .. import cache
from .. import util
from ..util.exceptions import ParameterError
from ..filters import get_window

__all__ = ['stft', 'istft', 'magphase',
'ifgram',
Expand Down Expand Up @@ -72,12 +73,6 @@ def stft(y, n_fft=2048, hop_length=None, win_length=None, window=None,
STFT matrix
Raises
------
ParameterError
If `window` is supplied as a vector of length `n_fft`.
See Also
--------
istft : Inverse STFT
Expand Down Expand Up @@ -138,24 +133,12 @@ def stft(y, n_fft=2048, hop_length=None, win_length=None, window=None,

# Set the default hop, if it's not already specified
if hop_length is None:
hop_length = int(win_length / 4)
hop_length = int(win_length // 4)

if window is None:
# Default is an asymmetric Hann window
fft_window = scipy.signal.hann(win_length, sym=False)

elif six.callable(window):
# User supplied a window function
fft_window = window(win_length)

else:
# User supplied a window vector.
# Make sure it's an array:
fft_window = np.asarray(window)
window = 'hann'

# validate length compatibility
if fft_window.size != n_fft:
raise ParameterError('Size mismatch between n_fft and len(window)')
fft_window = get_window(window, win_length, fftbins=True)

# Pad the window out to n_fft size
fft_window = util.pad_center(fft_window, n_fft)
Expand Down Expand Up @@ -242,11 +225,6 @@ def istft(stft_matrix, hop_length=None, win_length=None, window=None,
y : np.ndarray [shape=(n,)]
time domain signal reconstructed from `stft_matrix`
Raises
------
ParameterError
If `window` is supplied as a vector of length `n_fft`
See Also
--------
stft : Short-time Fourier Transform
Expand Down Expand Up @@ -283,24 +261,13 @@ def istft(stft_matrix, hop_length=None, win_length=None, window=None,

# Set the default hop, if it's not already specified
if hop_length is None:
hop_length = int(win_length / 4)
hop_length = int(win_length // 4)

if window is None:
# Default is an asymmetric Hann window.
ifft_window = scipy.signal.hann(win_length, sym=False)

elif six.callable(window):
# User supplied a windowing function
ifft_window = window(win_length)

else:
# User supplied a window vector.
# Make it into an array
ifft_window = np.asarray(window)
window = 'hann'

# Verify that the shape matches
if ifft_window.size != n_fft:
raise ParameterError('Size mismatch between n_fft and window size')
ifft_window = get_window(window, win_length, fftbins=True)

# Pad out to match n_fft
ifft_window = util.pad_center(ifft_window, n_fft)
Expand Down Expand Up @@ -331,7 +298,8 @@ def istft(stft_matrix, hop_length=None, win_length=None, window=None,


def ifgram(y, sr=22050, n_fft=2048, hop_length=None, win_length=None,
norm=False, center=True, ref_power=1e-6, clip=True, dtype=np.complex64):
norm=False, center=True, ref_power=1e-6, clip=True,
dtype=np.complex64):
'''Compute the instantaneous frequency (as a proportion of the sampling rate)
obtained as the time-derivative of the phase of the complex spectrum as
described by [1]_.
Expand Down Expand Up @@ -419,7 +387,8 @@ def ifgram(y, sr=22050, n_fft=2048, hop_length=None, win_length=None,
hop_length = int(win_length // 4)

# Construct a padded hann window
window = util.pad_center(scipy.signal.hann(win_length, sym=False), n_fft)
window = util.pad_center(get_window('hann', win_length, fftbins=True),
n_fft)

# Window for discrete differentiation
freq_angular = np.linspace(0, 2 * np.pi, n_fft, endpoint=False)
Expand Down
67 changes: 65 additions & 2 deletions librosa/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,30 @@
chroma
constant_q
Window functions
----------------
.. autosummary::
:toctree: generated/
window_bandwidth
get_window
Miscellaneous
-------------
.. autosummary::
:toctree: generated/
constant_q_lengths
cq_to_chroma
window_bandwidth
"""

import warnings

import numpy as np
import scipy
import scipy.signal
import six

from . import cache
from . import util
Expand All @@ -46,7 +55,8 @@
'constant_q',
'constant_q_lengths',
'cq_to_chroma',
'window_bandwidth']
'window_bandwidth',
'get_window']


@cache(level=10)
Expand Down Expand Up @@ -744,3 +754,56 @@ def window_bandwidth(window, default=1.0):
warnings.warn("Unknown window function '{:s}'.".format(key))

return WINDOW_BANDWIDTHS.get(key, default)


def get_window(window, Nx, fftbins=True):
'''Compute a window function
Parameters
----------
window : string, tuple, callable, or list-like
The window specification:
- If string, it's the name of the window function (e.g., `'hann'`)
- If tuple, it's the name of the window function and any parameters
(e.g., `('kaiser', 4.0)`)
- If callable, it's a function that accepts one integer argument
(the window length)
- If list-like, it's a pre-computed window of the correct length `Nx`
Nx : int > 0
The length of the window
fftbins : bool, optional
If True (default), create a periodic window for use with FFT
If False, create a symmetric window for use with filter design
Returns
-------
get_window : np.ndarray
A window of length `Nx` and type `window`
See Also
--------
scipy.signal.get_window
Raises
------
ParameterError
If `window` is supplied as a vector of length != `n_fft`,
or is otherwise mis-specified.
'''
if six.callable(window):
return window(Nx)

elif isinstance(window, (str, tuple)):
# TODO: if we add more window functions, put that index check here

return scipy.signal.get_window(window, Nx, fftbins=fftbins)
elif isinstance(window, (np.ndarray, list)):
if len(window) == Nx:
return np.asarray(window)
raise ParameterError('Window size mismatch: '
'{:d} != {:d}'.format(len(window), Nx))
else:
raise ParameterError('Invalid window specification: {}'.format(window))
14 changes: 14 additions & 0 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,17 @@ def __test(n_bins, bins_per_octave, n_chroma, fmin, base_c, window):
tf = __test
yield (tf, n_bins, bins_per_octave,
n_chroma, fmin, base_c, window)


def test_get_window_tuple():

x1 = scipy.signal.get_window(('kaiser', 4.0), 32)
x2 = librosa.filters.get_window(('kaiser', 4.0), 32)

assert np.allclose(x1, x2)


@raises(librosa.ParameterError)
def test_get_window_fail():

librosa.filters.get_window(None, 32)

0 comments on commit 37d098f

Please sign in to comment.