def profile_plot(self, bbox=None,
        start_freq=None, end_freq=None,
        start_time=None, end_time=None,
        t = None,
    ):  
    """
    generate plot of all of or bbox of spectrogram
    self ... Fingerprinter object
    """
    spc = self.spectrum
    if bbox is None:
        bbox = Bbox(spc, start_freq, end_freq, start_time, end_time)
    freq_slice, time_slice = bbox.ix()
    x2 = spc.db_arr[freq_slice, time_slice]
    mn, mx = np.percentile(x2,[25,99.9])
    Z = np.clip(x2,mn,mx)
    X,Y = np.meshgrid(spc.times[time_slice], spc.freqs[freq_slice],)
    # --build plot--
    plt.clf()
    # spectrograph heatmap
    plt.pcolormesh(X,Y,Z, cmap='gist_heat_r', shading='gouraud')
    # place dots on detected harmonic peaks
    if hasattr(self, 'harmonic_intvl') and self.harmonic_intvl is not None:
        for i in self.harmonics:
            plt.plot(spc.times, self.harmonic_intvl*i, '.', color='g', alpha=.25)
    # shade areas of interest
    for start, stop in self.interest_areas:
        plt.axvspan(start, stop, facecolor='y', alpha=.5, edgecolor='k')        
    if t is not None:
        plt.axvline(t, color='b')
    plt.grid(b=True, which='major',linestyle='-', alpha=.5)
    plt.xlim(bbox.start_time, bbox.end_time)
    plt.xlabel('Time (s)')
    plt.ylabel('Frequency (Hz)')
    return plt.gcf()
 def get_volume_power(self,
                      start_freq=None,
                      end_freq=None,
                      method='avg_pct'):
     """
     get the 1D volume of the sound and normalize it to "background" volume
     so that "signal" is > 1 and "background" is ~ 1
     this is highly dependant on how much of your sound file is composed of
     signal.  Some methods do better than others depending on this ratio
     """
     box = Bbox(self.spectrum, start_freq=start_freq, end_freq=end_freq)
     freq_slice, time_slice = box.ix()
     vol = np.sum(self.spectrum.abs_arr[freq_slice, :], axis=0)
     if method == 'rms':
         base = np.sqrt(np.average(vol**2))
     elif method == 'avg':
         base = np.average(vol)
     elif method == 'pct':
         base = np.percentile(vol, 10)
     elif method == 'avg_pct':
         base = np.average(np.sort(vol)[:vol.shape[0] / 10])
     elif method == 'absolute':
         base = 1.
     else:
         raise IndexError(
             '%s is not a valid method to compute volume_power' %
             (method, ))
     self.volume_power = vol / base
