<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Utility functions"""

import scipy.ndimage
import scipy.sparse
import six

import numpy as np
import numba
from numpy.lib.stride_tricks import as_strided

from .._cache import cache
from .exceptions import ParameterError
from .decorators import deprecated

# Constrain STFT block sizes to 256 KB
MAX_MEM_BLOCK = 2**8 * 2**10

__all__ = ['MAX_MEM_BLOCK',
           'frame', 'pad_center', 'fix_length',
           'valid_audio', 'valid_int', 'valid_intervals',
           'fix_frames',
           'axis_sort', 'localmax', 'normalize',
           'peak_pick',
           'sparsify_rows',
           'roll_sparse',
           'shear',
           'fill_off_diagonal',
           'index_to_slice',
           'sync',
           'softmask',
           'buf_to_float',
           'tiny',
           'cyclic_gradient']


def frame(y, frame_length=2048, hop_length=512):
    '''Slice a time series into overlapping frames.

    This implementation uses low-level stride manipulation to avoid
    redundant copies of the time series data.

    Parameters
    ----------
    y : np.ndarray [shape=(n,)]
        Time series to frame. Must be one-dimensional and contiguous
        in memory.

    frame_length : int > 0 [scalar]
        Length of the frame in samples

    hop_length : int > 0 [scalar]
        Number of samples to hop between frames

    Returns
    -------
    y_frames : np.ndarray [shape=(frame_length, N_FRAMES)]
        An array of frames sampled from `y`:
        `y_frames[i, j] == y[j * hop_length + i]`

    Raises
    ------
    ParameterError
        If `y` is not contiguous in memory, not an `np.ndarray`, or
        not one-dimensional.  See `np.ascontiguous()` for details.

        If `hop_length < 1`, frames cannot advance.

        If `len(y) < frame_length`.

    Examples
    --------
    Extract 2048-sample frames from `y` with a hop of 64 samples per frame

    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> librosa.util.frame(y, frame_length=2048, hop_length=64)
    array([[ -9.216e-06,   7.710e-06, ...,  -2.117e-06,  -4.362e-07],
           [  2.518e-06,  -6.294e-06, ...,  -1.775e-05,  -6.365e-06],
           ...,
           [ -7.429e-04,   5.173e-03, ...,   1.105e-05,  -5.074e-06],
           [  2.169e-03,   4.867e-03, ...,   3.666e-06,  -5.571e-06]], dtype=float32)

    '''

    if not isinstance(y, np.ndarray):
        raise ParameterError('Input must be of type numpy.ndarray, '
                             'given type(y)={}'.format(type(y)))

    if y.ndim != 1:
        raise ParameterError('Input must be one-dimensional, '
                             'given y.ndim={}'.format(y.ndim))

    if len(y) < frame_length:
        raise ParameterError('Buffer is too short (n={:d})'
                             ' for frame_length={:d}'.format(len(y), frame_length))

    if hop_length < 1:
        raise ParameterError('Invalid hop_length: {:d}'.format(hop_length))

    if not y.flags['C_CONTIGUOUS']:
        raise ParameterError('Input buffer must be contiguous.')

    # Compute the number of frames that will fit. The end may get truncated.
    n_frames = 1 + int((len(y) - frame_length) / hop_length)

    # Vertical stride is one sample
    # Horizontal stride is `hop_length` samples
    y_frames = as_strided(y, shape=(frame_length, n_frames),
                          strides=(y.itemsize, hop_length * y.itemsize))
    return y_frames


@cache(level=20)
def valid_audio(y, mono=True):
    '''Validate whether a variable contains valid, mono audio data.


    Parameters
    ----------
    y : np.ndarray
      The input data to validate

    mono : bool
      Whether or not to force monophonic audio

    Returns
    -------
    valid : bool
        True if all tests pass<commit_msg>fixed #944, implemented multidimensional framing<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Utility functions"""

import scipy.ndimage
import scipy.sparse
import six

import numpy as np
import numba
from numpy.lib.stride_tricks import as_strided

from .._cache import cache
from .exceptions import ParameterError
from .decorators import deprecated

# Constrain STFT block sizes to 256 KB
MAX_MEM_BLOCK = 2**8 * 2**10

__all__ = ['MAX_MEM_BLOCK',
           'frame', 'pad_center', 'fix_length',
           'valid_audio', 'valid_int', 'valid_intervals',
           'fix_frames',
           'axis_sort', 'localmax', 'normalize',
           'peak_pick',
           'sparsify_rows',
           'roll_sparse',
           'shear',
           'fill_off_diagonal',
           'index_to_slice',
           'sync',
           'softmask',
           'buf_to_float',
           'tiny',
           'cyclic_gradient']


