feat: Segmenter, RegularBeatFinder, SigQuality
This commit is contained in:
63
segmenter.py
Normal file
63
segmenter.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import numpy as np
|
||||
from sklearn.cluster import KMeans
|
||||
|
||||
def median_filter(a, w):
|
||||
ap = np.pad(a, (w//2, w//2), mode='edge')
|
||||
o = np.zeros(a.shape[0])
|
||||
for i in np.arange(a.shape[0]):
|
||||
sl = ap[i:i+w]
|
||||
o[i] = np.median(sl)
|
||||
return o
|
||||
|
||||
class Segmenter:
|
||||
seg_win_size_sec = 4.0 #: window size for stat. measures for segmentation, in sec
|
||||
seg_win_step_sec = 1.0 #: step for segmentation, in sec
|
||||
n_clusters = 8 #: clusters for KMeans algorithm
|
||||
seg_filt_win_sec = 20.0 #: median filter width for smoothing segments
|
||||
|
||||
def __init__(self): pass
|
||||
|
||||
def get_segment_boundaries(self, fs, guitar):
|
||||
"""split the spectral power signal 'guitar' into stochastically similar segments."""
|
||||
segment_ids = self.get_segments(fs, guitar)
|
||||
stxs = np.diff(segment_ids) != 0
|
||||
i_stxs = np.where(stxs)[0]
|
||||
return i_stxs
|
||||
|
||||
def get_segments(self, fs, guitar):
|
||||
"""split the spectral power signal 'guitar' into stochastically similar segments."""
|
||||
seg_filt_win = int(self.seg_filt_win_sec / self.seg_win_step_sec)
|
||||
seg_guitar_data = self._sig_stochastics(fs, guitar)
|
||||
X = np.vstack((
|
||||
seg_guitar_data[:,0]*1.4,
|
||||
np.sqrt(np.sum(seg_guitar_data[:,1:]**2, axis=1))
|
||||
)).T
|
||||
# cluster by stochastic characteristics
|
||||
kmeans = KMeans(n_clusters=self.n_clusters, random_state=0, n_init="auto").fit(X)
|
||||
segment_ids = np.floor(median_filter(kmeans.labels_, seg_filt_win)).astype(int)
|
||||
# up-sample segment id assignment
|
||||
iidx = np.linspace(0, segment_ids.shape[0], guitar.shape[0], endpoint=False).astype(int)
|
||||
return segment_ids[iidx]
|
||||
|
||||
def _sig_stochastics(self, fs, y):
|
||||
"""compute the stochastic moments of the signal. normalized."""
|
||||
seg_win_size = int(self.seg_win_size_sec * fs)
|
||||
seg_win_step = int(self.seg_win_step_sec * fs)
|
||||
#
|
||||
seg_y_data = np.zeros((y.shape[0] // seg_win_step, 4))
|
||||
y_pad = np.pad(y, (seg_win_size // 2, seg_win_size // 2))
|
||||
y_0_max, y_0_mean = np.max(y), np.mean(y)
|
||||
y_1_max = np.max(np.mean((y - y_0_mean)**2))
|
||||
y_2_max = np.max(np.mean(np.abs((y - y_0_mean)**3)))
|
||||
y_3_max = np.max(np.mean((y - y_0_mean)**4))
|
||||
wo = int(self.seg_win_size_sec/self.seg_win_step_sec)
|
||||
for i in np.arange(wo//2, y.shape[0] // seg_win_step - wo//2):
|
||||
i_c = int((i+0.5)*seg_win_step)
|
||||
y_slice = y_pad[i_c-seg_win_size//2:i_c+seg_win_size//2]
|
||||
mean = np.mean(y_slice)
|
||||
seg_y_data[i,0] = mean / y_0_max
|
||||
seg_y_data[i,1] = np.mean((y_slice - mean)**2) / y_1_max
|
||||
seg_y_data[i,2] = np.mean(np.abs((y_slice - mean)**3)) / y_2_max / 2
|
||||
seg_y_data[i,3] = np.mean((y_slice - mean)**4) / y_3_max / 4
|
||||
#
|
||||
return seg_y_data
|
||||
Reference in New Issue
Block a user