代码分析 长音频分割为短音频

import os

import json

import argparse

from pathlib import Path

#简单易用的音频处理库 pydub 支持加载、切片、格式转换、音量调整,底层依赖ffmpeg

#关键功能就是 audiosegment.from_wav("file.wav") 加载wav文件,audiostart_ms:end_ms按毫秒切片 clip.export("out.wav",format="wav")导出音频

from pydub import AudioSegment

#这个函数,里面的三个参数是jsonl路径,音频路径,输出路径

def split_audio_by_jsonl(jsonl_path, audio_dir, output_dir):

audio_dir = Path(audio_dir)#为啥要这样?将传入的字符转换为一个pathlib.path对象,因为path可以拼接路径audio_dir / "file.wav",而不是 os.path.join(audio_dir, "file.wav")

#还可以直接调用方法.exists() .is_file()等

output_dir = Path(output_dir)#指向命令行参数,意义同上

#parents=true 如果目录路径中包含多级不存在的父目录,自动递归创建所有上级目录

output_dir.mkdir(parents=True, exist_ok=True)#如果没有便创建

#打开jsonl文件,逐行读取

with open(jsonl_path, 'r', encoding='utf-8') as f:

for line_num, line in enumerate(f, 1):

line = line.strip()

if not line:

continue

#json.loads(line)将字符串line 解析为Python字典item

#.get("key") 获取字段key

try:

item = json.loads(line)

key = item.get("key")

#.get("utterances",\[\])获得utterances字段,若缺失则默认为空列表

utterances = item.get("utterances", \[\])

if not key or not utterances:

print(f"⚠️ 跳过第 {line_num} 行:缺少 key 或 utterances")

continue

#看一下这段代码,首先是直接audio_dir/key作为路径,没有的话 加上wav后缀,要是还没有就是没有

查找原始音频文件(支持 .wav)

audio_path = audio_dir / key

if not audio_path.exists():

尝试带 .wav 后缀(如果 key 本身不含���

audio_path = audio_dir / (key + ".wav")

if not audio_path.exists():

print(f"❌ 第 {line_num} 行:未找到音频文件 {key}(或 {key}.wav)")

continue

print(f"🔊 正在处理: {key}")

#然后这个是找到了,用pydub库加载一个.wav格式的音频文件,将其转化为一个可编程操作的音频对象

  • pydub 会调用底层音频引擎(通常是 ffmpeg)读取文件;
  • 将音频数据加载到内存中,转换为 AudioSegment 对象;
  • 对象内部包含:
    • 音频采样率(如 16000 Hz)
    • 通道数(单声道/立体声)
    • 采样位深(如 16-bit)
    • 原始音频数据(以 bytesarray 存储)

audio = AudioSegment.from_wav(audio_path)

#对于utternaces 这里面很多条的 得到开始和结束的 得到text部分,我这个jsonl文件懒得粘贴条目,应该就是里面有 开始 结束 和text这三部分

for utt in utterances:

start_ms = utt.get("start_time")

end_ms = utt.get("end_time")

text = utt.get("text", "").strip()

if start_ms is None or end_ms is None:

continue

确保时间不越界

start_ms = max(0, start_ms)

end_ms = min(len(audio), end_ms)

#很健壮

if end_ms <= start_ms:

continue

切片

clip = audiostart_ms:end_ms

生成文件名:key_start_end.wav

safe_key = key.replace(".wav", "") # 避免重复 .wav

#这是对于文件的命名,就是以文件名命名,但是不要.wav 然后加上开始和结束时间 作为命名

filename = f"{safe_key}{start_ms}{end_ms}.wav"

#构建路径

output_path = output_dir / filename

clip.export(output_path, format="wav")

print(f" ✅ 保存: {filename}")

except Exception as e:

print(f"❌ 第 {line_num} 行处理出错: {e}")

print(f"\n✅ 所有音频切分完成!输出目录: {output_dir}")

def main():

#命令行参数

parser = argparse.ArgumentParser(

description="根据 JSONL 中的 utterances 时间戳切分音频"

)

parser.add_argument("jsonl_file", help="输入的 .jsonl 文件路径")

parser.add_argument("audio_dir", help="原始音频所在文件夹")

parser.add_argument("output_dir", help="切分后音频的输出文件夹")

args = parser.parse_args()

split_audio_by_jsonl(args.jsonl_file, args.audio_dir, args.output_dir)

简单代码分析

相关推荐
东风破_3 小时前
JavaScript 面试常考的字符串算法:从反转字符串到回文判断
前端·javascript
巴勒个啦3 小时前
D3.js 入门实战:用力导向图可视化项目依赖关系
javascript
不好听6134 小时前
JavaScript 的 this 到底指向谁?
javascript·面试
触底反弹4 小时前
🔥 2026 年爆火的 Harness Engineering 到底是什么?从原理到实战一文讲透
javascript·人工智能·程序员
mONESY4 小时前
一文搞定JavaScript不同场景中 this 的指向问题
javascript
用户298698530144 小时前
在 React 中使用 JavaScript 合并 Excel 文件
前端·javascript·react.js
大流星4 小时前
LangChainJs之基础模型(一)
javascript·langchain
你好潘先生4 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
橘子星4 小时前
JavaScript this 指向全解实战指南
前端·javascript
weedsfly4 小时前
JS垃圾回收:从原理到项目实战,彻底根治内存泄漏
前端·javascript·面试