def peaks_plot(
    self,
    t=0.,
    bbox=None,
    start_time=None,
    end_time=None,
    start_freq=None,
    end_freq=None,
):
    """
    Create a plot of frequency strength in dB (y-axis) vs frequency(x-axis)
    place found harmonic peaks as dots on the plot
    a thin window of the spectrograph is shown above the plot giving some context
    self .. Fingerprinter object
    """
    import matplotlib.gridspec as gridspec
    if bbox is None:
        bbox = Bbox(self.spectrum, start_freq, end_freq, start_time, end_time)
    offset = int(t * self.spectrum.samplerate)
    freq_slice, time_slice = bbox.ix()
    db_arr = self.spectrum.db_arr
    db_arr2 = np.zeros((db_arr.shape[0], db_arr.shape[1] + 20), dtype=float)
    db_arr2[:, :] = np.average(db_arr)
    db_arr2[:, 10:-10] = db_arr
    db_band = db_arr2[freq_slice, offset:offset + 20]
    mn, mx = np.percentile(db_band, [25, 99.9])
    db_band = np.clip(db_band, mn, mx)
    db_slice = db_arr[freq_slice, offset]
    harmonics_strength = self.harmonics * self.harmonic_intvl[offset]
    # --build plot--
    plt.clf()
    gs = gridspec.GridSpec(2, 1, height_ratios=[1, 8], hspace=.1)
    ax2 = plt.subplot(gs[1])
    ax1 = plt.subplot(gs[0], sharex=ax2)
    ax2.set_ylabel('Signal (dB)')
    ax2.set_xlabel('Frequency (Hz)')
    Z = db_band.T
    X, Y = np.meshgrid(np.linspace(bbox.start_freq, bbox.end_freq, Z.shape[1]),
                       np.linspace(-1., 1., Z.shape[0]))
    ax1.pcolormesh(X, Y, Z, cmap='gist_heat_r', shading='gouraud')
    ax1.axhline(0, color='b')
    ax1.set_yticklabels([])
    ax2.plot(self.spectrum.freqs[freq_slice], db_slice)
    interp_fn = interp1d(self.spectrum.freqs[freq_slice],
                         db_slice,
                         kind='linear',
                         bounds_error=False)
    values = interp_fn(harmonics_strength)
    ax2.plot(harmonics_strength,
             values,
             linestyle='',
             marker='o',
             color='g',
             alpha=.5)
    ax2.set_ylim(-75, db_arr.max())
    ax2.set_xlim(bbox.start_freq, bbox.end_freq)
    return plt.gcf()
    def get_peaks(self, t, harmonics=None, interval_range=(None, None)):
        '''
        find harmonic peaks in spectrum at given time
        t .. time value (seconds) to sample spectrum
        harmonics (1d array) .. harmonics to match
        interval_range (2-tuple) .. hz
        returns list of freqencies where harmonic peaks are
        '''
        spc = self.spectrum
        arr = self.spectrum.timeslice(t)
        bbox = Bbox(spc,
                    start_freq=interval_range[0],
                    end_freq=interval_range[1])
        freq_ix_slice = bbox.ix()[0]
        mn_freq = bbox.start_freq
        mx_freq = bbox.end_freq

        if harmonics is None:
            harmonics = self.harmonics

        interp_func = interp1d(spc.freqs,
                               arr,
                               kind='linear',
                               bounds_error=False)

        def opt_func(x):
            """
            x ... guessed frequency interval
            returns .. value to minimize
            """
            freq_intvl = float(x)
            fqs = harmonics * freq_intvl
            return 1. / np.average(interp_func(fqs))

        # there are faster solvers than this, but needed the global solver
        # TODO? try an annealing solver
        result = scipy.optimize.brute(
            opt_func,
            ranges=(slice(mn_freq, mx_freq, (mx_freq - mn_freq) / 400.), ))
        freq_intvl = result[0]
        peak_freqs = harmonics * freq_intvl
        peak_mags = interp_func(peak_freqs)
        overall_mag = np.average(arr[freq_ix_slice])
        peaks_mag = np.average(peak_mags)
        harmonic_power = peaks_mag / overall_mag

        if not interval_range[0] < freq_intvl < interval_range[1] or np.isnan(
                harmonic_power):
            freq_intvl = 0.
            harmonic_power = 0.

        return peak_freqs, peak_mags, harmonic_power, freq_intvl
    def get_peaks(self, t, harmonics=None, interval_range=(None, None)):
        '''
        find harmonic peaks in spectrum at given time
        t .. time value (seconds) to sample spectrum
        harmonics (1d array) .. harmonics to match
        interval_range (2-tuple) .. hz
        returns list of freqencies where harmonic peaks are
        '''
        spc = self.spectrum
        arr = self.spectrum.timeslice(t)
        bbox = Bbox(spc, start_freq=interval_range[0], end_freq=interval_range[1])
        freq_ix_slice = bbox.ix()[0]
        mn_freq = bbox.start_freq
        mx_freq = bbox.end_freq

        if harmonics is None:
            harmonics = self.harmonics

        interp_func = interp1d(spc.freqs, arr,
            kind='linear', bounds_error=False)

        def opt_func(x):
            """
            x ... guessed frequency interval
            returns .. value to minimize
            """
            freq_intvl = float(x)
            fqs = harmonics * freq_intvl
            return 1./np.average(interp_func(fqs))

        # there are faster solvers than this, but needed the global solver
        # TODO? try an annealing solver 
        result = scipy.optimize.brute( 
            opt_func,
            ranges=(slice(mn_freq,mx_freq,(mx_freq-mn_freq)/400.),)
        )
        freq_intvl = result[0]
        peak_freqs = harmonics * freq_intvl
        peak_mags = interp_func(peak_freqs)
        overall_mag = np.average(arr[freq_ix_slice])
        peaks_mag = np.average(peak_mags)
        harmonic_power = peaks_mag/overall_mag

        if not interval_range[0]<freq_intvl<interval_range[1] or np.isnan(harmonic_power):
            freq_intvl = 0.
            harmonic_power = 0.

        return peak_freqs, peak_mags, harmonic_power, freq_intvl
    def get_harmonic_power2(self, interval_range=(15.,50.), 
            harmonics=None, n_control_pts=10):
        """
        root-find a function (with x control points) that best matches harmonics
        in a given spectrum.  (don't root-find every sample)
        TODO - in-work
        """
        cntrl_ixs = np.arange(n_control_pts)
        f0,f1 = interval_range
        bbox = Bbox(spc, start_freq=f0, end_freq=f1)
        freq_ix_slice = bbox.ix()[0]
        mn_freq = bbox.start_freq
        mx_freq = bbox.end_freq

        if harmonics is None:
            harmonics = self.harmonics        
