一、引言
本文从零开始搭建一条可以真正跑通的 LTC(Linear Timecode,线性时间码)测试链路:GinormoTime → 3.5mm → Rocky Linux → ALSA → WAV → LTC 解码。除了最终结果,也完整记录过程中遇到的"找不到 LTC Generator""ALSA 能录却只有 0%""录出来 WAV 近似静音"等问题,以及如何逐层定位。
最终验证结果
本次实验已经实际验证:GinormoTime 3.5.8 可以以 25.000 fps 生成 LTC,通过 Windows 电脑 3.5mm 模拟音频输出,经 3.5mm TRS 音频线进入 Rocky Linux 10.1 的 ALC221 Line In,再由 ALSA 以 48kHz / S16_LE / Stereo 采集为 WAV,并由 ltcdump -f 25 正确恢复连续的 25fps 时间码。
二、LTC 是什么?为什么普通 3.5mm 音频线能传
LTC 是 Linear Timecode 。可以把它简单理解成"编码在音频波形里的时间码"。发送端把帧级时间位置编码到一段连续的音频信号中,接收端再从这段波形恢复出 HH:MM:SS:FF。
因此,在这个实验里 LTC 并不是一串通过网线传输的数据,而是真实的模拟音频电信号。所以电脑声卡的 3.5mm 输出完全可以拿来做 LTC 实验。
bash
GinormoTime
↓ LTC 音频波形
Windows 3.5mm 输出
↓
3.5mm TRS 公对公音频线
↓
Rocky Linux Line In
↓
ALSA
↓
WAV
↓
LTC Decoder / ltcdump
↓
HH:MM:SS:FF
**注意:**本文验证的是"普通电脑模拟音频能否承载 LTC"的功能链路。专业现场设备常用的平衡 XLR、BNC 等 LTC 物理接口,会涉及电平、平衡、阻抗和接地等工程问题,不能简单等同于本实验。
三、实验环境与物理接线
| 角色 | 本次实验实际环境 |
|---|---|
| 发送端 | Windows + GinormoTime 3.5.8 |
| 接收端 | Rocky Linux 10.1(Red Quartz) |
| Rocky 声卡 | HDA Intel PCH / Realtek ALC221 |
| 采集设备 | ALSA hw:0,0 |
| 采样参数 | 48kHz / S16_LE / Stereo |
| 物理线材 | 3.5mm TRS 公对公音频线 |
bash
Windows + GinormoTime
3.5mm OUT
│
│ 3.5mm TRS 公对公
▼
Rocky Linux
蓝色 Line In
│
▼
ALC221
│
▼
ALSA hw:0,0
**接口不要接反:**普通 PC 通常绿色是 Line Out、蓝色是 Line In、粉色是 Mic In。本实验用蓝色 Line In 接收 LTC。
四、GinormoTime 下载与安装
本文实际使用 GinormoTime 3.5.8。官方页面介绍了内置实时、可配置的 LTC Generator,可通过电脑声卡或 USB Audio Interface 输出 LTC。
GinormoTime 官方下载 · 官方 Features · 官方 LTC 页面
官方 LTC 页面说明该软件免费使用,并要求 .NET Framework 4.7.2 或更高版本。下载 Windows 安装程序后按向导安装即可。
五、GinormoTime 配置 25fps LTC
(一)F12:选择 LTC 输出声卡
启动 GinormoTime,按 F12。找到 Linear Timecode Output Device。
本次使用:
[WASAPI] 扬声器 (3- High Definition Audio Device)
如果另一个选项叫 AOC TV (NVIDIA High Definition Audio),它更可能对应 HDMI/DP 音频。目标是从 3.5mm 模拟口输出时,应选择实际对应电脑模拟输出的"扬声器"设备。

GinormoTime F12 Settings 页面

Linear Timecode Output Device 设备列表
(二)为什么选 WASAPI
设备列表里可能同时有 DirectSound 和 WASAPI。同一物理设备可以有两个后端;本文最终使用 WASAPI。GinormoTime 官方资料推荐 WASAPI 作为较低延迟的音频输出方式。
(三)把工程帧率从 30fps 改成 25fps
一开始 GinormoTime 标题栏显示 [30.000 fps],而 F12 中没有 Frame Rate 字段。后来检查安装目录下的 data/config.json,发现:
"framerate": 30000,
改为:
"framerate": 25000,
完全退出并重新启动后,标题栏变为 [25.000 fps]。因此本次实验的工程帧率正式变成 25fps。
25fps 不需要 Drop Frame。 29.97 DF 是另一套时间基准问题;本实验直接使用 25fps 非 Drop Frame。
(四)在 Timecode Generator 中选择 Internal
最终的 LTC 设置为:
Source = Internal
Timecode = 00:00:00:00(测试时也可使用其它起始值)
Generator = On
Output = WASAPI
打开后,插在 Windows 电脑 3.5mm 输出端的耳机可以听到连续的数字脉冲声。这个步骤只能证明"有音频输出",最终是否是正确的 25fps LTC,还要看后面的解码结果。
六、找不到 LTC Generator:如何打开 Timecode Panel
这是本次排查最曲折的一步。主界面开始没有看到名为 "LTC Generator" 的明显按钮。F1 也没有提供一个独立的 LTC Generator 快捷键;F2、F11、右键主界面都没有解决问题。

