Skip to content
Snippets Groups Projects
Commit 72db42b4 authored by Blaß, Michael's avatar Blaß, Michael :speech_balloon:
Browse files

Merge branch 'develop'

Version 0.0.2
parents e708d1d7 52ba674c
No related branches found
No related tags found
No related merge requests found
Showing
with 152 additions and 48 deletions
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[metadata]
name = comsar
version = 0.0.1
version = 0.0.2
description = Computational Music and Sound Archiving
long_description = file: README.md
licence = BSD-3-Clause
......@@ -10,9 +10,8 @@ keywords = hmm, som, comsar, music, analysis
classifiers =
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.7
Programming Language :: Python :: Implementation :: CPython
Topic :: Scientific/Engineering
Topic :: Database
......@@ -22,16 +21,15 @@ classifiers =
License :: OSI Approved :: BSD License
[options]
zip_safe = True
include_package_data = True
packages = find:
scripts = scripts/comsar
setup_requires = numpy
zip_safe = False
package_dir =
=src
include_package_data = False
packages = find_namespace:
python_requires >= '3.7'
install_requires =
numpy
scipy >= "0.19.0"
matplotlib >= "2"
pandas >= "0.20"
setuptools >= "40.0.0"
sklearn >= "0.20"
pandas
[options.packages.find]
where = src
import pkg_resources as _pkg
from .tracks.timbre import TimbreTrack
from .tracks.utilities import TrackResult
__version__ = _pkg.get_distribution('comsar').version
File moved
File moved
File moved
File moved
......@@ -2,7 +2,7 @@
License: BSD-3-Clasuse
Copyright (C) 2020, Michael Blaß, michael.blass@uni-hamburg.de
"""
from dataclasses import dataclass
from datetime import datetime
from timeit import default_timer as timer
from typing import Optional
......@@ -13,10 +13,10 @@ from apollon.audio import AudioFile
from apollon.segment import Segmentation
from apollon.signal import container, features
from apollon.signal.spectral import StftSegments
from apollon.tools import time_stamp
import comsar
from comsar.tracks.utilities import TrackMeta, TrackParams, TrackResult, TimbreTrackParams
from comsar._tracks.utilities import (TrackMeta, TrackResult, SourceMeta,
TimbreTrackParams, TimbreTrackCorrGramParams)
STFT_DEFAULT = container.StftParams(fps=44100, window='hamming', n_fft=None,
......@@ -29,9 +29,90 @@ CORR_DIM_DEFAULT = container.CorrDimParams(delay=14, m_dim=80, n_bins=1000,
CORR_GRAM_DEFAULT = container.CorrGramParams(wlen=2**10, n_delay=2**8, total=True)
class TimbreTrack:
"""Compute timbre track of an audio file.
"""
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)
self.cutter = Segmentation(self.params.stft.n_perseg,
self.params.stft.n_overlap,
self.params.stft.extend,
self.params.stft.pad)
class TimbreTrack:
self.stft = StftSegments(self.params.stft.fps, self.params.stft.window,
self.params.stft.n_fft)
self.feature_names = ('SpectralCentroid', 'SpectralSpread',
'SpectralFlux', 'Roughness', 'Sharpness',
'SPL', 'CorrelationDimension')
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)
file_meta = SourceMeta(*snd.file_name.split('.'), snd.hash)
track_meta = TrackMeta(comsar.__version__, datetime.utcnow(),
file_meta)
out = pd.DataFrame(data=out, columns=self.feature_names)
snd.close()
return TrackResult(track_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
class TimbreTrackCorrGram:
"""Compute timbre track of an audio file.
"""
def __init__(self,
......@@ -41,7 +122,7 @@ class TimbreTrack:
"""
Args:
"""
self.params = TimbreTrackParams(stft_params or STFT_DEFAULT,
self.params = TimbreTrackCorrGramParams(stft_params or STFT_DEFAULT,
corr_dim_params or CORR_DIM_DEFAULT,
corr_gram_params or CORR_GRAM_DEFAULT)
......@@ -101,7 +182,7 @@ class TimbreTrack:
out[:, i] = self._worker(i, fun, arg, kwarg)
snd.close()
meta = TrackMeta(comsar.__version__, time_stamp(), snd.file_name)
meta = TrackMeta(comsar.__version__, datetime.utcnow(), snd.file_name)
out = pd.DataFrame(data=out, columns=self.feature_names)
return TrackResult(meta, self.params, out)
......
......@@ -2,6 +2,7 @@
License: BSD-3-Clasuse
Copyright (C) 2020, Michael Blaß, michael.blass@uni-hamburg.de
"""
import datetime
import pathlib
import pickle
from typing import ClassVar, Type, TypeVar, Union
......@@ -12,20 +13,30 @@ import pandas as pd
from apollon import io
from apollon import container
from apollon import signal
from apollon.signal import container as asc
from apollon.tools import standardize
from apollon import types
T = TypeVar('T')
@dataclass
class SourceMeta(container.Params):
"""Source file meta data."""
_schema: ClassVar[types.Schema] = None
name: str
extension: str
hash_: str
@dataclass
class TrackMeta(container.Params):
"""Track meta data."""
_schema: ClassVar[types.Schema] = None
version: str
time_stamp: str
source: str
extraction_date: datetime.datetime
source: SourceMeta
@dataclass
......@@ -37,9 +48,15 @@ class TrackParams(container.Params):
@dataclass
class TimbreTrackParams(TrackParams):
"""Parameter set for TimbreTrack"""
stft: signal.container.StftParams
corr_dim: signal.container.CorrDimParams
corr_gram: signal.container.CorrGramParams
stft: asc.StftParams
corr_dim: asc.CorrDimParams
@dataclass
class TimbreTrackCorrGramParams(TrackParams):
"""Parameter set for TimbreTrack"""
stft: asc.StftParams
corr_dim: asc.CorrDimParams
class TrackResult:
......@@ -84,13 +101,17 @@ class TrackResult:
"""Serialize TrackResults to dictionary."""
return {'meta': self._meta.to_dict(),
'params': self._params.to_dict(),
'data': self._data.to_dict()}
'data': self._data.to_dict(orient='list')}
def to_json(self, path: Union[str, pathlib.Path]) -> None:
"""Serialize TrackResults to JSON."""
io.json.dump(self.to_dict(), path)
def to_mongo(self, db_con) -> None:
"""Write TrackResults to open MongoDB connection:"""
pass
def to_pickle(self, path: Union[str, pathlib.Path]) -> None:
"""Serialize Track Results to pickle."""
path = pathlib.Path(path)
......
File moved
File moved
File moved
File moved
File moved
from . _tracks.timbre import TimbreTrack
from . _tracks.timbre import TimbreTrackCorrGram
......@@ -3,10 +3,7 @@ import numpy as np
import pandas as pd
from apollon.tools import time_stamp
from comsar.tracks.timbre import (TimbreTrack,
STFT_DEFAULT, CORR_DIM_DEFAULT, CORR_GRAM_DEFAULT)
import comsar
from comsar.tracks.utilities import TrackMeta, TrackParams, TrackResult, TimbreTrackParams
from comsar.tracks import TimbreTrack
class TestTimbreTrack(unittest.TestCase):
......@@ -15,5 +12,3 @@ class TestTimbreTrack(unittest.TestCase):
def test_nfeatures(self):
self.assertIsInstance(self.track.n_features, int)
......@@ -4,9 +4,8 @@ import unittest
from hypothesis import given
from comsar import TrackResult
from comsar.tracks.timbre import TimbreTrackParams
from .. utils import timbre_track_results
from comsar._tracks.utilities import TimbreTrackParams, TrackResult
from utils import timbre_track_results
class TestTrackResult(unittest.TestCase):
......
"""
Utilities for testing.
"""
import string
from hypothesis.strategies import (composite, integers, lists, sampled_from,
......@@ -7,8 +10,8 @@ import pandas as pd
from apollon.tools import time_stamp
import comsar
from comsar.tracks import timbre
from comsar.tracks.utilities import TrackMeta, TimbreTrackParams, TrackResult
from comsar._tracks import timbre
from comsar._tracks.utilities import TrackMeta, TimbreTrackParams, TrackResult
def ascii_strings() -> SearchStrategy:
......@@ -16,10 +19,12 @@ def ascii_strings() -> SearchStrategy:
return text(sampled_from(string.ascii_letters+string.digits),
min_size=2, max_size=10)
def lists_of_strings() -> SearchStrategy:
"""Lists of unique ascii_strings."""
return lists(ascii_strings(), min_size=2, max_size=10, unique=True)
@composite
def numerical_dataframes(draw) -> pd.DataFrame:
"""Generate pandas DataFrames.
......@@ -32,11 +37,14 @@ def numerical_dataframes(draw) -> pd.DataFrame:
data = draw(arrays('float64', (n_rows, len(names))))
return pd.DataFrame(data=data, columns=names)
@composite
def timbre_track_results(draw) -> TrackResult:
meta = TrackMeta(comsar.__version__, time_stamp(), 'testfile.wav')
"""Mock the result of a timbre track extraction pipeline.
"""
meta = TrackMeta(comsar.__version__, time_stamp(), 'testfile.wav',
draw(ascii_strings()))
params = TimbreTrackParams(timbre.STFT_DEFAULT,
timbre.CORR_DIM_DEFAULT,
timbre.CORR_GRAM_DEFAULT)
timbre.CORR_DIM_DEFAULT)
data = draw(numerical_dataframes())
return TrackResult(meta, params, data)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment