Archive ·

The card refused our audio for thirteen minutes in every sixty-eight: 16 September 2026

New counters on the second unit lit up within three minutes: after certain clip changes the engine offered the DeckLink card more audio than a frame holds, and the card refused the surplus. A prediction committed an hour ahead pinned the cycle to the schedule, one clip giving two different shortfalls pinned the cause, a capture on the wire measured the gaps it left, and a change to when the engine rebuilds its audio sizing cleared it on both units.

Written once, on the date above. Corrections are added at the end as dated addenda, and nothing above them is changed silently.

What we saw

On 16 September 2026 at 10:40 UTC the second unit restarted to take a set of new instruments. Three of them had never existed before: how many times the DeckLink Duo 2 card turned down audio the engine offered it, how many sample-frames it turned down, and how much audio was waiting in the card’s own buffer. Within three minutes all three were moving, on all four channels.

From 10:43 to 10:53 UTC every single output frame — 29,950 of them, one every 20 ms — came with audio the card would not take. The card’s audio buffer sat at about 53,500 sample-frames, 1.1 seconds of sound at 48 kHz, and stayed there. At 10:53 the refusals stopped dead, and a minute later the buffer fell to under 2,000 sample-frames, where a working buffer cycles. In all, 36,451 refused writes, and the same count, to within two, on each of the four channels: one card, one event.

Our first reading of the arithmetic was that every write had been refused in full, because the shortfall per refused write was 959.94 sample-frames and one 20 ms frame of audio at 48 kHz is 960. That was wrong, and we said so in our own record the same evening. The engine was offering 1,920 sample-frames a frame, twice what a frame holds; the card took 960 and refused the surplus. That is why its buffer stayed full rather than draining, and why sound kept playing at all.

It came back every sixty-eight minutes

It was not a start-up effect. The same thing began again at 11:50 and at 12:58 UTC, each time for about thirteen minutes, each time about 36,400 refused writes, on all four channels at once. The schedule the second unit was playing takes 68.33 minutes to go round once, and the intervals between onsets were 66 and 68 minutes.

Two intervals fit almost anything, so we wrote a prediction down and committed it at 13:00:06 UTC, an hour ahead: the next onset at 14:06, give or take two minutes, and the test refuted if the counter did not move between 14:04 and 14:10. A timer read the log unattended at 14:12. The onset was in the 14:07 sample. Four onsets, intervals of 66, 68 and 69 minutes, against a 68.33-minute pass.

One honest qualification. We had made an earlier call, for 12:57, minutes before the sample that confirmed it. It hit, but a prediction written minutes before its datum is worth far less than one committed an hour ahead with a timestamp, and only the second counted.

The cause, and the fingerprint that proved it

When the engine moves from one clip to the next, it decides whether to rebuild the part that cuts the decoded sound into one block per frame. It rebuilt it when the number of audio channels changed or the sample rate changed. It did not rebuild it when only the source’s frame rate changed. On 18 July 2026 we had made that block size depend on the source’s frame rate, to remove a click at 25 frames a second, and did not add the frame rate to the condition. From then on, a clip that followed one at a different frame rate, with the same channels and sample rate, inherited its predecessor’s block size. The engine then fed the card at the clip’s own frame rate times the predecessor’s block size: correct only when the two rates matched.

What made this certain rather than plausible is that the same clip, a 730-second programme item, produced two different shortfalls depending on what came before it:

OnsetClip before itShortfall per refused write, measuredThe model predicts
First, from the restart25 frames a second959.94960.00
Second29.97 frames a second641.64641.60
Third29.97 frames a second641.51641.60
Fourth29.97 frames a second641.70641.60

A fault in the file itself — a bad audio stream, an odd sample rate — cannot give one file two magnitudes. A cause that depends on where the file sits in the playlist can, and the two values fall out of the predecessor’s frame rate with nothing fitted. On a cold start the schedule reaches that clip from a 25 fps item; inside the loop, from a 29.97 fps one.

The half no counter saw

The fault runs both ways, and only one way raised a counter. Fed too fast, the card’s buffer filled and it refused the surplus: that is everything above, about 18 % of a pass. Fed too slowly, the buffer drained and the card ran short of sound, and nothing counted that at all. By the same model that was about 41 % of a pass, across ten items. The instrument that found the fault was measuring the smaller half of it.

What it did to the sound on the wire

A refused surplus might only have delayed audio. We wanted to know what reached the SDI output, so we wrote the test down first, then put the faulty build back on the second unit for one capture during a burst, recorded the output through a de-embedder, and put the fixed build back.

The level alone did not show it: programme audio was on the wire at about the expected level. Counting 20 ms blocks of digital silence did. In 25 seconds of a clip whose source never goes quiet, the capture during the burst held 5.2 % silent blocks — about 1.3 seconds of short, scattered dropouts. The control was the same clip’s quiet opening on the fixed build: its source is 25.2 % silent, and the capture was 25.3 % — one block in 1,249 — so the capture path passes real silence through and does not invent it. The dropouts were not periodic; they would be heard as intermittent gaps, not a buzz. Scaled to the whole clip, that is roughly 38 seconds of gaps in each airing of it, once a pass, on all four channels — an estimate from one capture, not a measurement of every airing.

The fix

We did not add a third term to the condition. The block size now has a named shape — channels, sample rate and source frame rate — and the engine rebuilds whenever the next clip’s shape differs from the current one. A dependency added to the block size in future is added to the shape, and the comparison follows; the comment at that spot says so. A test now drives the real accumulator across a real clip change in which only the source frame rate changes, and checks the sample counts it then produces. Not one of the 881 tests we had at the time did that: each built the block size fresh, at one rate, and none crossed a junction.

It went onto the second unit at 18:07:58 UTC and the first at 20:53:55 UTC on 16 September 2026. The acceptance was written down before it: one full pass of the schedule with no refused write, and a buffer that neither fills up nor runs dry — the second half because running dry is the direction no counter sees. It passed within 72 minutes, including the junction where a 25 fps clip gives way to a 50 fps one, the sharpest under-feed on that schedule. The run then went on untouched for 35.3 hours, 31 passes, with no refused write on any of the four channels and no late frame.

Before the fix (a 7.4-hour run)After it (35.3 hours)
Refused writes254,9850
Audio never written60.8 minutes, 13.7 % of the run0
Card audio bufferpinned full for 13 minutes in every 682,572–3,875 sample-frames throughout

The longer record since then is in the audio-continuity row of our claims register.

What this does not show

  • Every junction on the wire. We recorded one clip at one junction. What would settle it is the output’s audio recorded across every junction of a full pass and compared with the source, rather than a counter that stays at zero.
  • The first unit. Its schedule walked through a junction that should have exposed it, but it had none of the new counters, and they reached it in the same build as the fix. Its exposure is an inference from the schedule, never an observation.
  • The August run. The fault was in the software of the 339-hour run of August 2026. What it did to that run’s audio was not measured; that run’s frame and junction figures are video figures.

Why it took sixty days

Nothing looked at the card’s audio buffer until 16 September. The engine counted its own frames, and our tests checked each part on its own. The fault lived in the joint between two clips, and no test crossed it. The counters that found it lit up within three minutes of first being switched on.