Download test_f0_fallback.py from batoon/hum: direct link, hf CLI and curl.
- Browser
- Download file 3.71 kB
-
https://huggingface.co/spaces/batoon/hum/resolve/main/test_f0_fallback.py
- Command line
-
hf download hf://spaces/batoon/hum/test_f0_fallback.py
-
curl -L -o test_f0_fallback.py https://huggingface.co/spaces/batoon/hum/resolve/main/test_f0_fallback.py
3.71 kB
| """Source-time fallback contracts on a known hum-like signal and plain noise.""" | |
| from __future__ import annotations | |
| from pathlib import Path | |
| import tempfile | |
| import unittest | |
| class F0FallbackTest(unittest.TestCase): | |
| def test_short_stable_note_survives_sheet_sage_empty_melody(self): | |
| import numpy as np | |
| import pretty_midi | |
| import soundfile as sf | |
| from f0_fallback import transcribe_f0 | |
| rate = 24000 | |
| wave = np.zeros(round(.6 * rate), dtype="float32") | |
| t = np.arange(round(.48 * rate)) / rate | |
| wave[round(.08 * rate):round(.56 * rate)] = .12 * np.sin(2 * np.pi * 261.626 * t) | |
| with tempfile.TemporaryDirectory() as directory: | |
| source, target = (Path(directory) / name for name in ("hum.wav", "notes.mid")) | |
| sf.write(source, wave, rate) | |
| self.assertEqual(transcribe_f0(source, target), 1) | |
| note = pretty_midi.PrettyMIDI(str(target)).instruments[0].notes[0] | |
| self.assertEqual(note.pitch, 60) | |
| self.assertAlmostEqual(note.start, .08, delta=.05) | |
| self.assertAlmostEqual(note.end, .56, delta=.05) | |
| def test_unpitched_noise_does_not_create_midi(self): | |
| import numpy as np | |
| import soundfile as sf | |
| from f0_fallback import transcribe_f0 | |
| with tempfile.TemporaryDirectory() as directory: | |
| source, target = (Path(directory) / name for name in ("noise.wav", "notes.mid")) | |
| sf.write(source, np.random.default_rng(20260926).normal(0, .02, 72000), 24000) | |
| with self.assertRaisesRegex(ValueError, "устойчивую высоту"): | |
| transcribe_f0(source, target) | |
| self.assertFalse(target.exists()) | |
| def test_glide_stays_one_note_but_connected_syllables_retrigger(self): | |
| import numpy as np | |
| import pretty_midi | |
| import soundfile as sf | |
| from f0_fallback import transcribe_f0 | |
| rate = 24000 | |
| times = np.arange(round(2.5 * rate)) / rate | |
| active = (times >= .2) & (times < 2.2) | |
| for name in ("glide", "repeats"): | |
| pitch = np.linspace(57, 62, active.sum()) if name == "glide" else np.full(active.sum(), 57) | |
| frequency = 440 * 2 ** ((pitch - 69) / 12) | |
| phase = 2 * np.pi * np.cumsum(frequency) / rate | |
| signal = np.zeros(len(times), dtype=np.float32) | |
| signal[active] = .13 * (np.sin(phase) + .28 * np.sin(2 * phase)) | |
| if name == "repeats": | |
| rng = np.random.default_rng(818) | |
| for boundary in (.8, 1.5): | |
| center = round(boundary * rate) | |
| width = round(.035 * rate) | |
| indices = np.arange(-width, width) | |
| dip = .82 * np.exp(-.5 * (indices / (width / 2.5)) ** 2) | |
| signal[center - width:center + width] *= 1 - dip | |
| signal[center:center + round(.018 * rate)] += rng.normal( | |
| 0, .018, round(.018 * rate)).astype(np.float32) | |
| with self.subTest(name=name), tempfile.TemporaryDirectory() as directory: | |
| source, target = (Path(directory) / filename for filename in ("hum.wav", "notes.mid")) | |
| sf.write(source, signal, rate) | |
| expected = 1 if name == "glide" else 3 | |
| self.assertEqual(transcribe_f0(source, target), expected) | |
| notes = pretty_midi.PrettyMIDI(str(target)).instruments[0].notes | |
| if name == "repeats": | |
| for note, start in zip(notes, (.2, .8, 1.5)): | |
| self.assertEqual(note.pitch, 57) | |
| self.assertAlmostEqual(note.start, start, delta=.06) | |