amine@403
|
1 import filecmp
|
amine@403
|
2 import math
|
amine@106
|
3 import os
|
amine@106
|
4 import sys
|
amine@107
|
5 from array import array
|
amine@133
|
6 from tempfile import NamedTemporaryFile, TemporaryDirectory
|
amine@403
|
7 from unittest.mock import Mock, patch
|
amine@403
|
8
|
amine@400
|
9 import pytest
|
amine@403
|
10 from test_util import PURE_TONE_DICT, _generate_pure_tone, _sample_generator
|
amine@403
|
11
|
amine@110
|
12 from auditok.io import (
|
amine@121
|
13 AudioIOError,
|
amine@110
|
14 AudioParameterError,
|
amine@126
|
15 BufferAudioSource,
|
amine@162
|
16 RawAudioSource,
|
amine@403
|
17 StdinAudioSource,
|
amine@162
|
18 WaveAudioSource,
|
amine@403
|
19 _get_audio_parameters,
|
amine@143
|
20 _guess_audio_format,
|
amine@126
|
21 _load_raw,
|
amine@129
|
22 _load_wave,
|
amine@131
|
23 _load_with_pydub,
|
amine@111
|
24 _save_raw,
|
amine@110
|
25 _save_wave,
|
amine@141
|
26 _save_with_pydub,
|
amine@403
|
27 check_audio_data,
|
amine@403
|
28 from_file,
|
amine@403
|
29 get_audio_source,
|
amine@135
|
30 to_file,
|
amine@110
|
31 )
|
amine@403
|
32 from auditok.signal import FORMAT
|
amine@106
|
33
|
amine@120
|
34 AUDIO_PARAMS_SHORT = {"sr": 16000, "sw": 2, "ch": 1}
|
amine@106
|
35
|
amine@106
|
36
|
amine@400
|
37 @pytest.mark.parametrize(
|
amine@400
|
38 "data, sample_width, channels, valid",
|
amine@400
|
39 [
|
amine@400
|
40 (b"\0" * 113, 1, 1, True), # valid_mono
|
amine@400
|
41 (b"\0" * 160, 1, 2, True), # valid_stereo
|
amine@400
|
42 (b"\0" * 113, 2, 1, False), # invalid_mono_sw_2
|
amine@400
|
43 (b"\0" * 113, 1, 2, False), # invalid_stereo_sw_1
|
amine@400
|
44 (b"\0" * 158, 2, 2, False), # invalid_stereo_sw_2
|
amine@400
|
45 ],
|
amine@400
|
46 ids=[
|
amine@400
|
47 "valid_mono",
|
amine@400
|
48 "valid_stereo",
|
amine@400
|
49 "invalid_mono_sw_2",
|
amine@400
|
50 "invalid_stereo_sw_1",
|
amine@400
|
51 "invalid_stereo_sw_2",
|
amine@400
|
52 ],
|
amine@400
|
53 )
|
amine@400
|
54 def test_check_audio_data(data, sample_width, channels, valid):
|
amine@400
|
55 if not valid:
|
amine@400
|
56 with pytest.raises(AudioParameterError):
|
amine@400
|
57 check_audio_data(data, sample_width, channels)
|
amine@400
|
58 else:
|
amine@400
|
59 assert check_audio_data(data, sample_width, channels) is None
|
amine@400
|
60
|
amine@400
|
61
|
amine@400
|
62 @pytest.mark.parametrize(
|
amine@400
|
63 "fmt, filename, expected",
|
amine@400
|
64 [
|
amine@400
|
65 ("wav", "filename.wav", "wav"), # extention_and_format_same
|
amine@400
|
66 ("wav", "filename.mp3", "wav"), # extention_and_format_different
|
amine@400
|
67 (None, "filename.wav", "wav"), # extention_no_format
|
amine@400
|
68 ("wav", "filename", "wav"), # format_no_extension
|
amine@400
|
69 (None, "filename", None), # no_format_no_extension
|
amine@400
|
70 ("wave", "filename", "wav"), # wave_as_wav
|
amine@400
|
71 (None, "filename.wave", "wav"), # wave_as_wav_extension
|
amine@400
|
72 ],
|
amine@400
|
73 ids=[
|
amine@400
|
74 "extention_and_format_same",
|
amine@400
|
75 "extention_and_format_different",
|
amine@400
|
76 "extention_no_format",
|
amine@400
|
77 "format_no_extension",
|
amine@400
|
78 "no_format_no_extension",
|
amine@400
|
79 "wave_as_wav",
|
amine@400
|
80 "wave_as_wav_extension",
|
amine@400
|
81 ],
|
amine@400
|
82 )
|
amine@400
|
83 def test_guess_audio_format(fmt, filename, expected):
|
amine@400
|
84 result = _guess_audio_format(fmt, filename)
|
amine@400
|
85 assert result == expected
|
amine@400
|
86
|
amine@400
|
87
|
amine@400
|
88 def test_get_audio_parameters_short_params():
|
amine@400
|
89 expected = (8000, 2, 1)
|
amine@400
|
90 params = dict(zip(("sr", "sw", "ch"), expected))
|
amine@400
|
91 result = _get_audio_parameters(params)
|
amine@400
|
92 assert result == expected
|
amine@400
|
93
|
amine@400
|
94
|
amine@400
|
95 def test_get_audio_parameters_long_params():
|
amine@400
|
96 expected = (8000, 2, 1)
|
amine@400
|
97 params = dict(
|
amine@400
|
98 zip(
|
amine@400
|
99 ("sampling_rate", "sample_width", "channels", "use_channel"),
|
amine@400
|
100 expected,
|
amine@400
|
101 )
|
amine@108
|
102 )
|
amine@400
|
103 result = _get_audio_parameters(params)
|
amine@400
|
104 assert result == expected
|
amine@108
|
105
|
amine@110
|
106
|
amine@400
|
107 def test_get_audio_parameters_long_params_shadow_short_ones():
|
amine@400
|
108 expected = (8000, 2, 1)
|
amine@400
|
109 params = dict(zip(("sampling_rate", "sample_width", "channels"), expected))
|
amine@400
|
110 params.update(dict(zip(("sr", "sw", "ch"), "xxx")))
|
amine@400
|
111 result = _get_audio_parameters(params)
|
amine@400
|
112 assert result == expected
|
amine@143
|
113
|
amine@145
|
114
|
amine@400
|
115 @pytest.mark.parametrize(
|
amine@400
|
116 "values",
|
amine@400
|
117 [
|
amine@400
|
118 ("x", 2, 1), # str_sampling_rate
|
amine@400
|
119 (-8000, 2, 1), # negative_sampling_rate
|
amine@400
|
120 (8000, "x", 1), # str_sample_width
|
amine@400
|
121 (8000, -2, 1), # negative_sample_width
|
amine@400
|
122 (8000, 2, "x"), # str_channels
|
amine@400
|
123 (8000, 2, -1), # negative_channels
|
amine@400
|
124 ],
|
amine@400
|
125 ids=[
|
amine@400
|
126 "str_sampling_rate",
|
amine@400
|
127 "negative_sampling_rate",
|
amine@400
|
128 "str_sample_width",
|
amine@400
|
129 "negative_sample_width",
|
amine@400
|
130 "str_channels",
|
amine@400
|
131 "negative_channels",
|
amine@400
|
132 ],
|
amine@400
|
133 )
|
amine@400
|
134 def test_get_audio_parameters_invalid(values):
|
amine@400
|
135 params = dict(zip(("sampling_rate", "sample_width", "channels"), values))
|
amine@400
|
136 with pytest.raises(AudioParameterError):
|
amine@400
|
137 _get_audio_parameters(params)
|
amine@145
|
138
|
amine@145
|
139
|
amine@400
|
140 @pytest.mark.parametrize(
|
amine@400
|
141 "filename, audio_format, funtion_name, kwargs",
|
amine@400
|
142 [
|
amine@400
|
143 (
|
amine@120
|
144 "audio",
|
amine@120
|
145 "raw",
|
amine@120
|
146 "_load_raw",
|
amine@120
|
147 AUDIO_PARAMS_SHORT,
|
amine@400
|
148 ), # raw_with_audio_format
|
amine@400
|
149 (
|
amine@120
|
150 "audio.raw",
|
amine@120
|
151 None,
|
amine@120
|
152 "_load_raw",
|
amine@120
|
153 AUDIO_PARAMS_SHORT,
|
amine@400
|
154 ), # raw_with_extension
|
amine@400
|
155 ("audio", "wave", "_load_wave", None), # wave_with_audio_format
|
amine@400
|
156 ("audio", "wave", "_load_wave", None), # wav_with_audio_format
|
amine@400
|
157 ("audio.wav", None, "_load_wave", None), # wav_with_extension
|
amine@400
|
158 (
|
amine@400
|
159 "audio.dat",
|
amine@400
|
160 "wav",
|
amine@400
|
161 "_load_wave",
|
amine@400
|
162 None,
|
amine@400
|
163 ), # format_and_extension_both_given_a
|
amine@400
|
164 (
|
amine@400
|
165 "audio.raw",
|
amine@400
|
166 "wave",
|
amine@400
|
167 "_load_wave",
|
amine@400
|
168 None,
|
amine@400
|
169 ), # format_and_extension_both_given_b
|
amine@400
|
170 ("audio", None, "_load_with_pydub", None), # no_format_nor_extension
|
amine@400
|
171 ("audio.ogg", None, "_load_with_pydub", None), # other_formats_ogg
|
amine@400
|
172 ("audio", "webm", "_load_with_pydub", None), # other_formats_webm
|
amine@400
|
173 ],
|
amine@400
|
174 ids=[
|
amine@400
|
175 "raw_with_audio_format",
|
amine@400
|
176 "raw_with_extension",
|
amine@400
|
177 "wave_with_audio_format",
|
amine@400
|
178 "wav_with_audio_format",
|
amine@400
|
179 "wav_with_extension",
|
amine@400
|
180 "format_and_extension_both_given_a",
|
amine@400
|
181 "format_and_extension_both_given_b",
|
amine@400
|
182 "no_format_nor_extension",
|
amine@400
|
183 "other_formats_ogg",
|
amine@400
|
184 "other_formats_webm",
|
amine@400
|
185 ],
|
amine@400
|
186 )
|
amine@400
|
187 def test_from_file(filename, audio_format, funtion_name, kwargs):
|
amine@400
|
188 funtion_name = "auditok.io." + funtion_name
|
amine@400
|
189 if kwargs is None:
|
amine@400
|
190 kwargs = {}
|
amine@400
|
191 with patch(funtion_name) as patch_function:
|
amine@400
|
192 from_file(filename, audio_format, **kwargs)
|
amine@400
|
193 assert patch_function.called
|
amine@400
|
194
|
amine@400
|
195
|
amine@400
|
196 def test_from_file_large_file_raw():
|
amine@400
|
197 filename = "tests/data/test_16KHZ_mono_400Hz.raw"
|
amine@400
|
198 audio_source = from_file(
|
amine@400
|
199 filename,
|
amine@400
|
200 large_file=True,
|
amine@400
|
201 sampling_rate=16000,
|
amine@400
|
202 sample_width=2,
|
amine@400
|
203 channels=1,
|
amine@120
|
204 )
|
amine@400
|
205 assert isinstance(audio_source, RawAudioSource)
|
amine@120
|
206
|
amine@162
|
207
|
amine@400
|
208 def test_from_file_large_file_wave():
|
amine@400
|
209 filename = "tests/data/test_16KHZ_mono_400Hz.wav"
|
amine@400
|
210 audio_source = from_file(filename, large_file=True)
|
amine@400
|
211 assert isinstance(audio_source, WaveAudioSource)
|
amine@163
|
212
|
amine@162
|
213
|
amine@400
|
214 def test_from_file_large_file_compressed():
|
amine@400
|
215 filename = "tests/data/test_16KHZ_mono_400Hz.ogg"
|
amine@400
|
216 with pytest.raises(AudioIOError):
|
amine@400
|
217 from_file(filename, large_file=True)
|
amine@137
|
218
|
amine@121
|
219
|
amine@400
|
220 @pytest.mark.parametrize(
|
amine@400
|
221 "missing_param",
|
amine@400
|
222 [
|
amine@400
|
223 "sr", # missing_sampling_rate
|
amine@400
|
224 "sw", # missing_sample_width
|
amine@400
|
225 "ch", # missing_channels
|
amine@400
|
226 ],
|
amine@400
|
227 ids=["missing_sampling_rate", "missing_sample_width", "missing_channels"],
|
amine@400
|
228 )
|
amine@400
|
229 def test_from_file_missing_audio_param(missing_param):
|
amine@400
|
230 with pytest.raises(AudioParameterError):
|
amine@400
|
231 params = AUDIO_PARAMS_SHORT.copy()
|
amine@400
|
232 del params[missing_param]
|
amine@400
|
233 from_file("audio", audio_format="raw", **params)
|
amine@240
|
234
|
amine@400
|
235
|
amine@400
|
236 def test_from_file_no_pydub():
|
amine@400
|
237 with patch("auditok.io._WITH_PYDUB", False):
|
amine@400
|
238 with pytest.raises(AudioIOError):
|
amine@400
|
239 from_file("audio", "mp3")
|
amine@400
|
240
|
amine@400
|
241
|
amine@400
|
242 @pytest.mark.parametrize(
|
amine@400
|
243 "audio_format, function",
|
amine@400
|
244 [
|
amine@400
|
245 ("ogg", "from_ogg"), # ogg_first_channel
|
amine@400
|
246 ("ogg", "from_ogg"), # ogg_second_channel
|
amine@400
|
247 ("ogg", "from_ogg"), # ogg_mix
|
amine@400
|
248 ("ogg", "from_ogg"), # ogg_default
|
amine@400
|
249 ("mp3", "from_mp3"), # mp3_left_channel
|
amine@400
|
250 ("mp3", "from_mp3"), # mp3_right_channel
|
amine@400
|
251 ("flac", "from_file"), # flac_first_channel
|
amine@400
|
252 ("flac", "from_file"), # flac_second_channel
|
amine@400
|
253 ("flv", "from_flv"), # flv_left_channel
|
amine@400
|
254 ("webm", "from_file"), # webm_right_channel
|
amine@400
|
255 ],
|
amine@400
|
256 ids=[
|
amine@400
|
257 "ogg_first_channel",
|
amine@400
|
258 "ogg_second_channel",
|
amine@400
|
259 "ogg_mix",
|
amine@400
|
260 "ogg_default",
|
amine@400
|
261 "mp3_left_channel",
|
amine@400
|
262 "mp3_right_channel",
|
amine@400
|
263 "flac_first_channel",
|
amine@400
|
264 "flac_second_channel",
|
amine@400
|
265 "flv_left_channel",
|
amine@400
|
266 "webm_right_channel",
|
amine@400
|
267 ],
|
amine@400
|
268 )
|
amine@400
|
269 @patch("auditok.io._WITH_PYDUB", True)
|
amine@400
|
270 @patch("auditok.io.BufferAudioSource")
|
amine@400
|
271 def test_from_file_multichannel_audio_compressed(
|
amine@400
|
272 mock_buffer_audio_source, audio_format, function
|
amine@400
|
273 ):
|
amine@400
|
274 filename = "audio.{}".format(audio_format)
|
amine@400
|
275 segment_mock = Mock()
|
amine@400
|
276 segment_mock.sample_width = 2
|
amine@400
|
277 segment_mock.channels = 2
|
amine@400
|
278 segment_mock._data = b"abcd"
|
amine@400
|
279 with patch("auditok.io.AudioSegment.{}".format(function)) as open_func:
|
amine@400
|
280 open_func.return_value = segment_mock
|
amine@400
|
281 from_file(filename)
|
amine@400
|
282 assert open_func.called
|
amine@400
|
283
|
amine@400
|
284
|
amine@400
|
285 @pytest.mark.parametrize(
|
amine@400
|
286 "file_id, frequencies, large_file",
|
amine@400
|
287 [
|
amine@400
|
288 ("mono_400", (400,), False), # mono
|
amine@400
|
289 ("3channel_400-800-1600", (400, 800, 1600), False), # three_channel
|
amine@400
|
290 ("mono_400", (400,), True), # mono_large_file
|
amine@400
|
291 (
|
amine@313
|
292 "3channel_400-800-1600",
|
amine@313
|
293 (400, 800, 1600),
|
amine@313
|
294 True,
|
amine@400
|
295 ), # three_channel_large_file
|
amine@400
|
296 ],
|
amine@400
|
297 ids=[
|
amine@400
|
298 "mono",
|
amine@400
|
299 "three_channel",
|
amine@400
|
300 "mono_large_file",
|
amine@400
|
301 "three_channel_large_file",
|
amine@400
|
302 ],
|
amine@400
|
303 )
|
amine@400
|
304 def test_load_raw(file_id, frequencies, large_file):
|
amine@400
|
305 filename = "tests/data/test_16KHZ_{}Hz.raw".format(file_id)
|
amine@400
|
306 audio_source = _load_raw(
|
amine@400
|
307 filename, 16000, 2, len(frequencies), large_file=large_file
|
amine@126
|
308 )
|
amine@400
|
309 audio_source.open()
|
amine@400
|
310 data = audio_source.read(-1)
|
amine@400
|
311 audio_source.close()
|
amine@400
|
312 expected_class = RawAudioSource if large_file else BufferAudioSource
|
amine@400
|
313 assert isinstance(audio_source, expected_class)
|
amine@400
|
314 assert audio_source.sampling_rate == 16000
|
amine@400
|
315 assert audio_source.sample_width == 2
|
amine@400
|
316 assert audio_source.channels == len(frequencies)
|
amine@400
|
317 mono_channels = [PURE_TONE_DICT[freq] for freq in frequencies]
|
amine@400
|
318 fmt = FORMAT[audio_source.sample_width]
|
amine@400
|
319 expected = array(fmt, _sample_generator(*mono_channels)).tobytes()
|
amine@400
|
320 assert data == expected
|
amine@126
|
321
|
amine@128
|
322
|
amine@400
|
323 @pytest.mark.parametrize(
|
amine@400
|
324 "missing_param",
|
amine@400
|
325 [
|
amine@400
|
326 "sr", # missing_sampling_rate
|
amine@400
|
327 "sw", # missing_sample_width
|
amine@400
|
328 "ch", # missing_channels
|
amine@400
|
329 ],
|
amine@400
|
330 ids=["missing_sampling_rate", "missing_sample_width", "missing_channels"],
|
amine@400
|
331 )
|
amine@400
|
332 def test_load_raw_missing_audio_param(missing_param):
|
amine@400
|
333 with pytest.raises(AudioParameterError):
|
amine@400
|
334 params = AUDIO_PARAMS_SHORT.copy()
|
amine@400
|
335 del params[missing_param]
|
amine@400
|
336 srate, swidth, channels, _ = _get_audio_parameters(params)
|
amine@400
|
337 _load_raw("audio", srate, swidth, channels)
|
amine@400
|
338
|
amine@400
|
339
|
amine@400
|
340 @pytest.mark.parametrize(
|
amine@400
|
341 "file_id, frequencies, large_file",
|
amine@400
|
342 [
|
amine@400
|
343 ("mono_400", (400,), False), # mono
|
amine@400
|
344 ("3channel_400-800-1600", (400, 800, 1600), False), # three_channel
|
amine@400
|
345 ("mono_400", (400,), True), # mono_large_file
|
amine@400
|
346 (
|
amine@313
|
347 "3channel_400-800-1600",
|
amine@313
|
348 (400, 800, 1600),
|
amine@313
|
349 True,
|
amine@400
|
350 ), # three_channel_large_file
|
amine@400
|
351 ],
|
amine@400
|
352 ids=[
|
amine@400
|
353 "mono",
|
amine@400
|
354 "three_channel",
|
amine@400
|
355 "mono_large_file",
|
amine@400
|
356 "three_channel_large_file",
|
amine@400
|
357 ],
|
amine@400
|
358 )
|
amine@400
|
359 def test_load_wave(file_id, frequencies, large_file):
|
amine@400
|
360 filename = "tests/data/test_16KHZ_{}Hz.wav".format(file_id)
|
amine@400
|
361 audio_source = _load_wave(filename, large_file=large_file)
|
amine@400
|
362 audio_source.open()
|
amine@400
|
363 data = audio_source.read(-1)
|
amine@400
|
364 audio_source.close()
|
amine@400
|
365 expected_class = WaveAudioSource if large_file else BufferAudioSource
|
amine@400
|
366 assert isinstance(audio_source, expected_class)
|
amine@400
|
367 assert audio_source.sampling_rate == 16000
|
amine@400
|
368 assert audio_source.sample_width == 2
|
amine@400
|
369 assert audio_source.channels == len(frequencies)
|
amine@400
|
370 mono_channels = [PURE_TONE_DICT[freq] for freq in frequencies]
|
amine@400
|
371 fmt = FORMAT[audio_source.sample_width]
|
amine@400
|
372 expected = array(fmt, _sample_generator(*mono_channels)).tobytes()
|
amine@400
|
373 assert data == expected
|
amine@400
|
374
|
amine@400
|
375
|
amine@400
|
376 @pytest.mark.parametrize(
|
amine@400
|
377 "audio_format, channels, function",
|
amine@400
|
378 [
|
amine@400
|
379 ("ogg", 2, "from_ogg"), # ogg_default_first_channel
|
amine@400
|
380 ("ogg", 1, "from_ogg"), # ogg_first_channel
|
amine@400
|
381 ("ogg", 2, "from_ogg"), # ogg_second_channel
|
amine@400
|
382 ("ogg", 3, "from_ogg"), # ogg_mix_channels
|
amine@400
|
383 ("mp3", 1, "from_mp3"), # mp3_left_channel
|
amine@400
|
384 ("mp3", 2, "from_mp3"), # mp3_right_channel
|
amine@400
|
385 ("mp3", 3, "from_mp3"), # mp3_mix_channels
|
amine@400
|
386 ("flac", 2, "from_file"), # flac_first_channel
|
amine@400
|
387 ("flac", 2, "from_file"), # flac_second_channel
|
amine@400
|
388 ("flv", 1, "from_flv"), # flv_left_channel
|
amine@400
|
389 ("webm", 2, "from_file"), # webm_right_channel
|
amine@400
|
390 ("webm", 4, "from_file"), # webm_mix_channels
|
amine@400
|
391 ],
|
amine@400
|
392 ids=[
|
amine@400
|
393 "ogg_default_first_channel",
|
amine@400
|
394 "ogg_first_channel",
|
amine@400
|
395 "ogg_second_channel",
|
amine@400
|
396 "ogg_mix_channels",
|
amine@400
|
397 "mp3_left_channel",
|
amine@400
|
398 "mp3_right_channel",
|
amine@400
|
399 "mp3_mix_channels",
|
amine@400
|
400 "flac_first_channel",
|
amine@400
|
401 "flac_second_channel",
|
amine@400
|
402 "flv_left_channel",
|
amine@400
|
403 "webm_right_channel",
|
amine@400
|
404 "webm_mix_channels",
|
amine@400
|
405 ],
|
amine@400
|
406 )
|
amine@400
|
407 @patch("auditok.io._WITH_PYDUB", True)
|
amine@400
|
408 @patch("auditok.io.BufferAudioSource")
|
amine@400
|
409 def test_load_with_pydub(
|
amine@400
|
410 mock_buffer_audio_source, audio_format, channels, function
|
amine@400
|
411 ):
|
amine@400
|
412 filename = "audio.{}".format(audio_format)
|
amine@400
|
413 segment_mock = Mock()
|
amine@400
|
414 segment_mock.sample_width = 2
|
amine@400
|
415 segment_mock.channels = channels
|
amine@400
|
416 segment_mock._data = b"abcdefgh"
|
amine@400
|
417 with patch("auditok.io.AudioSegment.{}".format(function)) as open_func:
|
amine@400
|
418 open_func.return_value = segment_mock
|
amine@400
|
419 _load_with_pydub(filename, audio_format)
|
amine@400
|
420 assert open_func.called
|
amine@400
|
421
|
amine@400
|
422
|
amine@400
|
423 @pytest.mark.parametrize(
|
amine@400
|
424 "filename, frequencies",
|
amine@400
|
425 [
|
amine@400
|
426 ("mono_400Hz.raw", (400,)), # mono
|
amine@400
|
427 ("3channel_400-800-1600Hz.raw", (400, 800, 1600)), # three_channel
|
amine@400
|
428 ],
|
amine@400
|
429 ids=["mono", "three_channel"],
|
amine@400
|
430 )
|
amine@400
|
431 def test_save_raw(filename, frequencies):
|
amine@400
|
432 filename = "tests/data/test_16KHZ_{}".format(filename)
|
amine@400
|
433 sample_width = 2
|
amine@400
|
434 fmt = FORMAT[sample_width]
|
amine@400
|
435 mono_channels = [PURE_TONE_DICT[freq] for freq in frequencies]
|
amine@400
|
436 data = array(fmt, _sample_generator(*mono_channels)).tobytes()
|
amine@400
|
437 tmpfile = NamedTemporaryFile()
|
amine@400
|
438 _save_raw(data, tmpfile.name)
|
amine@400
|
439 assert filecmp.cmp(tmpfile.name, filename, shallow=False)
|
amine@400
|
440
|
amine@400
|
441
|
amine@400
|
442 @pytest.mark.parametrize(
|
amine@400
|
443 "filename, frequencies",
|
amine@400
|
444 [
|
amine@400
|
445 ("mono_400Hz.wav", (400,)), # mono
|
amine@400
|
446 ("3channel_400-800-1600Hz.wav", (400, 800, 1600)), # three_channel
|
amine@400
|
447 ],
|
amine@400
|
448 ids=["mono", "three_channel"],
|
amine@400
|
449 )
|
amine@400
|
450 def test_save_wave(filename, frequencies):
|
amine@400
|
451 filename = "tests/data/test_16KHZ_{}".format(filename)
|
amine@400
|
452 sampling_rate = 16000
|
amine@400
|
453 sample_width = 2
|
amine@400
|
454 channels = len(frequencies)
|
amine@400
|
455 fmt = FORMAT[sample_width]
|
amine@400
|
456 mono_channels = [PURE_TONE_DICT[freq] for freq in frequencies]
|
amine@400
|
457 data = array(fmt, _sample_generator(*mono_channels)).tobytes()
|
amine@400
|
458 tmpfile = NamedTemporaryFile()
|
amine@400
|
459 _save_wave(data, tmpfile.name, sampling_rate, sample_width, channels)
|
amine@400
|
460 assert filecmp.cmp(tmpfile.name, filename, shallow=False)
|
amine@400
|
461
|
amine@400
|
462
|
amine@400
|
463 @pytest.mark.parametrize(
|
amine@400
|
464 "missing_param",
|
amine@400
|
465 [
|
amine@400
|
466 "sr", # missing_sampling_rate
|
amine@400
|
467 "sw", # missing_sample_width
|
amine@400
|
468 "ch", # missing_channels
|
amine@400
|
469 ],
|
amine@400
|
470 ids=["missing_sampling_rate", "missing_sample_width", "missing_channels"],
|
amine@400
|
471 )
|
amine@400
|
472 def test_save_wave_missing_audio_param(missing_param):
|
amine@400
|
473 with pytest.raises(AudioParameterError):
|
amine@400
|
474 params = AUDIO_PARAMS_SHORT.copy()
|
amine@400
|
475 del params[missing_param]
|
amine@400
|
476 srate, swidth, channels, _ = _get_audio_parameters(params)
|
amine@400
|
477 _save_wave(b"\0\0", "audio", srate, swidth, channels)
|
amine@400
|
478
|
amine@400
|
479
|
amine@400
|
480 def test_save_with_pydub():
|
amine@400
|
481 with patch("auditok.io.AudioSegment.export") as export:
|
amine@400
|
482 tmpdir = TemporaryDirectory()
|
amine@400
|
483 filename = os.path.join(tmpdir.name, "audio.ogg")
|
amine@400
|
484 _save_with_pydub(b"\0\0", filename, "ogg", 16000, 2, 1)
|
amine@400
|
485 assert export.called
|
amine@400
|
486 tmpdir.cleanup()
|
amine@400
|
487
|
amine@400
|
488
|
amine@400
|
489 @pytest.mark.parametrize(
|
amine@400
|
490 "filename, audio_format",
|
amine@400
|
491 [
|
amine@400
|
492 ("audio", "raw"), # raw_with_audio_format
|
amine@400
|
493 ("audio.raw", None), # raw_with_extension
|
amine@400
|
494 ("audio.mp3", "raw"), # raw_with_audio_format_and_extension
|
amine@400
|
495 ("audio", None), # raw_no_audio_format_nor_extension
|
amine@400
|
496 ],
|
amine@400
|
497 ids=[
|
amine@400
|
498 "raw_with_audio_format",
|
amine@400
|
499 "raw_with_extension",
|
amine@400
|
500 "raw_with_audio_format_and_extension",
|
amine@400
|
501 "raw_no_audio_format_nor_extension",
|
amine@400
|
502 ],
|
amine@400
|
503 )
|
amine@400
|
504 def test_to_file_raw(filename, audio_format):
|
amine@400
|
505 exp_filename = "tests/data/test_16KHZ_mono_400Hz.raw"
|
amine@400
|
506 tmpdir = TemporaryDirectory()
|
amine@400
|
507 filename = os.path.join(tmpdir.name, filename)
|
amine@400
|
508 data = PURE_TONE_DICT[400].tobytes()
|
amine@400
|
509 to_file(data, filename, audio_format=audio_format)
|
amine@400
|
510 assert filecmp.cmp(filename, exp_filename, shallow=False)
|
amine@400
|
511 tmpdir.cleanup()
|
amine@400
|
512
|
amine@400
|
513
|
amine@400
|
514 @pytest.mark.parametrize(
|
amine@400
|
515 "filename, audio_format",
|
amine@400
|
516 [
|
amine@400
|
517 ("audio", "wav"), # wav_with_audio_format
|
amine@400
|
518 ("audio.wav", None), # wav_with_extension
|
amine@400
|
519 ("audio.mp3", "wav"), # wav_with_audio_format_and_extension
|
amine@400
|
520 ("audio", "wave"), # wave_with_audio_format
|
amine@400
|
521 ("audio.wave", None), # wave_with_extension
|
amine@400
|
522 ("audio.mp3", "wave"), # wave_with_audio_format_and_extension
|
amine@400
|
523 ],
|
amine@400
|
524 ids=[
|
amine@400
|
525 "wav_with_audio_format",
|
amine@400
|
526 "wav_with_extension",
|
amine@400
|
527 "wav_with_audio_format_and_extension",
|
amine@400
|
528 "wave_with_audio_format",
|
amine@400
|
529 "wave_with_extension",
|
amine@400
|
530 "wave_with_audio_format_and_extension",
|
amine@400
|
531 ],
|
amine@400
|
532 )
|
amine@400
|
533 def test_to_file_wave(filename, audio_format):
|
amine@400
|
534 exp_filename = "tests/data/test_16KHZ_mono_400Hz.wav"
|
amine@400
|
535 tmpdir = TemporaryDirectory()
|
amine@400
|
536 filename = os.path.join(tmpdir.name, filename)
|
amine@400
|
537 data = PURE_TONE_DICT[400].tobytes()
|
amine@400
|
538 to_file(
|
amine@400
|
539 data,
|
amine@400
|
540 filename,
|
amine@400
|
541 audio_format=audio_format,
|
amine@400
|
542 sampling_rate=16000,
|
amine@400
|
543 sample_width=2,
|
amine@400
|
544 channels=1,
|
amine@129
|
545 )
|
amine@400
|
546 assert filecmp.cmp(filename, exp_filename, shallow=False)
|
amine@400
|
547 tmpdir.cleanup()
|
amine@129
|
548
|
amine@240
|
549
|
amine@400
|
550 @pytest.mark.parametrize(
|
amine@400
|
551 "missing_param",
|
amine@400
|
552 [
|
amine@400
|
553 "sr", # missing_sampling_rate
|
amine@400
|
554 "sw", # missing_sample_width
|
amine@400
|
555 "ch", # missing_channels
|
amine@400
|
556 ],
|
amine@400
|
557 ids=["missing_sampling_rate", "missing_sample_width", "missing_channels"],
|
amine@400
|
558 )
|
amine@400
|
559 def test_to_file_missing_audio_param(missing_param):
|
amine@400
|
560 params = AUDIO_PARAMS_SHORT.copy()
|
amine@400
|
561 del params[missing_param]
|
amine@400
|
562 with pytest.raises(AudioParameterError):
|
amine@400
|
563 to_file(b"\0\0", "audio", audio_format="wav", **params)
|
amine@400
|
564 with pytest.raises(AudioParameterError):
|
amine@400
|
565 to_file(b"\0\0", "audio", audio_format="mp3", **params)
|
amine@132
|
566
|
amine@132
|
567
|
amine@400
|
568 def test_to_file_no_pydub():
|
amine@400
|
569 with patch("auditok.io._WITH_PYDUB", False):
|
amine@400
|
570 with pytest.raises(AudioIOError):
|
amine@400
|
571 to_file("audio", b"", "mp3")
|
amine@133
|
572
|
amine@141
|
573
|
amine@400
|
574 @pytest.mark.parametrize(
|
amine@400
|
575 "filename, audio_format",
|
amine@400
|
576 [
|
amine@400
|
577 ("audio.ogg", None), # ogg_with_extension
|
amine@400
|
578 ("audio", "ogg"), # ogg_with_audio_format
|
amine@400
|
579 ("audio.wav", "ogg"), # ogg_format_with_wrong_extension
|
amine@400
|
580 ],
|
amine@400
|
581 ids=[
|
amine@400
|
582 "ogg_with_extension",
|
amine@400
|
583 "ogg_with_audio_format",
|
amine@400
|
584 "ogg_format_with_wrong_extension",
|
amine@400
|
585 ],
|
amine@400
|
586 )
|
amine@400
|
587 @patch("auditok.io._WITH_PYDUB", True)
|
amine@400
|
588 def test_to_file_compressed(filename, audio_format):
|
amine@400
|
589 with patch("auditok.io.AudioSegment.export") as export:
|
amine@133
|
590 tmpdir = TemporaryDirectory()
|
amine@133
|
591 filename = os.path.join(tmpdir.name, filename)
|
amine@400
|
592 to_file(b"\0\0", filename, audio_format, **AUDIO_PARAMS_SHORT)
|
amine@400
|
593 assert export.called
|
amine@133
|
594 tmpdir.cleanup()
|
amine@134
|
595
|
amine@138
|
596
|
amine@400
|
597 @pytest.mark.parametrize(
|
amine@400
|
598 "input, expected_type, extra_args",
|
amine@400
|
599 [
|
amine@400
|
600 (
|
amine@190
|
601 "tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@190
|
602 BufferAudioSource,
|
amine@400
|
603 None,
|
amine@400
|
604 ), # string_wave
|
amine@400
|
605 (
|
amine@190
|
606 "tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@190
|
607 WaveAudioSource,
|
amine@190
|
608 {"large_file": True},
|
amine@400
|
609 ), # string_wave_large_file
|
amine@400
|
610 ("-", StdinAudioSource, None), # stdin
|
amine@400
|
611 (
|
amine@400
|
612 "tests/data/test_16KHZ_mono_400Hz.raw",
|
amine@400
|
613 BufferAudioSource,
|
amine@400
|
614 None,
|
amine@400
|
615 ), # string_raw
|
amine@400
|
616 (
|
amine@190
|
617 "tests/data/test_16KHZ_mono_400Hz.raw",
|
amine@190
|
618 RawAudioSource,
|
amine@190
|
619 {"large_file": True},
|
amine@400
|
620 ), # string_raw_large_file
|
amine@400
|
621 (b"0" * 8000, BufferAudioSource, None), # bytes_
|
amine@400
|
622 ],
|
amine@400
|
623 ids=[
|
amine@400
|
624 "string_wave",
|
amine@400
|
625 "string_wave_large_file",
|
amine@400
|
626 "stdin",
|
amine@400
|
627 "string_raw",
|
amine@400
|
628 "string_raw_large_file",
|
amine@400
|
629 "bytes_",
|
amine@400
|
630 ],
|
amine@400
|
631 )
|
amine@400
|
632 def test_get_audio_source(input, expected_type, extra_args):
|
amine@400
|
633 kwargs = {"sampling_rate": 16000, "sample_width": 2, "channels": 1}
|
amine@400
|
634 if extra_args is not None:
|
amine@400
|
635 kwargs.update(extra_args)
|
amine@400
|
636 audio_source = get_audio_source(input, **kwargs)
|
amine@400
|
637 assert isinstance(audio_source, expected_type)
|
amine@403
|
638 assert audio_source.sampling_rate == 16000, (
|
amine@403
|
639 "Unexpected sampling rate: audio_source.sampling_rate = "
|
amine@403
|
640 + f"{audio_source.sampling_rate} instead of 16000"
|
amine@403
|
641 )
|
amine@403
|
642 assert audio_source.sr == 16000, (
|
amine@403
|
643 "Unexpected sampling rate: audio_source.sr = "
|
amine@403
|
644 + f"{audio_source.sr} instead of 16000"
|
amine@403
|
645 )
|
amine@403
|
646 assert audio_source.sample_width == 2, (
|
amine@403
|
647 "Unexpected sample width: audio_source.sample_width = "
|
amine@403
|
648 + f"{audio_source.sample_width} instead of 2"
|
amine@403
|
649 )
|
amine@403
|
650 assert audio_source.sw == 2, (
|
amine@403
|
651 "Unexpected sample width: audio_source.sw = "
|
amine@403
|
652 + f"{audio_source.sw} instead of 2"
|
amine@403
|
653 )
|
amine@403
|
654 assert audio_source.channels == 1, (
|
amine@403
|
655 "Unexpected number of channels: audio_source.channels = "
|
amine@403
|
656 + f"{audio_source.channels} instead of 1"
|
amine@403
|
657 )
|
amine@403
|
658 assert audio_source.ch == 1, (
|
amine@403
|
659 "Unexpected number of channels: audio_source.ch = "
|
amine@403
|
660 + f"{audio_source.ch} instead of 1"
|
amine@403
|
661 )
|
amine@403
|
662
|
amine@403
|
663
|
amine@403
|
664 def test_get_audio_source_alias_prams():
|
amine@403
|
665 audio_source = get_audio_source(b"0" * 1600, sr=16000, sw=2, ch=1)
|
amine@403
|
666 assert audio_source.sampling_rate == 16000, (
|
amine@403
|
667 "Unexpected sampling rate: audio_source.sampling_rate = "
|
amine@403
|
668 + f"{audio_source.sampling_rate} instead of 16000"
|
amine@403
|
669 )
|
amine@403
|
670 assert audio_source.sr == 16000, (
|
amine@403
|
671 "Unexpected sampling rate: audio_source.sr = "
|
amine@403
|
672 + f"{audio_source.sr} instead of 16000"
|
amine@403
|
673 )
|
amine@403
|
674 assert audio_source.sample_width == 2, (
|
amine@403
|
675 "Unexpected sample width: audio_source.sample_width = "
|
amine@403
|
676 + f"{audio_source.sample_width} instead of 2"
|
amine@403
|
677 )
|
amine@403
|
678 assert audio_source.sw == 2, (
|
amine@403
|
679 "Unexpected sample width: audio_source.sw = "
|
amine@403
|
680 + f"{audio_source.sw} instead of 2"
|
amine@403
|
681 )
|
amine@403
|
682 assert audio_source.channels == 1, (
|
amine@403
|
683 "Unexpected number of channels: audio_source.channels = "
|
amine@403
|
684 + f"{audio_source.channels} instead of 1"
|
amine@403
|
685 )
|
amine@403
|
686 assert audio_source.ch == 1, (
|
amine@403
|
687 "Unexpected number of channels: audio_source.ch = "
|
amine@403
|
688 + f"{audio_source.ch} instead of 1"
|
amine@403
|
689 )
|