annotate tests/test_AudioReader.py @ 400:323d59b404a2

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