import os.path from glob import glob from typing import Any, Dict, cast from unittest import TestCase import wavinfo from .utils import all_files, ffprobe class TestWaveInfo(TestCase): def test_sanity(self): for wav_file in all_files(): info = wavinfo.WavInfoReader(wav_file) self.assertEqual( info.__repr__(), "WavInfoReader({}, latin_1, ascii)".format(os.path.abspath(wav_file)), ) self.assertIsNotNone(info) def test_fmt_against_ffprobe(self): for wav_file in all_files(): info = wavinfo.WavInfoReader(wav_file) ffprobe_info = ffprobe(wav_file) assert info.fmt is not None assert ffprobe_info is not None self.assertEqual( info.fmt.channel_count, ffprobe_info["streams"][0]["channels"] ) self.assertEqual( info.fmt.sample_rate, int(ffprobe_info["streams"][0]["sample_rate"]) ) self.assertEqual( info.fmt.bits_per_sample, int(ffprobe_info["streams"][0]["bits_per_sample"]), ) if info.fmt.audio_format == 1: self.assertTrue( ffprobe_info["streams"][0]["codec_name"].startswith("pcm") ) streams = ffprobe_info["streams"][0] byte_rate = ( int(streams["sample_rate"]) * streams["channels"] * int(streams["bits_per_sample"]) / 8 ) self.assertEqual(info.fmt.byte_rate, byte_rate) def test_data_against_ffprobe(self): for wav_file in all_files(): info = wavinfo.WavInfoReader(wav_file) ffprobe_info = cast(Dict[str, Any], ffprobe(wav_file)) assert ffprobe_info is not None assert info.data is not None self.assertEqual( info.data.frame_count, int(ffprobe_info["streams"][0]["duration_ts"]) ) def test_bext_against_ffprobe(self): for wav_file in all_files(): info = wavinfo.WavInfoReader(wav_file) ffprobe_info = ffprobe(wav_file) assert ffprobe_info is not None if info.bext: if "comment" in ffprobe_info["format"]["tags"]: self.assertEqual( info.bext.description, ffprobe_info["format"]["tags"]["comment"] ) else: self.assertEqual(info.bext.description, "") if "encoded_by" in ffprobe_info["format"]["tags"]: self.assertEqual( info.bext.originator, ffprobe_info["format"]["tags"]["encoded_by"], ) else: self.assertEqual(info.bext.originator, "") if "originator_reference" in ffprobe_info["format"]["tags"]: self.assertEqual( info.bext.originator_ref, ffprobe_info["format"]["tags"]["originator_reference"], ) else: self.assertEqual(info.bext.originator_ref, "") # these don't always reflect the bext info # self.assertEqual(info.bext.originator_date, # ffprobe_info['format']['tags']['date']) # self.assertEqual(info.bext.originator_time, # ffprobe_info['format']['tags']['creation_time']) self.assertEqual( info.bext.time_reference, int(ffprobe_info["format"]["tags"]["time_reference"]), ) if "coding_history" in ffprobe_info["format"]["tags"]: self.assertEqual( info.bext.coding_history, ffprobe_info["format"]["tags"]["coding_history"], ) else: self.assertEqual(info.bext.coding_history, "") def test_ixml(self): expected = { "A101_4.WAV": { "project": "BMH", "scene": "A101", "take": "4", "tape": "18Y12M31", "family_uid": "USSDVGR1112089007124015008231000", }, "A101_3.WAV": { "project": "BMH", "scene": "A101", "take": "3", "tape": "18Y12M31", "family_uid": "USSDVGR1112089007124014008228300", }, "A101_2.WAV": { "project": "BMH", "scene": "A101", "take": "2", "tape": "18Y12M31", "family_uid": "USSDVGR1112089007124004008218600", }, "A101_1.WAV": { "project": "BMH", "scene": "A101", "take": "1", "tape": "18Y12M31", "family_uid": "USSDVGR1112089007124001008206300", }, } for wav_file in all_files(): basename = os.path.basename(wav_file) if basename in expected: info = wavinfo.WavInfoReader(wav_file) e = expected[basename] self.assertIsNotNone(info.ixml) assert info.ixml is not None self.assertEqual(e["project"], info.ixml.project) self.assertEqual(e["scene"], info.ixml.scene) self.assertEqual(e["take"], info.ixml.take) self.assertEqual(e["tape"], info.ixml.tape) self.assertEqual(e["family_uid"], info.ixml.family_uid) for track in info.ixml.track_list: self.assertIsNotNone(track.channel_index) if basename == "A101_4.WAV" and track.channel_index == "1": self.assertEqual(track.name, "MKH516 A") def test_steinberg_ixml(self): nuendo_files = "tests/test_files/nuendo/*.wav" for file in glob(nuendo_files): info = wavinfo.WavInfoReader(file) assert info.ixml is not None self.assertIsNotNone(info.ixml.steinberg) assert info.ixml.steinberg is not None self.assertIsNotNone(info.ixml.steinberg.audio_speaker_arrangement) self.assertEqual(info.ixml.steinberg.sample_format_size, 3) self.assertEqual( info.ixml.steinberg.media_company, "https://github.com/iluvcapra/wavinfo", ) self.assertFalse(info.ixml.steinberg.media_drop_frames) self.assertEqual(info.ixml.steinberg.media_duration, 1200.0) def test_steinberg_missing(self): file_with_no_nuendo = "tests/test_files/sounddevices/A101_1.WAV" info = wavinfo.WavInfoReader(file_with_no_nuendo) assert info.ixml is not None self.assertIsNone(info.ixml.steinberg) def test_info_metadata(self): file_with_metadata = "tests/test_files/sound_grinder_pro/new_camera bumb 1.wav" self.assertTrue(os.path.exists(file_with_metadata)) info = wavinfo.WavInfoReader(file_with_metadata).info assert info is not None self.assertEqual(info.title, "camera bumb 1") self.assertEqual(info.artist, "Jamie Hardt") self.assertEqual(info.copyright, "© 2010 Jamie Hardt") self.assertEqual(info.product, "Test Sounds") # album self.assertEqual(info.album, info.product) self.assertEqual(info.comment, "Comments") self.assertEqual(info.software, "Sound Grinder Pro") self.assertEqual(info.created_date, "2010-12-28") self.assertEqual(info.engineer, "JPH") self.assertEqual(info.keywords, "Sound Effect, movement, microphone, bump") self.assertEqual(info.title, "camera bumb 1") self.assertEqual(type(info.to_dict()), dict) self.assertEqual(type(info.__repr__()), str)