speaking-midi / tests /test_roundtrip.py
k-l-lambda's picture
Deploy complete CPU-capable Speaking MIDI demo
bc3f652
Raw History Blame Contribute Delete
2.35 kB
import tempfile
import unittest
from pathlib import Path
import numpy as np
from speaking_midi.core import Piano, Note, write_midi, read_midi, SR, make_dictionary, fit_temporal, metrics, make_log_band_loss
class Roundtrip(unittest.TestCase):
def test_midi_timing_and_audio(self):
notes=[Note(60,75,.12,.24),Note(64,45,.36,.12),Note(60,90,.36,.06)]
with tempfile.TemporaryDirectory() as d:
path=Path(d)/'a.mid';write_midi(notes,path); decoded=read_midi(path)
expected=sorted(notes,key=lambda n:(n.start+n.duration,n.pitch))
for a,b in zip(expected,decoded):
self.assertEqual(a.pitch,b.pitch); self.assertEqual(a.velocity,b.velocity)
self.assertAlmostEqual(a.start,b.start,places=5); self.assertAlmostEqual(a.duration,b.duration,places=5)
piano=Piano(); audio=piano.render(decoded,1)
self.assertEqual(len(audio),SR); self.assertTrue(np.isfinite(audio).all())
self.assertGreater(np.max(np.abs(audio)),.001)
piano.render([Note(90,120,0,.1)],.543)
repeated=piano.render(decoded,1)
# FluidSynth has small first-voice/block and int16 dither differences.
self.assertLess(metrics(audio,repeated)['spectral_convergence'],.01)
piano.close()
def test_cached_objective_matches_reported_metric(self):
rng = np.random.default_rng(123)
target = rng.normal(0, .02, SR).astype(np.float32)
objective = make_log_band_loss(target)
for estimate in [np.zeros(SR), target, np.r_[target * .6, np.zeros(SR // 2)]]:
self.assertAlmostEqual(objective(estimate), metrics(target, estimate)['log_band_mae'], places=7)
def test_dictionary_recovers_single_note(self):
piano=Piano(); atoms,params,_=make_dictionary(piano,'outputs/cache')
y=piano.render([Note(60,75,0,.12)],.7)
notes,trace=fit_temporal(y,atoms,params,max_notes=1)
self.assertEqual(len(notes),1); self.assertEqual(notes[0].pitch,60)
self.assertEqual(notes[0].velocity,75); self.assertAlmostEqual(notes[0].duration,.12)
self.assertLessEqual(notes[0].start,.01)
estimate=piano.render(notes,.7)
self.assertLess(metrics(y,estimate)['spectral_convergence'],.1)
piano.close()
if __name__=='__main__': unittest.main()