def power_plot(
    self,
    t=None,
    bbox=None,
    start_time=None,
    end_time=None,
    start_freq=None,
    end_freq=None,
):
    """
    self .. Fingerprinter object
    """
    spc = self.spectrum
    if bbox is None:
        bbox = Bbox(spc, start_freq, end_freq, start_time, end_time)
    plt.cla()
    plt.clf()
    plt.plot(spc.times,
             self.harmonic_power,
             color='orange',
             label='harmonic power',
             alpha=.5)
    plt.plot(spc.times,
             self.volume_power,
             color='cyan',
             label='volume power',
             alpha=.5)

    plt.plot(spc.times, self.total_power, color='k', label='power')
    plt.ylabel('Power')
    plt.xlabel('Time (s)')
    #plt.legend(loc=2)
    ax1 = plt.gca()

    plt.twinx()
    plt.xlim(bbox.start_time, bbox.end_time)
    plt.plot(spc.times,
             self.harmonic_intvl,
             marker='o',
             markersize=3,
             ls='',
             color='g',
             alpha=.5,
             label='harmonic interval')
    ax2 = plt.gca()
    plt.xlim(bbox.start_time, bbox.end_time)
    plt.ylim(bbox.start_freq, bbox.end_freq)
    #plt.legend(loc=1)

    plt.ylabel('Frequency (Hz)')
    for start, stop in self.interest_areas:
        plt.axvspan(start, stop, color='y', alpha=.25)
    if t:
        plt.axvline(t, color='b')

    lines1, labels1 = ax1.get_legend_handles_labels()
    lines2, labels2 = ax2.get_legend_handles_labels()
    legend = ax2.legend(lines1 + lines2, labels1 + labels2, loc=1)
    legend.legendPatch._facecolor = (1., 1., 1., .75)
    return plt.gcf()
def peaks_plot(self, t=0., bbox=None,
    start_time=None, end_time=None,
    start_freq=None, end_freq=None, ):
    """
    Create a plot of frequency strength in dB (y-axis) vs frequency(x-axis)
    place found harmonic peaks as dots on the plot
    a thin window of the spectrograph is shown above the plot giving some context
    self .. Fingerprinter object
    """
    import matplotlib.gridspec as gridspec
    if bbox is None:
        bbox = Bbox(self.spectrum, start_freq, end_freq, start_time, end_time)
    offset = int(t*self.spectrum.samplerate)
    freq_slice, time_slice = bbox.ix()
    db_arr = self.spectrum.db_arr
    db_arr2 = np.zeros((db_arr.shape[0],db_arr.shape[1]+20),dtype=float)
    db_arr2[:,:] = np.average(db_arr)
    db_arr2[:,10:-10] = db_arr
    db_band = db_arr2[freq_slice, offset:offset+20]
    mn, mx = np.percentile(db_band,[25,99.9])
    db_band = np.clip(db_band,mn,mx)
    db_slice = db_arr[freq_slice, offset]
    harmonics_strength = self.harmonics * self.harmonic_intvl[offset]
    # --build plot--
    plt.clf()
    gs = gridspec.GridSpec(2, 1, height_ratios=[1,8], hspace=.1)
    ax2 = plt.subplot(gs[1])
    ax1 = plt.subplot(gs[0], sharex=ax2)
    ax2.set_ylabel('Signal (dB)')
    ax2.set_xlabel('Frequency (Hz)')
    Z = db_band.T
    X,Y = np.meshgrid(
        np.linspace(bbox.start_freq,bbox.end_freq,Z.shape[1]), 
        np.linspace(-1.,1.,Z.shape[0])
    )
    ax1.pcolormesh(X,Y,Z, cmap='gist_heat_r', shading='gouraud')
    ax1.axhline(0, color='b')
    ax1.set_yticklabels([])
    ax2.plot(self.spectrum.freqs[freq_slice], db_slice )
    interp_fn = interp1d(self.spectrum.freqs[freq_slice], db_slice,
            kind='linear', bounds_error=False)
    values = interp_fn(harmonics_strength)
    ax2.plot(harmonics_strength, values, linestyle='', marker='o', color='g', alpha=.5)
    ax2.set_ylim(-75, db_arr.max())
    ax2.set_xlim(bbox.start_freq, bbox.end_freq)
    return plt.gcf() 
