1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
"""Unit tests for sonification methods"""
import pytest
import mir_eval
import numpy as np
import scipy
@pytest.mark.parametrize("times", [np.array([1.0]), np.arange(10.0)])
@pytest.mark.parametrize("fs", [8000, 44100])
def test_clicks(times, fs):
# Test output length for a variety of parameter settings
click_signal = mir_eval.sonify.clicks(times, fs)
assert len(click_signal) == times.max() * fs + int(fs * 0.1) + 1
click_signal = mir_eval.sonify.clicks(times, fs, length=1000)
assert len(click_signal) == 1000
click_signal = mir_eval.sonify.clicks(times, fs, click=np.zeros(1000))
assert len(click_signal) == times.max() * fs + 1000 + 1
@pytest.mark.parametrize("fs", [8000, 44100])
def test_time_frequency(fs):
# Test length for different inputs
signal = mir_eval.sonify.time_frequency(
np.random.standard_normal((100, 1000)),
np.arange(1, 101),
np.linspace(0, 10, 1000),
fs,
)
assert len(signal) == 10 * fs
# Make one longer
signal = mir_eval.sonify.time_frequency(
np.random.standard_normal((100, 1000)),
np.arange(1, 101),
np.linspace(0, 10, 1000),
fs,
length=fs * 11,
)
assert len(signal) == 11 * fs
# Make one shorter
signal = mir_eval.sonify.time_frequency(
np.random.standard_normal((100, 1000)),
np.arange(1, 101),
np.linspace(0, 10, 1000),
fs,
length=fs * 5,
)
assert len(signal) == 5 * fs
def test_time_frequency_const():
# Sonify with a single interval to hit the const interpolator
s1 = mir_eval.sonify.time_frequency(
np.ones((1, 1)),
np.array([60]),
np.array([[0, 1]]),
8000,
)
# Sonify with two tiem intervals to hit the regular interpolator
# but the second frequency will have no energy, so it doesn't
# change the resulting signal
s2 = mir_eval.sonify.time_frequency(
np.array([[1, 1], [0, 0]]),
np.array([60, 90]),
np.array([[0, 1], [0, 1]]),
8000,
)
assert np.allclose(s1, s2)
def test_time_frequency_offset():
fs = 8000
# Length is 3 seconds, first interval starts at 5.
# Should produce an empty signal.
signal = mir_eval.sonify.time_frequency(
np.random.standard_normal((100, 100)),
np.arange(1, 101),
np.linspace(5, 10, 100),
fs,
length=fs * 3,
)
assert len(signal) == 3 * fs
assert np.allclose(signal, 0)
@pytest.mark.xfail(raises=ValueError)
def test_time_frequency_badtime():
fs = 8000
gram = np.ones((10, 20))
times = np.arange(10)
mir_eval.sonify.time_frequency(gram, np.arange(1, 11), times, fs)
@pytest.mark.xfail(raises=ValueError)
def test_time_frequency_badintervals():
fs = 8000
gram = np.ones((10, 20))
times = np.ones((11, 2))
mir_eval.sonify.time_frequency(gram, np.arange(1, 11), times, fs)
@pytest.mark.xfail(raises=ValueError)
def test_time_frequency_frequency():
fs = 8000
gram = np.ones((10, 20))
times = np.arange(20)
mir_eval.sonify.time_frequency(gram, np.arange(1, 8), times, fs)
@pytest.mark.parametrize("fs", [8000, 44100])
def test_chroma(fs):
signal = mir_eval.sonify.chroma(
np.random.standard_normal((12, 1000)), np.linspace(0, 10, 1000), fs
)
assert len(signal) == 10 * fs
signal = mir_eval.sonify.chroma(
np.random.standard_normal((12, 1000)),
np.linspace(0, 10, 1000),
fs,
length=fs * 11,
)
assert len(signal) == 11 * fs
@pytest.mark.parametrize("fs", [8000, 44100])
def test_chords(fs):
intervals = np.array([np.arange(10), np.arange(1, 11)]).T
signal = mir_eval.sonify.chords(
["C", "C:maj", "D:min7", "E:min", "C#", "C", "C", "C", "C", "C"], intervals, fs
)
assert len(signal) == 10 * fs
signal = mir_eval.sonify.chords(
["C", "C:maj", "D:min7", "E:min", "C#", "C", "C", "C", "C", "C"],
intervals,
fs,
length=fs * 11,
)
assert len(signal) == 11 * fs
def test_chord_x():
# This test verifies that X sonifies as silence
intervals = np.array([[0, 1]])
signal = mir_eval.sonify.chords(["X"], intervals, 8000)
assert not np.any(signal), signal
def test_pitch_contour():
# Generate some random pitch
fs = 8000
times = np.linspace(0, 5, num=5 * fs, endpoint=True)
noise = scipy.ndimage.gaussian_filter1d(np.random.randn(len(times)), sigma=256)
freqs = 440.0 * 2.0 ** (16 * noise)
amps = np.linspace(0, 1, num=5 * fs, endpoint=True)
# negate a bunch of sequences
idx = np.unique(np.random.randint(0, high=len(times), size=32))
for start, end in zip(idx[::2], idx[1::2]):
freqs[start:end] *= -1
# Test with inferring duration
x = mir_eval.sonify.pitch_contour(times, freqs, fs)
assert len(x) == fs * 5
# Test with an explicit duration
# This forces the interpolator to go off the end of the sampling grid,
# which should result in a constant sequence in the output
x = mir_eval.sonify.pitch_contour(times, freqs, fs, length=fs * 7)
assert len(x) == fs * 7
assert np.allclose(x[-fs * 2 :], x[-fs * 2])
# Test with an explicit duration and a fixed offset
# This forces the interpolator to go off the beginning of
# the sampling grid, which should result in a constant output
x = mir_eval.sonify.pitch_contour(times + 5.0, freqs, fs, length=fs * 7)
assert len(x) == fs * 7
assert np.allclose(x[: fs * 5], x[0])
# Test with explicit amplitude
x = mir_eval.sonify.pitch_contour(times, freqs, fs, length=fs * 7, amplitudes=amps)
assert len(x) == fs * 7
assert np.allclose(x[0], 0)
|