GinormoTime 主界面

F1 Keyboard Command Reference

F1 Playback 快捷键页面
最终检查 data/config.json 中的布局:
"layout": {
"cuelist": {
"splitterPos": 50,
"visible": true
},
"playlist": {
"splitterPos": 25,
"visible": false
},
"timecodePane": false,
"outputsPane": false,
"timelineExpanded": 0
}
把两个面板开关改成:
"timecodePane": true,
"outputsPane": true
重启 GinormoTime 后,右侧出现 Timecode Generator Panel。

启用 Timecode/Outputs Panel 后的 GinormoTime 主界面
修改 config.json 前务必备份。 本次修改只针对面板显示,不建议在不了解字段含义时随意修改其它配置。
七、Rocky Linux:确认 ALSA 录音设备
进入 Rocky Linux 后,先确认 Capture Device:
arecord -l
echo "----------------"
arecord -L
echo "----------------"
cat /proc/asound/cards
本次实际发现:
**** List of CAPTURE Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC221 Analog [ALC221 Analog]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 2: ALC221 Alt Analog [ALC221 Alt Analog]
Subdevices: 1/1
Subdevice #0: subdevice #0
第一优先选择 hw:0,0。
(一)验证硬件支持的采集参数
arecord -D hw:0,0 --dump-hw-params -f S16_LE -r 48000 -c 2 -d 1 /dev/zero
实际输出显示设备支持:
FORMAT: S16_LE S32_LE
CHANNELS: 2
RATE: [44100 192000]
当指定 48kHz / S16_LE / Stereo 时,ALSA 能正常建立采集。对于后续 LTC 文件测试,我们固定使用 48kHz、16bit、2 声道。
八、最大的坑:ALSA 能录,但为什么一直是 0%
第一次使用:
arecord -D hw:0,0 -f S16_LE -r 48000 -c 2 -vv /dev/null
设备可以正常打开,但电平一直:
#+ | 00%
录下的 WAV 用 FFmpeg 检查甚至得到:
mean_volume: -91.0 dB
max_volume: -91.0 dB
也就是说,"ALSA 能打开设备"和"ALSA 真正在采 Line In"是两回事。
(一)切换到 Capture 视图
alsamixer
按 F6 选择 HDA Intel PCH,再按 F4 进入 Capture。

ALSA mixer 的 Playback 页面

ALSA mixer 的 Capture 页面
进一步执行:
amixer -c 0 scontents
发现关键问题:虽然输入源可以设置为 Line,但 Capture 开关实际是 off:
Simple mixer control 'Capture',0
...
Front Left: Capture 57 [90%] [25.50dB] [off]
Front Right: Capture 57 [90%] [25.50dB] [off]
(二)打开 Capture,并选择 Line
在 Capture 页面确认:
Input Source = Line
Input Source 1 = Line
然后:
amixer -c 0 sset 'Capture' cap
再用:
amixer -c 0 scontents
确认 Capture 已经变为 [on]。

