一、引言
本文从零开始搭建一条可以真正跑通的 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 实验。
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 |
| 采集设备 | ALSAhw:0,0 |
| 采样参数 | 48kHz / S16_LE / Stereo |
| 物理线材 | 3.5mm TRS 公对公音频线 |
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%,也不再一直顶满。
九、改用 USB 音频接口:Onyx Producer 2-2 实测
在主板 ALC221 已经验证成功之后,又把 Rocky Linux 的 LTC 接收端改成了Onyx Producer 2-2 USB Audio Interface。这一步很有价值:它验证了 LTC 并不依赖主板自带声卡,而是可以通过独立 USB 音频接口稳定采集。
(一) Rocky Linux 发现新的 USB 声卡
重新执行:
arecord -l echo "----------------" arecord -L echo "----------------" cat /proc/asound/cards
实际输出中出现:
card 0: PCH [HDA Intel PCH], device 0: ALC221 Analog [ALC221 Analog] card 0: PCH [HDA Intel PCH], device 2: ALC221 Alt Analog [ALC221 Alt Analog] card 1: O22 [Onyx Producer 2-2], device 0: USB Audio [USB Audio]
因此新的 USB 采集设备对应:
hw:1,0
系统卡名是O22,长期使用时也可以考虑:
hw:O22,0
相比直接写hw:1,0,用卡名可以避免 USB 声卡插拔后卡号发生变化带来的不便。
(二)第一次尝试 S16_LE:失败,但原因很简单
沿用 ALC221 的录音参数执行:
arecord -D hw:1,0 -f S16_LE -r 48000 -c 2 -vv /dev/null
结果:
arecord: set_params:1393: Sample format non available Available formats: - S32_LE
这不是 LTC 问题,也不是 USB 声卡故障,而是 Onyx 的硬件采集端点不提供S16_LE。
(三)确认 Onyx 的实际硬件能力
arecord -D hw:1,0 --dump-hw-params \ -f S32_LE -r 48000 -c 2 -d 1 /dev/zero
实测结果确认:
FORMAT: S32_LE SAMPLE_BITS: 32 FRAME_BITS: 64 CHANNELS: 2 RATE: [44100 192000]
而在指定工作参数时,ALSA 成功建立:
FORMAT: S32_LE CHANNELS: 2 RATE: 48000 ... Recording WAVE '/dev/zero' : Signed 32 bit Little Endian, Rate 48000 Hz, Stereo
因此新的稳定采集参数变为:
| 项目 | ALC221 方案 | Onyx USB 方案 |
|---|---|---|
| ALSA 设备 | hw:0,0 | hw:1,0(或hw:O22,0) |
| 采样格式 | S16_LE | S32_LE |
| 采样率 | 48000 Hz | 48000 Hz |
| 声道 | 2 | 2 |
(四)第一次显示 0%:原来是线没接好
使用正确的 S32_LE 参数测试时,第一次仍然出现:
#+ | 00%
随后检查发现,原因不是 ALSA,也不是 Onyx 配置,而是3.5mm → Onyx 的物理线没有接好。
重新接好 LTC 音频线后,再执行:
arecord -D hw:1,0 \ -f S32_LE \ -r 48000 \ -c 2 \ -vv \ /dev/null
得到:
Recording WAVE '/dev/null' : Signed 32 bit Little Endian, Rate 48000 Hz, Stereo ########################################+ | 79%
79% 的稳定活动电平证明 Onyx 已经真正收到 LTC 音频。
(五)Onyx 版本正式录制 LTC
保持 GinormoTime 的:
25.000 fps Internal Timecode = 00:00:00:00 Generator = On WASAPI
Rocky Linux 使用:
arecord -D hw:1,0 \ -t wav \ -f S32_LE \ -r 48000 \ -c 2 \ -d 30 \ ltc_usb.wav
录制成功后生成 30 秒的 32-bit PCM WAV。随后使用 FFmpeg 检查:
ffmpeg -hide_banner -i ltc_usb.wav \ -af volumedetect -f null -
实际结果:
mean_volume: -6.3 dB max_volume: -2.0 dB
这说明 Onyx 录到的是强度正常的有效音频信号,峰值距离 0dB 数字满幅仍有约 2dB 余量。
USB 声卡方案的最终结论:
Onyx Producer 2-2 的 USB Capture Endpoint 使用S32_LE / 48kHz / Stereo。物理线接好后,ALSA 实时电平约 79%,录制出的ltc_usb.wav音量检测为mean=-6.3dB、max=-2.0dB,随后可以被ltcdump -f 25正确解码。这证明独立 USB 音频接口同样可以完整承载本实验的 LTC 接收链路。
十、录制 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
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
现在完成的是“文件型闭环”:
GinormoTime → 3.5mm → Line In → ALSA → WAV → ltcdump如果最终目标是自己的 LTC 控制程序,下一步可以把 WAV 去掉,让程序直接从 ALSA 读取实时 PCM,然后调用 libltc 实时解码:
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。
十五、参考资料
- GinormoTime 官方 Download
- GinormoTime 官方 Features
- GinormoTime 官方 LTC 页面
- x42/libltc
- x42/ltc-tools