annotate tests/test_core.py @ 416:14efef6f4bae

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