AgentSkillsCN

macwhisper-recover

在 MacWhisper 录音因崩溃而损坏后进行恢复。可通过“恢复 MacWhisper”、“MacWhisper 崩溃”、“录音损坏”、“缺失 moov 原子”、“修复 m4a”等短语触发。

SKILL.md
--- frontmatter
name: macwhisper-recover
description: Recover corrupted MacWhisper recordings after crashes. Triggers on "recover macwhisper", "macwhisper crash", "corrupted recording", "missing moov atom", "fix m4a".

MacWhisper Crash Recovery

When to Use

Use this skill when MacWhisper crashed during a recording and the resulting .m4a files are corrupted (missing moov atom). Symptoms:

  • MacWhisper force-quit or crashed mid-recording
  • .m4a files exist but won't play or open
  • ffprobe reports "moov atom not found"
  • Files have structure: ftyp(28) + wide(8) + mdat(size=0)

Prerequisites

  • faad2: brew install faad2
  • ffmpeg: brew install ffmpeg
  • Python 3

Recovery Workflow

Step 1: Locate corrupted files

Check these locations for broken recordings:

  • ~/Desktop/ — user may have already copied them
  • /var/folders/ — search for .recordkit directories containing .m4a files:
    bash
    find /var/folders -name "*.recordkit" -type d 2>/dev/null
    
  • Inside .recordkit dirs, look for microphone-*.m4a and appaudio-sck-*.m4a

Step 2: Verify files are corrupted

bash
ffprobe <file.m4a>  # Should show "moov atom not found"
python3 -c "
d=open('<file.m4a>','rb').read(52)
print('ftyp:', d[4:8])
print('wide:', d[32:36])
print('mdat:', d[40:44])
print('mdat_size:', int.from_bytes(d[36:40],'big'))
"

Corrupted signature: ftyp at 4, wide at 32, mdat at 40, mdat_size=0.

Step 3: Find a reference M4A

A working M4A with the same codec (AAC-LC, 48kHz) is needed for the stsd box:

bash
ls ~/Library/Application\ Support/MacWhisper/Database/ExternalMedia/*.m4a

Pick one _mic-audio_ file as mic reference and one _app-audio_ file as app reference.

Step 4: Run the recovery script

bash
python3 ~/.claude/skills/macwhisper-recover/scripts/recover.py \
  --broken <corrupted.m4a> \
  --reference <working.m4a> \
  --output <recovered.m4a> \
  --channels mono|stereo

The script:

  1. Compiles the C AAC scanner if needed (aac_scan.c)
  2. Extracts raw AAC data from the broken file (offset 44)
  3. Scans frame boundaries using faad2
  4. Builds a valid moov atom (stsd from reference, computed stsz/stco/stsc/stts)
  5. Writes a valid M4A: ftyp(28) + mdat(8+data) + moov

Step 5: Verify recovery

bash
ffprobe <recovered.m4a>
ffmpeg -i <recovered.m4a> -c:a aac -b:a 128k -t 30 /tmp/test_30s.m4a -y

Step 6: Merge tracks (optional)

bash
ffmpeg -i mic_recovered.m4a -i app_recovered.m4a \
  -filter_complex amerge=inputs=2 -ac 2 -c:a aac -b:a 256k \
  merged.m4a -y

Technical Details

  • Broken structure: ftyp(28) + wide(8) + mdat(size=0, data to EOF) — data at offset 44
  • Output structure: ftyp(28) + mdat(correct size, 8+data) + moov — data at offset 36
  • stco offsets: must point to 36 (start of data in output file), NOT 44
  • stsd: copied verbatim from reference file (same codec config)
  • Frame size: each AAC frame = 1024 samples; discovered via faad2 bytesconsumed
  • ASC mono mic: 0x11 0x88 (AAC-LC, 48kHz, 1ch)
  • ASC stereo app: 0x11 0x90 (AAC-LC, 48kHz, 2ch)
  • Chunks: 46 samples per chunk (matches MacWhisper's default)
  • Movie timescale: 600; audio timescale: 48000