annotate tests/test_AudioReader.py @ 330:9665dc53c394

Rename test_AudioDataSource.py as test_AudioReader.py and refactor it
author Amine Sehili <amine.sehili@gmail.com>
date Wed, 23 Oct 2019 21:24:33 +0100
parents
children 8220dfaa03c6
rev   line source
amine@330 1 """
amine@330 2 @author: Amine Sehili <amine.sehili@gmail.com>
amine@330 3 September 2015
amine@330 4
amine@330 5 """
amine@330 6
amine@330 7 import unittest
amine@330 8 from functools import partial
amine@330 9 import sys
amine@330 10 import wave
amine@330 11 from genty import genty, genty_dataset
amine@330 12 from auditok import (
amine@330 13 dataset,
amine@330 14 ADSFactory,
amine@330 15 AudioDataSource,
amine@330 16 AudioReader,
amine@330 17 Recorder,
amine@330 18 BufferAudioSource,
amine@330 19 WaveAudioSource,
amine@330 20 DuplicateArgument,
amine@330 21 )
amine@330 22
amine@330 23
amine@330 24 class TestADSFactoryFileAudioSource(unittest.TestCase):
amine@330 25 def setUp(self):
amine@330 26 self.audio_source = WaveAudioSource(
amine@330 27 filename=dataset.one_to_six_arabic_16000_mono_bc_noise
amine@330 28 )
amine@330 29
amine@330 30 def test_ADS_type(self):
amine@330 31
amine@330 32 ads = ADSFactory.ads(audio_source=self.audio_source)
amine@330 33
amine@330 34 err_msg = "wrong type for ads object, expected: 'AudioDataSource', "
amine@330 35 err_msg += "found: {0}"
amine@330 36 self.assertIsInstance(
amine@330 37 ads, AudioDataSource, err_msg.format(type(ads)),
amine@330 38 )
amine@330 39
amine@330 40 def test_default_block_size(self):
amine@330 41 ads = ADSFactory.ads(audio_source=self.audio_source)
amine@330 42 size = ads.block_size
amine@330 43 self.assertEqual(
amine@330 44 size,
amine@330 45 160,
amine@330 46 "Wrong default block_size, expected: 160, found: {0}".format(size),
amine@330 47 )
amine@330 48
amine@330 49 def test_block_size(self):
amine@330 50 ads = ADSFactory.ads(audio_source=self.audio_source, block_size=512)
amine@330 51 size = ads.block_size
amine@330 52 self.assertEqual(
amine@330 53 size,
amine@330 54 512,
amine@330 55 "Wrong block_size, expected: 512, found: {0}".format(size),
amine@330 56 )
amine@330 57
amine@330 58 # with alias keyword
amine@330 59 ads = ADSFactory.ads(audio_source=self.audio_source, bs=160)
amine@330 60 size = ads.block_size
amine@330 61 self.assertEqual(
amine@330 62 size,
amine@330 63 160,
amine@330 64 "Wrong block_size, expected: 160, found: {0}".format(size),
amine@330 65 )
amine@330 66
amine@330 67 def test_block_duration(self):
amine@330 68
amine@330 69 ads = ADSFactory.ads(
amine@330 70 audio_source=self.audio_source, block_dur=0.01
amine@330 71 ) # 10 ms
amine@330 72 size = ads.block_size
amine@330 73 self.assertEqual(
amine@330 74 size,
amine@330 75 160,
amine@330 76 "Wrong block_size, expected: 160, found: {0}".format(size),
amine@330 77 )
amine@330 78
amine@330 79 # with alias keyword
amine@330 80 ads = ADSFactory.ads(audio_source=self.audio_source, bd=0.025) # 25 ms
amine@330 81 size = ads.block_size
amine@330 82 self.assertEqual(
amine@330 83 size,
amine@330 84 400,
amine@330 85 "Wrong block_size, expected: 400, found: {0}".format(size),
amine@330 86 )
amine@330 87
amine@330 88 def test_hop_duration(self):
amine@330 89
amine@330 90 ads = ADSFactory.ads(
amine@330 91 audio_source=self.audio_source, block_dur=0.02, hop_dur=0.01
amine@330 92 ) # 10 ms
amine@330 93 size = ads.hop_size
amine@330 94 self.assertEqual(
amine@330 95 size, 160, "Wrong hop_size, expected: 160, found: {0}".format(size)
amine@330 96 )
amine@330 97
amine@330 98 # with alias keyword
amine@330 99 ads = ADSFactory.ads(
amine@330 100 audio_source=self.audio_source, bd=0.025, hop_dur=0.015
amine@330 101 ) # 15 ms
amine@330 102 size = ads.hop_size
amine@330 103 self.assertEqual(
amine@330 104 size,
amine@330 105 240,
amine@330 106 "Wrong block_size, expected: 240, found: {0}".format(size),
amine@330 107 )
amine@330 108
amine@330 109 def test_sampling_rate(self):
amine@330 110 ads = ADSFactory.ads(audio_source=self.audio_source)
amine@330 111
amine@330 112 srate = ads.sampling_rate
amine@330 113 self.assertEqual(
amine@330 114 srate,
amine@330 115 16000,
amine@330 116 "Wrong sampling rate, expected: 16000, found: {0}".format(srate),
amine@330 117 )
amine@330 118
amine@330 119 def test_sample_width(self):
amine@330 120 ads = ADSFactory.ads(audio_source=self.audio_source)
amine@330 121
amine@330 122 swidth = ads.sample_width
amine@330 123 self.assertEqual(
amine@330 124 swidth,
amine@330 125 2,
amine@330 126 "Wrong sample width, expected: 2, found: {0}".format(swidth),
amine@330 127 )
amine@330 128
amine@330 129 def test_channels(self):
amine@330 130 ads = ADSFactory.ads(audio_source=self.audio_source)
amine@330 131
amine@330 132 channels = ads.channels
amine@330 133 self.assertEqual(
amine@330 134 channels,
amine@330 135 1,
amine@330 136 "Wrong number of channels, expected: 1, found: {0}".format(
amine@330 137 channels
amine@330 138 ),
amine@330 139 )
amine@330 140
amine@330 141 def test_read(self):
amine@330 142 ads = ADSFactory.ads(audio_source=self.audio_source, block_size=256)
amine@330 143
amine@330 144 ads.open()
amine@330 145 ads_data = ads.read()
amine@330 146 ads.close()
amine@330 147
amine@330 148 audio_source = WaveAudioSource(
amine@330 149 filename=dataset.one_to_six_arabic_16000_mono_bc_noise
amine@330 150 )
amine@330 151 audio_source.open()
amine@330 152 audio_source_data = audio_source.read(256)
amine@330 153 audio_source.close()
amine@330 154
amine@330 155 self.assertEqual(
amine@330 156 ads_data, audio_source_data, "Unexpected data read from ads"
amine@330 157 )
amine@330 158
amine@330 159 def test_Limiter_Deco_read(self):
amine@330 160 # read a maximum of 0.75 seconds from audio source
amine@330 161 ads = ADSFactory.ads(audio_source=self.audio_source, max_time=0.75)
amine@330 162
amine@330 163 ads_data = []
amine@330 164 ads.open()
amine@330 165 while True:
amine@330 166 block = ads.read()
amine@330 167 if block is None:
amine@330 168 break
amine@330 169 ads_data.append(block)
amine@330 170 ads.close()
amine@330 171 ads_data = b"".join(ads_data)
amine@330 172
amine@330 173 audio_source = WaveAudioSource(
amine@330 174 filename=dataset.one_to_six_arabic_16000_mono_bc_noise
amine@330 175 )
amine@330 176 audio_source.open()
amine@330 177 audio_source_data = audio_source.read(int(16000 * 0.75))
amine@330 178 audio_source.close()
amine@330 179
amine@330 180 self.assertEqual(
amine@330 181 ads_data, audio_source_data, "Unexpected data read from LimiterADS"
amine@330 182 )
amine@330 183
amine@330 184 def test_Limiter_Deco_read_limit(self):
amine@330 185 # read a maximum of 1.191 seconds from audio source
amine@330 186 ads = ADSFactory.ads(audio_source=self.audio_source, max_time=1.191)
amine@330 187 total_samples = round(ads.sampling_rate * 1.191)
amine@330 188 nb_full_blocks, last_block_size = divmod(total_samples, ads.block_size)
amine@330 189 total_samples_with_overlap = (
amine@330 190 nb_full_blocks * ads.block_size + last_block_size
amine@330 191 )
amine@330 192 expected_read_bytes = (
amine@330 193 total_samples_with_overlap * ads.sw * ads.channels
amine@330 194 )
amine@330 195
amine@330 196 total_read = 0
amine@330 197 ads.open()
amine@330 198 i = 0
amine@330 199 while True:
amine@330 200 block = ads.read()
amine@330 201 if block is None:
amine@330 202 break
amine@330 203 i += 1
amine@330 204 total_read += len(block)
amine@330 205
amine@330 206 ads.close()
amine@330 207 err_msg = "Wrong data length read from LimiterADS, expected: {0}, "
amine@330 208 err_msg += "found: {1}"
amine@330 209 self.assertEqual(
amine@330 210 total_read,
amine@330 211 expected_read_bytes,
amine@330 212 err_msg.format(expected_read_bytes, total_read),
amine@330 213 )
amine@330 214
amine@330 215 def test_Recorder_Deco_read(self):
amine@330 216 ads = ADSFactory.ads(
amine@330 217 audio_source=self.audio_source, record=True, block_size=500
amine@330 218 )
amine@330 219
amine@330 220 ads_data = []
amine@330 221 ads.open()
amine@330 222 for i in range(10):
amine@330 223 block = ads.read()
amine@330 224 if block is None:
amine@330 225 break
amine@330 226 ads_data.append(block)
amine@330 227 ads.close()
amine@330 228 ads_data = b"".join(ads_data)
amine@330 229
amine@330 230 audio_source = WaveAudioSource(
amine@330 231 filename=dataset.one_to_six_arabic_16000_mono_bc_noise
amine@330 232 )
amine@330 233 audio_source.open()
amine@330 234 audio_source_data = audio_source.read(500 * 10)
amine@330 235 audio_source.close()
amine@330 236
amine@330 237 self.assertEqual(
amine@330 238 ads_data,
amine@330 239 audio_source_data,
amine@330 240 "Unexpected data read from RecorderADS",
amine@330 241 )
amine@330 242
amine@330 243 def test_Recorder_Deco_is_rewindable(self):
amine@330 244 ads = ADSFactory.ads(audio_source=self.audio_source, record=True)
amine@330 245
amine@330 246 self.assertTrue(
amine@330 247 ads.rewindable, "RecorderADS.is_rewindable should return True"
amine@330 248 )
amine@330 249
amine@330 250 def test_Recorder_Deco_rewind_and_read(self):
amine@330 251 ads = ADSFactory.ads(
amine@330 252 audio_source=self.audio_source, record=True, block_size=320
amine@330 253 )
amine@330 254
amine@330 255 ads.open()
amine@330 256 for i in range(10):
amine@330 257 ads.read()
amine@330 258
amine@330 259 ads.rewind()
amine@330 260
amine@330 261 # read all available data after rewind
amine@330 262 ads_data = []
amine@330 263 while True:
amine@330 264 block = ads.read()
amine@330 265 if block is None:
amine@330 266 break
amine@330 267 ads_data.append(block)
amine@330 268 ads.close()
amine@330 269 ads_data = b"".join(ads_data)
amine@330 270
amine@330 271 audio_source = WaveAudioSource(
amine@330 272 filename=dataset.one_to_six_arabic_16000_mono_bc_noise
amine@330 273 )
amine@330 274 audio_source.open()
amine@330 275 audio_source_data = audio_source.read(320 * 10)
amine@330 276 audio_source.close()
amine@330 277
amine@330 278 self.assertEqual(
amine@330 279 ads_data,
amine@330 280 audio_source_data,
amine@330 281 "Unexpected data read from RecorderADS",
amine@330 282 )
amine@330 283
amine@330 284 def test_Overlap_Deco_read(self):
amine@330 285
amine@330 286 # Use arbitrary valid block_size and hop_size
amine@330 287 block_size = 1714
amine@330 288 hop_size = 313
amine@330 289
amine@330 290 ads = ADSFactory.ads(
amine@330 291 audio_source=self.audio_source,
amine@330 292 block_size=block_size,
amine@330 293 hop_size=hop_size,
amine@330 294 )
amine@330 295
amine@330 296 # Read all available data overlapping blocks
amine@330 297 ads.open()
amine@330 298 ads_data = []
amine@330 299 while True:
amine@330 300 block = ads.read()
amine@330 301 if block is None:
amine@330 302 break
amine@330 303 ads_data.append(block)
amine@330 304 ads.close()
amine@330 305
amine@330 306 # Read all data from file and build a BufferAudioSource
amine@330 307 fp = wave.open(dataset.one_to_six_arabic_16000_mono_bc_noise, "r")
amine@330 308 wave_data = fp.readframes(fp.getnframes())
amine@330 309 fp.close()
amine@330 310 audio_source = BufferAudioSource(
amine@330 311 wave_data, ads.sampling_rate, ads.sample_width, ads.channels
amine@330 312 )
amine@330 313 audio_source.open()
amine@330 314
amine@330 315 # Compare all blocks read from OverlapADS to those read
amine@330 316 # from an audio source with a manual position setting
amine@330 317 for i, block in enumerate(ads_data):
amine@330 318
amine@330 319 tmp = audio_source.read(block_size)
amine@330 320
amine@330 321 self.assertEqual(
amine@330 322 block,
amine@330 323 tmp,
amine@330 324 "Unexpected block (N={0}) read from OverlapADS".format(i),
amine@330 325 )
amine@330 326
amine@330 327 audio_source.position = (i + 1) * hop_size
amine@330 328
amine@330 329 audio_source.close()
amine@330 330
amine@330 331 def test_Limiter_Overlap_Deco_read(self):
amine@330 332
amine@330 333 block_size = 256
amine@330 334 hop_size = 200
amine@330 335
amine@330 336 ads = ADSFactory.ads(
amine@330 337 audio_source=self.audio_source,
amine@330 338 max_time=0.50,
amine@330 339 block_size=block_size,
amine@330 340 hop_size=hop_size,
amine@330 341 )
amine@330 342
amine@330 343 # Read all available data overlapping blocks
amine@330 344 ads.open()
amine@330 345 ads_data = []
amine@330 346 while True:
amine@330 347 block = ads.read()
amine@330 348 if block is None:
amine@330 349 break
amine@330 350 ads_data.append(block)
amine@330 351 ads.close()
amine@330 352
amine@330 353 # Read all data from file and build a BufferAudioSource
amine@330 354 fp = wave.open(dataset.one_to_six_arabic_16000_mono_bc_noise, "r")
amine@330 355 wave_data = fp.readframes(fp.getnframes())
amine@330 356 fp.close()
amine@330 357 audio_source = BufferAudioSource(
amine@330 358 wave_data, ads.sampling_rate, ads.sample_width, ads.channels
amine@330 359 )
amine@330 360 audio_source.open()
amine@330 361
amine@330 362 # Compare all blocks read from OverlapADS to those read
amine@330 363 # from an audio source with a manual position setting
amine@330 364 for i, block in enumerate(ads_data):
amine@330 365 tmp = audio_source.read(len(block) // (ads.sw * ads.ch))
amine@330 366 self.assertEqual(
amine@330 367 len(block),
amine@330 368 len(tmp),
amine@330 369 "Unexpected block (N={0}) read from OverlapADS".format(i),
amine@330 370 )
amine@330 371 audio_source.position = (i + 1) * hop_size
amine@330 372
amine@330 373 audio_source.close()
amine@330 374
amine@330 375 def test_Limiter_Overlap_Deco_read_limit(self):
amine@330 376
amine@330 377 block_size = 313
amine@330 378 hop_size = 207
amine@330 379 ads = ADSFactory.ads(
amine@330 380 audio_source=self.audio_source,
amine@330 381 max_time=1.932,
amine@330 382 block_size=block_size,
amine@330 383 hop_size=hop_size,
amine@330 384 )
amine@330 385
amine@330 386 total_samples = round(ads.sampling_rate * 1.932)
amine@330 387 first_read_size = block_size
amine@330 388 next_read_size = block_size - hop_size
amine@330 389 nb_next_blocks, last_block_size = divmod(
amine@330 390 (total_samples - first_read_size), next_read_size
amine@330 391 )
amine@330 392 total_samples_with_overlap = (
amine@330 393 first_read_size + next_read_size * nb_next_blocks + last_block_size
amine@330 394 )
amine@330 395 expected_read_bytes = (
amine@330 396 total_samples_with_overlap * ads.sw * ads.channels
amine@330 397 )
amine@330 398
amine@330 399 cache_size = (block_size - hop_size) * ads.sample_width * ads.channels
amine@330 400 total_read = cache_size
amine@330 401
amine@330 402 ads.open()
amine@330 403 i = 0
amine@330 404 while True:
amine@330 405 block = ads.read()
amine@330 406 if block is None:
amine@330 407 break
amine@330 408 i += 1
amine@330 409 total_read += len(block) - cache_size
amine@330 410
amine@330 411 ads.close()
amine@330 412 err_msg = "Wrong data length read from LimiterADS, expected: {0}, "
amine@330 413 err_msg += "found: {1}"
amine@330 414 self.assertEqual(
amine@330 415 total_read,
amine@330 416 expected_read_bytes,
amine@330 417 err_msg.format(expected_read_bytes, total_read),
amine@330 418 )
amine@330 419
amine@330 420 def test_Recorder_Overlap_Deco_is_rewindable(self):
amine@330 421 ads = ADSFactory.ads(
amine@330 422 audio_source=self.audio_source,
amine@330 423 block_size=320,
amine@330 424 hop_size=160,
amine@330 425 record=True,
amine@330 426 )
amine@330 427 self.assertTrue(
amine@330 428 ads.rewindable, "RecorderADS.is_rewindable should return True"
amine@330 429 )
amine@330 430
amine@330 431 def test_Recorder_Overlap_Deco_rewind_and_read(self):
amine@330 432
amine@330 433 # Use arbitrary valid block_size and hop_size
amine@330 434 block_size = 1600
amine@330 435 hop_size = 400
amine@330 436
amine@330 437 ads = ADSFactory.ads(
amine@330 438 audio_source=self.audio_source,
amine@330 439 block_size=block_size,
amine@330 440 hop_size=hop_size,
amine@330 441 record=True,
amine@330 442 )
amine@330 443
amine@330 444 # Read all available data overlapping blocks
amine@330 445 ads.open()
amine@330 446 i = 0
amine@330 447 while True:
amine@330 448 block = ads.read()
amine@330 449 if block is None:
amine@330 450 break
amine@330 451 i += 1
amine@330 452
amine@330 453 ads.rewind()
amine@330 454
amine@330 455 # Read all data from file and build a BufferAudioSource
amine@330 456 fp = wave.open(dataset.one_to_six_arabic_16000_mono_bc_noise, "r")
amine@330 457 wave_data = fp.readframes(fp.getnframes())
amine@330 458 fp.close()
amine@330 459 audio_source = BufferAudioSource(
amine@330 460 wave_data, ads.sampling_rate, ads.sample_width, ads.channels
amine@330 461 )
amine@330 462 audio_source.open()
amine@330 463
amine@330 464 # Compare all blocks read from OverlapADS to those read
amine@330 465 # from an audio source with a manual position setting
amine@330 466 for j in range(i):
amine@330 467
amine@330 468 tmp = audio_source.read(block_size)
amine@330 469
amine@330 470 self.assertEqual(
amine@330 471 ads.read(),
amine@330 472 tmp,
amine@330 473 "Unexpected block (N={0}) read from OverlapADS".format(i),
amine@330 474 )
amine@330 475 audio_source.position = (j + 1) * hop_size
amine@330 476
amine@330 477 ads.close()
amine@330 478 audio_source.close()
amine@330 479
amine@330 480 def test_Limiter_Recorder_Overlap_Deco_rewind_and_read(self):
amine@330 481
amine@330 482 # Use arbitrary valid block_size and hop_size
amine@330 483 block_size = 1600
amine@330 484 hop_size = 400
amine@330 485
amine@330 486 ads = ADSFactory.ads(
amine@330 487 audio_source=self.audio_source,
amine@330 488 max_time=1.50,
amine@330 489 block_size=block_size,
amine@330 490 hop_size=hop_size,
amine@330 491 record=True,
amine@330 492 )
amine@330 493
amine@330 494 # Read all available data overlapping blocks
amine@330 495 ads.open()
amine@330 496 i = 0
amine@330 497 while True:
amine@330 498 block = ads.read()
amine@330 499 if block is None:
amine@330 500 break
amine@330 501 i += 1
amine@330 502
amine@330 503 ads.rewind()
amine@330 504
amine@330 505 # Read all data from file and build a BufferAudioSource
amine@330 506 fp = wave.open(dataset.one_to_six_arabic_16000_mono_bc_noise, "r")
amine@330 507 wave_data = fp.readframes(fp.getnframes())
amine@330 508 fp.close()
amine@330 509 audio_source = BufferAudioSource(
amine@330 510 wave_data, ads.sampling_rate, ads.sample_width, ads.channels
amine@330 511 )
amine@330 512 audio_source.open()
amine@330 513
amine@330 514 # Compare all blocks read from OverlapADS to those read
amine@330 515 # from an audio source with a manual position setting
amine@330 516 for j in range(i):
amine@330 517
amine@330 518 tmp = audio_source.read(block_size)
amine@330 519
amine@330 520 self.assertEqual(
amine@330 521 ads.read(),
amine@330 522 tmp,
amine@330 523 "Unexpected block (N={0}) read from OverlapADS".format(i),
amine@330 524 )
amine@330 525 audio_source.position = (j + 1) * hop_size
amine@330 526
amine@330 527 ads.close()
amine@330 528 audio_source.close()
amine@330 529
amine@330 530 def test_Limiter_Recorder_Overlap_Deco_rewind_and_read_limit(self):
amine@330 531
amine@330 532 # Use arbitrary valid block_size and hop_size
amine@330 533 block_size = 1000
amine@330 534 hop_size = 200
amine@330 535
amine@330 536 ads = ADSFactory.ads(
amine@330 537 audio_source=self.audio_source,
amine@330 538 max_time=1.317,
amine@330 539 block_size=block_size,
amine@330 540 hop_size=hop_size,
amine@330 541 record=True,
amine@330 542 )
amine@330 543 total_samples = round(ads.sampling_rate * 1.317)
amine@330 544 first_read_size = block_size
amine@330 545 next_read_size = block_size - hop_size
amine@330 546 nb_next_blocks, last_block_size = divmod(
amine@330 547 (total_samples - first_read_size), next_read_size
amine@330 548 )
amine@330 549 total_samples_with_overlap = (
amine@330 550 first_read_size + next_read_size * nb_next_blocks + last_block_size
amine@330 551 )
amine@330 552 expected_read_bytes = (
amine@330 553 total_samples_with_overlap * ads.sw * ads.channels
amine@330 554 )
amine@330 555
amine@330 556 cache_size = (block_size - hop_size) * ads.sample_width * ads.channels
amine@330 557 total_read = cache_size
amine@330 558
amine@330 559 ads.open()
amine@330 560 i = 0
amine@330 561 while True:
amine@330 562 block = ads.read()
amine@330 563 if block is None:
amine@330 564 break
amine@330 565 i += 1
amine@330 566 total_read += len(block) - cache_size
amine@330 567
amine@330 568 ads.close()
amine@330 569 err_msg = "Wrong data length read from LimiterADS, expected: {0}, "
amine@330 570 err_msg += "found: {1}"
amine@330 571 self.assertEqual(
amine@330 572 total_read,
amine@330 573 expected_read_bytes,
amine@330 574 err_msg.format(expected_read_bytes, total_read),
amine@330 575 )
amine@330 576
amine@330 577
amine@330 578 class TestADSFactoryBufferAudioSource(unittest.TestCase):
amine@330 579 def setUp(self):
amine@330 580 self.signal = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
amine@330 581 self.ads = ADSFactory.ads(
amine@330 582 data_buffer=self.signal,
amine@330 583 sampling_rate=16,
amine@330 584 sample_width=2,
amine@330 585 channels=1,
amine@330 586 block_size=4,
amine@330 587 )
amine@330 588
amine@330 589 def test_ADS_BAS_sampling_rate(self):
amine@330 590 srate = self.ads.sampling_rate
amine@330 591 self.assertEqual(
amine@330 592 srate,
amine@330 593 16,
amine@330 594 "Wrong sampling rate, expected: 16000, found: {0}".format(srate),
amine@330 595 )
amine@330 596
amine@330 597 def test_ADS_BAS_get_sample_width(self):
amine@330 598 swidth = self.ads.sample_width
amine@330 599 self.assertEqual(
amine@330 600 swidth,
amine@330 601 2,
amine@330 602 "Wrong sample width, expected: 2, found: {0}".format(swidth),
amine@330 603 )
amine@330 604
amine@330 605 def test_ADS_BAS_get_channels(self):
amine@330 606 channels = self.ads.channels
amine@330 607 self.assertEqual(
amine@330 608 channels,
amine@330 609 1,
amine@330 610 "Wrong number of channels, expected: 1, found: {0}".format(
amine@330 611 channels
amine@330 612 ),
amine@330 613 )
amine@330 614
amine@330 615 def test_Limiter_Recorder_Overlap_Deco_rewind_and_read(self):
amine@330 616
amine@330 617 # Use arbitrary valid block_size and hop_size
amine@330 618 block_size = 5
amine@330 619 hop_size = 4
amine@330 620
amine@330 621 ads = ADSFactory.ads(
amine@330 622 data_buffer=self.signal,
amine@330 623 sampling_rate=16,
amine@330 624 sample_width=2,
amine@330 625 channels=1,
amine@330 626 max_time=0.80,
amine@330 627 block_size=block_size,
amine@330 628 hop_size=hop_size,
amine@330 629 record=True,
amine@330 630 )
amine@330 631
amine@330 632 # Read all available data overlapping blocks
amine@330 633 ads.open()
amine@330 634 i = 0
amine@330 635 while True:
amine@330 636 block = ads.read()
amine@330 637 if block is None:
amine@330 638 break
amine@330 639 i += 1
amine@330 640
amine@330 641 ads.rewind()
amine@330 642
amine@330 643 # Build a BufferAudioSource
amine@330 644 audio_source = BufferAudioSource(
amine@330 645 self.signal, ads.sampling_rate, ads.sample_width, ads.channels
amine@330 646 )
amine@330 647 audio_source.open()
amine@330 648
amine@330 649 # Compare all blocks read from OverlapADS to those read
amine@330 650 # from an audio source with a manual position setting
amine@330 651 for j in range(i):
amine@330 652
amine@330 653 tmp = audio_source.read(block_size)
amine@330 654
amine@330 655 block = ads.read()
amine@330 656
amine@330 657 self.assertEqual(
amine@330 658 block,
amine@330 659 tmp,
amine@330 660 "Unexpected block '{}' (N={}) read from OverlapADS".format(
amine@330 661 block, i
amine@330 662 ),
amine@330 663 )
amine@330 664 audio_source.position = (j + 1) * hop_size
amine@330 665
amine@330 666 ads.close()
amine@330 667 audio_source.close()
amine@330 668
amine@330 669
amine@330 670 class TestADSFactoryAlias(unittest.TestCase):
amine@330 671 def setUp(self):
amine@330 672 self.signal = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
amine@330 673
amine@330 674 def test_sampling_rate_alias(self):
amine@330 675 ads = ADSFactory.ads(
amine@330 676 data_buffer=self.signal,
amine@330 677 sr=16,
amine@330 678 sample_width=2,
amine@330 679 channels=1,
amine@330 680 block_dur=0.5,
amine@330 681 )
amine@330 682 srate = ads.sampling_rate
amine@330 683 self.assertEqual(
amine@330 684 srate,
amine@330 685 16,
amine@330 686 "Wrong sampling rate, expected: 16000, found: {0}".format(srate),
amine@330 687 )
amine@330 688
amine@330 689 def test_sampling_rate_duplicate(self):
amine@330 690 func = partial(
amine@330 691 ADSFactory.ads,
amine@330 692 data_buffer=self.signal,
amine@330 693 sr=16,
amine@330 694 sampling_rate=16,
amine@330 695 sample_width=2,
amine@330 696 channels=1,
amine@330 697 )
amine@330 698 self.assertRaises(DuplicateArgument, func)
amine@330 699
amine@330 700 def test_sample_width_alias(self):
amine@330 701 ads = ADSFactory.ads(
amine@330 702 data_buffer=self.signal,
amine@330 703 sampling_rate=16,
amine@330 704 sw=2,
amine@330 705 channels=1,
amine@330 706 block_dur=0.5,
amine@330 707 )
amine@330 708 swidth = ads.sample_width
amine@330 709 self.assertEqual(
amine@330 710 swidth,
amine@330 711 2,
amine@330 712 "Wrong sample width, expected: 2, found: {0}".format(swidth),
amine@330 713 )
amine@330 714
amine@330 715 def test_sample_width_duplicate(self):
amine@330 716 func = partial(
amine@330 717 ADSFactory.ads,
amine@330 718 data_buffer=self.signal,
amine@330 719 sampling_rate=16,
amine@330 720 sw=2,
amine@330 721 sample_width=2,
amine@330 722 channels=1,
amine@330 723 )
amine@330 724 self.assertRaises(DuplicateArgument, func)
amine@330 725
amine@330 726 def test_channels_alias(self):
amine@330 727 ads = ADSFactory.ads(
amine@330 728 data_buffer=self.signal,
amine@330 729 sampling_rate=16,
amine@330 730 sample_width=2,
amine@330 731 ch=1,
amine@330 732 block_dur=4,
amine@330 733 )
amine@330 734 channels = ads.channels
amine@330 735 self.assertEqual(
amine@330 736 channels,
amine@330 737 1,
amine@330 738 "Wrong number of channels, expected: 1, found: {0}".format(
amine@330 739 channels
amine@330 740 ),
amine@330 741 )
amine@330 742
amine@330 743 def test_channels_duplicate(self):
amine@330 744 func = partial(
amine@330 745 ADSFactory.ads,
amine@330 746 data_buffer=self.signal,
amine@330 747 sampling_rate=16,
amine@330 748 sample_width=2,
amine@330 749 ch=1,
amine@330 750 channels=1,
amine@330 751 )
amine@330 752 self.assertRaises(DuplicateArgument, func)
amine@330 753
amine@330 754 def test_block_size_alias(self):
amine@330 755 ads = ADSFactory.ads(
amine@330 756 data_buffer=self.signal,
amine@330 757 sampling_rate=16,
amine@330 758 sample_width=2,
amine@330 759 channels=1,
amine@330 760 bs=8,
amine@330 761 )
amine@330 762 size = ads.block_size
amine@330 763 self.assertEqual(
amine@330 764 size,
amine@330 765 8,
amine@330 766 "Wrong block_size using bs alias, expected: 8, found: {0}".format(
amine@330 767 size
amine@330 768 ),
amine@330 769 )
amine@330 770
amine@330 771 def test_block_size_duplicate(self):
amine@330 772 func = partial(
amine@330 773 ADSFactory.ads,
amine@330 774 data_buffer=self.signal,
amine@330 775 sampling_rate=16,
amine@330 776 sample_width=2,
amine@330 777 channels=1,
amine@330 778 bs=4,
amine@330 779 block_size=4,
amine@330 780 )
amine@330 781 self.assertRaises(DuplicateArgument, func)
amine@330 782
amine@330 783 def test_block_duration_alias(self):
amine@330 784 ads = ADSFactory.ads(
amine@330 785 data_buffer=self.signal,
amine@330 786 sampling_rate=16,
amine@330 787 sample_width=2,
amine@330 788 channels=1,
amine@330 789 bd=0.75,
amine@330 790 )
amine@330 791 # 0.75 ms = 0.75 * 16 = 12
amine@330 792 size = ads.block_size
amine@330 793 err_msg = "Wrong block_size set with a block_dur alias 'bd', "
amine@330 794 err_msg += "expected: 8, found: {0}"
amine@330 795 self.assertEqual(
amine@330 796 size, 12, err_msg.format(size),
amine@330 797 )
amine@330 798
amine@330 799 def test_block_duration_duplicate(self):
amine@330 800 func = partial(
amine@330 801 ADSFactory.ads,
amine@330 802 data_buffer=self.signal,
amine@330 803 sampling_rate=16,
amine@330 804 sample_width=2,
amine@330 805 channels=1,
amine@330 806 bd=4,
amine@330 807 block_dur=4,
amine@330 808 )
amine@330 809 self.assertRaises(DuplicateArgument, func)
amine@330 810
amine@330 811 def test_block_size_duration_duplicate(self):
amine@330 812 func = partial(
amine@330 813 ADSFactory.ads,
amine@330 814 data_buffer=self.signal,
amine@330 815 sampling_rate=16,
amine@330 816 sample_width=2,
amine@330 817 channels=1,
amine@330 818 bd=4,
amine@330 819 bs=12,
amine@330 820 )
amine@330 821 self.assertRaises(DuplicateArgument, func)
amine@330 822
amine@330 823 def test_hop_duration_alias(self):
amine@330 824
amine@330 825 ads = ADSFactory.ads(
amine@330 826 data_buffer=self.signal,
amine@330 827 sampling_rate=16,
amine@330 828 sample_width=2,
amine@330 829 channels=1,
amine@330 830 bd=0.75,
amine@330 831 hd=0.5,
amine@330 832 )
amine@330 833 size = ads.hop_size
amine@330 834 self.assertEqual(
amine@330 835 size,
amine@330 836 8,
amine@330 837 "Wrong block_size using bs alias, expected: 8, found: {0}".format(
amine@330 838 size
amine@330 839 ),
amine@330 840 )
amine@330 841
amine@330 842 def test_hop_duration_duplicate(self):
amine@330 843
amine@330 844 func = partial(
amine@330 845 ADSFactory.ads,
amine@330 846 data_buffer=self.signal,
amine@330 847 sampling_rate=16,
amine@330 848 sample_width=2,
amine@330 849 channels=1,
amine@330 850 bd=0.75,
amine@330 851 hd=0.5,
amine@330 852 hop_dur=0.5,
amine@330 853 )
amine@330 854 self.assertRaises(DuplicateArgument, func)
amine@330 855
amine@330 856 def test_hop_size_duration_duplicate(self):
amine@330 857 func = partial(
amine@330 858 ADSFactory.ads,
amine@330 859 data_buffer=self.signal,
amine@330 860 sampling_rate=16,
amine@330 861 sample_width=2,
amine@330 862 channels=1,
amine@330 863 bs=8,
amine@330 864 hs=4,
amine@330 865 hd=1,
amine@330 866 )
amine@330 867 self.assertRaises(DuplicateArgument, func)
amine@330 868
amine@330 869 def test_hop_size_greater_than_block_size(self):
amine@330 870 func = partial(
amine@330 871 ADSFactory.ads,
amine@330 872 data_buffer=self.signal,
amine@330 873 sampling_rate=16,
amine@330 874 sample_width=2,
amine@330 875 channels=1,
amine@330 876 bs=4,
amine@330 877 hs=8,
amine@330 878 )
amine@330 879 self.assertRaises(ValueError, func)
amine@330 880
amine@330 881 def test_filename_duplicate(self):
amine@330 882
amine@330 883 func = partial(
amine@330 884 ADSFactory.ads,
amine@330 885 fn=dataset.one_to_six_arabic_16000_mono_bc_noise,
amine@330 886 filename=dataset.one_to_six_arabic_16000_mono_bc_noise,
amine@330 887 )
amine@330 888 self.assertRaises(DuplicateArgument, func)
amine@330 889
amine@330 890 def test_data_buffer_duplicate(self):
amine@330 891 func = partial(
amine@330 892 ADSFactory.ads,
amine@330 893 data_buffer=self.signal,
amine@330 894 db=self.signal,
amine@330 895 sampling_rate=16,
amine@330 896 sample_width=2,
amine@330 897 channels=1,
amine@330 898 )
amine@330 899 self.assertRaises(DuplicateArgument, func)
amine@330 900
amine@330 901 def test_max_time_alias(self):
amine@330 902 ads = ADSFactory.ads(
amine@330 903 data_buffer=self.signal,
amine@330 904 sampling_rate=16,
amine@330 905 sample_width=2,
amine@330 906 channels=1,
amine@330 907 mt=10,
amine@330 908 block_dur=0.5,
amine@330 909 )
amine@330 910 self.assertEqual(
amine@330 911 ads.max_read,
amine@330 912 10,
amine@330 913 "Wrong AudioDataSource.max_read, expected: 10, found: {}".format(
amine@330 914 ads.max_read
amine@330 915 ),
amine@330 916 )
amine@330 917
amine@330 918 def test_max_time_duplicate(self):
amine@330 919 func = partial(
amine@330 920 ADSFactory.ads,
amine@330 921 data_buffer=self.signal,
amine@330 922 sampling_rate=16,
amine@330 923 sample_width=2,
amine@330 924 channels=1,
amine@330 925 mt=True,
amine@330 926 max_time=True,
amine@330 927 )
amine@330 928
amine@330 929 self.assertRaises(DuplicateArgument, func)
amine@330 930
amine@330 931 def test_record_alias(self):
amine@330 932 ads = ADSFactory.ads(
amine@330 933 data_buffer=self.signal,
amine@330 934 sampling_rate=16,
amine@330 935 sample_width=2,
amine@330 936 channels=1,
amine@330 937 rec=True,
amine@330 938 block_dur=0.5,
amine@330 939 )
amine@330 940 self.assertTrue(
amine@330 941 ads.rewindable, "AudioDataSource.rewindable expected to be True"
amine@330 942 )
amine@330 943
amine@330 944 def test_record_duplicate(self):
amine@330 945 func = partial(
amine@330 946 ADSFactory.ads,
amine@330 947 data_buffer=self.signal,
amine@330 948 sampling_rate=16,
amine@330 949 sample_width=2,
amine@330 950 channels=1,
amine@330 951 rec=True,
amine@330 952 record=True,
amine@330 953 )
amine@330 954 self.assertRaises(DuplicateArgument, func)
amine@330 955
amine@330 956 def test_Limiter_Recorder_Overlap_Deco_rewind_and_read_alias(self):
amine@330 957
amine@330 958 # Use arbitrary valid block_size and hop_size
amine@330 959 block_size = 5
amine@330 960 hop_size = 4
amine@330 961
amine@330 962 ads = ADSFactory.ads(
amine@330 963 db=self.signal,
amine@330 964 sr=16,
amine@330 965 sw=2,
amine@330 966 ch=1,
amine@330 967 mt=0.80,
amine@330 968 bs=block_size,
amine@330 969 hs=hop_size,
amine@330 970 rec=True,
amine@330 971 )
amine@330 972
amine@330 973 # Read all available data overlapping blocks
amine@330 974 ads.open()
amine@330 975 i = 0
amine@330 976 while True:
amine@330 977 block = ads.read()
amine@330 978 if block is None:
amine@330 979 break
amine@330 980 i += 1
amine@330 981
amine@330 982 ads.rewind()
amine@330 983
amine@330 984 # Build a BufferAudioSource
amine@330 985 audio_source = BufferAudioSource(
amine@330 986 self.signal, ads.sampling_rate, ads.sample_width, ads.channels
amine@330 987 )
amine@330 988 audio_source.open()
amine@330 989
amine@330 990 # Compare all blocks read from AudioDataSource to those read
amine@330 991 # from an audio source with manual position definition
amine@330 992 for j in range(i):
amine@330 993 tmp = audio_source.read(block_size)
amine@330 994 block = ads.read()
amine@330 995 self.assertEqual(
amine@330 996 block,
amine@330 997 tmp,
amine@330 998 "Unexpected block (N={0}) read from OverlapADS".format(i),
amine@330 999 )
amine@330 1000 audio_source.position = (j + 1) * hop_size
amine@330 1001 ads.close()
amine@330 1002 audio_source.close()
amine@330 1003
amine@330 1004
amine@330 1005 def _read_all_data(reader):
amine@330 1006 blocks = []
amine@330 1007 while True:
amine@330 1008 data = reader.read()
amine@330 1009 if data is None:
amine@330 1010 break
amine@330 1011 blocks.append(data)
amine@330 1012 return b"".join(blocks)
amine@330 1013
amine@330 1014
amine@330 1015 @genty
amine@330 1016 class TestAudioReader(unittest.TestCase):
amine@330 1017
amine@330 1018 # TODO move all tests here when backward compatibility
amine@330 1019 # with ADSFactory is dropped
amine@330 1020
amine@330 1021 @genty_dataset(
amine@330 1022 mono=("mono_400", 0.5, 16000),
amine@330 1023 multichannel=("3channel_400-800-1600", 0.5, 16000 * 3),
amine@330 1024 )
amine@330 1025 def test_Limiter(self, file_id, max_read, size):
amine@330 1026 input_wav = "tests/data/test_16KHZ_{}Hz.wav".format(file_id)
amine@330 1027 input_raw = "tests/data/test_16KHZ_{}Hz.raw".format(file_id)
amine@330 1028 with open(input_raw, "rb") as fp:
amine@330 1029 expected = fp.read(size)
amine@330 1030
amine@330 1031 reader = AudioReader(input_wav, block_dur=0.1, max_read=max_read)
amine@330 1032 reader.open()
amine@330 1033 data = _read_all_data(reader)
amine@330 1034 reader.close()
amine@330 1035 self.assertEqual(data, expected)
amine@330 1036
amine@330 1037 @genty_dataset(mono=("mono_400",), multichannel=("3channel_400-800-1600",))
amine@330 1038 def test_Recorder(self, file_id):
amine@330 1039 input_wav = "tests/data/test_16KHZ_{}Hz.wav".format(file_id)
amine@330 1040 input_raw = "tests/data/test_16KHZ_{}Hz.raw".format(file_id)
amine@330 1041 with open(input_raw, "rb") as fp:
amine@330 1042 expected = fp.read()
amine@330 1043
amine@330 1044 reader = AudioReader(input_wav, block_dur=0.1, record=True)
amine@330 1045 reader.open()
amine@330 1046 data = _read_all_data(reader)
amine@330 1047 self.assertEqual(data, expected)
amine@330 1048
amine@330 1049 # rewind many times
amine@330 1050 for _ in range(3):
amine@330 1051 reader.rewind()
amine@330 1052 data = _read_all_data(reader)
amine@330 1053 self.assertEqual(data, expected)
amine@330 1054 self.assertEqual(data, reader.data)
amine@330 1055 reader.close()
amine@330 1056
amine@330 1057 @genty_dataset(mono=("mono_400",), multichannel=("3channel_400-800-1600",))
amine@330 1058 def test_Recorder_alias(self, file_id):
amine@330 1059 input_wav = "tests/data/test_16KHZ_{}Hz.wav".format(file_id)
amine@330 1060 input_raw = "tests/data/test_16KHZ_{}Hz.raw".format(file_id)
amine@330 1061 with open(input_raw, "rb") as fp:
amine@330 1062 expected = fp.read()
amine@330 1063
amine@330 1064 reader = Recorder(input_wav, block_dur=0.1)
amine@330 1065 reader.open()
amine@330 1066 data = _read_all_data(reader)
amine@330 1067 self.assertEqual(data, expected)
amine@330 1068
amine@330 1069 # rewind many times
amine@330 1070 for _ in range(3):
amine@330 1071 reader.rewind()
amine@330 1072 data = _read_all_data(reader)
amine@330 1073 self.assertEqual(data, expected)
amine@330 1074 self.assertEqual(data, reader.data)
amine@330 1075 reader.close()
amine@330 1076
amine@330 1077
amine@330 1078 if __name__ == "__main__":
amine@330 1079 unittest.main()