annotate tests/test_AudioSource.py @ 455:7dae98b84cdd tip master

Merge branch 'master' of https://github.com/amsehili/auditok
author www-data <www-data@c4dm-xenserv-virt2.eecs.qmul.ac.uk>
date Tue, 03 Dec 2024 09:18:01 +0000
parents c5b4178aa80f
children
rev   line source
amine@164 1 """
amine@164 2 @author: Amine Sehili <amine.sehili@gmail.com>
amine@164 3 """
amine@400 4
amine@164 5 from array import array
amine@403 6
amine@405 7 import numpy as np
amine@400 8 import pytest
amine@403 9
amine@164 10 from auditok.io import (
amine@405 11 AudioIOError,
amine@164 12 AudioParameterError,
amine@164 13 BufferAudioSource,
amine@164 14 RawAudioSource,
amine@164 15 WaveAudioSource,
amine@164 16 )
amine@405 17 from auditok.signal import SAMPLE_WIDTH_TO_DTYPE
amine@405 18
amine@405 19
amine@405 20 def _sample_generator(*data_buffers):
amine@405 21 """
amine@405 22 Takes a list of many mono audio data buffers and makes a sample generator
amine@405 23 of interleaved audio samples, one sample from each channel. The resulting
amine@405 24 generator can be used to build a multichannel audio buffer.
amine@405 25 >>> gen = _sample_generator("abcd", "ABCD")
amine@405 26 >>> list(gen)
amine@405 27 ["a", "A", "b", "B", "c", "C", "d", "D"]
amine@405 28 """
amine@426 29 frame_gen = zip(*data_buffers)
amine@405 30 return (sample for frame in frame_gen for sample in frame)
amine@405 31
amine@405 32
amine@405 33 def _generate_pure_tone(
amine@405 34 frequency, duration_sec=1, sampling_rate=16000, sample_width=2, volume=1e4
amine@405 35 ):
amine@405 36 """
amine@405 37 Generates a pure tone with the given frequency.
amine@405 38 """
amine@405 39 assert frequency <= sampling_rate / 2
amine@405 40 max_value = (2 ** (sample_width * 8) // 2) - 1
amine@405 41 if volume > max_value:
amine@405 42 volume = max_value
amine@405 43 dtype = SAMPLE_WIDTH_TO_DTYPE[sample_width]
amine@405 44 total_samples = int(sampling_rate * duration_sec)
amine@405 45 step = frequency / sampling_rate
amine@405 46 two_pi_step = 2 * np.pi * step
amine@405 47 data = np.array(
amine@405 48 [int(np.sin(two_pi_step * i) * volume) for i in range(total_samples)]
amine@405 49 ).astype(dtype)
amine@405 50 return data
amine@405 51
amine@405 52
amine@405 53 @pytest.fixture
amine@405 54 def pure_tone_data(freq):
amine@405 55
amine@405 56 PURE_TONE_DICT = {
amine@405 57 freq: _generate_pure_tone(freq, 1, 16000, 2)
amine@405 58 for freq in (400, 800, 1600)
amine@405 59 }
amine@405 60 PURE_TONE_DICT.update(
amine@405 61 {
amine@405 62 freq: _generate_pure_tone(freq, 0.1, 16000, 2)
amine@405 63 for freq in (600, 1150, 2400, 7220)
amine@405 64 }
amine@405 65 )
amine@405 66 return PURE_TONE_DICT[freq]
amine@405 67
amine@405 68
amine@405 69 PURE_TONE_DICT = {
amine@405 70 freq: _generate_pure_tone(freq, 1, 16000, 2) for freq in (400, 800, 1600)
amine@405 71 }
amine@405 72 PURE_TONE_DICT.update(
amine@405 73 {
amine@405 74 freq: _generate_pure_tone(freq, 0.1, 16000, 2)
amine@405 75 for freq in (600, 1150, 2400, 7220)
amine@405 76 }
amine@405 77 )
amine@164 78
amine@164 79
amine@164 80 def audio_source_read_all_gen(audio_source, size=None):
amine@164 81 if size is None:
amine@164 82 size = int(audio_source.sr * 0.1) # 100ms
amine@164 83 while True:
amine@164 84 data = audio_source.read(size)
amine@164 85 if data is None:
amine@164 86 break
amine@164 87 yield data
amine@164 88
amine@164 89
amine@400 90 @pytest.mark.parametrize(
amine@400 91 "file_suffix, frequencies",
amine@400 92 [
amine@400 93 ("mono_400Hz", (400,)), # mono
amine@400 94 ("3channel_400-800-1600Hz", (400, 800, 1600)), # multichannel
amine@400 95 ],
amine@400 96 ids=["mono", "multichannel"],
amine@400 97 )
amine@400 98 def test_BufferAudioSource_read_all(file_suffix, frequencies):
amine@400 99 file = "tests/data/test_16KHZ_{}.raw".format(file_suffix)
amine@400 100 with open(file, "rb") as fp:
amine@400 101 expected = fp.read()
amine@400 102 channels = len(frequencies)
amine@400 103 audio_source = BufferAudioSource(expected, 16000, 2, channels)
amine@400 104 audio_source.open()
amine@400 105 data = audio_source.read(None)
amine@400 106 assert data == expected
amine@400 107 audio_source.rewind()
amine@400 108 data = audio_source.read(-10)
amine@400 109 assert data == expected
amine@400 110 audio_source.close()
amine@164 111
amine@164 112
amine@400 113 @pytest.mark.parametrize(
amine@400 114 "file_suffix, frequencies",
amine@400 115 [
amine@400 116 ("mono_400Hz", (400,)), # mono
amine@400 117 ("3channel_400-800-1600Hz", (400, 800, 1600)), # multichannel
amine@400 118 ],
amine@400 119 ids=["mono", "multichannel"],
amine@400 120 )
amine@400 121 def test_RawAudioSource(file_suffix, frequencies):
amine@400 122 file = "tests/data/test_16KHZ_{}.raw".format(file_suffix)
amine@400 123 channels = len(frequencies)
amine@400 124 audio_source = RawAudioSource(file, 16000, 2, channels)
amine@400 125 audio_source.open()
amine@400 126 data_read_all = b"".join(audio_source_read_all_gen(audio_source))
amine@400 127 audio_source.close()
amine@400 128 mono_channels = [PURE_TONE_DICT[freq] for freq in frequencies]
amine@405 129 dtype = SAMPLE_WIDTH_TO_DTYPE[audio_source.sample_width]
amine@405 130 expected = np.fromiter(_sample_generator(*mono_channels), dtype).tobytes()
amine@238 131
amine@400 132 assert data_read_all == expected
amine@240 133
amine@400 134 # assert read all data with None
amine@400 135 audio_source = RawAudioSource(file, 16000, 2, channels)
amine@400 136 audio_source.open()
amine@400 137 data_read_all = audio_source.read(None)
amine@400 138 audio_source.close()
amine@400 139 assert data_read_all == expected
amine@164 140
amine@400 141 # assert read all data with a negative size
amine@400 142 audio_source = RawAudioSource(file, 16000, 2, channels)
amine@400 143 audio_source.open()
amine@400 144 data_read_all = audio_source.read(-10)
amine@400 145 audio_source.close()
amine@400 146 assert data_read_all == expected
amine@238 147
amine@238 148
amine@400 149 @pytest.mark.parametrize(
amine@400 150 "file_suffix, frequencies",
amine@400 151 [
amine@400 152 ("mono_400Hz", (400,)), # mono
amine@400 153 ("3channel_400-800-1600Hz", (400, 800, 1600)), # multichannel
amine@400 154 ],
amine@400 155 ids=["mono", "multichannel"],
amine@400 156 )
amine@400 157 def test_WaveAudioSource(file_suffix, frequencies):
amine@400 158 file = "tests/data/test_16KHZ_{}.wav".format(file_suffix)
amine@400 159 audio_source = WaveAudioSource(file)
amine@400 160 audio_source.open()
amine@400 161 data = b"".join(audio_source_read_all_gen(audio_source))
amine@400 162 audio_source.close()
amine@400 163 mono_channels = [PURE_TONE_DICT[freq] for freq in frequencies]
amine@405 164 dtype = SAMPLE_WIDTH_TO_DTYPE[audio_source.sample_width]
amine@405 165 expected = np.fromiter(_sample_generator(*mono_channels), dtype).tobytes()
amine@164 166
amine@400 167 assert data == expected
amine@164 168
amine@400 169 # assert read all data with None
amine@400 170 audio_source = WaveAudioSource(file)
amine@400 171 audio_source.open()
amine@400 172 data_read_all = audio_source.read(None)
amine@400 173 audio_source.close()
amine@400 174 assert data_read_all == expected
amine@238 175
amine@400 176 # assert read all data with a negative size
amine@400 177 audio_source = WaveAudioSource(file)
amine@400 178 audio_source.open()
amine@400 179 data_read_all = audio_source.read(-10)
amine@400 180 audio_source.close()
amine@400 181 assert data_read_all == expected
amine@238 182
amine@164 183
amine@400 184 class TestBufferAudioSource_SR10_SW1_CH1:
amine@400 185 @pytest.fixture(autouse=True)
amine@400 186 def setup_and_teardown(self):
amine@164 187 self.data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
amine@164 188 self.audio_source = BufferAudioSource(
amine@321 189 data=self.data, sampling_rate=10, sample_width=1, channels=1
amine@164 190 )
amine@164 191 self.audio_source.open()
amine@400 192 yield
amine@164 193 self.audio_source.close()
amine@164 194
amine@164 195 def test_sr10_sw1_ch1_read_1(self):
amine@164 196 block = self.audio_source.read(1)
amine@164 197 exp = b"A"
amine@400 198 assert block == exp
amine@164 199
amine@164 200 def test_sr10_sw1_ch1_read_6(self):
amine@164 201 block = self.audio_source.read(6)
amine@164 202 exp = b"ABCDEF"
amine@400 203 assert block == exp
amine@164 204
amine@164 205 def test_sr10_sw1_ch1_read_multiple(self):
amine@164 206 block = self.audio_source.read(1)
amine@164 207 exp = b"A"
amine@400 208 assert block == exp
amine@164 209
amine@164 210 block = self.audio_source.read(6)
amine@164 211 exp = b"BCDEFG"
amine@400 212 assert block == exp
amine@164 213
amine@164 214 block = self.audio_source.read(13)
amine@164 215 exp = b"HIJKLMNOPQRST"
amine@400 216 assert block == exp
amine@164 217
amine@164 218 block = self.audio_source.read(9999)
amine@164 219 exp = b"UVWXYZ012345"
amine@400 220 assert block == exp
amine@164 221
amine@164 222 def test_sr10_sw1_ch1_read_all(self):
amine@164 223 block = self.audio_source.read(9999)
amine@400 224 assert block == self.data
amine@164 225
amine@164 226 block = self.audio_source.read(1)
amine@400 227 assert block is None
amine@164 228
amine@335 229 def test_sr10_sw1_ch1_sampling_rate(self):
amine@335 230 srate = self.audio_source.sampling_rate
amine@400 231 assert srate == 10
amine@164 232
amine@335 233 def test_sr10_sw1_ch1_sample_width(self):
amine@335 234 swidth = self.audio_source.sample_width
amine@400 235 assert swidth == 1
amine@164 236
amine@335 237 def test_sr10_sw1_ch1_channels(self):
amine@335 238 channels = self.audio_source.channels
amine@400 239 assert channels == 1
amine@164 240
amine@400 241 @pytest.mark.parametrize(
amine@400 242 "block_sizes, expected_sample, expected_second, expected_ms",
amine@400 243 [
amine@400 244 ([], 0, 0, 0), # empty
amine@400 245 ([0], 0, 0, 0), # zero
amine@400 246 ([5], 5, 0.5, 500), # five
amine@400 247 ([5, 20], 25, 2.5, 2500), # multiple
amine@400 248 ],
amine@400 249 ids=["empty", "zero", "five", "multiple"],
amine@166 250 )
amine@166 251 def test_position(
amine@166 252 self, block_sizes, expected_sample, expected_second, expected_ms
amine@166 253 ):
amine@166 254 for block_size in block_sizes:
amine@166 255 self.audio_source.read(block_size)
amine@166 256 position = self.audio_source.position
amine@400 257 assert position == expected_sample
amine@166 258
amine@166 259 position_s = self.audio_source.position_s
amine@400 260 assert position_s == expected_second
amine@166 261
amine@166 262 position_ms = self.audio_source.position_ms
amine@400 263 assert position_ms == expected_ms
amine@166 264
amine@400 265 @pytest.mark.parametrize(
amine@400 266 "position, expected_sample, expected_second, expected_ms",
amine@400 267 [
amine@400 268 (0, 0, 0, 0), # zero
amine@400 269 (1, 1, 0.1, 100), # one
amine@400 270 (10, 10, 1, 1000), # ten
amine@400 271 (-1, 31, 3.1, 3100), # negative_1
amine@400 272 (-7, 25, 2.5, 2500), # negative_2
amine@400 273 ],
amine@400 274 ids=["zero", "one", "ten", "negative_1", "negative_2"],
amine@166 275 )
amine@166 276 def test_position_setter(
amine@166 277 self, position, expected_sample, expected_second, expected_ms
amine@166 278 ):
amine@166 279 self.audio_source.position = position
amine@166 280
amine@166 281 position = self.audio_source.position
amine@400 282 assert position == expected_sample
amine@166 283
amine@166 284 position_s = self.audio_source.position_s
amine@400 285 assert position_s == expected_second
amine@166 286
amine@166 287 position_ms = self.audio_source.position_ms
amine@400 288 assert position_ms == expected_ms
amine@166 289
amine@400 290 @pytest.mark.parametrize(
amine@400 291 "position_s, expected_sample, expected_second, expected_ms",
amine@400 292 [
amine@400 293 (0, 0, 0, 0), # zero
amine@400 294 (0.1, 1, 0.1, 100), # one
amine@400 295 (1, 10, 1, 1000), # ten
amine@400 296 (-0.1, 31, 3.1, 3100), # negative_1
amine@400 297 (-0.7, 25, 2.5, 2500), # negative_2
amine@400 298 ],
amine@400 299 ids=["zero", "one", "ten", "negative_1", "negative_2"],
amine@166 300 )
amine@166 301 def test_position_s_setter(
amine@166 302 self, position_s, expected_sample, expected_second, expected_ms
amine@166 303 ):
amine@166 304 self.audio_source.position_s = position_s
amine@166 305
amine@166 306 position = self.audio_source.position
amine@400 307 assert position == expected_sample
amine@166 308
amine@166 309 position_s = self.audio_source.position_s
amine@400 310 assert position_s == expected_second
amine@166 311
amine@166 312 position_ms = self.audio_source.position_ms
amine@400 313 assert position_ms == expected_ms
amine@166 314
amine@400 315 @pytest.mark.parametrize(
amine@400 316 "position_ms, expected_sample, expected_second, expected_ms",
amine@400 317 [
amine@400 318 (0, 0, 0, 0), # zero
amine@400 319 (100, 1, 0.1, 100), # one
amine@400 320 (1000, 10, 1, 1000), # ten
amine@400 321 (-100, 31, 3.1, 3100), # negative_1
amine@400 322 (-700, 25, 2.5, 2500), # negative_2
amine@400 323 ],
amine@400 324 ids=["zero", "one", "ten", "negative_1", "negative_2"],
amine@166 325 )
amine@166 326 def test_position_ms_setter(
amine@166 327 self, position_ms, expected_sample, expected_second, expected_ms
amine@166 328 ):
amine@166 329 self.audio_source.position_ms = position_ms
amine@166 330
amine@166 331 position = self.audio_source.position
amine@400 332 assert position == expected_sample
amine@166 333
amine@166 334 position_s = self.audio_source.position_s
amine@400 335 assert position_s == expected_second
amine@166 336
amine@166 337 position_ms = self.audio_source.position_ms
amine@400 338 assert position_ms == expected_ms
amine@166 339
amine@400 340 @pytest.mark.parametrize(
amine@400 341 "position",
amine@400 342 [
amine@400 343 100, # positive
amine@400 344 -100, # negative
amine@400 345 ],
amine@400 346 ids=["positive", "negative"],
amine@400 347 )
amine@166 348 def test_position_setter_out_of_range(self, position):
amine@400 349 with pytest.raises(IndexError):
amine@166 350 self.audio_source.position = position
amine@166 351
amine@400 352 @pytest.mark.parametrize(
amine@400 353 "position_s",
amine@400 354 [
amine@400 355 100, # positive
amine@400 356 -100, # negative
amine@400 357 ],
amine@400 358 ids=["positive", "negative"],
amine@400 359 )
amine@166 360 def test_position_s_setter_out_of_range(self, position_s):
amine@400 361 with pytest.raises(IndexError):
amine@166 362 self.audio_source.position_s = position_s
amine@166 363
amine@400 364 @pytest.mark.parametrize(
amine@400 365 "position_ms",
amine@400 366 [
amine@400 367 10000, # positive
amine@400 368 -10000, # negative
amine@400 369 ],
amine@400 370 ids=["positive", "negative"],
amine@400 371 )
amine@166 372 def test_position_ms_setter_out_of_range(self, position_ms):
amine@400 373 with pytest.raises(IndexError):
amine@166 374 self.audio_source.position_ms = position_ms
amine@166 375
amine@330 376 def test_sr10_sw1_ch1_initial_position_s_0(self):
amine@216 377 tp = self.audio_source.position_s
amine@400 378 assert tp == 0.0
amine@164 379
amine@330 380 def test_sr10_sw1_ch1_position_s_1_after_read(self):
amine@330 381 srate = self.audio_source.sampling_rate
amine@164 382 # read one second
amine@164 383 self.audio_source.read(srate)
amine@216 384 tp = self.audio_source.position_s
amine@400 385 assert tp == 1.0
amine@164 386
amine@216 387 def test_sr10_sw1_ch1_position_s_2_5(self):
amine@164 388 # read 2.5 seconds
amine@164 389 self.audio_source.read(25)
amine@216 390 tp = self.audio_source.position_s
amine@400 391 assert tp == 2.5
amine@164 392
amine@216 393 def test_sr10_sw1_ch1_position_s_0(self):
amine@164 394 self.audio_source.read(10)
amine@216 395 self.audio_source.position_s = 0
amine@216 396 tp = self.audio_source.position_s
amine@400 397 assert tp == 0.0
amine@164 398
amine@216 399 def test_sr10_sw1_ch1_position_s_1(self):
amine@216 400 self.audio_source.position_s = 1
amine@216 401 tp = self.audio_source.position_s
amine@400 402 assert tp == 1.0
amine@164 403
amine@164 404 def test_sr10_sw1_ch1_rewind(self):
amine@164 405 self.audio_source.read(10)
amine@164 406 self.audio_source.rewind()
amine@169 407 tp = self.audio_source.position
amine@400 408 assert tp == 0
amine@164 409
amine@164 410 def test_sr10_sw1_ch1_read_closed(self):
amine@164 411 self.audio_source.close()
amine@405 412 with pytest.raises(AudioIOError):
amine@164 413 self.audio_source.read(1)
amine@164 414
amine@209 415
amine@400 416 class TestBufferAudioSource_SR16_SW2_CH1:
amine@400 417 @pytest.fixture(autouse=True)
amine@400 418 def setup_and_teardown(self):
amine@164 419 self.data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
amine@164 420 self.audio_source = BufferAudioSource(
amine@321 421 data=self.data, sampling_rate=16, sample_width=2, channels=1
amine@164 422 )
amine@164 423 self.audio_source.open()
amine@400 424 yield
amine@164 425 self.audio_source.close()
amine@164 426
amine@164 427 def test_sr16_sw2_ch1_read_1(self):
amine@164 428 block = self.audio_source.read(1)
amine@164 429 exp = b"AB"
amine@400 430 assert block == exp
amine@164 431
amine@164 432 def test_sr16_sw2_ch1_read_6(self):
amine@164 433 block = self.audio_source.read(6)
amine@164 434 exp = b"ABCDEFGHIJKL"
amine@400 435 assert block == exp
amine@164 436
amine@164 437 def test_sr16_sw2_ch1_read_multiple(self):
amine@164 438 block = self.audio_source.read(1)
amine@164 439 exp = b"AB"
amine@400 440 assert block == exp
amine@164 441
amine@164 442 block = self.audio_source.read(6)
amine@164 443 exp = b"CDEFGHIJKLMN"
amine@400 444 assert block == exp
amine@164 445
amine@164 446 block = self.audio_source.read(5)
amine@164 447 exp = b"OPQRSTUVWX"
amine@400 448 assert block == exp
amine@164 449
amine@164 450 block = self.audio_source.read(9999)
amine@164 451 exp = b"YZ012345"
amine@400 452 assert block == exp
amine@164 453
amine@164 454 def test_sr16_sw2_ch1_read_all(self):
amine@164 455 block = self.audio_source.read(9999)
amine@400 456 assert block == self.data
amine@164 457
amine@164 458 block = self.audio_source.read(1)
amine@400 459 assert block is None
amine@164 460
amine@335 461 def test_sr16_sw2_ch1_sampling_rate(self):
amine@335 462 srate = self.audio_source.sampling_rate
amine@400 463 assert srate == 16
amine@164 464
amine@335 465 def test_sr16_sw2_ch1_sample_width(self):
amine@335 466 swidth = self.audio_source.sample_width
amine@400 467 assert swidth == 2
amine@164 468
amine@335 469 def test_sr16_sw2_ch1_channels(self):
amine@400 470 channels = self.audio_source.channels
amine@400 471 assert channels == 1
amine@164 472
amine@400 473 @pytest.mark.parametrize(
amine@400 474 "block_sizes, expected_sample, expected_second, expected_ms",
amine@400 475 [
amine@400 476 ([], 0, 0, 0), # empty
amine@400 477 ([0], 0, 0, 0), # zero
amine@400 478 ([2], 2, 2 / 16, int(2000 / 16)), # two
amine@400 479 ([11], 11, 11 / 16, int(11 * 1000 / 16)), # eleven
amine@400 480 ([4, 8], 12, 0.75, 750), # multiple
amine@400 481 ],
amine@400 482 ids=["empty", "zero", "two", "eleven", "multiple"],
amine@169 483 )
amine@169 484 def test_position(
amine@169 485 self, block_sizes, expected_sample, expected_second, expected_ms
amine@169 486 ):
amine@169 487 for block_size in block_sizes:
amine@169 488 self.audio_source.read(block_size)
amine@169 489 position = self.audio_source.position
amine@400 490 assert position == expected_sample
amine@169 491
amine@169 492 position_s = self.audio_source.position_s
amine@400 493 assert position_s == expected_second
amine@169 494
amine@169 495 position_ms = self.audio_source.position_ms
amine@400 496 assert position_ms == expected_ms
amine@169 497
amine@216 498 def test_sr16_sw2_ch1_read_position_0(self):
amine@169 499 self.audio_source.read(10)
amine@169 500 self.audio_source.position = 0
amine@169 501 pos = self.audio_source.position
amine@400 502 assert pos == 0
amine@164 503
amine@400 504 @pytest.mark.parametrize(
amine@400 505 "position, expected_sample, expected_second, expected_ms",
amine@400 506 [
amine@400 507 (0, 0, 0, 0), # zero
amine@400 508 (1, 1, 1 / 16, int(1000 / 16)), # one
amine@400 509 (10, 10, 10 / 16, int(10000 / 16)), # ten
amine@400 510 (-1, 15, 15 / 16, int(15000 / 16)), # negative_1
amine@400 511 (-7, 9, 9 / 16, int(9000 / 16)), # negative_2
amine@400 512 ],
amine@400 513 ids=["zero", "one", "ten", "negative_1", "negative_2"],
amine@169 514 )
amine@169 515 def test_position_setter(
amine@169 516 self, position, expected_sample, expected_second, expected_ms
amine@169 517 ):
amine@169 518 self.audio_source.position = position
amine@169 519
amine@169 520 position = self.audio_source.position
amine@400 521 assert position == expected_sample
amine@164 522
amine@169 523 position_s = self.audio_source.position_s
amine@400 524 assert position_s == expected_second
amine@164 525
amine@169 526 position_ms = self.audio_source.position_ms
amine@400 527 assert position_ms == expected_ms
amine@164 528
amine@400 529 @pytest.mark.parametrize(
amine@400 530 "position_s, expected_sample, expected_second, expected_ms",
amine@400 531 [
amine@400 532 (0, 0, 0, 0), # zero
amine@400 533 (0.1, 1, 1 / 16, int(1000 / 16)), # one
amine@400 534 (1 / 8, 2, 1 / 8, int(1 / 8 * 1000)), # two
amine@400 535 (0.75, 12, 0.75, 750), # twelve
amine@400 536 (-0.1, 15, 15 / 16, int(15000 / 16)), # negative_1
amine@400 537 (-0.7, 5, 5 / 16, int(5000 / 16)), # negative_2
amine@400 538 ],
amine@400 539 ids=["zero", "one", "two", "twelve", "negative_1", "negative_2"],
amine@169 540 )
amine@169 541 def test_position_s_setter(
amine@169 542 self, position_s, expected_sample, expected_second, expected_ms
amine@169 543 ):
amine@169 544 self.audio_source.position_s = position_s
amine@169 545
amine@169 546 position = self.audio_source.position
amine@400 547 assert position == expected_sample
amine@164 548
amine@169 549 position_s = self.audio_source.position_s
amine@400 550 assert position_s == expected_second
amine@164 551
amine@169 552 position_ms = self.audio_source.position_ms
amine@400 553 assert position_ms == expected_ms
amine@164 554
amine@400 555 @pytest.mark.parametrize(
amine@400 556 "position_ms, expected_sample, expected_second, expected_ms",
amine@400 557 [
amine@400 558 (0, 0, 0, 0), # zero
amine@400 559 (100, 1, 1 / 16, int(1000 / 16)), # one
amine@400 560 (1000, 16, 1, 1000), # ten
amine@400 561 (-100, 15, 15 / 16, int(15 * 1000 / 16)), # negative_1
amine@400 562 (-500, 8, 0.5, 500), # negative_2
amine@400 563 (-700, 5, 5 / 16, int(5 * 1000 / 16)), # negative_3
amine@400 564 ],
amine@400 565 ids=["zero", "one", "ten", "negative_1", "negative_2", "negative_3"],
amine@169 566 )
amine@169 567 def test_position_ms_setter(
amine@169 568 self, position_ms, expected_sample, expected_second, expected_ms
amine@169 569 ):
amine@169 570 self.audio_source.position_ms = position_ms
amine@169 571
amine@169 572 position = self.audio_source.position
amine@400 573 assert position == expected_sample
amine@164 574
amine@169 575 position_s = self.audio_source.position_s
amine@400 576 assert position_s == expected_second
amine@164 577
amine@169 578 position_ms = self.audio_source.position_ms
amine@400 579 assert position_ms == expected_ms
amine@164 580
amine@164 581 def test_sr16_sw2_ch1_rewind(self):
amine@164 582 self.audio_source.read(10)
amine@164 583 self.audio_source.rewind()
amine@216 584 tp = self.audio_source.position
amine@400 585 assert tp == 0
amine@164 586
amine@164 587
amine@400 588 class TestBufferAudioSource_SR11_SW4_CH1:
amine@400 589 @pytest.fixture(autouse=True)
amine@400 590 def setup_and_teardown(self):
amine@164 591 self.data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh"
amine@164 592 self.audio_source = BufferAudioSource(
amine@321 593 data=self.data, sampling_rate=11, sample_width=4, channels=1
amine@164 594 )
amine@164 595 self.audio_source.open()
amine@400 596 yield
amine@164 597 self.audio_source.close()
amine@164 598
amine@164 599 def test_sr11_sw4_ch1_read_1(self):
amine@164 600 block = self.audio_source.read(1)
amine@164 601 exp = b"ABCD"
amine@400 602 assert block == exp
amine@164 603
amine@164 604 def test_sr11_sw4_ch1_read_6(self):
amine@164 605 block = self.audio_source.read(6)
amine@164 606 exp = b"ABCDEFGHIJKLMNOPQRSTUVWX"
amine@400 607 assert block == exp
amine@164 608
amine@164 609 def test_sr11_sw4_ch1_read_multiple(self):
amine@164 610 block = self.audio_source.read(1)
amine@164 611 exp = b"ABCD"
amine@400 612 assert block == exp
amine@164 613
amine@164 614 block = self.audio_source.read(6)
amine@164 615 exp = b"EFGHIJKLMNOPQRSTUVWXYZ01"
amine@400 616 assert block == exp
amine@164 617
amine@164 618 block = self.audio_source.read(3)
amine@164 619 exp = b"23456789abcd"
amine@400 620 assert block == exp
amine@164 621
amine@164 622 block = self.audio_source.read(9999)
amine@164 623 exp = b"efgh"
amine@400 624 assert block == exp
amine@164 625
amine@164 626 def test_sr11_sw4_ch1_read_all(self):
amine@164 627 block = self.audio_source.read(9999)
amine@400 628 assert block == self.data
amine@164 629
amine@164 630 block = self.audio_source.read(1)
amine@400 631 assert block is None
amine@164 632
amine@335 633 def test_sr11_sw4_ch1_sampling_rate(self):
amine@335 634 srate = self.audio_source.sampling_rate
amine@400 635 assert srate == 11
amine@164 636
amine@335 637 def test_sr11_sw4_ch1_sample_width(self):
amine@335 638 swidth = self.audio_source.sample_width
amine@400 639 assert swidth == 4
amine@164 640
amine@335 641 def test_sr11_sw4_ch1_channels(self):
amine@335 642 channels = self.audio_source.channels
amine@400 643 assert channels == 1
amine@164 644
amine@330 645 def test_sr11_sw4_ch1_intial_position_0(self):
amine@216 646 pos = self.audio_source.position
amine@400 647 assert pos == 0
amine@164 648
amine@216 649 def test_sr11_sw4_ch1_position_5(self):
amine@164 650 self.audio_source.read(5)
amine@216 651 pos = self.audio_source.position
amine@400 652 assert pos == 5
amine@164 653
amine@216 654 def test_sr11_sw4_ch1_position_9(self):
amine@164 655 self.audio_source.read(5)
amine@164 656 self.audio_source.read(4)
amine@216 657 pos = self.audio_source.position
amine@400 658 assert pos == 9
amine@164 659
amine@216 660 def test_sr11_sw4_ch1_position_0(self):
amine@164 661 self.audio_source.read(10)
amine@216 662 self.audio_source.position = 0
amine@216 663 pos = self.audio_source.position
amine@400 664 assert pos == 0
amine@164 665
amine@216 666 def test_sr11_sw4_ch1_position_10(self):
amine@216 667 self.audio_source.position = 10
amine@216 668 pos = self.audio_source.position
amine@400 669 assert pos == 10
amine@164 670
amine@330 671 def test_sr11_sw4_ch1_initial_position_s_0(self):
amine@216 672 tp = self.audio_source.position_s
amine@400 673 assert tp == 0.0
amine@164 674
amine@330 675 def test_sr11_sw4_ch1_position_s_1_after_read(self):
amine@330 676 srate = self.audio_source.sampling_rate
amine@164 677 # read one second
amine@164 678 self.audio_source.read(srate)
amine@216 679 tp = self.audio_source.position_s
amine@400 680 assert tp == 1.0
amine@164 681
amine@216 682 def test_sr11_sw4_ch1_position_s_0_63(self):
amine@164 683 # read 2.5 seconds
amine@164 684 self.audio_source.read(7)
amine@216 685 tp = self.audio_source.position_s
amine@400 686 assert tp, pytest.approx(0.636363636364)
amine@164 687
amine@216 688 def test_sr11_sw4_ch1_position_s_0(self):
amine@164 689 self.audio_source.read(10)
amine@216 690 self.audio_source.position_s = 0
amine@216 691 tp = self.audio_source.position_s
amine@400 692 assert tp == 0.0
amine@164 693
amine@216 694 def test_sr11_sw4_ch1_position_s_1(self):
amine@216 695 self.audio_source.position_s = 1
amine@216 696 tp = self.audio_source.position_s
amine@400 697 assert tp == 1.0
amine@164 698
amine@164 699 def test_sr11_sw4_ch1_rewind(self):
amine@164 700 self.audio_source.read(10)
amine@164 701 self.audio_source.rewind()
amine@169 702 tp = self.audio_source.position
amine@400 703 assert tp == 0
amine@164 704
amine@164 705
amine@400 706 class TestBufferAudioSourceCreationException:
amine@164 707 def test_wrong_sample_width_value(self):
amine@400 708 with pytest.raises(AudioParameterError) as audio_param_err:
amine@164 709 _ = BufferAudioSource(
amine@321 710 data=b"ABCDEFGHI", sampling_rate=9, sample_width=3, channels=1
amine@164 711 )
amine@400 712 assert (
amine@400 713 str(audio_param_err.value)
amine@400 714 == "Sample width must be one of: 1, 2 or 4 (bytes)"
amine@164 715 )
amine@164 716
amine@164 717 def test_wrong_data_buffer_size(self):
amine@400 718 with pytest.raises(AudioParameterError) as audio_param_err:
amine@164 719 _ = BufferAudioSource(
amine@321 720 data=b"ABCDEFGHI", sampling_rate=8, sample_width=2, channels=1
amine@164 721 )
amine@405 722 msg = "The length of audio data must be an integer multiple of "
amine@405 723 msg += "`sample_width * channels`"
amine@405 724 assert str(audio_param_err.value) == msg
amine@164 725
amine@164 726
amine@400 727 class TestAudioSourceProperties:
amine@164 728 def test_read_properties(self):
amine@164 729 data = b""
amine@164 730 sampling_rate = 8000
amine@164 731 sample_width = 2
amine@164 732 channels = 1
amine@164 733 a_source = BufferAudioSource(
amine@164 734 data, sampling_rate, sample_width, channels
amine@164 735 )
amine@164 736
amine@400 737 assert a_source.sampling_rate == sampling_rate
amine@400 738 assert a_source.sample_width == sample_width
amine@400 739 assert a_source.channels == channels
amine@164 740
amine@164 741 def test_set_readonly_properties_exception(self):
amine@164 742 data = b""
amine@164 743 sampling_rate = 8000
amine@164 744 sample_width = 2
amine@164 745 channels = 1
amine@164 746 a_source = BufferAudioSource(
amine@164 747 data, sampling_rate, sample_width, channels
amine@164 748 )
amine@164 749
amine@400 750 with pytest.raises(AttributeError):
amine@164 751 a_source.sampling_rate = 16000
amine@405 752
amine@405 753 with pytest.raises(AttributeError):
amine@164 754 a_source.sample_width = 1
amine@405 755
amine@405 756 with pytest.raises(AttributeError):
amine@164 757 a_source.channels = 2
amine@164 758
amine@164 759
amine@400 760 class TestAudioSourceShortProperties:
amine@164 761 def test_read_short_properties(self):
amine@164 762 data = b""
amine@164 763 sampling_rate = 8000
amine@164 764 sample_width = 2
amine@164 765 channels = 1
amine@164 766 a_source = BufferAudioSource(
amine@164 767 data, sampling_rate, sample_width, channels
amine@164 768 )
amine@164 769
amine@400 770 assert a_source.sr == sampling_rate
amine@400 771 assert a_source.sw == sample_width
amine@400 772 assert a_source.ch == channels
amine@164 773
amine@164 774 def test_set_readonly_short_properties_exception(self):
amine@164 775 data = b""
amine@164 776 sampling_rate = 8000
amine@164 777 sample_width = 2
amine@164 778 channels = 1
amine@164 779 a_source = BufferAudioSource(
amine@164 780 data, sampling_rate, sample_width, channels
amine@164 781 )
amine@164 782
amine@400 783 with pytest.raises(AttributeError):
amine@164 784 a_source.sr = 16000
amine@405 785
amine@405 786 with pytest.raises(AttributeError):
amine@164 787 a_source.sw = 1
amine@405 788
amine@405 789 with pytest.raises(AttributeError):
amine@164 790 a_source.ch = 2