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

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)

简单代码分析

相关推荐
我命由我123452 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
从零开始学习人工智能3 小时前
【踩坑实录】WSL2 解决 onnxruntime\-gpu ImportError: libcudart\.so\.13 无 CUDA13 运行库问题
python
抱抱宝3 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
用户938515635074 小时前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
卷无止境4 小时前
在 awesome-fastapi 里,哪些库值得一看?
后端·python
zhanghaha13144 小时前
Python进阶教程:6_JSON 数据解析 —— 新手完全指南
开发语言·python·json
Python私教5 小时前
API 输出模型怎么设计:从 model_dump() 到显式展示层
python·fastapi
Python私教5 小时前
本地 AI 工具服务该绑定 127.0.0.1 还是 0.0.0.0?
python·fastapi
卷无止境5 小时前
FastAPI 的Admin面板生态
后端·python
ctlover6 小时前
Streamlit 框架
python