amine@403
|
1 import math
|
amine@192
|
2 import os
|
amine@88
|
3 from random import random
|
amine@192
|
4 from tempfile import TemporaryDirectory
|
amine@403
|
5 from unittest.mock import Mock, patch
|
amine@403
|
6
|
amine@405
|
7 import numpy as np
|
amine@400
|
8 import pytest
|
amine@403
|
9
|
amine@403
|
10 from auditok import AudioParameterError, AudioRegion, load, split
|
amine@323
|
11 from auditok.core import (
|
amine@323
|
12 _duration_to_nb_windows,
|
amine@323
|
13 _make_audio_region,
|
amine@323
|
14 _read_chunks_online,
|
amine@323
|
15 _read_offline,
|
amine@323
|
16 )
|
amine@315
|
17 from auditok.io import get_audio_source
|
amine@405
|
18 from auditok.signal import to_array
|
amine@403
|
19 from auditok.util import AudioReader
|
amine@86
|
20
|
amine@86
|
21
|
amine@299
|
22 def _make_random_length_regions(
|
amine@299
|
23 byte_seq, sampling_rate, sample_width, channels
|
amine@299
|
24 ):
|
amine@88
|
25 regions = []
|
amine@88
|
26 for b in byte_seq:
|
amine@88
|
27 duration = round(random() * 10, 6)
|
amine@95
|
28 data = b * int(duration * sampling_rate) * sample_width * channels
|
amine@244
|
29 region = AudioRegion(data, sampling_rate, sample_width, channels)
|
amine@88
|
30 regions.append(region)
|
amine@88
|
31 return regions
|
amine@88
|
32
|
amine@88
|
33
|
amine@400
|
34 @pytest.mark.parametrize(
|
amine@400
|
35 "skip, max_read, channels",
|
amine@400
|
36 [
|
amine@405
|
37 (0, -1, 1), # no_skip_read_all
|
amine@405
|
38 (0, -1, 2), # no_skip_read_all_stereo
|
amine@405
|
39 (2, -1, 1), # skip_2_read_all
|
amine@405
|
40 (2, None, 1), # skip_2_read_all_None
|
amine@405
|
41 (2, 3, 1), # skip_2_read_3
|
amine@405
|
42 (2, 3.5, 2), # skip_2_read_3_5_stereo
|
amine@405
|
43 (2.4, 3.5, 2), # skip_2_4_read_3_5_stereo
|
amine@400
|
44 ],
|
amine@400
|
45 ids=[
|
amine@400
|
46 "no_skip_read_all",
|
amine@400
|
47 "no_skip_read_all_stereo",
|
amine@400
|
48 "skip_2_read_all",
|
amine@400
|
49 "skip_2_read_all_None",
|
amine@400
|
50 "skip_2_read_3",
|
amine@400
|
51 "skip_2_read_3_5_stereo",
|
amine@400
|
52 "skip_2_4_read_3_5_stereo",
|
amine@400
|
53 ],
|
amine@400
|
54 )
|
amine@400
|
55 def test_load(skip, max_read, channels):
|
amine@400
|
56 sampling_rate = 10
|
amine@400
|
57 sample_width = 2
|
amine@400
|
58 filename = "tests/data/test_split_10HZ_{}.raw"
|
amine@400
|
59 filename = filename.format("mono" if channels == 1 else "stereo")
|
amine@400
|
60 region = load(
|
amine@400
|
61 filename,
|
amine@400
|
62 skip=skip,
|
amine@400
|
63 max_read=max_read,
|
amine@400
|
64 sr=sampling_rate,
|
amine@400
|
65 sw=sample_width,
|
amine@400
|
66 ch=channels,
|
amine@371
|
67 )
|
amine@400
|
68 with open(filename, "rb") as fp:
|
amine@400
|
69 fp.read(round(skip * sampling_rate * sample_width * channels))
|
amine@400
|
70 if max_read is None or max_read < 0:
|
amine@400
|
71 to_read = -1
|
amine@400
|
72 else:
|
amine@400
|
73 to_read = round(max_read * sampling_rate * sample_width * channels)
|
amine@400
|
74 expected = fp.read(to_read)
|
amine@400
|
75 assert bytes(region) == expected
|
amine@400
|
76
|
amine@400
|
77
|
amine@400
|
78 @pytest.mark.parametrize(
|
amine@400
|
79 "duration, analysis_window, round_fn, expected, kwargs",
|
amine@400
|
80 [
|
amine@405
|
81 (0, 1, None, 0, None), # zero_duration
|
amine@405
|
82 (0.3, 0.1, round, 3, None), # multiple
|
amine@405
|
83 (0.35, 0.1, math.ceil, 4, None), # not_multiple_ceil
|
amine@405
|
84 (0.35, 0.1, math.floor, 3, None), # not_multiple_floor
|
amine@405
|
85 (0.05, 0.1, round, 0, None), # small_duration
|
amine@405
|
86 (0.05, 0.1, math.ceil, 1, None), # small_duration_ceil
|
amine@405
|
87 (0.3, 0.1, math.floor, 3, {"epsilon": 1e-6}), # with_round_error
|
amine@405
|
88 (-0.5, 0.1, math.ceil, ValueError, None), # negative_duration
|
amine@405
|
89 (0.5, -0.1, math.ceil, ValueError, None), # negative_analysis_window
|
amine@400
|
90 ],
|
amine@400
|
91 ids=[
|
amine@400
|
92 "zero_duration",
|
amine@400
|
93 "multiple",
|
amine@400
|
94 "not_multiple_ceil",
|
amine@400
|
95 "not_multiple_floor",
|
amine@400
|
96 "small_duration",
|
amine@400
|
97 "small_duration_ceil",
|
amine@400
|
98 "with_round_error",
|
amine@400
|
99 "negative_duration",
|
amine@400
|
100 "negative_analysis_window",
|
amine@400
|
101 ],
|
amine@400
|
102 )
|
amine@400
|
103 def test_duration_to_nb_windows(
|
amine@400
|
104 duration, analysis_window, round_fn, expected, kwargs
|
amine@400
|
105 ):
|
amine@400
|
106 if expected == ValueError:
|
amine@400
|
107 with pytest.raises(ValueError):
|
amine@400
|
108 _duration_to_nb_windows(duration, analysis_window, round_fn)
|
amine@400
|
109 else:
|
amine@400
|
110 if kwargs is None:
|
amine@400
|
111 kwargs = {}
|
amine@400
|
112 result = _duration_to_nb_windows(
|
amine@400
|
113 duration, analysis_window, round_fn, **kwargs
|
amine@371
|
114 )
|
amine@400
|
115 assert result == expected
|
amine@371
|
116
|
amine@400
|
117
|
amine@400
|
118 @pytest.mark.parametrize(
|
amine@400
|
119 "channels, skip, max_read",
|
amine@400
|
120 [
|
amine@405
|
121 (1, 0, None), # mono_skip_0_max_read_None
|
amine@405
|
122 (1, 3, None), # mono_skip_3_max_read_None
|
amine@405
|
123 (1, 2, -1), # mono_skip_2_max_read_negative
|
amine@405
|
124 (1, 2, 3), # mono_skip_2_max_read_3
|
amine@405
|
125 (2, 0, None), # stereo_skip_0_max_read_None
|
amine@405
|
126 (2, 3, None), # stereo_skip_3_max_read_None
|
amine@405
|
127 (2, 2, -1), # stereo_skip_2_max_read_negative
|
amine@405
|
128 (2, 2, 3), # stereo_skip_2_max_read_3
|
amine@400
|
129 ],
|
amine@400
|
130 ids=[
|
amine@400
|
131 "mono_skip_0_max_read_None",
|
amine@400
|
132 "mono_skip_3_max_read_None",
|
amine@400
|
133 "mono_skip_2_max_read_negative",
|
amine@400
|
134 "mono_skip_2_max_read_3",
|
amine@400
|
135 "stereo_skip_0_max_read_None",
|
amine@400
|
136 "stereo_skip_3_max_read_None",
|
amine@400
|
137 "stereo_skip_2_max_read_negative",
|
amine@400
|
138 "stereo_skip_2_max_read_3",
|
amine@400
|
139 ],
|
amine@400
|
140 )
|
amine@400
|
141 def test_read_offline(channels, skip, max_read):
|
amine@400
|
142 sampling_rate = 10
|
amine@400
|
143 sample_width = 2
|
amine@400
|
144 mono_or_stereo = "mono" if channels == 1 else "stereo"
|
amine@400
|
145 filename = "tests/data/test_split_10HZ_{}.raw".format(mono_or_stereo)
|
amine@400
|
146 with open(filename, "rb") as fp:
|
amine@400
|
147 data = fp.read()
|
amine@400
|
148 onset = round(skip * sampling_rate * sample_width * channels)
|
amine@400
|
149 if max_read in (-1, None):
|
amine@400
|
150 offset = len(data) + 1
|
amine@400
|
151 else:
|
amine@400
|
152 offset = onset + round(
|
amine@400
|
153 max_read * sampling_rate * sample_width * channels
|
amine@400
|
154 )
|
amine@400
|
155 expected_data = data[onset:offset]
|
amine@400
|
156 read_data, *audio_params = _read_offline(
|
amine@400
|
157 filename,
|
amine@400
|
158 skip=skip,
|
amine@400
|
159 max_read=max_read,
|
amine@400
|
160 sr=sampling_rate,
|
amine@400
|
161 sw=sample_width,
|
amine@400
|
162 ch=channels,
|
amine@215
|
163 )
|
amine@400
|
164 assert read_data == expected_data
|
amine@400
|
165 assert tuple(audio_params) == (sampling_rate, sample_width, channels)
|
amine@215
|
166
|
amine@323
|
167
|
amine@400
|
168 @pytest.mark.parametrize(
|
amine@405
|
169 (
|
amine@405
|
170 "min_dur, max_dur, max_silence, drop_trailing_silence, "
|
amine@405
|
171 + "strict_min_dur, kwargs, expected"
|
amine@405
|
172 ),
|
amine@400
|
173 [
|
amine@405
|
174 (
|
amine@405
|
175 0.2,
|
amine@405
|
176 5,
|
amine@405
|
177 0.2,
|
amine@405
|
178 False,
|
amine@405
|
179 False,
|
amine@405
|
180 {"eth": 50},
|
amine@405
|
181 [(2, 16), (17, 31), (34, 76)],
|
amine@405
|
182 ), # simple
|
amine@400
|
183 (
|
amine@400
|
184 0.3,
|
amine@400
|
185 2,
|
amine@400
|
186 0.2,
|
amine@400
|
187 False,
|
amine@400
|
188 False,
|
amine@400
|
189 {"eth": 50},
|
amine@400
|
190 [(2, 16), (17, 31), (34, 54), (54, 74), (74, 76)],
|
amine@405
|
191 ), # short_max_dur
|
amine@405
|
192 (3, 5, 0.2, False, False, {"eth": 50}, [(34, 76)]), # long_min_dur
|
amine@405
|
193 (0.2, 80, 10, False, False, {"eth": 50}, [(2, 76)]), # long_max_silence
|
amine@400
|
194 (
|
amine@400
|
195 0.2,
|
amine@400
|
196 5,
|
amine@400
|
197 0.0,
|
amine@400
|
198 False,
|
amine@400
|
199 False,
|
amine@400
|
200 {"eth": 50},
|
amine@400
|
201 [(2, 14), (17, 24), (26, 29), (34, 76)],
|
amine@405
|
202 ), # zero_max_silence
|
amine@400
|
203 (
|
amine@299
|
204 0.2,
|
amine@299
|
205 5,
|
amine@299
|
206 0.2,
|
amine@299
|
207 False,
|
amine@299
|
208 False,
|
amine@207
|
209 {"energy_threshold": 40},
|
amine@207
|
210 [(0, 50), (50, 76)],
|
amine@405
|
211 ), # low_energy_threshold
|
amine@405
|
212 (
|
amine@405
|
213 0.2,
|
amine@405
|
214 5,
|
amine@405
|
215 0.2,
|
amine@405
|
216 False,
|
amine@405
|
217 False,
|
amine@405
|
218 {"energy_threshold": 60},
|
amine@405
|
219 [],
|
amine@405
|
220 ), # high_energy_threshold
|
amine@405
|
221 (
|
amine@405
|
222 0.2,
|
amine@405
|
223 10,
|
amine@405
|
224 0.5,
|
amine@405
|
225 True,
|
amine@405
|
226 False,
|
amine@405
|
227 {"eth": 50},
|
amine@405
|
228 [(2, 76)],
|
amine@405
|
229 ), # trim_leading_and_trailing_silence
|
amine@405
|
230 (
|
amine@405
|
231 0.2,
|
amine@405
|
232 5,
|
amine@405
|
233 0.2,
|
amine@405
|
234 True,
|
amine@405
|
235 False,
|
amine@405
|
236 {"eth": 50},
|
amine@405
|
237 [(2, 14), (17, 29), (34, 76)],
|
amine@405
|
238 ), # drop_trailing_silence
|
amine@405
|
239 (
|
amine@405
|
240 1.5,
|
amine@405
|
241 5,
|
amine@405
|
242 0.2,
|
amine@405
|
243 True,
|
amine@405
|
244 False,
|
amine@405
|
245 {"eth": 50},
|
amine@405
|
246 [(34, 76)],
|
amine@405
|
247 ), # drop_trailing_silence_2
|
amine@400
|
248 (
|
amine@207
|
249 0.3,
|
amine@207
|
250 2,
|
amine@207
|
251 0.2,
|
amine@207
|
252 False,
|
amine@207
|
253 True,
|
amine@207
|
254 {"eth": 50},
|
amine@207
|
255 [(2, 16), (17, 31), (34, 54), (54, 74)],
|
amine@405
|
256 ), # strict_min_dur
|
amine@400
|
257 ],
|
amine@400
|
258 ids=[
|
amine@400
|
259 "simple",
|
amine@400
|
260 "short_max_dur",
|
amine@400
|
261 "long_min_dur",
|
amine@400
|
262 "long_max_silence",
|
amine@400
|
263 "zero_max_silence",
|
amine@400
|
264 "low_energy_threshold",
|
amine@400
|
265 "high_energy_threshold",
|
amine@400
|
266 "trim_leading_and_trailing_silence",
|
amine@400
|
267 "drop_trailing_silence",
|
amine@400
|
268 "drop_trailing_silence_2",
|
amine@400
|
269 "strict_min_dur",
|
amine@400
|
270 ],
|
amine@400
|
271 )
|
amine@400
|
272 def test_split_params(
|
amine@400
|
273 min_dur,
|
amine@400
|
274 max_dur,
|
amine@400
|
275 max_silence,
|
amine@400
|
276 drop_trailing_silence,
|
amine@400
|
277 strict_min_dur,
|
amine@400
|
278 kwargs,
|
amine@400
|
279 expected,
|
amine@400
|
280 ):
|
amine@400
|
281 with open("tests/data/test_split_10HZ_mono.raw", "rb") as fp:
|
amine@400
|
282 data = fp.read()
|
amine@400
|
283
|
amine@400
|
284 regions = split(
|
amine@400
|
285 data,
|
amine@207
|
286 min_dur,
|
amine@207
|
287 max_dur,
|
amine@207
|
288 max_silence,
|
amine@207
|
289 drop_trailing_silence,
|
amine@207
|
290 strict_min_dur,
|
amine@400
|
291 analysis_window=0.1,
|
amine@400
|
292 sr=10,
|
amine@400
|
293 sw=2,
|
amine@400
|
294 ch=1,
|
amine@400
|
295 **kwargs
|
amine@400
|
296 )
|
amine@207
|
297
|
amine@400
|
298 region = AudioRegion(data, 10, 2, 1)
|
amine@400
|
299 regions_ar = region.split(
|
amine@400
|
300 min_dur,
|
amine@400
|
301 max_dur,
|
amine@400
|
302 max_silence,
|
amine@400
|
303 drop_trailing_silence,
|
amine@400
|
304 strict_min_dur,
|
amine@400
|
305 analysis_window=0.1,
|
amine@400
|
306 **kwargs
|
amine@400
|
307 )
|
amine@255
|
308
|
amine@400
|
309 regions = list(regions)
|
amine@400
|
310 regions_ar = list(regions_ar)
|
amine@400
|
311 err_msg = "Wrong number of regions after split, expected: "
|
amine@400
|
312 err_msg += "{}, found: {}".format(len(expected), len(regions))
|
amine@400
|
313 assert len(regions) == len(expected), err_msg
|
amine@400
|
314 err_msg = "Wrong number of regions after AudioRegion.split, expected: "
|
amine@400
|
315 err_msg += "{}, found: {}".format(len(expected), len(regions_ar))
|
amine@400
|
316 assert len(regions_ar) == len(expected), err_msg
|
amine@255
|
317
|
amine@400
|
318 sample_width = 2
|
amine@405
|
319 for reg, reg_ar, exp in zip(regions, regions_ar, expected, strict=True):
|
amine@400
|
320 onset, offset = exp
|
amine@400
|
321 exp_data = data[onset * sample_width : offset * sample_width]
|
amine@400
|
322 assert bytes(reg) == exp_data
|
amine@400
|
323 assert reg == reg_ar
|
amine@207
|
324
|
amine@299
|
325
|
amine@400
|
326 @pytest.mark.parametrize(
|
amine@400
|
327 "channels, kwargs, expected",
|
amine@400
|
328 [
|
amine@405
|
329 (2, {}, [(2, 32), (34, 76)]), # stereo_all_default
|
amine@405
|
330 (1, {"max_read": 5}, [(2, 16), (17, 31), (34, 50)]), # mono_max_read
|
amine@405
|
331 (
|
amine@405
|
332 1,
|
amine@405
|
333 {"mr": 5},
|
amine@405
|
334 [(2, 16), (17, 31), (34, 50)],
|
amine@405
|
335 ), # mono_max_read_short_name
|
amine@405
|
336 (
|
amine@405
|
337 1,
|
amine@405
|
338 {"eth": 50, "use_channel": 0},
|
amine@405
|
339 [(2, 16), (17, 31), (34, 76)],
|
amine@405
|
340 ), # mono_use_channel_1
|
amine@405
|
341 (1, {"eth": 50, "uc": 1}, [(2, 16), (17, 31), (34, 76)]), # mono_uc_1
|
amine@405
|
342 (
|
amine@405
|
343 1,
|
amine@405
|
344 {"eth": 50, "use_channel": None},
|
amine@405
|
345 [(2, 16), (17, 31), (34, 76)],
|
amine@405
|
346 ), # mono_use_channel_None
|
amine@405
|
347 (
|
amine@405
|
348 2,
|
amine@405
|
349 {"eth": 50, "use_channel": 0},
|
amine@405
|
350 [(2, 16), (17, 31), (34, 76)],
|
amine@405
|
351 ), # stereo_use_channel_1
|
amine@405
|
352 (
|
amine@405
|
353 2,
|
amine@405
|
354 {"eth": 50},
|
amine@405
|
355 [(2, 32), (34, 76)],
|
amine@405
|
356 ), # stereo_use_channel_no_use_channel_given
|
amine@405
|
357 (
|
amine@405
|
358 2,
|
amine@405
|
359 {"eth": 50, "use_channel": -2},
|
amine@405
|
360 [(2, 16), (17, 31), (34, 76)],
|
amine@405
|
361 ), # stereo_use_channel_minus_2
|
amine@405
|
362 (2, {"eth": 50, "uc": 1}, [(10, 32), (36, 76)]), # stereo_uc_2
|
amine@405
|
363 (2, {"eth": 50, "uc": -1}, [(10, 32), (36, 76)]), # stereo_uc_minus_1
|
amine@405
|
364 (
|
amine@405
|
365 1,
|
amine@405
|
366 {"eth": 50, "uc": "mix"},
|
amine@405
|
367 [(2, 16), (17, 31), (34, 76)],
|
amine@405
|
368 ), # mono_uc_mix
|
amine@405
|
369 (
|
amine@405
|
370 2,
|
amine@405
|
371 {"energy_threshold": 53.5, "use_channel": "mix"},
|
amine@405
|
372 [(54, 76)],
|
amine@405
|
373 ), # stereo_use_channel_mix
|
amine@405
|
374 (2, {"eth": 52, "uc": "mix"}, [(17, 26), (54, 76)]), # stereo_uc_mix
|
amine@405
|
375 (
|
amine@405
|
376 2,
|
amine@405
|
377 {"uc": "mix"},
|
amine@405
|
378 [(10, 16), (17, 31), (36, 76)],
|
amine@405
|
379 ), # stereo_uc_mix_default_eth
|
amine@400
|
380 ],
|
amine@400
|
381 ids=[
|
amine@400
|
382 "stereo_all_default",
|
amine@400
|
383 "mono_max_read",
|
amine@400
|
384 "mono_max_read_short_name",
|
amine@400
|
385 "mono_use_channel_1",
|
amine@400
|
386 "mono_uc_1",
|
amine@400
|
387 "mono_use_channel_None",
|
amine@400
|
388 "stereo_use_channel_1",
|
amine@400
|
389 "stereo_use_channel_no_use_channel_given",
|
amine@400
|
390 "stereo_use_channel_minus_2",
|
amine@400
|
391 "stereo_uc_2",
|
amine@400
|
392 "stereo_uc_minus_1",
|
amine@400
|
393 "mono_uc_mix",
|
amine@400
|
394 "stereo_use_channel_mix",
|
amine@400
|
395 "stereo_uc_mix",
|
amine@400
|
396 "stereo_uc_mix_default_eth",
|
amine@400
|
397 ],
|
amine@400
|
398 )
|
amine@400
|
399 def test_split_kwargs(channels, kwargs, expected):
|
amine@400
|
400
|
amine@400
|
401 mono_or_stereo = "mono" if channels == 1 else "stereo"
|
amine@400
|
402 filename = "tests/data/test_split_10HZ_{}.raw".format(mono_or_stereo)
|
amine@400
|
403 with open(filename, "rb") as fp:
|
amine@400
|
404 data = fp.read()
|
amine@400
|
405
|
amine@400
|
406 regions = split(
|
amine@400
|
407 data,
|
amine@400
|
408 min_dur=0.2,
|
amine@400
|
409 max_dur=5,
|
amine@400
|
410 max_silence=0.2,
|
amine@400
|
411 drop_trailing_silence=False,
|
amine@400
|
412 strict_min_dur=False,
|
amine@400
|
413 analysis_window=0.1,
|
amine@400
|
414 sr=10,
|
amine@400
|
415 sw=2,
|
amine@400
|
416 ch=channels,
|
amine@400
|
417 **kwargs
|
amine@211
|
418 )
|
amine@211
|
419
|
amine@400
|
420 region = AudioRegion(data, 10, 2, channels)
|
amine@400
|
421 max_read = kwargs.get("max_read", kwargs.get("mr"))
|
amine@400
|
422 if max_read is not None:
|
amine@400
|
423 region = region.sec[:max_read]
|
amine@400
|
424 kwargs.pop("max_read", None)
|
amine@400
|
425 kwargs.pop("mr", None)
|
amine@211
|
426
|
amine@400
|
427 regions_ar = region.split(
|
amine@400
|
428 min_dur=0.2,
|
amine@400
|
429 max_dur=5,
|
amine@400
|
430 max_silence=0.2,
|
amine@400
|
431 drop_trailing_silence=False,
|
amine@400
|
432 strict_min_dur=False,
|
amine@400
|
433 analysis_window=0.1,
|
amine@400
|
434 **kwargs
|
amine@400
|
435 )
|
amine@255
|
436
|
amine@400
|
437 regions = list(regions)
|
amine@400
|
438 regions_ar = list(regions_ar)
|
amine@400
|
439 err_msg = "Wrong number of regions after split, expected: "
|
amine@400
|
440 err_msg += "{}, found: {}".format(len(expected), len(regions))
|
amine@400
|
441 assert len(regions) == len(expected), err_msg
|
amine@400
|
442 err_msg = "Wrong number of regions after AudioRegion.split, expected: "
|
amine@400
|
443 err_msg += "{}, found: {}".format(len(expected), len(regions_ar))
|
amine@400
|
444 assert len(regions_ar) == len(expected), err_msg
|
amine@306
|
445
|
amine@400
|
446 sample_width = 2
|
amine@400
|
447 sample_size_bytes = sample_width * channels
|
amine@405
|
448 for reg, reg_ar, exp in zip(regions, regions_ar, expected, strict=True):
|
amine@400
|
449 onset, offset = exp
|
amine@400
|
450 exp_data = data[onset * sample_size_bytes : offset * sample_size_bytes]
|
amine@400
|
451 assert len(bytes(reg)) == len(exp_data)
|
amine@400
|
452 assert reg == reg_ar
|
amine@255
|
453
|
amine@255
|
454
|
amine@400
|
455 @pytest.mark.parametrize(
|
amine@400
|
456 "min_dur, max_dur, max_silence, channels, kwargs, expected",
|
amine@400
|
457 [
|
amine@405
|
458 (
|
amine@405
|
459 0.2,
|
amine@405
|
460 5,
|
amine@405
|
461 0.2,
|
amine@405
|
462 1,
|
amine@405
|
463 {"aw": 0.2},
|
amine@405
|
464 [(2, 30), (34, 76)],
|
amine@405
|
465 ), # mono_aw_0_2_max_silence_0_2
|
amine@405
|
466 (
|
amine@405
|
467 0.2,
|
amine@405
|
468 5,
|
amine@405
|
469 0.3,
|
amine@405
|
470 1,
|
amine@405
|
471 {"aw": 0.2},
|
amine@405
|
472 [(2, 30), (34, 76)],
|
amine@405
|
473 ), # mono_aw_0_2_max_silence_0_3
|
amine@405
|
474 (
|
amine@405
|
475 0.2,
|
amine@405
|
476 5,
|
amine@405
|
477 0.4,
|
amine@405
|
478 1,
|
amine@405
|
479 {"aw": 0.2},
|
amine@405
|
480 [(2, 32), (34, 76)],
|
amine@405
|
481 ), # mono_aw_0_2_max_silence_0_4
|
amine@405
|
482 (
|
amine@405
|
483 0.2,
|
amine@405
|
484 5,
|
amine@405
|
485 0,
|
amine@405
|
486 1,
|
amine@405
|
487 {"aw": 0.2},
|
amine@405
|
488 [(2, 14), (16, 24), (26, 28), (34, 76)],
|
amine@405
|
489 ), # mono_aw_0_2_max_silence_0
|
amine@405
|
490 (0.2, 5, 0.2, 1, {"aw": 0.2}, [(2, 30), (34, 76)]), # mono_aw_0_2
|
amine@405
|
491 (
|
amine@405
|
492 0.3,
|
amine@405
|
493 5,
|
amine@405
|
494 0,
|
amine@405
|
495 1,
|
amine@405
|
496 {"aw": 0.3},
|
amine@405
|
497 [(3, 12), (15, 24), (36, 76)],
|
amine@405
|
498 ), # mono_aw_0_3_max_silence_0
|
amine@405
|
499 (
|
amine@405
|
500 0.3,
|
amine@405
|
501 5,
|
amine@405
|
502 0.3,
|
amine@405
|
503 1,
|
amine@405
|
504 {"aw": 0.3},
|
amine@405
|
505 [(3, 27), (36, 76)],
|
amine@405
|
506 ), # mono_aw_0_3_max_silence_0_3
|
amine@405
|
507 (
|
amine@405
|
508 0.3,
|
amine@405
|
509 5,
|
amine@405
|
510 0.5,
|
amine@405
|
511 1,
|
amine@405
|
512 {"aw": 0.3},
|
amine@405
|
513 [(3, 27), (36, 76)],
|
amine@405
|
514 ), # mono_aw_0_3_max_silence_0_5
|
amine@405
|
515 (
|
amine@405
|
516 0.3,
|
amine@405
|
517 5,
|
amine@405
|
518 0.6,
|
amine@405
|
519 1,
|
amine@405
|
520 {"aw": 0.3},
|
amine@405
|
521 [(3, 30), (36, 76)],
|
amine@405
|
522 ), # mono_aw_0_3_max_silence_0_6
|
amine@405
|
523 (
|
amine@405
|
524 0.2,
|
amine@405
|
525 5,
|
amine@405
|
526 0,
|
amine@405
|
527 1,
|
amine@405
|
528 {"aw": 0.4},
|
amine@405
|
529 [(4, 12), (16, 24), (36, 76)],
|
amine@405
|
530 ), # mono_aw_0_4_max_silence_0
|
amine@405
|
531 (
|
amine@405
|
532 0.2,
|
amine@405
|
533 5,
|
amine@405
|
534 0.3,
|
amine@405
|
535 1,
|
amine@405
|
536 {"aw": 0.4},
|
amine@405
|
537 [(4, 12), (16, 24), (36, 76)],
|
amine@405
|
538 ), # mono_aw_0_4_max_silence_0_3
|
amine@405
|
539 (
|
amine@405
|
540 0.2,
|
amine@405
|
541 5,
|
amine@405
|
542 0.4,
|
amine@405
|
543 1,
|
amine@405
|
544 {"aw": 0.4},
|
amine@405
|
545 [(4, 28), (36, 76)],
|
amine@405
|
546 ), # mono_aw_0_4_max_silence_0_4
|
amine@405
|
547 (
|
amine@405
|
548 0.2,
|
amine@405
|
549 5,
|
amine@405
|
550 0.2,
|
amine@405
|
551 2,
|
amine@405
|
552 {"analysis_window": 0.2},
|
amine@405
|
553 [(2, 32), (34, 76)],
|
amine@405
|
554 ), # stereo_uc_None_analysis_window_0_2
|
amine@400
|
555 (
|
amine@316
|
556 0.2,
|
amine@316
|
557 5,
|
amine@316
|
558 0.2,
|
amine@316
|
559 2,
|
amine@316
|
560 {"uc": None, "analysis_window": 0.2},
|
amine@316
|
561 [(2, 32), (34, 76)],
|
amine@405
|
562 ), # stereo_uc_any_analysis_window_0_2
|
amine@400
|
563 (
|
amine@316
|
564 0.2,
|
amine@316
|
565 5,
|
amine@316
|
566 0.2,
|
amine@316
|
567 2,
|
amine@316
|
568 {"use_channel": None, "analysis_window": 0.3},
|
amine@316
|
569 [(3, 30), (36, 76)],
|
amine@405
|
570 ), # stereo_use_channel_None_aw_0_3_max_silence_0_2
|
amine@400
|
571 (
|
amine@316
|
572 0.2,
|
amine@316
|
573 5,
|
amine@316
|
574 0.3,
|
amine@316
|
575 2,
|
amine@316
|
576 {"use_channel": "any", "analysis_window": 0.3},
|
amine@316
|
577 [(3, 33), (36, 76)],
|
amine@405
|
578 ), # stereo_use_channel_any_aw_0_3_max_silence_0_3
|
amine@400
|
579 (
|
amine@316
|
580 0.2,
|
amine@316
|
581 5,
|
amine@316
|
582 0.2,
|
amine@316
|
583 2,
|
amine@316
|
584 {"use_channel": None, "analysis_window": 0.4},
|
amine@316
|
585 [(4, 28), (36, 76)],
|
amine@405
|
586 ), # stereo_use_channel_None_aw_0_4_max_silence_0_2
|
amine@400
|
587 (
|
amine@316
|
588 0.2,
|
amine@316
|
589 5,
|
amine@316
|
590 0.4,
|
amine@316
|
591 2,
|
amine@316
|
592 {"use_channel": "any", "analysis_window": 0.4},
|
amine@316
|
593 [(4, 32), (36, 76)],
|
amine@405
|
594 ), # stereo_use_channel_any_aw_0_3_max_silence_0_4
|
amine@400
|
595 (
|
amine@241
|
596 0.2,
|
amine@241
|
597 5,
|
amine@241
|
598 0.2,
|
amine@241
|
599 2,
|
amine@241
|
600 {"uc": 0, "analysis_window": 0.2},
|
amine@241
|
601 [(2, 30), (34, 76)],
|
amine@405
|
602 ), # stereo_uc_0_analysis_window_0_2
|
amine@400
|
603 (
|
amine@220
|
604 0.2,
|
amine@220
|
605 5,
|
amine@220
|
606 0.2,
|
amine@220
|
607 2,
|
amine@220
|
608 {"uc": 1, "analysis_window": 0.2},
|
amine@231
|
609 [(10, 32), (36, 76)],
|
amine@405
|
610 ), # stereo_uc_1_analysis_window_0_2
|
amine@400
|
611 (
|
amine@233
|
612 0.2,
|
amine@233
|
613 5,
|
amine@233
|
614 0,
|
amine@233
|
615 2,
|
amine@233
|
616 {"uc": "mix", "analysis_window": 0.1},
|
amine@233
|
617 [(10, 14), (17, 24), (26, 29), (36, 76)],
|
amine@405
|
618 ), # stereo_uc_mix_aw_0_1_max_silence_0
|
amine@400
|
619 (
|
amine@233
|
620 0.2,
|
amine@233
|
621 5,
|
amine@233
|
622 0.1,
|
amine@233
|
623 2,
|
amine@233
|
624 {"uc": "mix", "analysis_window": 0.1},
|
amine@233
|
625 [(10, 15), (17, 25), (26, 30), (36, 76)],
|
amine@405
|
626 ), # stereo_uc_mix_aw_0_1_max_silence_0_1
|
amine@400
|
627 (
|
amine@233
|
628 0.2,
|
amine@233
|
629 5,
|
amine@233
|
630 0.2,
|
amine@233
|
631 2,
|
amine@233
|
632 {"uc": "mix", "analysis_window": 0.1},
|
amine@233
|
633 [(10, 16), (17, 31), (36, 76)],
|
amine@405
|
634 ), # stereo_uc_mix_aw_0_1_max_silence_0_2
|
amine@400
|
635 (
|
amine@233
|
636 0.2,
|
amine@233
|
637 5,
|
amine@233
|
638 0.3,
|
amine@233
|
639 2,
|
amine@233
|
640 {"uc": "mix", "analysis_window": 0.1},
|
amine@233
|
641 [(10, 32), (36, 76)],
|
amine@405
|
642 ), # stereo_uc_mix_aw_0_1_max_silence_0_3
|
amine@400
|
643 (
|
amine@233
|
644 0.3,
|
amine@233
|
645 5,
|
amine@233
|
646 0,
|
amine@233
|
647 2,
|
amine@316
|
648 {"uc": "avg", "analysis_window": 0.2},
|
amine@233
|
649 [(10, 14), (16, 24), (36, 76)],
|
amine@405
|
650 ), # stereo_uc_avg_aw_0_2_max_silence_0_min_dur_0_3
|
amine@400
|
651 (
|
amine@233
|
652 0.41,
|
amine@233
|
653 5,
|
amine@233
|
654 0,
|
amine@233
|
655 2,
|
amine@316
|
656 {"uc": "average", "analysis_window": 0.2},
|
amine@233
|
657 [(16, 24), (36, 76)],
|
amine@405
|
658 ), # stereo_uc_average_aw_0_2_max_silence_0_min_dur_0_41
|
amine@400
|
659 (
|
amine@233
|
660 0.2,
|
amine@233
|
661 5,
|
amine@233
|
662 0.1,
|
amine@233
|
663 2,
|
amine@233
|
664 {"uc": "mix", "analysis_window": 0.2},
|
amine@233
|
665 [(10, 14), (16, 24), (26, 28), (36, 76)],
|
amine@405
|
666 ), # stereo_uc_mix_aw_0_2_max_silence_0_1
|
amine@400
|
667 (
|
amine@233
|
668 0.2,
|
amine@233
|
669 5,
|
amine@233
|
670 0.2,
|
amine@233
|
671 2,
|
amine@233
|
672 {"uc": "mix", "analysis_window": 0.2},
|
amine@233
|
673 [(10, 30), (36, 76)],
|
amine@405
|
674 ), # stereo_uc_mix_aw_0_2_max_silence_0_2
|
amine@400
|
675 (
|
amine@233
|
676 0.2,
|
amine@233
|
677 5,
|
amine@233
|
678 0.4,
|
amine@233
|
679 2,
|
amine@233
|
680 {"uc": "mix", "analysis_window": 0.2},
|
amine@233
|
681 [(10, 32), (36, 76)],
|
amine@405
|
682 ), # stereo_uc_mix_aw_0_2_max_silence_0_4
|
amine@400
|
683 (
|
amine@233
|
684 0.2,
|
amine@233
|
685 5,
|
amine@233
|
686 0.5,
|
amine@233
|
687 2,
|
amine@233
|
688 {"uc": "mix", "analysis_window": 0.2},
|
amine@233
|
689 [(10, 32), (36, 76)],
|
amine@405
|
690 ), # stereo_uc_mix_aw_0_2_max_silence_0_5
|
amine@400
|
691 (
|
amine@233
|
692 0.2,
|
amine@233
|
693 5,
|
amine@233
|
694 0.6,
|
amine@233
|
695 2,
|
amine@233
|
696 {"uc": "mix", "analysis_window": 0.2},
|
amine@233
|
697 [(10, 34), (36, 76)],
|
amine@405
|
698 ), # stereo_uc_mix_aw_0_2_max_silence_0_6
|
amine@400
|
699 (
|
amine@233
|
700 0.2,
|
amine@233
|
701 5,
|
amine@233
|
702 0,
|
amine@233
|
703 2,
|
amine@233
|
704 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
705 [(9, 24), (27, 30), (36, 76)],
|
amine@405
|
706 ), # stereo_uc_mix_aw_0_3_max_silence_0
|
amine@400
|
707 (
|
amine@233
|
708 0.4,
|
amine@233
|
709 5,
|
amine@233
|
710 0,
|
amine@233
|
711 2,
|
amine@233
|
712 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
713 [(9, 24), (36, 76)],
|
amine@405
|
714 ), # stereo_uc_mix_aw_0_3_max_silence_0_min_dur_0_3
|
amine@400
|
715 (
|
amine@233
|
716 0.2,
|
amine@233
|
717 5,
|
amine@233
|
718 0.6,
|
amine@233
|
719 2,
|
amine@233
|
720 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
721 [(9, 57), (57, 76)],
|
amine@405
|
722 ), # stereo_uc_mix_aw_0_3_max_silence_0_6
|
amine@400
|
723 (
|
amine@233
|
724 0.2,
|
amine@233
|
725 5.1,
|
amine@233
|
726 0.6,
|
amine@233
|
727 2,
|
amine@233
|
728 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
729 [(9, 60), (60, 76)],
|
amine@405
|
730 ), # stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_1
|
amine@400
|
731 (
|
amine@233
|
732 0.2,
|
amine@233
|
733 5.2,
|
amine@233
|
734 0.6,
|
amine@233
|
735 2,
|
amine@233
|
736 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
737 [(9, 60), (60, 76)],
|
amine@405
|
738 ), # stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_2
|
amine@400
|
739 (
|
amine@233
|
740 0.2,
|
amine@233
|
741 5.3,
|
amine@233
|
742 0.6,
|
amine@233
|
743 2,
|
amine@233
|
744 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
745 [(9, 60), (60, 76)],
|
amine@405
|
746 ), # stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_3
|
amine@400
|
747 (
|
amine@233
|
748 0.2,
|
amine@233
|
749 5.4,
|
amine@233
|
750 0.6,
|
amine@233
|
751 2,
|
amine@233
|
752 {"uc": "mix", "analysis_window": 0.3},
|
amine@233
|
753 [(9, 63), (63, 76)],
|
amine@405
|
754 ), # stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_4
|
amine@400
|
755 (
|
amine@233
|
756 0.2,
|
amine@233
|
757 5,
|
amine@233
|
758 0,
|
amine@233
|
759 2,
|
amine@233
|
760 {"uc": "mix", "analysis_window": 0.4},
|
amine@233
|
761 [(16, 24), (36, 76)],
|
amine@405
|
762 ), # stereo_uc_mix_aw_0_4_max_silence_0
|
amine@400
|
763 (
|
amine@233
|
764 0.2,
|
amine@233
|
765 5,
|
amine@233
|
766 0.3,
|
amine@233
|
767 2,
|
amine@233
|
768 {"uc": "mix", "analysis_window": 0.4},
|
amine@233
|
769 [(16, 24), (36, 76)],
|
amine@405
|
770 ), # stereo_uc_mix_aw_0_4_max_silence_0_3
|
amine@400
|
771 (
|
amine@233
|
772 0.2,
|
amine@233
|
773 5,
|
amine@233
|
774 0.4,
|
amine@233
|
775 2,
|
amine@233
|
776 {"uc": "mix", "analysis_window": 0.4},
|
amine@233
|
777 [(16, 28), (36, 76)],
|
amine@405
|
778 ), # stereo_uc_mix_aw_0_4_max_silence_0_4
|
amine@400
|
779 ],
|
amine@400
|
780 ids=[
|
amine@400
|
781 "mono_aw_0_2_max_silence_0_2",
|
amine@400
|
782 "mono_aw_0_2_max_silence_0_3",
|
amine@400
|
783 "mono_aw_0_2_max_silence_0_4",
|
amine@400
|
784 "mono_aw_0_2_max_silence_0",
|
amine@400
|
785 "mono_aw_0_2",
|
amine@400
|
786 "mono_aw_0_3_max_silence_0",
|
amine@400
|
787 "mono_aw_0_3_max_silence_0_3",
|
amine@400
|
788 "mono_aw_0_3_max_silence_0_5",
|
amine@400
|
789 "mono_aw_0_3_max_silence_0_6",
|
amine@400
|
790 "mono_aw_0_4_max_silence_0",
|
amine@400
|
791 "mono_aw_0_4_max_silence_0_3",
|
amine@400
|
792 "mono_aw_0_4_max_silence_0_4",
|
amine@400
|
793 "stereo_uc_None_analysis_window_0_2",
|
amine@400
|
794 "stereo_uc_any_analysis_window_0_2",
|
amine@400
|
795 "stereo_use_channel_None_aw_0_3_max_silence_0_2",
|
amine@400
|
796 "stereo_use_channel_any_aw_0_3_max_silence_0_3",
|
amine@400
|
797 "stereo_use_channel_None_aw_0_4_max_silence_0_2",
|
amine@400
|
798 "stereo_use_channel_any_aw_0_3_max_silence_0_4",
|
amine@400
|
799 "stereo_uc_0_analysis_window_0_2",
|
amine@400
|
800 "stereo_uc_1_analysis_window_0_2",
|
amine@400
|
801 "stereo_uc_mix_aw_0_1_max_silence_0",
|
amine@400
|
802 "stereo_uc_mix_aw_0_1_max_silence_0_1",
|
amine@400
|
803 "stereo_uc_mix_aw_0_1_max_silence_0_2",
|
amine@400
|
804 "stereo_uc_mix_aw_0_1_max_silence_0_3",
|
amine@400
|
805 "stereo_uc_avg_aw_0_2_max_silence_0_min_dur_0_3",
|
amine@400
|
806 "stereo_uc_average_aw_0_2_max_silence_0_min_dur_0_41",
|
amine@400
|
807 "stereo_uc_mix_aw_0_2_max_silence_0_1",
|
amine@400
|
808 "stereo_uc_mix_aw_0_2_max_silence_0_2",
|
amine@400
|
809 "stereo_uc_mix_aw_0_2_max_silence_0_4",
|
amine@400
|
810 "stereo_uc_mix_aw_0_2_max_silence_0_5",
|
amine@400
|
811 "stereo_uc_mix_aw_0_2_max_silence_0_6",
|
amine@400
|
812 "stereo_uc_mix_aw_0_3_max_silence_0",
|
amine@400
|
813 "stereo_uc_mix_aw_0_3_max_silence_0_min_dur_0_3",
|
amine@400
|
814 "stereo_uc_mix_aw_0_3_max_silence_0_6",
|
amine@400
|
815 "stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_1",
|
amine@400
|
816 "stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_2",
|
amine@400
|
817 "stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_3",
|
amine@400
|
818 "stereo_uc_mix_aw_0_3_max_silence_0_6_max_dur_5_4",
|
amine@400
|
819 "stereo_uc_mix_aw_0_4_max_silence_0",
|
amine@400
|
820 "stereo_uc_mix_aw_0_4_max_silence_0_3",
|
amine@400
|
821 "stereo_uc_mix_aw_0_4_max_silence_0_4",
|
amine@400
|
822 ],
|
amine@400
|
823 )
|
amine@400
|
824 def test_split_analysis_window(
|
amine@400
|
825 min_dur, max_dur, max_silence, channels, kwargs, expected
|
amine@400
|
826 ):
|
amine@400
|
827
|
amine@400
|
828 mono_or_stereo = "mono" if channels == 1 else "stereo"
|
amine@400
|
829 filename = "tests/data/test_split_10HZ_{}.raw".format(mono_or_stereo)
|
amine@400
|
830 with open(filename, "rb") as fp:
|
amine@400
|
831 data = fp.read()
|
amine@400
|
832
|
amine@400
|
833 regions = split(
|
amine@400
|
834 data,
|
amine@400
|
835 min_dur=min_dur,
|
amine@400
|
836 max_dur=max_dur,
|
amine@400
|
837 max_silence=max_silence,
|
amine@400
|
838 drop_trailing_silence=False,
|
amine@400
|
839 strict_min_dur=False,
|
amine@400
|
840 sr=10,
|
amine@400
|
841 sw=2,
|
amine@400
|
842 ch=channels,
|
amine@400
|
843 eth=49.99,
|
amine@400
|
844 **kwargs
|
amine@220
|
845 )
|
amine@220
|
846
|
amine@400
|
847 region = AudioRegion(data, 10, 2, channels)
|
amine@400
|
848 regions_ar = region.split(
|
amine@400
|
849 min_dur=min_dur,
|
amine@400
|
850 max_dur=max_dur,
|
amine@400
|
851 max_silence=max_silence,
|
amine@400
|
852 drop_trailing_silence=False,
|
amine@400
|
853 strict_min_dur=False,
|
amine@400
|
854 eth=49.99,
|
amine@400
|
855 **kwargs
|
amine@400
|
856 )
|
amine@220
|
857
|
amine@400
|
858 regions = list(regions)
|
amine@400
|
859 regions_ar = list(regions_ar)
|
amine@400
|
860 err_msg = "Wrong number of regions after split, expected: "
|
amine@400
|
861 err_msg += "{}, found: {}".format(len(expected), len(regions))
|
amine@400
|
862 assert len(regions) == len(expected), err_msg
|
amine@400
|
863 err_msg = "Wrong number of regions after AudioRegion.split, expected: "
|
amine@400
|
864 err_msg += "{}, found: {}".format(len(expected), len(regions_ar))
|
amine@400
|
865 assert len(regions_ar) == len(expected), err_msg
|
amine@255
|
866
|
amine@400
|
867 sample_width = 2
|
amine@400
|
868 sample_size_bytes = sample_width * channels
|
amine@405
|
869 for reg, reg_ar, exp in zip(regions, regions_ar, expected, strict=True):
|
amine@400
|
870 onset, offset = exp
|
amine@400
|
871 exp_data = data[onset * sample_size_bytes : offset * sample_size_bytes]
|
amine@400
|
872 assert bytes(reg) == exp_data
|
amine@400
|
873 assert reg == reg_ar
|
amine@255
|
874
|
amine@255
|
875
|
amine@400
|
876 def test_split_custom_validator():
|
amine@400
|
877 filename = "tests/data/test_split_10HZ_mono.raw"
|
amine@400
|
878 with open(filename, "rb") as fp:
|
amine@400
|
879 data = fp.read()
|
amine@299
|
880
|
amine@400
|
881 regions = split(
|
amine@400
|
882 data,
|
amine@400
|
883 min_dur=0.2,
|
amine@400
|
884 max_dur=5,
|
amine@400
|
885 max_silence=0.2,
|
amine@400
|
886 drop_trailing_silence=False,
|
amine@400
|
887 strict_min_dur=False,
|
amine@400
|
888 sr=10,
|
amine@400
|
889 sw=2,
|
amine@400
|
890 ch=1,
|
amine@400
|
891 analysis_window=0.1,
|
amine@405
|
892 validator=lambda x: to_array(x, sample_width=2, channels=1)[0] >= 320,
|
amine@400
|
893 )
|
amine@299
|
894
|
amine@400
|
895 region = AudioRegion(data, 10, 2, 1)
|
amine@400
|
896 regions_ar = region.split(
|
amine@400
|
897 min_dur=0.2,
|
amine@400
|
898 max_dur=5,
|
amine@400
|
899 max_silence=0.2,
|
amine@400
|
900 drop_trailing_silence=False,
|
amine@400
|
901 strict_min_dur=False,
|
amine@400
|
902 analysis_window=0.1,
|
amine@405
|
903 validator=lambda x: to_array(x, sample_width=2, channels=1)[0] >= 320,
|
amine@400
|
904 )
|
amine@299
|
905
|
amine@400
|
906 expected = [(2, 16), (17, 31), (34, 76)]
|
amine@400
|
907 regions = list(regions)
|
amine@400
|
908 regions_ar = list(regions_ar)
|
amine@400
|
909 err_msg = "Wrong number of regions after split, expected: "
|
amine@400
|
910 err_msg += "{}, found: {}".format(len(expected), len(regions))
|
amine@400
|
911 assert len(regions) == len(expected), err_msg
|
amine@400
|
912 err_msg = "Wrong number of regions after AudioRegion.split, expected: "
|
amine@400
|
913 err_msg += "{}, found: {}".format(len(expected), len(regions_ar))
|
amine@400
|
914 assert len(regions_ar) == len(expected), err_msg
|
amine@299
|
915
|
amine@400
|
916 sample_size_bytes = 2
|
amine@405
|
917 for reg, reg_ar, exp in zip(regions, regions_ar, expected, strict=True):
|
amine@400
|
918 onset, offset = exp
|
amine@400
|
919 exp_data = data[onset * sample_size_bytes : offset * sample_size_bytes]
|
amine@400
|
920 assert bytes(reg) == exp_data
|
amine@400
|
921 assert reg == reg_ar
|
amine@299
|
922
|
amine@220
|
923
|
amine@400
|
924 @pytest.mark.parametrize(
|
amine@400
|
925 "input, kwargs",
|
amine@400
|
926 [
|
amine@400
|
927 (
|
amine@212
|
928 "tests/data/test_split_10HZ_stereo.raw",
|
amine@212
|
929 {"audio_format": "raw", "sr": 10, "sw": 2, "ch": 2},
|
amine@405
|
930 ), # filename_audio_format
|
amine@400
|
931 (
|
amine@212
|
932 "tests/data/test_split_10HZ_stereo.raw",
|
amine@212
|
933 {"fmt": "raw", "sr": 10, "sw": 2, "ch": 2},
|
amine@405
|
934 ), # filename_audio_format_short_name
|
amine@405
|
935 (
|
amine@405
|
936 "tests/data/test_split_10HZ_stereo.raw",
|
amine@405
|
937 {"sr": 10, "sw": 2, "ch": 2},
|
amine@405
|
938 ), # filename_no_audio_format
|
amine@400
|
939 (
|
amine@212
|
940 "tests/data/test_split_10HZ_stereo.raw",
|
amine@212
|
941 {"sampling_rate": 10, "sample_width": 2, "channels": 2},
|
amine@405
|
942 ), # filename_no_long_audio_params
|
amine@400
|
943 (
|
amine@212
|
944 open("tests/data/test_split_10HZ_stereo.raw", "rb").read(),
|
amine@212
|
945 {"sr": 10, "sw": 2, "ch": 2},
|
amine@405
|
946 ), # bytes_
|
amine@400
|
947 (
|
amine@403
|
948 AudioReader(
|
amine@212
|
949 "tests/data/test_split_10HZ_stereo.raw",
|
amine@212
|
950 sr=10,
|
amine@212
|
951 sw=2,
|
amine@212
|
952 ch=2,
|
amine@212
|
953 block_dur=0.1,
|
amine@212
|
954 ),
|
amine@212
|
955 {},
|
amine@405
|
956 ), # audio_reader
|
amine@400
|
957 (
|
amine@212
|
958 AudioRegion(
|
amine@299
|
959 open("tests/data/test_split_10HZ_stereo.raw", "rb").read(),
|
amine@299
|
960 10,
|
amine@299
|
961 2,
|
amine@299
|
962 2,
|
amine@212
|
963 ),
|
amine@212
|
964 {},
|
amine@405
|
965 ), # audio_region
|
amine@400
|
966 (
|
amine@212
|
967 get_audio_source(
|
amine@212
|
968 "tests/data/test_split_10HZ_stereo.raw", sr=10, sw=2, ch=2
|
amine@212
|
969 ),
|
amine@212
|
970 {},
|
amine@405
|
971 ), # audio_source
|
amine@400
|
972 ],
|
amine@400
|
973 ids=[
|
amine@400
|
974 "filename_audio_format",
|
amine@400
|
975 "filename_audio_format_short_name",
|
amine@400
|
976 "filename_no_audio_format",
|
amine@400
|
977 "filename_no_long_audio_params",
|
amine@400
|
978 "bytes_",
|
amine@400
|
979 "audio_reader",
|
amine@400
|
980 "audio_region",
|
amine@400
|
981 "audio_source",
|
amine@400
|
982 ],
|
amine@400
|
983 )
|
amine@400
|
984 def test_split_input_type(input, kwargs):
|
amine@400
|
985
|
amine@400
|
986 with open("tests/data/test_split_10HZ_stereo.raw", "rb") as fp:
|
amine@400
|
987 data = fp.read()
|
amine@400
|
988
|
amine@400
|
989 regions = split(
|
amine@400
|
990 input,
|
amine@400
|
991 min_dur=0.2,
|
amine@400
|
992 max_dur=5,
|
amine@400
|
993 max_silence=0.2,
|
amine@400
|
994 drop_trailing_silence=False,
|
amine@400
|
995 strict_min_dur=False,
|
amine@400
|
996 analysis_window=0.1,
|
amine@400
|
997 **kwargs
|
amine@212
|
998 )
|
amine@400
|
999 regions = list(regions)
|
amine@400
|
1000 expected = [(2, 32), (34, 76)]
|
amine@400
|
1001 sample_width = 2
|
amine@400
|
1002 err_msg = "Wrong number of regions after split, expected: "
|
amine@400
|
1003 err_msg += "{}, found: {}".format(expected, regions)
|
amine@400
|
1004 assert len(regions) == len(expected), err_msg
|
amine@405
|
1005 for reg, exp in zip(regions, expected, strict=True):
|
amine@400
|
1006 onset, offset = exp
|
amine@400
|
1007 exp_data = data[onset * sample_width * 2 : offset * sample_width * 2]
|
amine@400
|
1008 assert bytes(reg) == exp_data
|
amine@212
|
1009
|
amine@212
|
1010
|
amine@400
|
1011 @pytest.mark.parametrize(
|
amine@400
|
1012 "min_dur, max_dur, analysis_window",
|
amine@400
|
1013 [
|
amine@400
|
1014 (0.5, 0.4, 0.1),
|
amine@400
|
1015 (0.44, 0.49, 0.1),
|
amine@400
|
1016 ],
|
amine@400
|
1017 ids=[
|
amine@400
|
1018 "min_dur_greater_than_max_dur",
|
amine@400
|
1019 "durations_OK_but_wrong_number_of_analysis_windows",
|
amine@400
|
1020 ],
|
amine@400
|
1021 )
|
amine@400
|
1022 def test_split_wrong_min_max_dur(min_dur, max_dur, analysis_window):
|
amine@400
|
1023
|
amine@400
|
1024 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1025 split(
|
amine@400
|
1026 b"0" * 16,
|
amine@400
|
1027 min_dur=min_dur,
|
amine@400
|
1028 max_dur=max_dur,
|
amine@400
|
1029 max_silence=0.2,
|
amine@400
|
1030 sr=16000,
|
amine@400
|
1031 sw=1,
|
amine@400
|
1032 ch=1,
|
amine@400
|
1033 analysis_window=analysis_window,
|
amine@400
|
1034 )
|
amine@400
|
1035
|
amine@400
|
1036 err_msg = "'min_dur' ({0} sec.) results in {1} analysis "
|
amine@400
|
1037 err_msg += "window(s) ({1} == ceil({0} / {2})) which is "
|
amine@400
|
1038 err_msg += "higher than the number of analysis window(s) for "
|
amine@400
|
1039 err_msg += "'max_dur' ({3} == floor({4} / {2}))"
|
amine@400
|
1040
|
amine@400
|
1041 err_msg = err_msg.format(
|
amine@400
|
1042 min_dur,
|
amine@400
|
1043 math.ceil(min_dur / analysis_window),
|
amine@400
|
1044 analysis_window,
|
amine@400
|
1045 math.floor(max_dur / analysis_window),
|
amine@400
|
1046 max_dur,
|
amine@400
|
1047 )
|
amine@400
|
1048 assert err_msg == str(val_err.value)
|
amine@400
|
1049
|
amine@400
|
1050
|
amine@400
|
1051 @pytest.mark.parametrize(
|
amine@400
|
1052 "max_silence, max_dur, analysis_window",
|
amine@400
|
1053 [
|
amine@405
|
1054 (0.5, 0.5, 0.1), # max_silence_equals_max_dur
|
amine@405
|
1055 (0.5, 0.4, 0.1), # max_silence_greater_than_max_dur
|
amine@405
|
1056 (0.44, 0.49, 0.1), # durations_OK_but_wrong_number_of_analysis_windows
|
amine@400
|
1057 ],
|
amine@400
|
1058 ids=[
|
amine@400
|
1059 "max_silence_equals_max_dur",
|
amine@400
|
1060 "max_silence_greater_than_max_dur",
|
amine@400
|
1061 "durations_OK_but_wrong_number_of_analysis_windows",
|
amine@400
|
1062 ],
|
amine@400
|
1063 )
|
amine@400
|
1064 def test_split_wrong_max_silence_max_dur(max_silence, max_dur, analysis_window):
|
amine@400
|
1065
|
amine@400
|
1066 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1067 split(
|
amine@400
|
1068 b"0" * 16,
|
amine@400
|
1069 min_dur=0.2,
|
amine@400
|
1070 max_dur=max_dur,
|
amine@400
|
1071 max_silence=max_silence,
|
amine@400
|
1072 sr=16000,
|
amine@400
|
1073 sw=1,
|
amine@400
|
1074 ch=1,
|
amine@400
|
1075 analysis_window=analysis_window,
|
amine@400
|
1076 )
|
amine@400
|
1077
|
amine@400
|
1078 err_msg = "'max_silence' ({0} sec.) results in {1} analysis "
|
amine@400
|
1079 err_msg += "window(s) ({1} == floor({0} / {2})) which is "
|
amine@400
|
1080 err_msg += "higher or equal to the number of analysis window(s) for "
|
amine@400
|
1081 err_msg += "'max_dur' ({3} == floor({4} / {2}))"
|
amine@400
|
1082
|
amine@400
|
1083 err_msg = err_msg.format(
|
amine@400
|
1084 max_silence,
|
amine@400
|
1085 math.floor(max_silence / analysis_window),
|
amine@400
|
1086 analysis_window,
|
amine@400
|
1087 math.floor(max_dur / analysis_window),
|
amine@400
|
1088 max_dur,
|
amine@400
|
1089 )
|
amine@400
|
1090 assert err_msg == str(val_err.value)
|
amine@400
|
1091
|
amine@400
|
1092
|
amine@400
|
1093 @pytest.mark.parametrize(
|
amine@400
|
1094 "wrong_param",
|
amine@400
|
1095 [
|
amine@405
|
1096 {"min_dur": -1}, # negative_min_dur
|
amine@405
|
1097 {"min_dur": 0}, # zero_min_dur
|
amine@405
|
1098 {"max_dur": -1}, # negative_max_dur
|
amine@405
|
1099 {"max_dur": 0}, # zero_max_dur
|
amine@405
|
1100 {"max_silence": -1}, # negative_max_silence
|
amine@405
|
1101 {"analysis_window": 0}, # zero_analysis_window
|
amine@405
|
1102 {"analysis_window": -1}, # negative_analysis_window
|
amine@400
|
1103 ],
|
amine@400
|
1104 ids=[
|
amine@400
|
1105 "negative_min_dur",
|
amine@400
|
1106 "zero_min_dur",
|
amine@400
|
1107 "negative_max_dur",
|
amine@400
|
1108 "zero_max_dur",
|
amine@400
|
1109 "negative_max_silence",
|
amine@400
|
1110 "zero_analysis_window",
|
amine@400
|
1111 "negative_analysis_window",
|
amine@400
|
1112 ],
|
amine@400
|
1113 )
|
amine@400
|
1114 def test_split_negative_temporal_params(wrong_param):
|
amine@400
|
1115
|
amine@400
|
1116 params = {
|
amine@400
|
1117 "min_dur": 0.2,
|
amine@400
|
1118 "max_dur": 0.5,
|
amine@400
|
1119 "max_silence": 0.1,
|
amine@400
|
1120 "analysis_window": 0.1,
|
amine@400
|
1121 }
|
amine@400
|
1122 params.update(wrong_param)
|
amine@400
|
1123 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1124 split(None, **params)
|
amine@400
|
1125
|
amine@400
|
1126 name = set(wrong_param).pop()
|
amine@400
|
1127 value = wrong_param[name]
|
amine@400
|
1128 err_msg = "'{}' ({}) must be >{} 0".format(
|
amine@400
|
1129 name, value, "=" if name == "max_silence" else ""
|
amine@400
|
1130 )
|
amine@400
|
1131 assert err_msg == str(val_err.value)
|
amine@400
|
1132
|
amine@400
|
1133
|
amine@400
|
1134 def test_split_too_small_analysis_window():
|
amine@400
|
1135 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1136 split(b"", sr=10, sw=1, ch=1, analysis_window=0.09)
|
amine@403
|
1137 err_msg = "Too small 'analysis_window' (0.09) for sampling rate (10)."
|
amine@403
|
1138 err_msg += " Analysis window should at least be 1/10 to cover one "
|
amine@403
|
1139 err_msg += "data sample"
|
amine@400
|
1140 assert err_msg == str(val_err.value)
|
amine@400
|
1141
|
amine@400
|
1142
|
amine@400
|
1143 def test_split_and_plot():
|
amine@400
|
1144
|
amine@400
|
1145 with open("tests/data/test_split_10HZ_mono.raw", "rb") as fp:
|
amine@400
|
1146 data = fp.read()
|
amine@400
|
1147
|
amine@400
|
1148 region = AudioRegion(data, 10, 2, 1)
|
amine@405
|
1149 with patch("auditok.core.plot") as patch_fn:
|
amine@400
|
1150 regions = region.split_and_plot(
|
amine@212
|
1151 min_dur=0.2,
|
amine@212
|
1152 max_dur=5,
|
amine@212
|
1153 max_silence=0.2,
|
amine@212
|
1154 drop_trailing_silence=False,
|
amine@212
|
1155 strict_min_dur=False,
|
amine@212
|
1156 analysis_window=0.1,
|
amine@400
|
1157 sr=10,
|
amine@400
|
1158 sw=2,
|
amine@400
|
1159 ch=1,
|
amine@400
|
1160 eth=50,
|
amine@212
|
1161 )
|
amine@400
|
1162 assert patch_fn.called
|
amine@400
|
1163 expected = [(2, 16), (17, 31), (34, 76)]
|
amine@400
|
1164 sample_width = 2
|
amine@400
|
1165 expected_regions = []
|
amine@400
|
1166 for onset, offset in expected:
|
amine@400
|
1167 onset *= sample_width
|
amine@400
|
1168 offset *= sample_width
|
amine@400
|
1169 expected_regions.append(AudioRegion(data[onset:offset], 10, 2, 1))
|
amine@400
|
1170 assert regions == expected_regions
|
amine@211
|
1171
|
amine@223
|
1172
|
amine@400
|
1173 def test_split_exception():
|
amine@400
|
1174 with open("tests/data/test_split_10HZ_mono.raw", "rb") as fp:
|
amine@400
|
1175 data = fp.read()
|
amine@400
|
1176 region = AudioRegion(data, 10, 2, 1)
|
amine@223
|
1177
|
amine@400
|
1178 with pytest.raises(RuntimeWarning):
|
amine@400
|
1179 # max_read is not accepted when calling AudioRegion.split
|
amine@400
|
1180 region.split(max_read=2)
|
amine@223
|
1181
|
amine@223
|
1182
|
amine@400
|
1183 @pytest.mark.parametrize(
|
amine@405
|
1184 (
|
amine@405
|
1185 "data, start, sampling_rate, sample_width, channels, expected_end, "
|
amine@405
|
1186 + "expected_duration_s, expected_duration_ms"
|
amine@405
|
1187 ),
|
amine@400
|
1188 [
|
amine@405
|
1189 (b"\0" * 8000, 0, 8000, 1, 1, 1, 1, 1000), # simple
|
amine@405
|
1190 (
|
amine@405
|
1191 b"\0" * 7992,
|
amine@405
|
1192 0,
|
amine@405
|
1193 8000,
|
amine@405
|
1194 1,
|
amine@405
|
1195 1,
|
amine@405
|
1196 0.999,
|
amine@405
|
1197 0.999,
|
amine@405
|
1198 999,
|
amine@405
|
1199 ), # one_ms_less_than_1_sec
|
amine@405
|
1200 (
|
amine@405
|
1201 b"\0" * 7994,
|
amine@405
|
1202 0,
|
amine@405
|
1203 8000,
|
amine@405
|
1204 1,
|
amine@405
|
1205 1,
|
amine@405
|
1206 0.99925,
|
amine@405
|
1207 0.99925,
|
amine@405
|
1208 999,
|
amine@405
|
1209 ), # tree_quarter_ms_less_than_1_sec
|
amine@405
|
1210 (
|
amine@405
|
1211 b"\0" * 7996,
|
amine@405
|
1212 0,
|
amine@405
|
1213 8000,
|
amine@405
|
1214 1,
|
amine@405
|
1215 1,
|
amine@405
|
1216 0.9995,
|
amine@405
|
1217 0.9995,
|
amine@405
|
1218 1000,
|
amine@405
|
1219 ), # half_ms_less_than_1_sec
|
amine@405
|
1220 (
|
amine@405
|
1221 b"\0" * 7998,
|
amine@405
|
1222 0,
|
amine@405
|
1223 8000,
|
amine@405
|
1224 1,
|
amine@405
|
1225 1,
|
amine@405
|
1226 0.99975,
|
amine@405
|
1227 0.99975,
|
amine@405
|
1228 1000,
|
amine@405
|
1229 ), # quarter_ms_less_than_1_sec
|
amine@405
|
1230 (b"\0" * 8000 * 2, 0, 8000, 2, 1, 1, 1, 1000), # simple_sample_width_2
|
amine@405
|
1231 (b"\0" * 8000 * 2, 0, 8000, 1, 2, 1, 1, 1000), # simple_stereo
|
amine@405
|
1232 (b"\0" * 8000 * 5, 0, 8000, 1, 5, 1, 1, 1000), # simple_multichannel
|
amine@405
|
1233 (
|
amine@405
|
1234 b"\0" * 8000 * 2 * 5,
|
amine@405
|
1235 0,
|
amine@405
|
1236 8000,
|
amine@405
|
1237 2,
|
amine@405
|
1238 5,
|
amine@405
|
1239 1,
|
amine@405
|
1240 1,
|
amine@405
|
1241 1000,
|
amine@405
|
1242 ), # simple_sample_width_2_multichannel
|
amine@405
|
1243 (
|
amine@405
|
1244 b"\0" * 7992 * 2 * 5,
|
amine@405
|
1245 0,
|
amine@405
|
1246 8000,
|
amine@405
|
1247 2,
|
amine@405
|
1248 5,
|
amine@405
|
1249 0.999,
|
amine@405
|
1250 0.999,
|
amine@405
|
1251 999,
|
amine@405
|
1252 ), # one_ms_less_than_1s_sw_2_multichannel
|
amine@405
|
1253 (
|
amine@405
|
1254 b"\0" * 7994 * 2 * 5,
|
amine@405
|
1255 0,
|
amine@405
|
1256 8000,
|
amine@405
|
1257 2,
|
amine@405
|
1258 5,
|
amine@405
|
1259 0.99925,
|
amine@405
|
1260 0.99925,
|
amine@405
|
1261 999,
|
amine@405
|
1262 ), # tree_qrt_ms_lt_1_s_sw_2_multichannel
|
amine@405
|
1263 (
|
amine@405
|
1264 b"\0" * 7996 * 2 * 5,
|
amine@405
|
1265 0,
|
amine@405
|
1266 8000,
|
amine@405
|
1267 2,
|
amine@405
|
1268 5,
|
amine@405
|
1269 0.9995,
|
amine@405
|
1270 0.9995,
|
amine@405
|
1271 1000,
|
amine@405
|
1272 ), # half_ms_lt_1s_sw_2_multichannel
|
amine@405
|
1273 (
|
amine@405
|
1274 b"\0" * 7998 * 2 * 5,
|
amine@405
|
1275 0,
|
amine@405
|
1276 8000,
|
amine@405
|
1277 2,
|
amine@405
|
1278 5,
|
amine@405
|
1279 0.99975,
|
amine@405
|
1280 0.99975,
|
amine@405
|
1281 1000,
|
amine@405
|
1282 ), # quarter_ms_lt_1s_sw_2_multichannel
|
amine@405
|
1283 (
|
amine@405
|
1284 b"\0" * int(8000 * 1.33),
|
amine@405
|
1285 2.7,
|
amine@405
|
1286 8000,
|
amine@405
|
1287 1,
|
amine@405
|
1288 1,
|
amine@405
|
1289 4.03,
|
amine@405
|
1290 1.33,
|
amine@405
|
1291 1330,
|
amine@405
|
1292 ), # arbitrary_length_1
|
amine@405
|
1293 (
|
amine@405
|
1294 b"\0" * int(8000 * 0.476),
|
amine@405
|
1295 11.568,
|
amine@405
|
1296 8000,
|
amine@405
|
1297 1,
|
amine@405
|
1298 1,
|
amine@405
|
1299 12.044,
|
amine@405
|
1300 0.476,
|
amine@405
|
1301 476,
|
amine@405
|
1302 ), # arbitrary_length_2
|
amine@400
|
1303 (
|
amine@86
|
1304 b"\0" * int(8000 * 1.711) * 2 * 3,
|
amine@86
|
1305 9.415,
|
amine@86
|
1306 8000,
|
amine@86
|
1307 2,
|
amine@86
|
1308 3,
|
amine@86
|
1309 11.126,
|
amine@86
|
1310 1.711,
|
amine@86
|
1311 1711,
|
amine@405
|
1312 ), # arbitrary_length_sw_2_multichannel
|
amine@400
|
1313 (
|
amine@86
|
1314 b"\0" * int(3172 * 1.318),
|
amine@86
|
1315 17.236,
|
amine@86
|
1316 3172,
|
amine@86
|
1317 1,
|
amine@86
|
1318 1,
|
amine@86
|
1319 17.236 + int(3172 * 1.318) / 3172,
|
amine@86
|
1320 int(3172 * 1.318) / 3172,
|
amine@86
|
1321 1318,
|
amine@405
|
1322 ), # arbitrary_sampling_rate
|
amine@400
|
1323 (
|
amine@86
|
1324 b"\0" * int(11317 * 0.716) * 2 * 3,
|
amine@86
|
1325 18.811,
|
amine@86
|
1326 11317,
|
amine@86
|
1327 2,
|
amine@86
|
1328 3,
|
amine@86
|
1329 18.811 + int(11317 * 0.716) / 11317,
|
amine@86
|
1330 int(11317 * 0.716) / 11317,
|
amine@86
|
1331 716,
|
amine@405
|
1332 ), # arbitrary_sr_sw_2_multichannel
|
amine@400
|
1333 ],
|
amine@400
|
1334 ids=[
|
amine@400
|
1335 "simple",
|
amine@400
|
1336 "one_ms_less_than_1_sec",
|
amine@400
|
1337 "tree_quarter_ms_less_than_1_sec",
|
amine@400
|
1338 "half_ms_less_than_1_sec",
|
amine@400
|
1339 "quarter_ms_less_than_1_sec",
|
amine@400
|
1340 "simple_sample_width_2",
|
amine@400
|
1341 "simple_stereo",
|
amine@400
|
1342 "simple_multichannel",
|
amine@400
|
1343 "simple_sample_width_2_multichannel",
|
amine@400
|
1344 "one_ms_less_than_1s_sw_2_multichannel",
|
amine@400
|
1345 "tree_qrt_ms_lt_1_s_sw_2_multichannel",
|
amine@400
|
1346 "half_ms_lt_1s_sw_2_multichannel",
|
amine@400
|
1347 "quarter_ms_lt_1s_sw_2_multichannel",
|
amine@400
|
1348 "arbitrary_length_1",
|
amine@400
|
1349 "arbitrary_length_2",
|
amine@400
|
1350 "arbitrary_length_sw_2_multichannel",
|
amine@405
|
1351 "arbitrary_sampling_rate",
|
amine@400
|
1352 "arbitrary_sr_sw_2_multichannel",
|
amine@400
|
1353 ],
|
amine@400
|
1354 )
|
amine@400
|
1355 def test_creation(
|
amine@400
|
1356 data,
|
amine@400
|
1357 start,
|
amine@400
|
1358 sampling_rate,
|
amine@400
|
1359 sample_width,
|
amine@400
|
1360 channels,
|
amine@400
|
1361 expected_end,
|
amine@400
|
1362 expected_duration_s,
|
amine@400
|
1363 expected_duration_ms,
|
amine@400
|
1364 ):
|
amine@400
|
1365 meta = {"start": start, "end": expected_end}
|
amine@400
|
1366 region = AudioRegion(data, sampling_rate, sample_width, channels, meta)
|
amine@400
|
1367 assert region.sampling_rate == sampling_rate
|
amine@400
|
1368 assert region.sr == sampling_rate
|
amine@400
|
1369 assert region.sample_width == sample_width
|
amine@400
|
1370 assert region.sw == sample_width
|
amine@400
|
1371 assert region.channels == channels
|
amine@400
|
1372 assert region.ch == channels
|
amine@400
|
1373 assert region.meta.start == start
|
amine@400
|
1374 assert region.meta.end == expected_end
|
amine@400
|
1375 assert region.duration == expected_duration_s
|
amine@400
|
1376 assert len(region.ms) == expected_duration_ms
|
amine@400
|
1377 assert bytes(region) == data
|
amine@400
|
1378
|
amine@400
|
1379
|
amine@400
|
1380 def test_creation_invalid_data_exception():
|
amine@400
|
1381 with pytest.raises(AudioParameterError) as audio_param_err:
|
amine@400
|
1382 _ = AudioRegion(
|
amine@400
|
1383 data=b"ABCDEFGHI", sampling_rate=8, sample_width=2, channels=1
|
amine@400
|
1384 )
|
amine@400
|
1385 assert str(audio_param_err.value) == (
|
amine@400
|
1386 "The length of audio data must be an integer "
|
amine@400
|
1387 "multiple of `sample_width * channels`"
|
amine@86
|
1388 )
|
amine@88
|
1389
|
amine@97
|
1390
|
amine@400
|
1391 @pytest.mark.parametrize(
|
amine@400
|
1392 "skip, max_read, channels",
|
amine@400
|
1393 [
|
amine@405
|
1394 (0, -1, 1), # no_skip_read_all
|
amine@405
|
1395 (0, -1, 2), # no_skip_read_all_stereo
|
amine@405
|
1396 (2, -1, 1), # skip_2_read_all
|
amine@405
|
1397 (2, None, 1), # skip_2_read_all_None
|
amine@405
|
1398 (2, 3, 1), # skip_2_read_3
|
amine@405
|
1399 (2, 3.5, 2), # skip_2_read_3_5_stereo
|
amine@405
|
1400 (2.4, 3.5, 2), # skip_2_4_read_3_5_stereo
|
amine@400
|
1401 ],
|
amine@400
|
1402 ids=[
|
amine@400
|
1403 "no_skip_read_all",
|
amine@400
|
1404 "no_skip_read_all_stereo",
|
amine@400
|
1405 "skip_2_read_all",
|
amine@400
|
1406 "skip_2_read_all_None",
|
amine@400
|
1407 "skip_2_read_3",
|
amine@400
|
1408 "skip_2_read_3_5_stereo",
|
amine@400
|
1409 "skip_2_4_read_3_5_stereo",
|
amine@400
|
1410 ],
|
amine@400
|
1411 )
|
amine@400
|
1412 def test_load_AudioRegion(skip, max_read, channels):
|
amine@400
|
1413 sampling_rate = 10
|
amine@400
|
1414 sample_width = 2
|
amine@400
|
1415 filename = "tests/data/test_split_10HZ_{}.raw"
|
amine@400
|
1416 filename = filename.format("mono" if channels == 1 else "stereo")
|
amine@400
|
1417 region = AudioRegion.load(
|
amine@400
|
1418 filename,
|
amine@400
|
1419 skip=skip,
|
amine@400
|
1420 max_read=max_read,
|
amine@400
|
1421 sr=sampling_rate,
|
amine@400
|
1422 sw=sample_width,
|
amine@400
|
1423 ch=channels,
|
amine@308
|
1424 )
|
amine@400
|
1425 with open(filename, "rb") as fp:
|
amine@400
|
1426 fp.read(round(skip * sampling_rate * sample_width * channels))
|
amine@400
|
1427 if max_read is None or max_read < 0:
|
amine@400
|
1428 to_read = -1
|
amine@400
|
1429 else:
|
amine@400
|
1430 to_read = round(max_read * sampling_rate * sample_width * channels)
|
amine@400
|
1431 expected = fp.read(to_read)
|
amine@400
|
1432 assert bytes(region) == expected
|
amine@308
|
1433
|
amine@308
|
1434
|
amine@400
|
1435 def test_load_from_microphone():
|
amine@400
|
1436 with patch("auditok.io.PyAudioSource") as patch_pyaudio_source:
|
amine@400
|
1437 with patch("auditok.core.AudioReader.read") as patch_reader:
|
amine@400
|
1438 patch_reader.return_value = None
|
amine@400
|
1439 with patch(
|
amine@400
|
1440 "auditok.core.AudioRegion.__init__"
|
amine@400
|
1441 ) as patch_AudioRegion:
|
amine@400
|
1442 patch_AudioRegion.return_value = None
|
amine@400
|
1443 AudioRegion.load(None, skip=0, max_read=5, sr=16000, sw=2, ch=1)
|
amine@400
|
1444 assert patch_pyaudio_source.called
|
amine@400
|
1445 assert patch_reader.called
|
amine@400
|
1446 assert patch_AudioRegion.called
|
amine@307
|
1447
|
amine@308
|
1448
|
amine@400
|
1449 @pytest.mark.parametrize(
|
amine@400
|
1450 "max_read",
|
amine@400
|
1451 [
|
amine@405
|
1452 None, # None
|
amine@405
|
1453 -1, # negative
|
amine@400
|
1454 ],
|
amine@400
|
1455 ids=[
|
amine@405
|
1456 "None",
|
amine@400
|
1457 "negative",
|
amine@400
|
1458 ],
|
amine@400
|
1459 )
|
amine@400
|
1460 def test_load_from_microphone_without_max_read_exception(max_read):
|
amine@400
|
1461 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1462 AudioRegion.load(None, max_read=max_read, sr=16000, sw=2, ch=1)
|
amine@400
|
1463 assert str(val_err.value) == (
|
amine@400
|
1464 "'max_read' should not be None when reading from microphone"
|
amine@400
|
1465 )
|
amine@400
|
1466
|
amine@400
|
1467
|
amine@400
|
1468 def test_load_from_microphone_with_nonzero_skip_exception():
|
amine@400
|
1469 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1470 AudioRegion.load(None, skip=1, max_read=5, sr=16000, sw=2, ch=1)
|
amine@400
|
1471 assert str(val_err.value) == (
|
amine@400
|
1472 "'skip' should be 0 when reading from microphone"
|
amine@400
|
1473 )
|
amine@400
|
1474
|
amine@400
|
1475
|
amine@400
|
1476 @pytest.mark.parametrize(
|
amine@400
|
1477 "format, start, expected",
|
amine@400
|
1478 [
|
amine@405
|
1479 ("output.wav", 1.230, "output.wav"), # simple
|
amine@405
|
1480 ("output_{meta.start:g}.wav", 1.230, "output_1.23.wav"), # start
|
amine@405
|
1481 ("output_{meta.start}.wav", 1.233712, "output_1.233712.wav"), # start_2
|
amine@405
|
1482 (
|
amine@405
|
1483 "output_{meta.start:.2f}.wav",
|
amine@405
|
1484 1.2300001,
|
amine@405
|
1485 "output_1.23.wav",
|
amine@405
|
1486 ), # start_3
|
amine@405
|
1487 (
|
amine@405
|
1488 "output_{meta.start:.3f}.wav",
|
amine@405
|
1489 1.233712,
|
amine@405
|
1490 "output_1.234.wav",
|
amine@405
|
1491 ), # start_4
|
amine@405
|
1492 (
|
amine@405
|
1493 "output_{meta.start:.8f}.wav",
|
amine@405
|
1494 1.233712,
|
amine@405
|
1495 "output_1.23371200.wav",
|
amine@405
|
1496 ), # start_5
|
amine@400
|
1497 (
|
amine@244
|
1498 "output_{meta.start}_{meta.end}_{duration}.wav",
|
amine@192
|
1499 1.455,
|
amine@192
|
1500 "output_1.455_2.455_1.0.wav",
|
amine@405
|
1501 ), # start_end_duration
|
amine@400
|
1502 (
|
amine@244
|
1503 "output_{meta.start}_{meta.end}_{duration}.wav",
|
amine@192
|
1504 1.455321,
|
amine@192
|
1505 "output_1.455321_2.455321_1.0.wav",
|
amine@405
|
1506 ), # start_end_duration_2
|
amine@400
|
1507 ],
|
amine@400
|
1508 ids=[
|
amine@400
|
1509 "simple",
|
amine@400
|
1510 "start",
|
amine@400
|
1511 "start_2",
|
amine@400
|
1512 "start_3",
|
amine@400
|
1513 "start_4",
|
amine@400
|
1514 "start_5",
|
amine@400
|
1515 "start_end_duration",
|
amine@400
|
1516 "start_end_duration_2",
|
amine@400
|
1517 ],
|
amine@400
|
1518 )
|
amine@400
|
1519 def test_save(format, start, expected):
|
amine@400
|
1520 with TemporaryDirectory() as tmpdir:
|
amine@400
|
1521 region = AudioRegion(b"0" * 160, 160, 1, 1)
|
amine@400
|
1522 meta = {"start": start, "end": start + region.duration}
|
amine@400
|
1523 region.meta = meta
|
amine@400
|
1524 format = os.path.join(tmpdir, format)
|
amine@400
|
1525 filename = region.save(format)[len(tmpdir) + 1 :]
|
amine@400
|
1526 assert filename == expected
|
amine@192
|
1527
|
amine@193
|
1528
|
amine@400
|
1529 def test_save_file_exists_exception():
|
amine@400
|
1530 with TemporaryDirectory() as tmpdir:
|
amine@400
|
1531 filename = os.path.join(tmpdir, "output.wav")
|
amine@400
|
1532 open(filename, "w").close()
|
amine@400
|
1533 region = AudioRegion(b"0" * 160, 160, 1, 1)
|
amine@400
|
1534 with pytest.raises(FileExistsError):
|
amine@400
|
1535 region.save(filename, exists_ok=False)
|
amine@400
|
1536
|
amine@400
|
1537
|
amine@400
|
1538 @pytest.mark.parametrize(
|
amine@400
|
1539 "region, slice_, expected_data",
|
amine@400
|
1540 [
|
amine@400
|
1541 (
|
amine@244
|
1542 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@194
|
1543 slice(0, 500),
|
amine@405
|
1544 b"a" * 80, # first_half
|
amine@244
|
1545 ),
|
amine@400
|
1546 (
|
amine@244
|
1547 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1548 slice(500, None),
|
amine@405
|
1549 b"b" * 80, # second_half
|
amine@244
|
1550 ),
|
amine@400
|
1551 (
|
amine@244
|
1552 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1553 slice(-500, None),
|
amine@405
|
1554 b"b" * 80, # second_half_negative
|
amine@244
|
1555 ),
|
amine@400
|
1556 (
|
amine@244
|
1557 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1558 slice(200, 750),
|
amine@405
|
1559 b"a" * 48 + b"b" * 40, # middle
|
amine@244
|
1560 ),
|
amine@400
|
1561 (
|
amine@244
|
1562 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1563 slice(-800, -250),
|
amine@405
|
1564 b"a" * 48 + b"b" * 40, # middle_negative
|
amine@244
|
1565 ),
|
amine@400
|
1566 (
|
amine@244
|
1567 AudioRegion(b"a" * 160 + b"b" * 160, 160, 2, 1),
|
amine@244
|
1568 slice(200, 750),
|
amine@405
|
1569 b"a" * 96 + b"b" * 80, # middle_sw2
|
amine@244
|
1570 ),
|
amine@400
|
1571 (
|
amine@244
|
1572 AudioRegion(b"a" * 160 + b"b" * 160, 160, 1, 2),
|
amine@244
|
1573 slice(200, 750),
|
amine@405
|
1574 b"a" * 96 + b"b" * 80, # middle_ch2
|
amine@244
|
1575 ),
|
amine@400
|
1576 (
|
amine@244
|
1577 AudioRegion(b"a" * 320 + b"b" * 320, 160, 2, 2),
|
amine@244
|
1578 slice(200, 750),
|
amine@405
|
1579 b"a" * 192 + b"b" * 160, # middle_sw2_ch2
|
amine@244
|
1580 ),
|
amine@400
|
1581 (
|
amine@244
|
1582 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@244
|
1583 slice(1, None),
|
amine@405
|
1584 b"a" * (4000 - 8) + b"b" * 4000, # but_first_sample
|
amine@244
|
1585 ),
|
amine@400
|
1586 (
|
amine@244
|
1587 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@244
|
1588 slice(-999, None),
|
amine@405
|
1589 b"a" * (4000 - 8) + b"b" * 4000, # but_first_sample_negative
|
amine@244
|
1590 ),
|
amine@400
|
1591 (
|
amine@244
|
1592 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@244
|
1593 slice(0, 999),
|
amine@405
|
1594 b"a" * 4000 + b"b" * (4000 - 8), # but_last_sample
|
amine@244
|
1595 ),
|
amine@400
|
1596 (
|
amine@244
|
1597 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@244
|
1598 slice(0, -1),
|
amine@405
|
1599 b"a" * 4000 + b"b" * (4000 - 8), # but_last_sample_negative
|
amine@244
|
1600 ),
|
amine@405
|
1601 (
|
amine@405
|
1602 AudioRegion(b"a" * 160, 160, 1, 1),
|
amine@405
|
1603 slice(-5000, None),
|
amine@405
|
1604 b"a" * 160, # big_negative_start
|
amine@405
|
1605 ),
|
amine@405
|
1606 (
|
amine@405
|
1607 AudioRegion(b"a" * 160, 160, 1, 1),
|
amine@405
|
1608 slice(None, -1500),
|
amine@405
|
1609 b"", # big_negative_stop
|
amine@405
|
1610 ),
|
amine@405
|
1611 (
|
amine@405
|
1612 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@405
|
1613 slice(0, 0),
|
amine@405
|
1614 b"", # empty
|
amine@405
|
1615 ),
|
amine@405
|
1616 (
|
amine@405
|
1617 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@405
|
1618 slice(200, 100),
|
amine@405
|
1619 b"", # empty_start_stop_reversed
|
amine@405
|
1620 ),
|
amine@405
|
1621 (
|
amine@405
|
1622 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@405
|
1623 slice(2000, 3000),
|
amine@405
|
1624 b"", # empty_big_positive_start
|
amine@405
|
1625 ),
|
amine@405
|
1626 (
|
amine@405
|
1627 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@405
|
1628 slice(-100, -200),
|
amine@405
|
1629 b"", # empty_negative_reversed
|
amine@405
|
1630 ),
|
amine@405
|
1631 (
|
amine@405
|
1632 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@405
|
1633 slice(0, -2000),
|
amine@405
|
1634 b"", # empty_big_negative_stop
|
amine@405
|
1635 ),
|
amine@400
|
1636 (
|
amine@244
|
1637 AudioRegion(b"a" * 124 + b"b" * 376, 1234, 1, 1),
|
amine@244
|
1638 slice(100, 200),
|
amine@405
|
1639 b"a" + b"b" * 123, # arbitrary_sampling_rate
|
amine@244
|
1640 ),
|
amine@400
|
1641 ],
|
amine@400
|
1642 ids=[
|
amine@400
|
1643 "first_half",
|
amine@400
|
1644 "second_half",
|
amine@400
|
1645 "second_half_negative",
|
amine@400
|
1646 "middle",
|
amine@400
|
1647 "middle_negative",
|
amine@400
|
1648 "middle_sw2",
|
amine@400
|
1649 "middle_ch2",
|
amine@400
|
1650 "middle_sw2_ch2",
|
amine@400
|
1651 "but_first_sample",
|
amine@400
|
1652 "but_first_sample_negative",
|
amine@400
|
1653 "but_last_sample",
|
amine@400
|
1654 "but_last_sample_negative",
|
amine@400
|
1655 "big_negative_start",
|
amine@400
|
1656 "big_negative_stop",
|
amine@400
|
1657 "empty",
|
amine@400
|
1658 "empty_start_stop_reversed",
|
amine@400
|
1659 "empty_big_positive_start",
|
amine@400
|
1660 "empty_negative_reversed",
|
amine@400
|
1661 "empty_big_negative_stop",
|
amine@400
|
1662 "arbitrary_sampling_rate",
|
amine@400
|
1663 ],
|
amine@400
|
1664 )
|
amine@400
|
1665 def test_region_temporal_slicing(region, slice_, expected_data):
|
amine@400
|
1666 sub_region = region.millis[slice_]
|
amine@400
|
1667 assert bytes(sub_region) == expected_data
|
amine@400
|
1668 start_sec = slice_.start / 1000 if slice_.start is not None else None
|
amine@400
|
1669 stop_sec = slice_.stop / 1000 if slice_.stop is not None else None
|
amine@400
|
1670 sub_region = region.sec[start_sec:stop_sec]
|
amine@400
|
1671 assert bytes(sub_region) == expected_data
|
amine@244
|
1672
|
amine@400
|
1673
|
amine@400
|
1674 @pytest.mark.parametrize(
|
amine@400
|
1675 "region, slice_, time_shift, expected_data",
|
amine@400
|
1676 [
|
amine@400
|
1677 (
|
amine@244
|
1678 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1679 slice(0, 80),
|
amine@194
|
1680 0,
|
amine@405
|
1681 b"a" * 80, # first_half
|
amine@194
|
1682 ),
|
amine@400
|
1683 (
|
amine@244
|
1684 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1685 slice(80, None),
|
amine@194
|
1686 0.5,
|
amine@405
|
1687 b"b" * 80, # second_half
|
amine@194
|
1688 ),
|
amine@400
|
1689 (
|
amine@244
|
1690 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1691 slice(-80, None),
|
amine@194
|
1692 0.5,
|
amine@405
|
1693 b"b" * 80, # second_half_negative
|
amine@194
|
1694 ),
|
amine@400
|
1695 (
|
amine@244
|
1696 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1697 slice(160 // 5, 160 // 4 * 3),
|
amine@194
|
1698 0.2,
|
amine@405
|
1699 b"a" * 48 + b"b" * 40, # middle
|
amine@194
|
1700 ),
|
amine@400
|
1701 (
|
amine@244
|
1702 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1703 slice(-160 // 5 * 4, -160 // 4),
|
amine@194
|
1704 0.2,
|
amine@405
|
1705 b"a" * 48 + b"b" * 40, # middle_negative
|
amine@194
|
1706 ),
|
amine@400
|
1707 (
|
amine@244
|
1708 AudioRegion(b"a" * 160 + b"b" * 160, 160, 2, 1),
|
amine@244
|
1709 slice(160 // 5, 160 // 4 * 3),
|
amine@194
|
1710 0.2,
|
amine@405
|
1711 b"a" * 96 + b"b" * 80, # middle_sw2
|
amine@194
|
1712 ),
|
amine@400
|
1713 (
|
amine@244
|
1714 AudioRegion(b"a" * 160 + b"b" * 160, 160, 1, 2),
|
amine@244
|
1715 slice(160 // 5, 160 // 4 * 3),
|
amine@194
|
1716 0.2,
|
amine@405
|
1717 b"a" * 96 + b"b" * 80, # middle_ch2
|
amine@194
|
1718 ),
|
amine@400
|
1719 (
|
amine@244
|
1720 AudioRegion(b"a" * 320 + b"b" * 320, 160, 2, 2),
|
amine@244
|
1721 slice(160 // 5, 160 // 4 * 3),
|
amine@194
|
1722 0.2,
|
amine@405
|
1723 b"a" * 192 + b"b" * 160, # middle_sw2_ch2
|
amine@194
|
1724 ),
|
amine@400
|
1725 (
|
amine@244
|
1726 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@194
|
1727 slice(1, None),
|
amine@244
|
1728 1 / 8000,
|
amine@405
|
1729 b"a" * (4000 - 1) + b"b" * 4000, # but_first_sample
|
amine@194
|
1730 ),
|
amine@400
|
1731 (
|
amine@244
|
1732 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@244
|
1733 slice(-7999, None),
|
amine@244
|
1734 1 / 8000,
|
amine@405
|
1735 b"a" * (4000 - 1) + b"b" * 4000, # but_first_sample_negative
|
amine@194
|
1736 ),
|
amine@400
|
1737 (
|
amine@244
|
1738 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@244
|
1739 slice(0, 7999),
|
amine@194
|
1740 0,
|
amine@405
|
1741 b"a" * 4000 + b"b" * (4000 - 1), # but_last_sample
|
amine@194
|
1742 ),
|
amine@400
|
1743 (
|
amine@244
|
1744 AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1),
|
amine@194
|
1745 slice(0, -1),
|
amine@194
|
1746 0,
|
amine@405
|
1747 b"a" * 4000 + b"b" * (4000 - 1), # but_last_sample_negative
|
amine@194
|
1748 ),
|
amine@405
|
1749 (
|
amine@405
|
1750 AudioRegion(b"a" * 160, 160, 1, 1),
|
amine@405
|
1751 slice(-1600, None),
|
amine@405
|
1752 0,
|
amine@405
|
1753 b"a" * 160, # big_negative_start
|
amine@405
|
1754 ),
|
amine@405
|
1755 (
|
amine@405
|
1756 AudioRegion(b"a" * 160, 160, 1, 1),
|
amine@405
|
1757 slice(None, -1600),
|
amine@405
|
1758 0,
|
amine@405
|
1759 b"", # big_negative_stop
|
amine@405
|
1760 ),
|
amine@405
|
1761 (
|
amine@405
|
1762 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@405
|
1763 slice(0, 0),
|
amine@405
|
1764 0,
|
amine@405
|
1765 b"", # empty
|
amine@405
|
1766 ),
|
amine@400
|
1767 (
|
amine@244
|
1768 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1769 slice(80, 40),
|
amine@244
|
1770 0.5,
|
amine@405
|
1771 b"", # empty_start_stop_reversed
|
amine@194
|
1772 ),
|
amine@400
|
1773 (
|
amine@244
|
1774 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1775 slice(1600, 3000),
|
amine@244
|
1776 10,
|
amine@405
|
1777 b"", # empty_big_positive_start
|
amine@194
|
1778 ),
|
amine@400
|
1779 (
|
amine@244
|
1780 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@244
|
1781 slice(-16, -32),
|
amine@194
|
1782 0.9,
|
amine@405
|
1783 b"", # empty_negative_reversed
|
amine@194
|
1784 ),
|
amine@400
|
1785 (
|
amine@244
|
1786 AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1),
|
amine@194
|
1787 slice(0, -2000),
|
amine@194
|
1788 0,
|
amine@405
|
1789 b"", # empty_big_negative_stop
|
amine@194
|
1790 ),
|
amine@400
|
1791 (
|
amine@244
|
1792 AudioRegion(b"a" * 124 + b"b" * 376, 1235, 1, 1),
|
amine@231
|
1793 slice(100, 200),
|
amine@231
|
1794 100 / 1235,
|
amine@405
|
1795 b"a" * 24 + b"b" * 76, # arbitrary_sampling_rate
|
amine@231
|
1796 ),
|
amine@400
|
1797 (
|
amine@244
|
1798 AudioRegion(b"a" * 124 + b"b" * 376, 1235, 2, 2),
|
amine@231
|
1799 slice(25, 50),
|
amine@231
|
1800 25 / 1235,
|
amine@405
|
1801 b"a" * 24 + b"b" * 76, # arbitrary_sampling_rate_middle_sw2_ch2
|
amine@231
|
1802 ),
|
amine@400
|
1803 ],
|
amine@400
|
1804 ids=[
|
amine@400
|
1805 "first_half",
|
amine@400
|
1806 "second_half",
|
amine@400
|
1807 "second_half_negative",
|
amine@400
|
1808 "middle",
|
amine@400
|
1809 "middle_negative",
|
amine@400
|
1810 "middle_sw2",
|
amine@400
|
1811 "middle_ch2",
|
amine@400
|
1812 "middle_sw2_ch2",
|
amine@400
|
1813 "but_first_sample",
|
amine@400
|
1814 "but_first_sample_negative",
|
amine@400
|
1815 "but_last_sample",
|
amine@400
|
1816 "but_last_sample_negative",
|
amine@400
|
1817 "big_negative_start",
|
amine@400
|
1818 "big_negative_stop",
|
amine@400
|
1819 "empty",
|
amine@400
|
1820 "empty_start_stop_reversed",
|
amine@400
|
1821 "empty_big_positive_start",
|
amine@400
|
1822 "empty_negative_reversed",
|
amine@400
|
1823 "empty_big_negative_stop",
|
amine@400
|
1824 "arbitrary_sampling_rate",
|
amine@400
|
1825 "arbitrary_sampling_rate_middle_sw2_ch2",
|
amine@400
|
1826 ],
|
amine@400
|
1827 )
|
amine@400
|
1828 def test_region_sample_slicing(region, slice_, time_shift, expected_data):
|
amine@400
|
1829 sub_region = region[slice_]
|
amine@400
|
1830 assert bytes(sub_region) == expected_data
|
amine@400
|
1831
|
amine@400
|
1832
|
amine@400
|
1833 @pytest.mark.parametrize(
|
amine@400
|
1834 "sampling_rate, sample_width, channels",
|
amine@400
|
1835 [
|
amine@405
|
1836 (8000, 1, 1), # simple
|
amine@405
|
1837 (8000, 2, 2), # stereo_sw_2
|
amine@405
|
1838 (5413, 2, 3), # arbitrary_sr_multichannel
|
amine@400
|
1839 ],
|
amine@400
|
1840 ids=[
|
amine@400
|
1841 "simple",
|
amine@400
|
1842 "stereo_sw_2",
|
amine@400
|
1843 "arbitrary_sr_multichannel",
|
amine@400
|
1844 ],
|
amine@400
|
1845 )
|
amine@400
|
1846 def test_concatenation(sampling_rate, sample_width, channels):
|
amine@400
|
1847
|
amine@400
|
1848 region_1, region_2 = _make_random_length_regions(
|
amine@400
|
1849 [b"a", b"b"], sampling_rate, sample_width, channels
|
amine@231
|
1850 )
|
amine@400
|
1851 expected_duration = region_1.duration + region_2.duration
|
amine@400
|
1852 expected_data = bytes(region_1) + bytes(region_2)
|
amine@400
|
1853 concat_region = region_1 + region_2
|
amine@400
|
1854 assert concat_region.duration == pytest.approx(expected_duration, abs=1e-6)
|
amine@400
|
1855 assert bytes(concat_region) == expected_data
|
amine@231
|
1856
|
amine@400
|
1857
|
amine@400
|
1858 @pytest.mark.parametrize(
|
amine@400
|
1859 "sampling_rate, sample_width, channels",
|
amine@400
|
1860 [
|
amine@405
|
1861 (8000, 1, 1), # simple
|
amine@405
|
1862 (8000, 2, 2), # stereo_sw_2
|
amine@405
|
1863 (5413, 2, 3), # arbitrary_sr_multichannel
|
amine@400
|
1864 ],
|
amine@400
|
1865 ids=[
|
amine@400
|
1866 "simple",
|
amine@400
|
1867 "stereo_sw_2",
|
amine@400
|
1868 "arbitrary_sr_multichannel",
|
amine@400
|
1869 ],
|
amine@400
|
1870 )
|
amine@400
|
1871 def test_concatenation_many(sampling_rate, sample_width, channels):
|
amine@400
|
1872
|
amine@400
|
1873 regions = _make_random_length_regions(
|
amine@400
|
1874 [b"a", b"b", b"c"], sampling_rate, sample_width, channels
|
amine@88
|
1875 )
|
amine@400
|
1876 expected_duration = sum(r.duration for r in regions)
|
amine@400
|
1877 expected_data = b"".join(bytes(r) for r in regions)
|
amine@400
|
1878 concat_region = sum(regions)
|
amine@88
|
1879
|
amine@400
|
1880 assert concat_region.duration == pytest.approx(expected_duration, abs=1e-6)
|
amine@400
|
1881 assert bytes(concat_region) == expected_data
|
amine@88
|
1882
|
amine@400
|
1883
|
amine@400
|
1884 def test_concatenation_different_sampling_rate_error():
|
amine@400
|
1885 region_1 = AudioRegion(b"a" * 100, 8000, 1, 1)
|
amine@400
|
1886 region_2 = AudioRegion(b"b" * 100, 3000, 1, 1)
|
amine@400
|
1887
|
amine@400
|
1888 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1889 region_1 + region_2
|
amine@400
|
1890 assert str(val_err.value) == (
|
amine@400
|
1891 "Can only concatenate AudioRegions of the same "
|
amine@405
|
1892 "sampling rate (8000 != 3000)" # different_sampling_rate
|
amine@88
|
1893 )
|
amine@88
|
1894
|
amine@88
|
1895
|
amine@400
|
1896 def test_concatenation_different_sample_width_error():
|
amine@400
|
1897 region_1 = AudioRegion(b"a" * 100, 8000, 2, 1)
|
amine@400
|
1898 region_2 = AudioRegion(b"b" * 100, 8000, 4, 1)
|
amine@88
|
1899
|
amine@400
|
1900 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1901 region_1 + region_2
|
amine@400
|
1902 assert str(val_err.value) == (
|
amine@405
|
1903 "Can only concatenate AudioRegions of the same sample width (2 != 4)"
|
amine@400
|
1904 )
|
amine@88
|
1905
|
amine@88
|
1906
|
amine@400
|
1907 def test_concatenation_different_number_of_channels_error():
|
amine@400
|
1908 region_1 = AudioRegion(b"a" * 100, 8000, 1, 1)
|
amine@400
|
1909 region_2 = AudioRegion(b"b" * 100, 8000, 1, 2)
|
amine@88
|
1910
|
amine@400
|
1911 with pytest.raises(ValueError) as val_err:
|
amine@400
|
1912 region_1 + region_2
|
amine@400
|
1913 assert str(val_err.value) == (
|
amine@400
|
1914 "Can only concatenate AudioRegions of the same "
|
amine@405
|
1915 "number of channels (1 != 2)" # different_number_of_channels
|
amine@400
|
1916 )
|
amine@88
|
1917
|
amine@88
|
1918
|
amine@400
|
1919 @pytest.mark.parametrize(
|
amine@400
|
1920 "duration, expected_duration, expected_len, expected_len_ms",
|
amine@400
|
1921 [
|
amine@405
|
1922 (0.01, 0.03, 240, 30), # simple
|
amine@405
|
1923 (0.00575, 0.01725, 138, 17), # rounded_len_floor
|
amine@405
|
1924 (0.00625, 0.01875, 150, 19), # rounded_len_ceil
|
amine@400
|
1925 ],
|
amine@400
|
1926 ids=[
|
amine@400
|
1927 "simple",
|
amine@400
|
1928 "rounded_len_floor",
|
amine@400
|
1929 "rounded_len_ceil",
|
amine@400
|
1930 ],
|
amine@400
|
1931 )
|
amine@400
|
1932 def test_multiplication(
|
amine@400
|
1933 duration, expected_duration, expected_len, expected_len_ms
|
amine@400
|
1934 ):
|
amine@400
|
1935 sw = 2
|
amine@400
|
1936 data = b"0" * int(duration * 8000 * sw)
|
amine@400
|
1937 region = AudioRegion(data, 8000, sw, 1)
|
amine@400
|
1938 m_region = 1 * region * 3
|
amine@400
|
1939 assert bytes(m_region) == data * 3
|
amine@400
|
1940 assert m_region.sr == 8000
|
amine@400
|
1941 assert m_region.sw == 2
|
amine@400
|
1942 assert m_region.ch == 1
|
amine@400
|
1943 assert m_region.duration == expected_duration
|
amine@400
|
1944 assert len(m_region) == expected_len
|
amine@400
|
1945 assert m_region.len == expected_len
|
amine@400
|
1946 assert m_region.s.len == expected_duration
|
amine@400
|
1947 assert len(m_region.ms) == expected_len_ms
|
amine@400
|
1948 assert m_region.ms.len == expected_len_ms
|
amine@88
|
1949
|
amine@196
|
1950
|
amine@400
|
1951 @pytest.mark.parametrize(
|
amine@400
|
1952 "factor, _type",
|
amine@400
|
1953 [
|
amine@405
|
1954 ("x", str), # string
|
amine@405
|
1955 (1.4, float), # float
|
amine@400
|
1956 ],
|
amine@400
|
1957 ids=[
|
amine@405
|
1958 "string",
|
amine@405
|
1959 "float",
|
amine@400
|
1960 ],
|
amine@400
|
1961 )
|
amine@400
|
1962 def test_multiplication_non_int(factor, _type):
|
amine@400
|
1963 with pytest.raises(TypeError) as type_err:
|
amine@400
|
1964 AudioRegion(b"0" * 80, 8000, 1, 1) * factor
|
amine@405
|
1965 err_msg = "Can't multiply AudioRegion by a non-int of type '{}'"
|
amine@405
|
1966 assert err_msg.format(_type) == str(type_err.value)
|
amine@197
|
1967
|
amine@254
|
1968
|
amine@400
|
1969 @pytest.mark.parametrize(
|
amine@400
|
1970 "data",
|
amine@400
|
1971 [
|
amine@405
|
1972 [b"a" * 80, b"b" * 80], # simple
|
amine@405
|
1973 [b"a" * 31, b"b" * 31, b"c" * 30], # extra_samples_1
|
amine@405
|
1974 [b"a" * 31, b"b" * 30, b"c" * 30], # extra_samples_2
|
amine@405
|
1975 [b"a" * 11, b"b" * 11, b"c" * 10, b"c" * 10], # extra_samples_3
|
amine@400
|
1976 ],
|
amine@400
|
1977 ids=[
|
amine@400
|
1978 "simple",
|
amine@400
|
1979 "extra_samples_1",
|
amine@400
|
1980 "extra_samples_2",
|
amine@400
|
1981 "extra_samples_3",
|
amine@400
|
1982 ],
|
amine@400
|
1983 )
|
amine@400
|
1984 def test_truediv(data):
|
amine@254
|
1985
|
amine@400
|
1986 region = AudioRegion(b"".join(data), 80, 1, 1)
|
amine@252
|
1987
|
amine@400
|
1988 sub_regions = region / len(data)
|
amine@405
|
1989 for data_i, region in zip(data, sub_regions, strict=True):
|
amine@400
|
1990 assert len(data_i) == len(bytes(region))
|
amine@254
|
1991
|
amine@254
|
1992
|
amine@400
|
1993 @pytest.mark.parametrize(
|
amine@405
|
1994 "data, sample_width, channels, expected",
|
amine@400
|
1995 [
|
amine@405
|
1996 (b"a" * 10, 1, 1, [97] * 10), # mono_sw_1
|
amine@405
|
1997 (b"a" * 10, 2, 1, [24929] * 5), # mono_sw_2
|
amine@405
|
1998 (b"a" * 8, 4, 1, [1633771873] * 2), # mono_sw_4
|
amine@405
|
1999 (b"ab" * 5, 1, 2, [[97] * 5, [98] * 5]), # stereo_sw_1
|
amine@400
|
2000 ],
|
amine@400
|
2001 ids=[
|
amine@400
|
2002 "mono_sw_1",
|
amine@400
|
2003 "mono_sw_2",
|
amine@400
|
2004 "mono_sw_4",
|
amine@400
|
2005 "stereo_sw_1",
|
amine@400
|
2006 ],
|
amine@400
|
2007 )
|
amine@405
|
2008 def test_samples(data, sample_width, channels, expected):
|
amine@337
|
2009
|
amine@400
|
2010 region = AudioRegion(data, 10, sample_width, channels)
|
amine@405
|
2011 expected = np.array(expected)
|
amine@405
|
2012 assert (region.samples == expected).all()
|
amine@405
|
2013 assert (region.numpy() == expected).all()
|
amine@405
|
2014 assert (np.array(region) == expected).all()
|