annotate tests/test_core.py @ 455:7dae98b84cdd tip master

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