一盘磁带,标签上用马克笔写着“nala.webp”。

2026年1月4日 • 更新于 2026年2月14日

Cassette Drive:聆听你的文件。

网络升级之后,重温拨号上网技术,把文件存到磁带上。

技术: Python, NumPy, SciPy, ffmpeg, Reed-Solomon
Link: 源代码

Cassette Drive:磁带机时光机

几个月前,我决定升级我的家庭网络:为了进一步试验网络技术,我把我那台疲惫不堪的 Telmex 调制解调器/路由器的路由功能,换成了运行 OpenWRT 的 ER605v2。


计划很简单,现实却不然。时断时续的 WAN 掉线、奇怪的射频噪声,还有一个盯着网口指示灯的漫长夜晚。


在恢复出厂设置和翻论坛帖子的间隙,我点开了一段老式拨号上网声音的 YouTube 视频,结果一头扎进了兔子洞。调制、解调、纠错、同步音,整套模拟到数字的握手故事。几个小时后,我开始勾勒一个新点子:如果我能用软件造一个小小的磁带机,把文件以音频的形式存到磁带上会怎样?


于是就有了现在。Cassette Drive 是一个小巧的 Python 工具,可以把字节变成音频,再变回来。它使用 MFSK(多频移键控)把比特映射到音调上,添加前导码 + 同步字来定位有效载荷,并用 Reed-Solomon 纠错码包裹数据。结果是一条现代而有韧性的数据流,足以经受廉价磁带机带来的种种混乱。我在 Amazon 上买了一台 20 美元的磁带录放机,还有一盒五盘装、每面 45 分钟的磁带,突然之间,我就有了一种全新的存储介质!你知道人们常说的 3-2-1 备份原则吧……它肯定改成 3-3-1 原则会好得多,对吧?对吧???


我凌乱桌面上的磁带录音机
我凌乱桌面上的磁带录音机

概述

编码器接收一个文件,构建一个包含音频设置和元数据的紧凑头部,把数据分割成固定大小的块,并添加 Reed-Solomon ECC。然后它用前导码(交替的 0/1 比特)和同步字对所有内容进行封装,使解码器能够锁定信号。调制解调层使用 MFSK:每个符号是一个音调,每个音调编码多少比特取决于你选择了多少种不同的频率。在回程中,解码器对录音进行带通滤波,找到同步模式,用 Goertzel 检测器解调符号,重建原始文件,并用 CRC-32 进行校验。

我的第一个实验:磁带上的 Nala

我想存储的第一样东西,是我的猫 Nala 的一张照片。我用 ImageMagick 把图片缩小到 5 KB 以内,并将其编码成 WAV 文件。然后我通过磁带录音机播放这段音频,倒带,再把它录回我的笔记本电脑进行解码。


编码后标着“nala.webp”的磁带
编码后标着“nala.webp”的磁带


我本来预期会有错误,结果第一次就得到了完美的 CRC!公平地说,仅仅存储这张 5 KB 的图片就用掉了整整 45 分钟的磁带(作为参照,如果我把它存成 base64 字符串,用 8pt 字号轻松就能印在一张信纸上),但它成功了!


录制的 MFSK 音调的频率分析
录制的 MFSK 音调的频率分析

底层是怎么运作的?

Cassette Drive 有三层:


  1. 封装与元数据
  • 一个紧凑的二进制头部存储采样率、符号率、音调间隔、文件大小和文件名。
  • 头部包含一个 CRC-32,让解码器可以确认整个文件完好无损。
  1. 纠错
  • 每个数据块都由 Reed-Solomon ECC 保护,与二维码和 CD 使用的原理相同。
  • 你可以调整 ECC 百分比,以速度为代价换取更强的抗干扰能力。
  1. 调制解调层
  • MFSK 把比特组变成音调(音调越多 -> 每个符号的比特越多)。
  • 交替比特组成的前导码为解码器提供稳健的对齐目标。
  • 同步字标记有效载荷的边界,使数据流可以按字节对齐。

这一切都被设计成能容忍真实世界的噪声:电机抖动、磁带嘶嘶声,或是桌面上乱糟糟的走线。

针对真实录放设备进行校准

校准模式会生成一个包含多种符号率的 WAV 文件。


用于选择符号率的校准频谱图
用于选择符号率的校准频谱图


你把它通过你的音频链路播放,然后分析录音,找出仍能清晰解码的最快速率。这正是磁带机展现实力的地方。有些能很好地处理较高的符号率,有些则需要更慢、更宽容的设置。至于我那台廉价的录音机,它能承受的并不多。

如何试试

如果你想复现这个实验,从小处着手。用宽容的设置(较低的符号率和较高的 ECC)编码一个小于 5 KB 的文件。成功之后,你可以尝试提高速度。


试试解码这条消息吧!


Download hello.wav
编码后的消息,“hello.txt”


# 克隆仓库
git clone https://code.marvil.co/dumb-stuff/cassette-drive.git
cd cassette-drive

# 创建虚拟环境并安装依赖
python -m venv .venv
pip install -r requirements.txt

# 解码示例消息(请先下载 hello.wav 文件并放入 modulated/ 文件夹!)
python -m src decode --input modulated/hello.wav --output demodulated/hello.txt

或者,编码你自己的文件:


# 编码
python -m src encode --input in/myfile.bin --output modulated/myfile.wav

# 录制之后解码(需匹配相同的音调/频率设置)
python -m src decode --input modulated/myfile_recorded.wav --output demodulated/myfile_decoded.bin

最后的思考

从 Telmex 升级到 OpenWRT 的过程一团糟,但它促使我做了这个小而酷的项目。也许把它用于存储是个馊主意,但用于学习却是个绝妙的主意 :)


如果你试了,我想看看你的磁带。请在留言板告诉我!


微信联系

扫一扫,添加我的微信

扫描二维码添加我的微信
微信号