예제 #1
0
def spectral_rolloff(y=None,
                     sr=22050,
                     S=None,
                     n_fft=2048,
                     hop_length=512,
                     freq=None,
                     roll_percent=0.85):

    if not 0.0 < roll_percent < 1.0:
        raise ParameterError('roll_percent must lie in the range (0, 1)')

    S, n_fft = _spectrogram(y=y, S=S, n_fft=n_fft, hop_length=hop_length)

    if not np.isrealobj(S):
        raise ParameterError('Spectral rolloff is only defined '
                             'with real-valued input')
    elif np.any(S < 0):
        raise ParameterError('Spectral rolloff is only defined '
                             'with non-negative energies')

    # Compute the center frequencies of each bin
    if freq is None:
        freq = fft_frequencies(sr=sr, n_fft=n_fft)

    # Make sure that frequency can be broadcast
    if freq.ndim == 1:
        freq = freq.reshape((-1, 1))

    total_energy = np.cumsum(S, axis=0)

    threshold = roll_percent * total_energy[-1]

    ind = np.where(total_energy < threshold, np.nan, 1)

    return np.nanmin(ind * freq, axis=0, keepdims=True)
예제 #2
0
def spectral_bandwidth(y=None, sr=22050, S=None, n_fft=2048, hop_length=512,
                       freq=None, centroid=None, norm=True, p=2):


    S, n_fft = _spectrogram(y=y, S=S, n_fft=n_fft, hop_length=hop_length)

    if not np.isrealobj(S):
        raise ParameterError('Spectral bandwidth is only defined '
                             'with real-valued input')
    elif np.any(S < 0):
        raise ParameterError('Spectral bandwidth is only defined '
                             'with non-negative energies')

    if centroid is None:
        centroid = spectral_centroid(y=y, sr=sr, S=S,
                                     n_fft=n_fft,
                                     hop_length=hop_length,
                                     freq=freq)

    # Compute the center frequencies of each bin
    if freq is None:
        freq = fft_frequencies(sr=sr, n_fft=n_fft)

    if freq.ndim == 1:
        deviation = np.abs(np.subtract.outer(freq, centroid[0]))
    else:
        deviation = np.abs(freq - centroid[0])

    # Column-normalize S
    if norm:
        S = util.normalize(S, norm=1, axis=0)

    return np.sum(S * deviation**p, axis=0, keepdims=True)**(1./p)
예제 #3
0
def melspectrogram(y, sr, filterbank, n_fft, hop_length, win_length):
    S, _ = spectrum._spectrogram(y=y,
                                 power=2.0,
                                 n_fft=n_fft,
                                 hop_length=hop_length,
                                 win_length=win_length)
    return np.dot(filterbank, S)
예제 #4
0
def spectral_centroid(y=None,
                      sr=22050,
                      S=None,
                      n_fft=2048,
                      hop_length=512,
                      freq=None):

    S, n_fft = _spectrogram(y=y, S=S, n_fft=n_fft, hop_length=hop_length)

    if not np.isrealobj(S):
        raise ParameterError('Spectral centroid is only defined '
                             'with real-valued input')
    elif np.any(S < 0):
        raise ParameterError('Spectral centroid is only defined '
                             'with non-negative energies')

    # Compute the center frequencies of each bin
    if freq is None:
        freq = fft_frequencies(sr=sr, n_fft=n_fft)

    if freq.ndim == 1:
        freq = freq.reshape((-1, 1))

    # Column-normalize S
    return np.sum(freq * util.normalize(S, norm=1, axis=0),
                  axis=0,
                  keepdims=True)
예제 #5
0
    def test_get_psd(self):
        psd1, _ = _spectrogram(y=self.sig,
                               S=None,
                               n_fft=nfft,
                               hop_length=stepsize)
        psd2 = get_psd(self.args)

        self.assertTrue(np.allclose(psd1, psd2))