最终确认 Line 输入源与 Capture 的 mixer 设置
一开始 Capture=90% 时,arecord -vv 一度达到 MAX。因此逐步降低到 30%:
amixer -c 0 sset 'Capture' 30%
amixer -c 0 sget 'Capture'
最终得到:
Front Left: Capture 19 [30%] [-3.00dB] [on]
Front Right: Capture 19 [30%] [-3.00dB] [on]
再次运行:
arecord -D hw:0,0 -f S16_LE -r 48000 -c 2 -vv /dev/null
实际输入电平约为 43%,不再是 0%,也不再一直顶满。
九、录制 LTC WAV 并检查音频
(一)正式录音
让 GinormoTime 输出 25fps LTC,然后在 Rocky Linux 执行:
arecord -D hw:0,0 -t wav -f S16_LE -r 48000 -c 2 -d 30 ltc_test.wav
(二)用 FFmpeg 检查 WAV
ffprobe -hide_banner ltc_test.wav
成功得到:
Duration: 00:00:30.00
Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s
然后用:
ffmpeg -hide_banner -i ltc_test.wav -af volumedetect -f null -
成功得到:
mean_volume: -7.9 dB
max_volume: -6.8 dB
这和之前的 -91dB 形成鲜明对比,说明 LTC 音频已经真实进入 WAV,而且峰值没有贴到 0dB 数字满幅。
十、LTC 解码:用 ltcdump 验证 25fps
Rocky Linux 本次环境的 DNF 仓库没有直接提供:
libltc
ltc-tools
ltcdump
所以参考《Rocky Linux 安装 libltc、ltc-tools 和 ltcdump》
然后:
ltcdump -f 25 -c 1 ltc_test.wav
-f 25 表示按 25fps 解码,-c 1 表示选择第 1 个音频声道。
(一)第一次成功解码
第一次成功解码结果类似:
17:14:09:01
17:14:09:02
17:14:09:03
...
17:14:09:24
17:14:10:00
17:14:10:01
这已经证明帧号按 25fps 的规则从 00 到 24,然后进入下一秒的 00。
(二)第二次严格验证起始时间码
重新测试后,ltcdump -f 25 -c 1 ltc_test3.wav 开头出现若干次 #DISCONTINUITY 和重复的 00:00:00:00;随后进入稳定连续的帧序:
00:00:00:01
00:00:00:02
...
00:00:00:24
00:00:01:00
00:00:01:01
...
00:00:01:24
00:00:02:00
这说明解码器在录音文件起始部分经历了锁定过程,但一旦锁定后,时间码持续稳定运行。
十一、怎样证明整条链路真的成功
① 有 LTC 声音耳机可以听到持续数字脉冲声
② ALSA 有输入 arecord -vv 不再是 0%
③ WAV 有效48kHz / S16_LE / Stereo
④ LTC 可解码 ltcdump -f 25 连续输出
⑤ 帧序正确00→01→...→24→00
bash
GinormoTime 3.5.8
├─ 25.000 fps
├─ Internal
├─ Timecode Generator = On
└─ WASAPI
│
▼
Windows 3.5mm OUT
│
▼
3.5mm TRS 音频线
│
▼
Rocky Linux ALC221 Line In
│
▼
ALSA hw:0,0
│
▼
arecord → ltc_test.wav
│
▼
ltcdump -f 25
│
▼
00:00:00:01
00:00:00:02
...
00:00:00:24
00:00:01:00
(一)从采样点进一步验证 25fps
48kHz 与 25fps 的理论关系是:
48000 / 25 = 1920 samples / frame
实际 ltcdump 输出中,相邻时间码帧的采样位置基本按约 1920 samples 递增,例如:
17:14:09:01 → 1009 ... 2927
17:14:09:02 → 2928 ... 4847
17:14:09:03 → 4848 ... 6767
因此不仅"声音能听见",而且从采样位置上也与 25fps 的时间基准相符。
十二、本次所有问题与解决方案
| 问题 | 现象 | 原因/判断 | 解决方式 |
|---|---|---|---|
| 找不到 LTC Generator | F1、F2、F11、F12、右键都没找到 | Timecode Generator Panel 没显示 | config.json 中 timecodePane、outputsPane 改为 true |
| 默认 30fps | 标题栏显示 [30.000 fps] |
"framerate": 30000 |
改为 "framerate": 25000,重启确认 |
| ALSA 可录但没有信号 | 电平 00%,WAV 为 -91dB | Input Source/Capture 路由不完整 | Input Source=Line,并打开 Capture switch |
| Capture 音量过高 | arecord -vv 显示 MAX |
输入增益过大 | 降到 30%,实际活动电平约 43% |
| DNF 找不到 libltc | dnf search 无匹配 |
当前环境无现成包 | 源码构建 libltc + ltc-tools |
| 首次解码起始码偏后 | 出现 17:14:09:01 等 |
录音开始时 Generator 已经运行 | 重新同步启动录音与 Generator |
| 开头出现 #DISCONTINUITY | 起始区域反复出现 | 解码器启动/重新锁定 | 观察后续帧;本次后续完全连续 |
十三、下一步:实时 LTC → OSC
现在完成的是"文件型闭环":
bash
GinormoTime → 3.5mm → Line In → ALSA → WAV → ltcdump
如果最终目标是自己的 LTC 控制程序,下一步可以把 WAV 去掉,让程序直接从 ALSA 读取实时 PCM,然后调用 libltc 实时解码:
bash
GinormoTime
│ LTC
▼
3.5mm
│
▼
ALSA hw:0,0
│
▼
实时 PCM
│
▼
libltc LTCDecoder
│
├─ 00:00:12:18
├─ 00:00:12:19
├─ 00:00:12:20
└─ ...
│
▼
Cue / 时间条件判断
│
▼
OSC
这条路线就与实际的 "LTC → OSC" 项目非常接近:ALSA 负责采集,libltc 负责恢复时间码,业务程序根据 HH:MM:SS:FF 判断 cue,再发送 OSC。