def profile_plot(
    self,
    bbox=None,
    start_freq=None,
    end_freq=None,
    start_time=None,
    end_time=None,
    t=None,
):
    """
    generate plot of all of or bbox of spectrogram
    self ... Fingerprinter object
    """
    spc = self.spectrum
    if bbox is None:
        bbox = Bbox(spc, start_freq, end_freq, start_time, end_time)
    freq_slice, time_slice = bbox.ix()
    x2 = spc.db_arr[freq_slice, time_slice]
    mn, mx = np.percentile(x2, [25, 99.9])
    Z = np.clip(x2, mn, mx)
    X, Y = np.meshgrid(
        spc.times[time_slice],
        spc.freqs[freq_slice],
    )
    # --build plot--
    plt.clf()
    # spectrograph heatmap
    plt.pcolormesh(X, Y, Z, cmap='gist_heat_r', shading='gouraud')
    # place dots on detected harmonic peaks
    if hasattr(self, 'harmonic_intvl') and self.harmonic_intvl is not None:
        for i in self.harmonics:
            plt.plot(spc.times,
                     self.harmonic_intvl * i,
                     '.',
                     color='g',
                     alpha=.25)
    # shade areas of interest
    for start, stop in self.interest_areas:
        plt.axvspan(start, stop, facecolor='y', alpha=.5, edgecolor='k')
    if t is not None:
        plt.axvline(t, color='b')
    plt.grid(b=True, which='major', linestyle='-', alpha=.5)
    plt.xlim(bbox.start_time, bbox.end_time)
    plt.xlabel('Time (s)')
    plt.ylabel('Frequency (Hz)')
    return plt.gcf()
Пример #10
0
    def get_harmonic_power2(self,
                            interval_range=(15., 50.),
                            harmonics=None,
                            n_control_pts=10):
        """
        root-find a function (with x control points) that best matches harmonics
        in a given spectrum.  (don't root-find every sample)
        TODO - in-work
        """
        cntrl_ixs = np.arange(n_control_pts)
        f0, f1 = interval_range
        bbox = Bbox(spc, start_freq=f0, end_freq=f1)
        freq_ix_slice = bbox.ix()[0]
        mn_freq = bbox.start_freq
        mx_freq = bbox.end_freq

        if harmonics is None:
            harmonics = self.harmonics
Пример #11
0
    def get_harmonic_power3(self, interval_range=(15., 100.), harmonics=None):
        """
        Instead of using root-finding methods, do a brute sweep on a numpy array
        """
        if harmonics is None: harmonics = self.harmonics
        spc = self.spectrum
        a = spc.abs_arr

        bbox = Bbox(spc,
                    start_freq=interval_range[0],
                    end_freq=interval_range[1])
        freq_ix_slice = bbox.ix()[0]
        strt, stop = interval_range
        intvls = np.linspace(strt, stop, 1000)

        X, Y = np.meshgrid(intvls, harmonics)
        b = X * Y
        arr = np.arange(len(spc.freqs))
        freq2ix = interp1d(spc.freqs, arr, kind='linear', bounds_error=False)
        ix = freq2ix(b).astype(int)
        z = a[ix].sum(0)
        win = hann(7)
        z = convolve1d(z, win, axis=1)
        x = np.argmax(z, 0)
        h = intvls[x]

        peaks_ix = np.outer(harmonics, freq2ix(h))

        peaks_mag = np.zeros_like(peaks_ix)
        peaks_ix = peaks_ix.astype(int)

        for i in range(peaks_ix.shape[1]):
            ix = peaks_ix[:, i]
            peaks_mag[:, i] = a[ix, i]

        peaks_avg = np.average(peaks_mag, 0)

        overall_avg = np.average(a[0:stop * harmonics[-1], :], axis=0)
        h_power = peaks_avg / overall_avg

        self.fingerprint = peaks_mag
        self.harmonic_intvl = h
        self.harmonic_power = h_power
