diff --git a/comsar/tracks/timbre.py b/comsar/tracks/timbre.py index 14e173ba89b0f3255f57efa1d300ef23977a9515..3a2acc5a964b570e925ceedf19db794e1ccbbee4 100644 --- a/comsar/tracks/timbre.py +++ b/comsar/tracks/timbre.py @@ -113,3 +113,85 @@ class TimbreTrack: self.pace[idx] = pace print(f'{pace:.4} s.') return res + + +class TimbreTrackAlt: + """Compute timbre track of an audio file. Do not use correlogram. + """ + def __init__(self, + stft_params: Optional[container.StftParams] = None, + corr_dim_params: Optional[container.CorrDimParams] = None, + ) -> None: + """ + Args: + """ + self.params = TimbreTrackParams(stft_params or STFT_DEFAULT, + corr_dim_params or CORR_DIM_DEFAULT, + corr_gram_params or CORR_GRAM_DEFAULT) + + self.cutter = Segmentation(self.params.stft.n_perseg, + self.params.stft.n_overlap, + self.params.stft.extend, + self.params.stft.pad) + + self.stft = StftSegments(self.params.stft.fps, self.params.stft.window, + self.params.stft.n_fft) + + self.feature_names = ('Spectral Centroid', 'Spectral Spread', + 'Spectral Flux', 'Roughness', 'Sharpness', + 'SPL', 'Correlation Dimension') + + self.funcs = [features.spectral_centroid, + features.spectral_spread, + features.spectral_flux, + features.roughness_helmholtz, + features.sharpness, + features.spl, + features.cdim] + + self.pace = np.zeros(self.n_features) + self.verbose = False + + @property + def n_features(self) -> int: + """Number of features on track""" + return len(self.feature_names) + + def extract(self, path) -> pd.DataFrame: + """Perform extraction. + """ + snd = AudioFile(path) + if snd.fps != self.params.stft.fps: + snd.close() + raise ValueError('Sample rate of {snd!str} differs from init.') + + segs = self.cutter.transform(snd.data.squeeze()) + sxx = self.stft.transform(segs) + + args = [(sxx.frqs, sxx.power), + (sxx.frqs, sxx.power), + (sxx.abs,), + (sxx.d_frq, sxx.abs, 15000), + (sxx.frqs, sxx.abs), + (segs.data,), + (segs.data,)] + + kwargs = [{}, {}, {}, {}, {}, {}, self.params.corr_dim.to_dict()] + + out = np.zeros((segs.n_segs, self.n_features)) + for i, (fun, arg, kwarg) in enumerate(zip(self.funcs, args, kwargs)): + out[:, i] = self._worker(i, fun, arg, kwarg) + snd.close() + + meta = TrackMeta(comsar.__version__, time_stamp(), snd.file_name) + out = pd.DataFrame(data=out, columns=self.feature_names) + return TrackResult(meta, self.params, out) + + def _worker(self, idx, func, args, kwargs) -> np.ndarray: + print(self.feature_names[idx], end=' ... ') + pace = timer() + res = func(*args, **kwargs) + pace = timer() - pace + self.pace[idx] = pace + print(f'{pace:.4} s.') + return res