Source code for msaf.algorithms.scluster.segmenter

#!/usr/bin/env python
# coding: utf-8
import numpy as np

import msaf
from msaf.algorithms.interface import SegmenterInterface
from msaf.base import Features
from . import main


[docs]class Segmenter(SegmenterInterface): """ This script identifies the boundaries of a given track using the Spectral Clustering method published here: Mcfee, B., & Ellis, D. P. W. (2014). Analyzing Song Structure with Spectral Clustering. In Proc. of the 15th International Society for Music Information Retrieval Conference (pp. 405–410). Taipei, Taiwan. Original code by Brian McFee from: https://github.com/bmcfee/laplacian_segmentation """ def process(self): """Main process. Returns ------- est_idxs : np.array(N) or list Estimated times for the segment boundaries in frame indeces. List if hierarchical segmentation. est_labels : np.array(N-1) or list Estimated labels for the segments. List if hierarchical segmentation. """ # This algorithm only accepts one specific kind of features: # Combination of PCP + MFCC. Let's get them: pcp_obj = Features.select_features( "pcp", self.file_struct, self.annot_beats, self.framesync) mfcc_obj = Features.select_features( "mfcc", self.file_struct, self.annot_beats, self.framesync) # Get frame times and make sure they're the same in both features frame_times = pcp_obj.frame_times assert np.array_equal(frame_times, mfcc_obj.frame_times) # Brian wants PCP and MFCC # (tranpsosed, because he's that kind of person) F = (pcp_obj.features.T, mfcc_obj.features.T) # Do actual segmentation est_idxs, est_labels = main.do_segmentation( F, frame_times, self.config, self.in_bound_idxs) return est_idxs, est_labels, F def processFlat(self): """Main process.for flat segmentation. Returns ------- est_idxs : np.array(N) Estimated times for the segment boundaries in frame indeces. est_labels : np.array(N-1) Estimated labels for the segments. """ est_idxs, est_labels, F = self.process() assert est_idxs[0] == 0 and est_idxs[-1] == F[0].shape[1] - 1 return self._postprocess(est_idxs, est_labels) def processHierarchical(self): """Main process.for hierarchial segmentation. Returns ------- est_idxs : list List with np.arrays for each layer of segmentation containing the estimated indeces for the segment boundaries. est_labels : list List with np.arrays containing the labels for each layer of the hierarchical segmentation. """ est_idxs, est_labels, F = self.process() for layer in range(len(est_idxs)): assert est_idxs[layer][0] == 0 and \ est_idxs[layer][-1] == F[0].shape[1] - 1 est_idxs[layer], est_labels[layer] = \ self._postprocess(est_idxs[layer], est_labels[layer]) return est_idxs, est_labels