annotate tests/test_core.py @ 192:8e63fc5d1af6

Add tests for AudioRegion.save
author Amine Sehili <amine.sehili@gmail.com>
date Sun, 21 Apr 2019 19:10:07 +0100
parents 94d2f7560a8e
children b274a22c9685
rev   line source
amine@192 1 import os
amine@86 2 import unittest
amine@88 3 from random import random
amine@192 4 from tempfile import TemporaryDirectory
amine@86 5 from genty import genty, genty_dataset
amine@97 6 from auditok import AudioRegion, AudioParameterError
amine@86 7
amine@86 8
amine@88 9 def _make_random_length_regions(
amine@88 10 byte_seq, sampling_rate, sample_width, channels
amine@88 11 ):
amine@88 12 regions = []
amine@88 13 for b in byte_seq:
amine@88 14 duration = round(random() * 10, 6)
amine@95 15 data = b * int(duration * sampling_rate) * sample_width * channels
amine@88 16 start = round(random() * 13, 3)
amine@88 17 region = AudioRegion(
amine@88 18 data, start, sampling_rate, sample_width, channels
amine@88 19 )
amine@88 20 regions.append(region)
amine@88 21 return regions
amine@88 22
amine@88 23
amine@86 24 @genty
amine@86 25 class TestAudioRegion(unittest.TestCase):
amine@86 26 @genty_dataset(
amine@86 27 simple=(b"\0" * 8000, 0, 8000, 1, 1, 1, 1, 1000),
amine@86 28 one_ms_less_than_1_sec=(
amine@86 29 b"\0" * 7992,
amine@86 30 0,
amine@86 31 8000,
amine@86 32 1,
amine@86 33 1,
amine@86 34 0.999,
amine@86 35 0.999,
amine@86 36 999,
amine@86 37 ),
amine@86 38 tree_quarter_ms_less_than_1_sec=(
amine@86 39 b"\0" * 7994,
amine@86 40 0,
amine@86 41 8000,
amine@86 42 1,
amine@86 43 1,
amine@86 44 0.99925,
amine@86 45 0.99925,
amine@86 46 999,
amine@86 47 ),
amine@86 48 half_ms_less_than_1_sec=(
amine@86 49 b"\0" * 7996,
amine@86 50 0,
amine@86 51 8000,
amine@86 52 1,
amine@86 53 1,
amine@86 54 0.9995,
amine@86 55 0.9995,
amine@86 56 1000,
amine@86 57 ),
amine@86 58 quarter_ms_less_than_1_sec=(
amine@86 59 b"\0" * 7998,
amine@86 60 0,
amine@86 61 8000,
amine@86 62 1,
amine@86 63 1,
amine@86 64 0.99975,
amine@86 65 0.99975,
amine@86 66 1000,
amine@86 67 ),
amine@86 68 simple_sample_width_2=(b"\0" * 8000 * 2, 0, 8000, 2, 1, 1, 1, 1000),
amine@86 69 simple_stereo=(b"\0" * 8000 * 2, 0, 8000, 1, 2, 1, 1, 1000),
amine@86 70 simple_multichannel=(b"\0" * 8000 * 5, 0, 8000, 1, 5, 1, 1, 1000),
amine@86 71 simple_sample_width_2_multichannel=(
amine@86 72 b"\0" * 8000 * 2 * 5,
amine@86 73 0,
amine@86 74 8000,
amine@86 75 2,
amine@86 76 5,
amine@86 77 1,
amine@86 78 1,
amine@86 79 1000,
amine@86 80 ),
amine@86 81 one_ms_less_than_1s_sw_2_multichannel=(
amine@86 82 b"\0" * 7992 * 2 * 5,
amine@86 83 0,
amine@86 84 8000,
amine@86 85 2,
amine@86 86 5,
amine@86 87 0.999,
amine@86 88 0.999,
amine@86 89 999,
amine@86 90 ),
amine@86 91 tree_qrt_ms_lt_1_s_sw_2_multichannel=(
amine@86 92 b"\0" * 7994 * 2 * 5,
amine@86 93 0,
amine@86 94 8000,
amine@86 95 2,
amine@86 96 5,
amine@86 97 0.99925,
amine@86 98 0.99925,
amine@86 99 999,
amine@86 100 ),
amine@86 101 half_ms_lt_1s_sw_2_multichannel=(
amine@86 102 b"\0" * 7996 * 2 * 5,
amine@86 103 0,
amine@86 104 8000,
amine@86 105 2,
amine@86 106 5,
amine@86 107 0.9995,
amine@86 108 0.9995,
amine@86 109 1000,
amine@86 110 ),
amine@86 111 quarter_ms_lt_1s_sw_2_multichannel=(
amine@86 112 b"\0" * 7998 * 2 * 5,
amine@86 113 0,
amine@86 114 8000,
amine@86 115 2,
amine@86 116 5,
amine@86 117 0.99975,
amine@86 118 0.99975,
amine@86 119 1000,
amine@86 120 ),
amine@86 121 arbitrary_length_1=(
amine@86 122 b"\0" * int(8000 * 1.33),
amine@86 123 2.7,
amine@86 124 8000,
amine@86 125 1,
amine@86 126 1,
amine@86 127 4.03,
amine@86 128 1.33,
amine@86 129 1330,
amine@86 130 ),
amine@86 131 arbitrary_length_2=(
amine@86 132 b"\0" * int(8000 * 0.476),
amine@86 133 11.568,
amine@86 134 8000,
amine@86 135 1,
amine@86 136 1,
amine@86 137 12.044,
amine@86 138 0.476,
amine@86 139 476,
amine@86 140 ),
amine@86 141 arbitrary_length_sw_2_multichannel=(
amine@86 142 b"\0" * int(8000 * 1.711) * 2 * 3,
amine@86 143 9.415,
amine@86 144 8000,
amine@86 145 2,
amine@86 146 3,
amine@86 147 11.126,
amine@86 148 1.711,
amine@86 149 1711,
amine@86 150 ),
amine@86 151 arbitrary_samplig_rate=(
amine@86 152 b"\0" * int(3172 * 1.318),
amine@86 153 17.236,
amine@86 154 3172,
amine@86 155 1,
amine@86 156 1,
amine@86 157 17.236 + int(3172 * 1.318) / 3172,
amine@86 158 int(3172 * 1.318) / 3172,
amine@86 159 1318,
amine@86 160 ),
amine@86 161 arbitrary_sr_sw_2_multichannel=(
amine@86 162 b"\0" * int(11317 * 0.716) * 2 * 3,
amine@86 163 18.811,
amine@86 164 11317,
amine@86 165 2,
amine@86 166 3,
amine@86 167 18.811 + int(11317 * 0.716) / 11317,
amine@86 168 int(11317 * 0.716) / 11317,
amine@86 169 716,
amine@86 170 ),
amine@86 171 )
amine@86 172 def test_creation(
amine@86 173 self,
amine@86 174 data,
amine@86 175 start,
amine@86 176 sampling_rate,
amine@86 177 sample_width,
amine@86 178 channels,
amine@86 179 expected_end,
amine@86 180 expected_duration_s,
amine@86 181 expected_duration_ms,
amine@86 182 ):
amine@86 183 region = AudioRegion(
amine@86 184 data, start, sampling_rate, sample_width, channels
amine@86 185 )
amine@86 186 self.assertEqual(region.sampling_rate, sampling_rate)
amine@86 187 self.assertEqual(region.sr, sampling_rate)
amine@86 188 self.assertEqual(region.sample_width, sample_width)
amine@86 189 self.assertEqual(region.sw, sample_width)
amine@86 190 self.assertEqual(region.channels, channels)
amine@86 191 self.assertEqual(region.ch, channels)
amine@86 192 self.assertEqual(region.start, start)
amine@86 193 self.assertEqual(region.end, expected_end)
amine@86 194 self.assertEqual(region.duration, expected_duration_s)
amine@86 195 self.assertEqual(len(region), expected_duration_ms)
amine@86 196 self.assertEqual(bytes(region), data)
amine@88 197
amine@97 198 def test_creation_invalid_data_exception(self):
amine@97 199 with self.assertRaises(AudioParameterError) as audio_param_err:
amine@97 200 _ = AudioRegion(
amine@97 201 data=b"ABCDEFGHI",
amine@97 202 start=0,
amine@97 203 sampling_rate=8,
amine@97 204 sample_width=2,
amine@97 205 channels=1,
amine@97 206 )
amine@97 207 self.assertEqual(
amine@97 208 "The length of audio data must be an integer "
amine@97 209 "multiple of `sample_width * channels`",
amine@97 210 str(audio_param_err.exception),
amine@97 211 )
amine@97 212
amine@88 213 @genty_dataset(
amine@192 214 simple=("output.wav", 1.230, "output.wav"),
amine@192 215 start=("output_{start}.wav", 1.230, "output_1.23.wav"),
amine@192 216 start_2=("output_{start}.wav", 1.233712, "output_1.233712.wav"),
amine@192 217 start_3=("output_{start}.wav", 1.2300001, "output_1.23.wav"),
amine@192 218 start_4=("output_{start:.3f}.wav", 1.233712, "output_1.234.wav"),
amine@192 219 start_5=(
amine@192 220 "output_{start:.8f}.wav",
amine@192 221 1.233712345,
amine@192 222 "output_1.23371200.wav",
amine@192 223 ),
amine@192 224 start_end_duration=(
amine@192 225 "output_{start}_{end}_{duration}.wav",
amine@192 226 1.455,
amine@192 227 "output_1.455_2.455_1.0.wav",
amine@192 228 ),
amine@192 229 start_end_duration_2=(
amine@192 230 "output_{start}_{end}_{duration}.wav",
amine@192 231 1.455321,
amine@192 232 "output_1.455321_2.455321_1.0.wav",
amine@192 233 ),
amine@192 234 )
amine@192 235 def test_save(self, format, start, expected):
amine@192 236 with TemporaryDirectory() as tmpdir:
amine@192 237 region = AudioRegion(b"0" * 160, start, 160, 1, 1)
amine@192 238 format = os.path.join(tmpdir, format)
amine@192 239 filename = region.save(format)[len(tmpdir) + 1 :]
amine@192 240 self.assertEqual(filename, expected)
amine@192 241
amine@192 242 @genty_dataset(
amine@88 243 simple=(8000, 1, 1),
amine@88 244 stereo_sw_2=(8000, 2, 2),
amine@88 245 arbitray_sr_multichannel=(5413, 2, 3),
amine@88 246 )
amine@88 247 def test_concatenation(self, sampling_rate, sample_width, channels):
amine@88 248
amine@88 249 region_1, region_2 = _make_random_length_regions(
amine@88 250 [b"a", b"b"], sampling_rate, sample_width, channels
amine@88 251 )
amine@88 252
amine@88 253 expected_start = region_1.start
amine@88 254 expected_duration = region_1.duration + region_2.duration
amine@88 255 expected_end = expected_start + expected_duration
amine@88 256 expected_data = bytes(region_1) + bytes(region_2)
amine@88 257 concat_region = region_1 + region_2
amine@88 258
amine@88 259 self.assertEqual(concat_region.start, expected_start)
amine@88 260 self.assertAlmostEqual(concat_region.end, expected_end, places=6)
amine@88 261 self.assertAlmostEqual(
amine@88 262 concat_region.duration, expected_duration, places=6
amine@88 263 )
amine@88 264 self.assertEqual(bytes(concat_region), expected_data)
amine@88 265
amine@88 266 @genty_dataset(
amine@88 267 simple=(8000, 1, 1),
amine@88 268 stereo_sw_2=(8000, 2, 2),
amine@88 269 arbitray_sr_multichannel=(5413, 2, 3),
amine@88 270 )
amine@88 271 def test_concatenation_many(self, sampling_rate, sample_width, channels):
amine@88 272
amine@88 273 regions = _make_random_length_regions(
amine@88 274 [b"a", b"b", b"c"], sampling_rate, sample_width, channels
amine@88 275 )
amine@88 276 expected_start = regions[0].start
amine@88 277 expected_duration = sum(r.duration for r in regions)
amine@88 278 expected_end = expected_start + expected_duration
amine@88 279 expected_data = b"".join(bytes(r) for r in regions)
amine@88 280 concat_region = sum(regions)
amine@88 281
amine@88 282 self.assertEqual(concat_region.start, expected_start)
amine@88 283 self.assertAlmostEqual(concat_region.end, expected_end, places=6)
amine@88 284 self.assertAlmostEqual(
amine@88 285 concat_region.duration, expected_duration, places=6
amine@88 286 )
amine@88 287 self.assertEqual(bytes(concat_region), expected_data)
amine@192 288 # see test_concatenation
amine@192 289 self.assertEqual(len(concat_region), round(expected_duration * 1000))
amine@88 290
amine@88 291 def test_concatenation_different_sampling_rate_error(self):
amine@88 292
amine@88 293 region_1 = AudioRegion(b"a" * 100, 0, 8000, 1, 1)
amine@88 294 region_2 = AudioRegion(b"b" * 100, 0, 3000, 1, 1)
amine@88 295
amine@88 296 with self.assertRaises(ValueError) as val_err:
amine@88 297 region_1 + region_2
amine@88 298 self.assertEqual(
amine@88 299 "Can only concatenate AudioRegions of the same "
amine@88 300 "sampling rate (8000 != 3000)",
amine@88 301 str(val_err.exception),
amine@88 302 )
amine@88 303
amine@88 304 def test_concatenation_different_sample_width_error(self):
amine@88 305
amine@88 306 region_1 = AudioRegion(b"a" * 100, 0, 8000, 2, 1)
amine@88 307 region_2 = AudioRegion(b"b" * 100, 0, 8000, 4, 1)
amine@88 308
amine@88 309 with self.assertRaises(ValueError) as val_err:
amine@88 310 region_1 + region_2
amine@88 311 self.assertEqual(
amine@88 312 "Can only concatenate AudioRegions of the same "
amine@88 313 "sample width (2 != 4)",
amine@88 314 str(val_err.exception),
amine@88 315 )
amine@88 316
amine@88 317 def test_concatenation_different_number_of_channels_error(self):
amine@88 318
amine@88 319 region_1 = AudioRegion(b"a" * 100, 0, 8000, 1, 1)
amine@88 320 region_2 = AudioRegion(b"b" * 100, 0, 8000, 1, 2)
amine@88 321
amine@88 322 with self.assertRaises(ValueError) as val_err:
amine@88 323 region_1 + region_2
amine@88 324 self.assertEqual(
amine@88 325 "Can only concatenate AudioRegions of the same "
amine@88 326 "number of channels (1 != 2)",
amine@88 327 str(val_err.exception),
amine@88 328 )