SC timecode: LTC Listen.app decodes the tracks' LTC from SoundGrid; PROP shows TIMECODE LOST mid-song
ProPresenter can't report its timecode, so LTC Listen (a small app on SC's ProPresenter Mac, microphone permission allowed on site 2026-10-26, LaunchAgent org.waterschurch.ltc-listen) reads the same SoundGrid input (com_waves_WCAudioGridEngine, channel 1) and writes the running timecode. The prop guard logs a drop in a song (2 s without timecode) with the song and timecode, and serves 127.0.0.1:8095/timecode, which SC's PROP key checks (TIMECODE LOST). Decoder tested against generated LTC and live (00:27:37:28). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -88,5 +88,39 @@ class TestGuard(unittest.TestCase):
|
||||
self.assertEqual(self.fake.calls.count("/v1/presentation/active/timeline/play"), 1)
|
||||
|
||||
|
||||
class TestTimecode(unittest.TestCase):
|
||||
def test_timecode_lost_in_a_song_and_back(self):
|
||||
fake, clock = FakeProP(), [1000.0]
|
||||
fake.layout = "Worship"
|
||||
orig_api, orig_ltc = pg.api, pg.Guard.ltc
|
||||
ltc = {"running": True, "tc": "00:01:00:00"}
|
||||
pg.api = fake
|
||||
pg.Guard.ltc = lambda self: dict(ltc, time=clock[0])
|
||||
try:
|
||||
g = pg.Guard(now=lambda: clock[0])
|
||||
def at(t):
|
||||
clock[0] = 1000.0 + t
|
||||
g.tick()
|
||||
at(0)
|
||||
at(5)
|
||||
ltc["running"] = False # gone mid-song
|
||||
at(6)
|
||||
self.assertFalse(g.lost) # not yet 2 s
|
||||
at(8.5)
|
||||
self.assertTrue(g.lost)
|
||||
self.assertEqual(g.state["ltc_drops"][0]["song"], "Jehovah")
|
||||
ltc["running"] = True
|
||||
at(10)
|
||||
self.assertFalse(g.lost)
|
||||
self.assertIn("back", g.state["ltc_drops"][0])
|
||||
fake.song = None # between songs no timecode is fine
|
||||
ltc["running"] = False
|
||||
at(20)
|
||||
at(30)
|
||||
self.assertFalse(g.lost)
|
||||
finally:
|
||||
pg.api, pg.Guard.ltc = orig_api, orig_ltc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user