Download ComfyUI-MiniMaxH3-Context-Loop/tests/_audio_rounding_unit_test.py from dzmdd/Fast_deploy: direct link, hf CLI and curl.
- Browser
- Download file 6.42 kB
-
https://huggingface.co/dzmdd/Fast_deploy/resolve/main/ComfyUI-MiniMaxH3-Context-Loop/tests/_audio_rounding_unit_test.py
- Command line
-
hf download hf://dzmdd/Fast_deploy/ComfyUI-MiniMaxH3-Context-Loop/tests/_audio_rounding_unit_test.py
-
curl -L -o _audio_rounding_unit_test.py https://huggingface.co/dzmdd/Fast_deploy/resolve/main/ComfyUI-MiniMaxH3-Context-Loop/tests/_audio_rounding_unit_test.py
6.42 kB
| #!/usr/bin/env python3 | |
| """Standalone regressions for cumulative H3 audio sample budgeting.""" | |
| import importlib.util | |
| import pathlib | |
| import sys | |
| import types | |
| import torch | |
| ROOT = pathlib.Path(__file__).resolve().parents[1] | |
| PACKAGE = "h3_audio_rounding_unit" | |
| folder_paths = types.ModuleType("folder_paths") | |
| folder_paths.get_output_directory = lambda: str(ROOT) | |
| folder_paths.get_temp_directory = lambda: str(ROOT) | |
| folder_paths.get_input_directory = lambda: str(ROOT) | |
| folder_paths.get_annotated_filepath = lambda value: str(value) | |
| sys.modules["folder_paths"] = folder_paths | |
| package = types.ModuleType(PACKAGE) | |
| package.__path__ = [str(ROOT)] | |
| sys.modules[PACKAGE] = package | |
| shared_nodes = types.ModuleType(PACKAGE + ".nodes") | |
| shared_nodes.MiniMaxH3MotionContext = object | |
| shared_nodes._claim_inline_patch_ownership = lambda _conditioning=None: "test patch owner" | |
| shared_nodes._prepare_native_guide_conditioning = lambda *args: None | |
| shared_nodes._resize = lambda *args: None | |
| shared_nodes._streams_from_latent = lambda *args: None | |
| sys.modules[shared_nodes.__name__] = shared_nodes | |
| spec = importlib.util.spec_from_file_location( | |
| PACKAGE + ".chain_nodes", ROOT / "chain_nodes.py") | |
| chain = importlib.util.module_from_spec(spec) | |
| sys.modules[spec.name] = chain | |
| spec.loader.exec_module(chain) | |
| def generated_audio_case(frames, saved_samples): | |
| loads = iter([ | |
| {"delivered_audio": torch.ones((1, 2, count))} | |
| for count in saved_samples | |
| ]) | |
| chain._st_load = lambda _path: next(loads) | |
| return chain._generated_audio({"segments": [ | |
| { | |
| "index": index, | |
| "checkpoint": "clip_%04d.safetensors" % index, | |
| "sample_rate": 8000, | |
| "delivered_frames": frame_count, | |
| } | |
| for index, frame_count in enumerate(frames, start=1) | |
| ]}) | |
| def main(): | |
| original_st_load = chain._st_load | |
| original_prelude_audio = chain._prelude_audio | |
| try: | |
| trimmed = generated_audio_case([5, 5], [1667, 1667]) | |
| assert trimmed["waveform"].shape[-1] == round(10 / 24 * 8000) | |
| padded = generated_audio_case([4, 4], [1333, 1333]) | |
| assert padded["waveform"].shape[-1] == round(8 / 24 * 8000) | |
| assert torch.count_nonzero(padded["waveform"][..., -1:]) == 0 | |
| # A later masked-AV scene owns its complete decoded overlap. This is | |
| # the only way Soft AV's audio feather survives Loop Trim into the | |
| # final generated soundtrack. | |
| loads = iter([ | |
| {"delivered_audio": torch.ones((1, 1, 100))}, | |
| { | |
| "delivered_audio": torch.full((1, 1, 61), 3.0), | |
| "audio_with_overlap": torch.cat(( | |
| torch.full((1, 1, 39), 2.0), | |
| torch.full((1, 1, 61), 3.0), | |
| ), dim=-1), | |
| }, | |
| ]) | |
| chain._st_load = lambda _path: next(loads) | |
| owned = chain._generated_audio({ | |
| "compatibility": {"continuation_mode": "guide"}, | |
| "segments": [ | |
| {"index": 1, "checkpoint": "one", "sample_rate": 24, | |
| "raw_frames": 100, "delivered_frames": 100, | |
| "continuation_mode": "guide"}, | |
| {"index": 2, "checkpoint": "two", "sample_rate": 24, | |
| "raw_frames": 100, "delivered_frames": 61, | |
| "continuation_mode": "audio_feathered_av"}, | |
| ], | |
| }) | |
| assert owned["waveform"].shape[-1] == 161 | |
| assert torch.equal( | |
| owned["waveform"][0, 0, :61], torch.ones(61)) | |
| assert torch.equal( | |
| owned["waveform"][0, 0, 61:100], torch.full((39,), 2.0)) | |
| assert torch.equal( | |
| owned["waveform"][0, 0, 100:], torch.full((61,), 3.0)) | |
| # Scene 1 can itself continue an external video prelude. Carry its | |
| # private raw AV audio through _generated_audio so the generated scene | |
| # owns the incoming overlap at that boundary too. | |
| loads = iter([{ | |
| "delivered_audio": torch.full((1, 1, 61), 3.0), | |
| "audio_with_overlap": torch.cat(( | |
| torch.full((1, 1, 39), 2.0), | |
| torch.full((1, 1, 61), 3.0), | |
| ), dim=-1), | |
| }]) | |
| chain._st_load = lambda _path: next(loads) | |
| first_owned = chain._generated_audio({ | |
| "compatibility": { | |
| "continuation_mode": "audio_feathered_av", | |
| }, | |
| "segments": [ | |
| {"index": 1, "checkpoint": "first", "sample_rate": 24, | |
| "raw_frames": 100, "delivered_frames": 61, | |
| "continuation_mode": "audio_feathered_av"}, | |
| ], | |
| }) | |
| assert first_owned[chain.AUDIO_WITH_OVERLAP_FRAMES_KEY] == 100 | |
| assert first_owned[chain.AUDIO_TRIM_FRAMES_KEY] == 39 | |
| chain._prelude_audio = lambda _record: { | |
| "waveform": torch.ones((1, 1, 100)), "sample_rate": 24} | |
| external_owned = chain._audio_with_prelude( | |
| first_owned, 61, {"frame_count": 100}) | |
| assert external_owned["waveform"].shape[-1] == 161 | |
| assert torch.equal( | |
| external_owned["waveform"][0, 0, :61], torch.ones(61)) | |
| assert torch.equal( | |
| external_owned["waveform"][0, 0, 61:100], | |
| torch.full((39,), 2.0)) | |
| assert torch.equal( | |
| external_owned["waveform"][0, 0, 100:], | |
| torch.full((61,), 3.0)) | |
| chain._prelude_audio = lambda _record: { | |
| "waveform": torch.ones((1, 2, 1667)), "sample_rate": 8000} | |
| joined = chain._audio_with_prelude( | |
| {"waveform": torch.ones((1, 2, 1667)), "sample_rate": 8000}, | |
| 5, {"frame_count": 5}) | |
| assert joined["waveform"].shape[-1] == round(10 / 24 * 8000) | |
| one_short = chain._fit_pyav_audio_samples( | |
| torch.ones((2, 226666)), 226667) | |
| assert one_short.shape[-1] == 226667 | |
| assert torch.count_nonzero(one_short[..., -1:]) == 0 | |
| try: | |
| chain._fit_pyav_audio_samples(torch.ones((2, 226665)), 226667) | |
| except ValueError as exc: | |
| assert "226665 samples; 226667 are required" in str(exc) | |
| else: | |
| raise AssertionError("PyAV accepted an audio deficit above one sample") | |
| finally: | |
| chain._st_load = original_st_load | |
| chain._prelude_audio = original_prelude_audio | |
| print("H3 audio rounding: cumulative scene and prelude boundaries are exact") | |
| if __name__ == "__main__": | |
| main() | |