annotate tests/test_core.py @ 338:f424ac9193b7

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