Completed
Pull Request — master (#91)
by Brian
01:04
created

jams.chord()   A

Complexity

Conditions 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 9
rs 9.6666
1
#!/usr/bin/env python
2
# CREATED:2015-12-12 18:20:37 by Brian McFee <[email protected]>
3
r'''
4
Sonification
5
============
6
7
.. autosummary::
8
    :toctree: generated/
9
10
    sonify
11
'''
12
13
import six
14
import numpy as np
15
import mir_eval.sonify
16
from mir_eval.util import filter_kwargs
17
from .eval import validate_annotation
18
from .exceptions import NamespaceError
19
20
__all__ = ['sonify']
21
22
23
24
def clicks(annotation, sr=22050, length=None, **kwargs):
25
    '''Sonify clicks timings
26
27
    '''
28
29
    interval, _ = annotation.data.to_interval_values()
30
31
    return filter_kwargs(mir_eval.sonify.clicks, interval[:, 0],
32
                         fs=sr, length=length, **kwargs)
33
34
35
def chord(annotation, sr=22050, length=None, **kwargs):
36
    '''Sonify chords'''
37
38
    intervals, chords = annotation.data.to_interval_values()
39
40
    return filter_kwargs(mir_eval.sonify.chords,
41
                         chords, intervals,
42
                         fs=sr, length=length,
43
                         **kwargs)
44
45
46
def pitch_midi(annotation, sr=22050, length=None, **kwargs):
47
    '''Sonify midi pitches'''
48
49
    intervals, notes = annotation.data.to_interval_values()
50
51
    freqs = 440.0 * (2.0 ** ((np.arange(128) - 69.0)/12.0))
52
53
    gram = np.zeros((len(freqs), len(notes)))
54
55
    for t, n in enumerate(notes):
56
        gram[n, t] = 1.0
57
58
    # Compress for efficiency
59
    idx = gram.max(axis=1) > 0
60
61
    gram = gram[idx]
62
    freqs = freqs[idx]
63
64
    return filter_kwargs(mir_eval.sonify.time_frequency,
65
                         gram, freqs, intervals,
66
                         fs=sr, length=length,
67
                         **kwargs)
68
69
70
SONIFY_MAPPING = {'beat.*|segment.*|onset.*': clicks,
71
                  'chord|chord_harte': chord,
72
                  'pitch_midi': pitch_midi}
73
74
75
def sonify(annotation, sr=22050, duration=None, **kwargs):
76
    '''Sonify a jams annotation through mir_eval
77
78
    Parameters
79
    ----------
80
    annotation : jams.Annotation
81
        The annotation to sonify
82
83
    sr = : int > 0
84
        The sampling rate of the output waveform
85
86
    duration : float (optional)
87
        Optional length (in seconds) of the output waveform
88
89
    kwargs
90
        Additional keyword arguments to mir_eval.sonify functions
91
92
    Returns
93
    -------
94
    y_sonified : np.ndarray
95
        The waveform of the sonified annotation
96
97
    Raises
98
    ------
99
    NamespaceError
100
        If the annotation has an un-sonifiable namespace
101
    '''
102
103
    length = None
104
    if duration is not None:
105
        length = int(duration * sr)
106
107
    for namespace, func in six.iteritems(SONIFY_MAPPING):
108
        try:
109
            validate_annotation(annotation, namespace)
110
            return func(annotation, sr=sr, length=length, **kwargs)
111
        except NamespaceError:
112
            pass
113
114
    raise NamespaceError('Unable to sonify annotation of namespace="{:s}"'
115
                         .format(annotation.namespace))
116