예제 #6
0
    def test_stft_from_sig(self):
        psd1, _ = _spectrogram(y=self.sig,
                               S=None,
                               n_fft=nfft,
                               hop_length=stepsize)
        psd2 = np.abs(
            stft_from_sig(self.sig, nfft, noverlap, win_length, 'hann', True))

        self.assertTrue(np.allclose(psd1, psd2))
예제 #7
0
def melspectrogram(y=None, sr=22050, S=None, n_fft=2048, hop_length=512,
                   power=2.0, **kwargs):
    #Compute a mel-scaled spectrogram.

    S, n_fft = _spectrogram(y=y, S=S, n_fft=n_fft, hop_length=hop_length,
                            power=power)

    # Build a Mel filter
    mel_basis = mel(sr, n_fft, **kwargs)

    return np.dot(mel_basis, S)
예제 #8
0
def signal_noise_split(audio):
    S, _ = spectrum._spectrogram(y=audio, power=1.0, n_fft=2048, hop_length=512, win_length=2048)
    
    col_median = np.median(S, axis=0, keepdims=True)
    row_median = np.median(S, axis=1, keepdims=True)
    S[S < row_median * 3] = 0.0
    S[S < col_median * 3] = 0.0
    S[S > 0] = 1
    
    S = binary_erosion(S, structure=np.ones((4, 4)))
    S = binary_dilation(S, structure=np.ones((4, 4)))
    
    indicator = S.any(axis=0)
    indicator = binary_dilation(indicator, structure=np.ones(4), iterations=2)
    
    mask = np.repeat(indicator, hop_length)
    mask = binary_dilation(mask, structure=np.ones(win_length - hop_length), origin=-(win_length - hop_length)//2)
    mask = mask[:len(audio)]
    signal = audio[mask]
    noise = audio[~mask]
    return signal, noise
예제 #9
0
def spectral_contrast(y=None,
                      sr=22050,
                      S=None,
                      n_fft=2048,
                      hop_length=512,
                      freq=None,
                      fmin=200.0,
                      n_bands=6,
                      quantile=0.02,
                      linear=False):

    S, n_fft = _spectrogram(y=y, S=S, n_fft=n_fft, hop_length=hop_length)

    # Compute the center frequencies of each bin
    if freq is None:
        freq = fft_frequencies(sr=sr, n_fft=n_fft)

    freq = np.atleast_1d(freq)

    if freq.ndim != 1 or len(freq) != S.shape[0]:
        raise ParameterError('freq.shape mismatch: expected '
                             '({:d},)'.format(S.shape[0]))

    if n_bands < 1 or not isinstance(n_bands, int):
        raise ParameterError('n_bands must be a positive integer')

    if not 0.0 < quantile < 1.0:
        raise ParameterError('quantile must lie in the range (0, 1)')

    if fmin <= 0:
        raise ParameterError('fmin must be a positive number')

    octa = np.zeros(n_bands + 2)
    octa[1:] = fmin * (2.0**np.arange(0, n_bands + 1))

    if np.any(octa[:-1] >= 0.5 * sr):
        raise ParameterError('Frequency band exceeds Nyquist. '
                             'Reduce either fmin or n_bands.')

    valley = np.zeros((n_bands + 1, S.shape[1]))
    peak = np.zeros_like(valley)

    for k, (f_low, f_high) in enumerate(zip(octa[:-1], octa[1:])):
        current_band = np.logical_and(freq >= f_low, freq <= f_high)

        idx = np.flatnonzero(current_band)

        if k > 0:
            current_band[idx[0] - 1] = True

        if k == n_bands:
            current_band[idx[-1] + 1:] = True

        sub_band = S[current_band]

        if k < n_bands:
            sub_band = sub_band[:-1]

        # Always take at least one bin from each side
        idx = np.rint(quantile * np.sum(current_band))
        idx = int(np.maximum(idx, 1))

        sortedr = np.sort(sub_band, axis=0)

        valley[k] = np.mean(sortedr[:idx], axis=0)
        peak[k] = np.mean(sortedr[-idx:], axis=0)

    if linear:
        return peak - valley
    else:
        return power_to_db(peak) - power_to_db(valley)