def frame(x, frame_length=2048, hop_length=512, axis=-1):
    '''Slice a data array into (overlapping) frames.

    This implementation uses low-level stride manipulation to avoid
    making a copy of the data.  The resulting frame representation
    is a new view of the input data.

    For example, a one-dimensional input `x = [0, 1, 2, 3, 4, 5, 6]`
    can be framed with frame-length 3 and hop length 2 in two ways.
    The first (`axis=-1`), results in the array `x_frames`:

        `[[0, 2, 4],
          [1, 3, 5],
          [2, 4, 6]]`

    where each column `x_frames[:, i]` contains a contiguous slice of 
    the input `x[i * hop_length : i * hop_length + frame_length]`.

    The second way (`axis=0`) results in the array `x_frames`:

        `[[0, 1, 2],
          [2, 3, 4],
          [4, 5, 6]]`

    where each row `x_frames[i]` contains a contiguous slice of the input.

    This generalizes to higher dimensional inputs, as shown in the examples below.
    In general, the framing operation increments by 1 the number of dimensions,
    adding a new "frame axis" either to the end of the array (`axis=-1`)
    or the beginning of the array (`axis=0`).


    Parameters
    ----------
    x : np.ndarray
        Time series to frame. Must be contiguous in memory, see the "Raises"
        section below for more information.

    frame_length : int > 0 [scalar]
        Length of the frame

    hop_length : int > 0 [scalar]
        Number of steps to advance between frames

    axis : 0 or -1
        The axis along which to frame.

        If `axis=-1` (the default), then `x` is framed along its last dimension.
        `x` must be "F-contiguous" in this case.

        If `axis=0`, then `x` is framed along its first dimension.
        `x` must be "C-contiguous" in this case.

    Returns
    -------
    x_frames : np.ndarray [shape=(..., frame_length, N_FRAMES) or (N_FRAMES, frame_length, ...)]
        A framed view of `x`, for example with `axis=-1` (framing on the last dimension):
        `x_frames[..., j] == x[..., j * hop_length : j * hop_length + frame_length]`

        If `axis=0` (framing on the first dimension), then:
        `x_frames[j] = x[j * hop_length : j * hop_length + frame_length]`

    Raises
    ------
    ParameterError
        If `x` is not contiguous in memory or not an `np.ndarray`.

        If `x.shape[axis] < frame_length`, there is not enough data to fill one frame.

        If `hop_length < 1`, frames cannot advance.

        If `axis` is not 0 or -1.  Framing is only supported along the first or last axis.
            If `axis=-1` (the default), then `x` must be "F-contiguous".
            If `axis=0`, then `x` must be "C-contiguous".

        If the contiguity of `x` is incompatible with the framing axis.

    See Also
    --------
    np.asfortranarray : Convert data to F-contiguous representation
    np.ascontiguousarray : Convert data to C-contiguous representation
    np.ndarray.flags : information about the memory layout of a numpy `ndarray`.

    Examples
    --------
    Extract 2048-sample frames from monophonic `y` with a hop of 64 samples per frame

    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> frames = librosa.util.frame(y, frame_length=2048, hop_length=64)
    >>> frames
    array([[ 0.000e+00,  0.000e+00, ..., -2.448e-06, -6.789e-07],
           [ 0.000e+00,  0.000e+00, ..., -1.399e-05,  1.004e-06],
           ...,
           [-7.352e-04,  5.162e-03, ...,  0.000e+00,  0.000e+00],
           [ 2.168e-03,  4.870e-03, ...,  0.000e+00,  0.000e+00]],
          dtype=float32)
    >>> y.shape
    (1355168,)
    >>> frames.shape
    (2048, 21143)

    Or frame along the first axis instead of the last:

    >>> frames = librosa.util.frame(y, frame_length=2048, hop_length=64, axis=0)
    >>> frames.shape
    (21143, 2048)

    Frame a stereo signal:

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), mono=False)
    >>> y.shape
    (2, 1355168)
    >>> frames = librosa.util.frame(y, frame_length=2048, hop_length=64)
    (2, 2048, 21143)

    Carve an STFT into fixed-length patches of 32 frames with no overlap

    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> S = np.abs(librosa.stft(y))
    >>> S.shape
    (1025, 2647)
    >>> S_patch = librosa.util.frame(S, frame_length=32, hop_length=32)
    >>> S_patch.shape
    (1025, 32, 82)
    >>> # The first patch is equivalent to the first 32 frames of S
    >>> np.allclose(S_patch[:, :, 0], S[:, :32])
    True
    '''

    if not isinstance(x, np.ndarray):
        raise ParameterError('Input must be of type numpy.ndarray, '
                             'given type(x)={}'.format(type(x)))

    if x.shape[axis] < frame_length:
        raise ParameterError('Input is too short (n={:d})'
                             ' for frame_length={:d}'.format(x.shape[axis], frame_length))

    if hop_length < 1:
        raise ParameterError('Invalid hop_length: {:d}'.format(hop_length))

    n_frames = 1 + (x.shape[axis] - frame_length) // hop_length
    strides = np.asarray(x.strides)

    if axis == -1:
        if not x.flags['F_CONTIGUOUS']:
            raise ParameterError('Input array must be F-contiguous '
                                 'for framing along axis={}'.format(axis))

        shape = list(x.shape)[:-1] + [frame_length, n_frames]
        strides = list(strides) + [hop_length * np.prod(strides // x.itemsize) * x.itemsize]

    elif axis == 0:
        if not x.flags['C_CONTIGUOUS']:
            raise ParameterError('Input array must be C-contiguous '
                                 'for framing along axis={}'.format(axis))

        shape = list(x.shape)[1:] + [n_frames, frame_length]
        strides = [hop_length * np.prod(strides // x.itemsize) * x.itemsize] + list(strides)
    else:
        raise ParameterError('Frame axis={} must be either 0 or -1'.format(axis))

    return as_strided(x, shape=shape, strides=strides)


@cache(level=20)
def valid_audio(y, mono=True):
    '''Validate whether a variable contains valid, mono audio data.


    Parameters
    ----------
    y : np.ndarray
      The input data to validate

    mono : bool
      Whether or not to force monophonic audio

    Returns
    -------
    valid : bool
        True if all tests pass
{'fraction_non_alphanumeric': 0.13029315960912052, 'fraction_numerical': 0.03637350705754615, 'mean_word_length': 2.2527957622130663, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 64, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4293992', 'n_tokens_mistral': 3875, 'n_tokens_neox': 3489, 'n_words': 1080}