8.28.26 four-mic master

Eight mics down to four channels, four separate 4.97 GB files off Google Drive, stacked into one time-synced master and verified bit-exact against every source.

4mic channels
5:12:25runtime
5.32 GBmaster, FLAC
12/12bit-exact checks
27complete songs

The four sources

All four came off Drive as separate stereo files. The recorder wrote them on one clock, which shows in four identical durations.

ChLocal fileDrive title BytesDuration s
1mic1_4-40PM.wav4.40 PM4,966,484,33218745.373515
2mic2_4-48PM.wav4.48 PM 34,966,484,33218745.373515
3mic3_4-53PM.wav4.53 PM4,960,025,94818745.373515
4mic4_4-44PM.wav4.44 PM II4,966,484,33218745.373515

One file carries one mic

Every source is true dual-mono. Sampled 20 s at 30, 90 and 180 minutes into each file, the left and right channels are bit-identical:

max |L − R| = 0.00e+00 at all nine windows
Correlation +1.000000 in every one. Half of each 4.97 GB file is a duplicate of the other half, so four files give four real channels, which is exactly the four-channel submix off eight mics. The merge takes one channel per file and discards the duplicate.

The lags between mics are acoustic, not clock drift

GCC-PHAT against mic1. If these were clock offsets they would hold steady or drift in one direction. They move with the window instead, because the loudest source moves.

Windowmic2 samplesmic2 mic3 samplesmic3
30 min+53912.222 ms+62614.195 ms
90 min+54112.268 ms+63614.422 ms
180 min+55112.494 ms+64314.580 ms
240 min-207-4.694 ms-161-3.651 ms

12 ms of air is about 4.1 m and 14.5 ms about 5 m, both plausible room distances. So the master stacks at zero offset. Correcting these lags would smear the room image, which is the failure the multi-mic tooling exists to prevent.

The phone tape shares the recorder's clock

The song timecodes were derived from the 24 kbps AAC that Messages produced. Rather than assume they transfer, the phone tape was cross-correlated against mic1 at six windows:

WindowOffsetpeak / median
10 min+0.0697 s521.6
45 min+0.0697 s1008.6
90 min+0.0697 s832.2
150 min+0.0697 s192.2
210 min+0.0697 s357.2
270 min+0.0697 s356.9
Identical to four decimals across 4.5 hours
No drift at all. The phone runs 69.7 ms late, so mic_time = phone_time − 0.0697 converts every song boundary onto the mic feeds.

Bit-exact verification

Each master channel read against its own source, raw channel to raw channel, no downmix anywhere in the path:

Windowch0 vs mic1ch1 vs mic2 ch2 vs mic3ch3 vs mic4
20 min0.000e+000.000e+000.000e+000.000e+00
120 min0.000e+000.000e+000.000e+000.000e+00
260 min0.000e+000.000e+000.000e+000.000e+00

Twelve of twelve bit-exact, RMS ratio 1.000000 in every cell. The FLAC master is a lossless container around the same samples the recorder wrote.

Expanding to WAV

ffmpeg -i practice-8-28-4ch.flac -c:a pcm_s24le -rf64 auto practice-8-28-4ch.wav

FLAC was chosen because a 4-channel 24-bit WAV of this runtime is 9.9 GB and the drive had 13.4 GB free at that moment. Measured FLAC ratio on real content was 0.468.

Eight things that went wrong

A watcher that could never match
The candidate filenames used a plain space. Google Drive writes U+202F, a narrow no-break space, before PM. Proven from manifest.json on all three feeds that had already landed. The watcher sat silent for hours on a name that does not exist on disk.
launchd cannot list ~/Downloads
An interactive shell enumerates it fine. A background job gets nothing from a glob, and a permission-bit test still reports the directory readable, so the check has to be a real probe. The daemon logs glob=BLOCKED exact-stat=yes every tick. Detection by exact path works, and reading the bytes is a separate capability that fails on its own.
Jobs that died with their parent chat
The first watcher and merger ran as children of a chat process and vanished silently when it exited, losing about three hours. Everything now runs under a launchd agent.
A pgrep that matched its own watcher
pgrep -f practice-8-28-4ch matched any process merely naming the file, so the daemon logged “merge in progress” and skipped every tick while the fourth mic sat ready on disk. Now scoped to ffmpeg.*.
A copy that reported success after failing
The log line ran outside the && chain, so a failed copy still printed “imported” with an empty byte count. The copy result and the resulting size are both checked now.
Two writers on one inode
A 5 GB copy takes about 40 s, long enough for a daemon tick to begin during an interactive import and write into the same fixed .part path. The temp path carries the PID now. The file was verified clean anyway, cmp against the Drive original returned 0.
ffmpeg cannot infer a muxer from .part
The first merge died with Invalid argument before writing a byte. The format is explicit now and the temp file carries a real extension.
The verification was the bug, not the master
A first pass compared master channels against sources decoded with -ac 1 and every channel read 0.70711, exactly 1/√2, which looks precisely like a pan-filter downmix normalization. pan=mono|c0=c0, pan=1c|c0=c0 and channelsplit all produced the identical figure, and a filter difference cannot survive channelsplit, which applies no gain. Reading the raw interleaved channel instead gave bit-exact agreement. -ac 1 inflates dual-mono by √2.

The 27 complete songs

Out of 120 takes: 27 songs, 7 false starts, 13 workshop passes, 59 fragments, 14 noodles. The last column is the corrected start on the mic master.

#StartEndSec ScoreBPMMic start s4-ch cut
10:00:000:07:4146187.4118-0.0697127 MB
20:53:010:58:4634586.31183180.9303104 MB
31:00:541:07:1938582.61023653.9303116 MB
41:08:141:11:3920581.91334093.930364 MB
51:19:211:25:4938889.01024760.9303121 MB
61:36:401:39:1315372.41335799.930347 MB
71:39:261:44:0527991.2545965.930387 MB
81:44:281:46:009275.11296267.930330 MB
91:51:291:53:4914073.71106688.930340 MB
101:59:592:02:0212388.4767198.930340 MB
112:02:202:11:1353391.81187339.9303174 MB
122:12:332:14:3211980.51187952.930336 MB
132:21:162:31:5063484.51008475.9303199 MB
142:46:422:49:2516379.311310001.930346 MB
152:52:013:00:0348288.812010320.9303151 MB
163:01:213:08:0740681.09810880.9303129 MB
173:10:513:23:2375281.08111450.9303219 MB
183:23:563:30:0637083.211312235.9303114 MB
193:35:513:45:2257180.910712950.9303155 MB
203:47:383:50:5319577.310713657.930360 MB
213:55:093:59:4427584.310014108.930382 MB
224:00:084:04:4227483.59214407.930383 MB
234:04:584:07:1713980.514314697.930342 MB
244:10:074:20:2762091.212515006.9303197 MB
254:22:114:32:0959883.612815730.9303165 MB
264:32:154:54:04130990.16916334.9303394 MB
275:01:475:08:1939271.211818106.9303127 MB

Per-song cuts

All 27 songs are cut as 4-channel FLAC
Written to ~/Music/Band-Practice/songs-8-28-4ch/, 3.15 GB total, each one carrying the same four mics in the same order as the master. Every cut applies the 69.7 ms phone correction, uses a sample-accurate seek in place of -c copy, and is checked for length and channel count before it is kept. Spot-checked against the master at the same instant: all four channels 0.000e+00.