annotate tests/test_core.py @ 328:85b4ba237e0f

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