Пример #12
0
    def get_harmonic_power3(self, interval_range=(15.,100.), harmonics=None):
        """
        Instead of using root-finding methods, do a brute sweep on a numpy array
        """
        if harmonics is None: harmonics=self.harmonics
        spc = self.spectrum
        a = spc.abs_arr
        
        bbox = Bbox(spc, start_freq=interval_range[0], end_freq=interval_range[1])
        freq_ix_slice = bbox.ix()[0]
        strt, stop = interval_range
        intvls = np.linspace(strt,stop,1000)

        X, Y = np.meshgrid(intvls, harmonics)
        b = X * Y
        arr = np.arange(len(spc.freqs))
        freq2ix = interp1d(spc.freqs, arr,
                    kind='linear', bounds_error=False)
        ix = freq2ix(b).astype(int)
        z = a[ix].sum(0)
        win = hann(7)
        z = convolve1d(z,win, axis=1)
        x = np.argmax(z,0)
        h = intvls[x]

        peaks_ix = np.outer(harmonics, freq2ix(h))

        peaks_mag = np.zeros_like(peaks_ix)
        peaks_ix = peaks_ix.astype(int)

        for i in range(peaks_ix.shape[1]):
            ix = peaks_ix[:,i]
            peaks_mag[:,i] = a[ix,i]
            
        peaks_avg = np.average(peaks_mag, 0)

        overall_avg = np.average(a[0:stop*harmonics[-1],:], axis=0)
        h_power = peaks_avg/overall_avg
       
        self.fingerprint = peaks_mag
        self.harmonic_intvl = h
        self.harmonic_power = h_power
Пример #13
0
 def get_volume_power(self, start_freq=None, end_freq=None, method='avg_pct'):
     """
     get the 1D volume of the sound and normalize it to "background" volume
     so that "signal" is > 1 and "background" is ~ 1
     this is highly dependant on how much of your sound file is composed of
     signal.  Some methods do better than others depending on this ratio
     """
     box = Bbox(self.spectrum, start_freq=start_freq, end_freq=end_freq)
     freq_slice, time_slice = box.ix()
     vol = np.sum(self.spectrum.abs_arr[freq_slice,:], axis=0)
     if method == 'rms':
         base = np.sqrt(np.average(vol**2))
     elif method == 'avg':
         base = np.average(vol)
     elif method == 'pct':
         base = np.percentile(vol, 10)
     elif method == 'avg_pct':
         base = np.average(np.sort(vol)[:vol.shape[0]/10])
     elif method == 'absolute':
         base = 1.
     else:
         raise IndexError('%s is not a valid method to compute volume_power'%(method,))
     self.volume_power = vol/base
Пример #14
0
def make_video(profile, name='test', bbox=None, plot_type='profile_plot'):
    """
    plot_type .. 'power_plot', 'profile_plot', 'peaks_plot'
    """
    if bbox is None: bbox = Bbox(profile.spectrum, end_freq=500.)
    registry = ['power_plot', 'profile_plot', 'peaks_plot']
    if plot_type == 'all': plot_type = registry
    if type(plot_type) is not str:
        for ptype in plot_type:
            make_video(profile, name, bbox, ptype)
        return
    import moviepy.editor as mpy  # deferred import in case moviepy is not installed
    from moviepy.video.io.bindings import mplfig_to_npimage
    sound = profile.spectrum.sound
    # normalize in case very quiet
    sound_array = sound.data / (2 * np.abs(sound.data).max())

    def video_fn(t):
        """make one frame of video"""
        t += bbox.start_time
        fn = getattr(profile, plot_type)
        fig = fn(t=t, bbox=bbox)
        return mplfig_to_npimage(fig)

    def audio_fn(t):
        """make one "frame" of audio"""
        t += bbox.start_time
        if type(t) is int:
            i = t * sound.samplerate
        elif type(t) is float:
            i = int(t * sound.samplerate)
        else:
            i = (t * sound.samplerate).astype(int)
        return sound_array[i]

    duration = bbox.end_time - bbox.start_time
    video_clip = mpy.VideoClip(video_fn, duration=duration)
    audio_clip = mpy.AudioClip(audio_fn, duration=duration)
    animation = video_clip.set_audio(audio_clip)
    animation.to_videofile(name + '_' + plot_type + '.avi',
                           codec='libx264',
                           fps=24)  # codec='mpeg4'