1
0
Эх сурвалжийг харах

更新字幕转 VAD List的方法

Signed-off-by: allan716 <[email protected]>
allan716 3 жил өмнө
parent
commit
60aad303ce

+ 11 - 0
internal/pkg/my_util/util.go

@@ -495,3 +495,14 @@ func MakePowerOfTwo(x int64) int64 {
 
 	return int64(math.Pow(2, float64(tmpRound)))
 }
+
+// Make10msMultiple 将传入的秒,规整到 10ms 的倍数,返回依然是 秒
+func Make10msMultiple(input float64) float64 {
+	const bb = 100
+	// 先转到 10 ms 单位,比如传入是 1.912 - > 191.2
+	t10ms := input * bb
+	// 191.2 - > 191.0
+	newT10ms := math.Floor(t10ms)
+	// 转换回来
+	return newT10ms / bb
+}

+ 123 - 16
internal/pkg/sub_helper/sub_helper.go

@@ -1,6 +1,7 @@
 package sub_helper
 
 import (
+	"errors"
 	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/archive_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
@@ -9,6 +10,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/regex_things"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
 	"github.com/go-rod/rod/lib/utils"
@@ -370,9 +372,9 @@ func MergeMultiDialogue4EngSubtitle(inSubParser *subparser.FileInfo) {
 }
 
 // GetVADInfoFeatureFromSub 跟下面的 GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert 函数功能一致
-func GetVADInfoFeatureFromSub(infoSrc *subparser.FileInfo, FrontAndEndPer float64, SubUnitMaxCount int, insert bool) ([]SubUnit, error) {
+func GetVADInfoFeatureFromSub(fileInfo *subparser.FileInfo, frontAndEndPer float64, subUnitMaxCount int, insert bool) ([]SubUnit, error) {
 
-	return GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(infoSrc, FrontAndEndPer, SubUnitMaxCount, 0, insert)
+	return GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo, frontAndEndPer, subUnitMaxCount, 0, insert)
 }
 
 /*
@@ -382,46 +384,52 @@ func GetVADInfoFeatureFromSub(infoSrc *subparser.FileInfo, FrontAndEndPer float6
 	2. 将整个字幕,抽取连续 5 句对话为一个单元,提取时间片段信息
 	3. 这里抽取的是特征,也就有额外的逻辑去找这个特征(本程序内会描述为“钥匙”)
 */
-func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(infoSrc *subparser.FileInfo, SkipFrontAndEndPer float64, SubUnitMaxCount int, offsetTime float64, insert bool) ([]SubUnit, error) {
-	if SubUnitMaxCount < 0 {
-		SubUnitMaxCount = 0
+func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64, subUnitMaxCount int, offsetTime float64, insert bool) ([]SubUnit, error) {
+	if subUnitMaxCount < 0 {
+		subUnitMaxCount = 0
 	}
 	srcSubUnitList := make([]SubUnit, 0)
 	srcSubDialogueList := make([]subparser.OneDialogueEx, 0)
 	srcOneSubUnit := NewSubUnit()
 
-	// srcDuration
-	lastDialogueExTimeEnd, err := infoSrc.ParseTime(infoSrc.DialoguesEx[len(infoSrc.DialoguesEx)-1].EndTime)
+	// 最后一个对话的结束时间
+	lastDialogueExTimeEnd, err := fileInfo.ParseTime(fileInfo.DialoguesEx[len(fileInfo.DialoguesEx)-1].EndTime)
 	if err != nil {
 		return nil, err
 	}
-	srcDuration := my_util.Time2SecendNumber(lastDialogueExTimeEnd)
+	// 相当于总时长
+	fullDuration := my_util.Time2SecendNumber(lastDialogueExTimeEnd)
+	// 最低的起始时间,因为可能需要裁剪范围
+	startRangeTimeMin := fullDuration * SkipFrontAndEndPer
+	endRangeTimeMax := fullDuration * (1.0 - SkipFrontAndEndPer)
 
-	for i := 0; i < len(infoSrc.DialoguesEx); i++ {
+	println(startRangeTimeMin)
+	println(endRangeTimeMax)
 
-		oneDialogueExTimeStart, err := infoSrc.ParseTime(infoSrc.DialoguesEx[i].StartTime)
+	for i := 0; i < len(fileInfo.DialoguesEx); i++ {
+
+		oneDialogueExTimeStart, err := fileInfo.ParseTime(fileInfo.DialoguesEx[i].StartTime)
 		if err != nil {
 			return nil, err
 		}
-		oneDialogueExTimeEnd, err := infoSrc.ParseTime(infoSrc.DialoguesEx[i].EndTime)
+		oneDialogueExTimeEnd, err := fileInfo.ParseTime(fileInfo.DialoguesEx[i].EndTime)
 		if err != nil {
 			return nil, err
 		}
 
 		oneStart := my_util.Time2SecendNumber(oneDialogueExTimeStart)
-
 		if SkipFrontAndEndPer > 0 {
-			if srcDuration*SkipFrontAndEndPer > oneStart || srcDuration*(1.0-SkipFrontAndEndPer) < oneStart {
+			if fullDuration*SkipFrontAndEndPer > oneStart || fullDuration*(1.0-SkipFrontAndEndPer) < oneStart {
 				continue
 			}
 		}
 
 		// 如果当前的这一句话,为空,或者进过正则表达式剔除特殊字符后为空,则跳过
-		if my_util.ReplaceSpecString(infoSrc.GetDialogueExContent(i), "") == "" {
+		if my_util.ReplaceSpecString(fileInfo.GetDialogueExContent(i), "") == "" {
 			continue
 		}
 		// 低于 5句对白,则添加
-		if srcOneSubUnit.GetDialogueCount() < SubUnitMaxCount {
+		if srcOneSubUnit.GetDialogueCount() < subUnitMaxCount {
 			// 算上偏移
 			offsetTimeDuration := time.Duration(offsetTime * math.Pow10(9))
 			oneDialogueExTimeStart = oneDialogueExTimeStart.Add(offsetTimeDuration)
@@ -433,7 +441,7 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(infoSrc *subparser.FileInf
 				srcOneSubUnit.Add(oneDialogueExTimeStart, oneDialogueExTimeEnd)
 			}
 			// 这一个单元的 Dialogue 需要合并起来,才能判断是否符合“钥匙”的要求
-			srcSubDialogueList = append(srcSubDialogueList, infoSrc.DialoguesEx[i])
+			srcSubDialogueList = append(srcSubDialogueList, fileInfo.DialoguesEx[i])
 
 		} else {
 			// 用完清空
@@ -450,3 +458,102 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(infoSrc *subparser.FileInf
 
 	return srcSubUnitList, nil
 }
+
+/*
+	GetVADInfosFromSub 将 Sub 文件转换为 VAD List 信息
+*/
+func GetVADInfosFromSub(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64, pieces int) ([]SubUnit, error) {
+	// 至少分为一份
+	if pieces <= 0 {
+		pieces = 1
+	}
+	outSubUnits := make([]SubUnit, 0)
+	if len(fileInfo.DialoguesEx) <= 0 {
+		return nil, errors.New("GetVADInfosFromSub fileInfo Dialogue Length is 0")
+	}
+	/*
+		先拼凑出完整的一个 VAD List
+		因为 VAD 的窗口是 10ms,那么需要多每一句话按 10 ms 的单位进行取整
+		每一句话开始、结束的时间,需要向下取整
+	*/
+	// 字幕的开始时间
+	subStartTime, err := fileInfo.ParseTime(fileInfo.DialoguesEx[0].StartTime)
+	if err != nil {
+		return nil, err
+	}
+	// 字幕的结束时间
+	subEndTime, err := fileInfo.ParseTime(fileInfo.DialoguesEx[len(fileInfo.DialoguesEx)-1].EndTime)
+	if err != nil {
+		return nil, err
+	}
+	// 字幕的时长,对时间进行向下取整
+	subStartTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(subStartTime))
+	subEndTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(subEndTime))
+
+	subFullSecondTimeFloor := subEndTimeFloor - subStartTimeFloor
+	// 根据这个时长就能够得到一个完整的 VAD List,然后再通过每一句对白进行 VAD 值的调整即可,这样就能够保证
+	// 相同的一个字幕因为使用 ffmpeg 导出 srt 和 ass 后的,可能存在总体时间轴不一致的问题
+	// 123.450 - > 12345
+	vadLen := int(subFullSecondTimeFloor * 100)
+	subVADs := make([]vad.VADInfo, vadLen)
+	subStartTimeFloor10ms := subStartTimeFloor * 100
+	for i := 0; i < vadLen; i++ {
+		subVADs[i] = *vad.NewVADInfoBase(false, time.Duration((subStartTimeFloor10ms+float64(i))*math.Pow10(7)))
+	}
+	// 计算出需要截取的片段,起始和结束
+	skipStartIndex := int(float64(vadLen) * SkipFrontAndEndPer)
+	skipEndIndex := vadLen - skipStartIndex
+	// 现在需要从 fileInfo 的每一句对白也就对应一段连续的 VAD active = true 来进行改写,记得向下取整
+	for _, dialogueEx := range fileInfo.DialoguesEx {
+
+		// 字幕的开始时间
+		oneDialogueStartTime, err := fileInfo.ParseTime(dialogueEx.StartTime)
+		if err != nil {
+			return nil, err
+		}
+		// 字幕的结束时间
+		oneDialogueEndTime, err := fileInfo.ParseTime(dialogueEx.EndTime)
+		if err != nil {
+			return nil, err
+		}
+		// 字幕的时长,对时间进行向下取整
+		oneDialogueStartTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(oneDialogueStartTime))
+		oneDialogueEndTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(oneDialogueEndTime))
+		// 得到一句对白的时长
+		changeVADStartIndex := int(oneDialogueStartTimeFloor * 100)
+		changeVADEndIndex := int(oneDialogueEndTimeFloor * 100)
+		// 跳过整体的前后百分比
+		if changeVADStartIndex < skipStartIndex {
+			changeVADStartIndex = skipStartIndex
+		}
+		if changeVADEndIndex > skipEndIndex {
+			changeVADEndIndex = skipEndIndex
+		}
+		// 调整之前做好的整体 VAD 的信息,符合 VAD active = true
+		for i := changeVADStartIndex; i < changeVADEndIndex; i++ {
+			subVADs[i].Active = true
+		}
+	}
+	// 整体的 VAD 信息构建完了,现在需要进行切割,分成多份
+	onePartLen := vadLen / pieces
+	// 余下的不要了,暂定
+	//yu := vadLen % pieces
+	for i := 0; i < pieces; i++ {
+		tmpSubUnit := NewSubUnit()
+		tmpVADList := subVADs[i*onePartLen : i*onePartLen+onePartLen]
+		tmpSubUnit.VADList = tmpVADList
+
+		tmpStartTime := time.Time{}
+		tmpStartTime = tmpStartTime.Add(tmpVADList[0].Time)
+		tmpEndTime := time.Time{}
+		tmpEndTime = tmpEndTime.Add(tmpVADList[len(tmpVADList)-1].Time)
+
+		tmpSubUnit.SetBaseTime(tmpStartTime)
+		tmpSubUnit.SetOffsetStartTime(tmpStartTime)
+		tmpSubUnit.SetOffsetEndTime(tmpEndTime)
+
+		outSubUnits = append(outSubUnits, *tmpSubUnit)
+	}
+
+	return outSubUnits, nil
+}

+ 87 - 7
internal/pkg/sub_helper/sub_helper_test.go

@@ -1,7 +1,11 @@
 package sub_helper
 
 import (
+	"fmt"
+	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
+	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
 	"path/filepath"
 	"testing"
 )
@@ -22,20 +26,96 @@ func TestDeleteOneSeasonSubCacheFolder(t *testing.T) {
 	}
 }
 
-func TestSearchMatchedSubFileByOneVideo(t *testing.T) {
+func TestGetVADInfoFeatureFromSub(t *testing.T) {
 
-	testDataPath := "../../../TestData/sub_helper"
-	testRootDir, err := my_util.CopyTestData(testDataPath)
+	// 这两个字幕是一样的,只不过是格式不同而已
+	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
+	baseSubFile := "C:\\Tmp\\Rick and Morty - S05E01\\英_2.srt"
+	srcSubFile := "C:\\Tmp\\Rick and Morty - S05E01\\英_2.ass"
+
+	bFind, infoBase, err := subParserHub.DetermineFileTypeFromFile(baseSubFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if bFind == false {
+		t.Fatal("sub not match")
+	}
+	bFind, infoSrc, err := subParserHub.DetermineFileTypeFromFile(srcSubFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if bFind == false {
+		t.Fatal("sub not match")
+	}
+
+	if len(infoBase.DialoguesEx) != len(infoSrc.DialoguesEx) {
+		t.Fatal(fmt.Sprintf("info Base And Src Parse Error, infoBase.DialoguesEx Len = %v, infoSrc.DialoguesEx Len = %v",
+			len(infoBase.DialoguesEx), len(infoSrc.DialoguesEx)))
+	}
+
+	baseUnitList, err := GetVADInfoFeatureFromSub(infoBase, FrontAndEndPerBase, 10000, true)
+	if err != nil {
+		t.Fatal(err)
+	}
+	baseUnit := baseUnitList[0]
+	// Src,截取的部分要小于 Base 的部分
+	srcUnitList, err := GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerBase, 10000, true)
+	if err != nil {
+		t.Fatal(err)
+	}
+	srcUnit := srcUnitList[0]
+
+	if len(baseUnit.VADList) != len(srcUnit.VADList) {
+
+		t.Fatal(fmt.Sprintf("VAD List Base And Src Not Same Length, baseUnit.VADList Len = %v, srcUnit.VADList Len = %v",
+			len(baseUnit.VADList), len(srcUnit.VADList)))
+	}
+
+	//for i := 0; i < len(baseUnit.VADList); i++ {
+	//
+	//}
+
+	println("Done")
+}
+
+const FrontAndEndPerBase = 0
+
+func TestGetVADInfosFromSub(t *testing.T) {
+
+	// 这两个字幕是一样的,只不过是格式不同而已
+	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
+	baseSubFile := "C:\\Tmp\\Rick and Morty - S05E01\\英_2.srt"
+	srcSubFile := "C:\\Tmp\\Rick and Morty - S05E01\\英_2.ass"
+
+	bFind, infoBase, err := subParserHub.DetermineFileTypeFromFile(baseSubFile)
 	if err != nil {
 		t.Fatal(err)
 	}
-	videoFPath := filepath.Join(testRootDir, "R&M-S05E10", "Rick and Morty - S05E10 - Rickmurai Jack WEBRip-1080p.mp4")
-	subFiles, err := SearchMatchedSubFileByOneVideo(videoFPath)
+	if bFind == false {
+		t.Fatal("sub not match")
+	}
+	bFind, infoSrc, err := subParserHub.DetermineFileTypeFromFile(srcSubFile)
 	if err != nil {
 		t.Fatal(err)
 	}
+	if bFind == false {
+		t.Fatal("sub not match")
+	}
 
-	if len(subFiles) != 5 {
-		t.Fatal("subFiles len != 5")
+	if len(infoBase.DialoguesEx) != len(infoSrc.DialoguesEx) {
+		t.Fatal(fmt.Sprintf("info Base And Src Parse Error, infoBase.DialoguesEx Len = %v, infoSrc.DialoguesEx Len = %v",
+			len(infoBase.DialoguesEx), len(infoSrc.DialoguesEx)))
+	}
+
+	baseSubUnits, err := GetVADInfosFromSub(infoBase, 0, 1)
+	if err != nil {
+		t.Fatal(err)
 	}
+	srcSubUnits, err := GetVADInfosFromSub(infoSrc, 0, 1)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	println(len(baseSubUnits))
+	println(len(srcSubUnits))
 }

+ 18 - 3
internal/pkg/sub_helper/sub_unit.go

@@ -72,11 +72,11 @@ func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
 		needAddRange := nowStartOffsetTime - nowEndOffsetTime
 
 		if needAddRange == 0 {
-			// 说明是连续的句子,向后加 0.002 秒
-			addMore := time.Duration((s.GetEndTimeNumber(true) + 0.002) * math.Pow10(9))
+			// 说明是连续的句子,向后加 0.002 秒 addMoreTime
+			addMore := time.Duration((s.GetEndTimeNumber(true) + addMoreTime) * math.Pow10(9))
 			s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, addMore))
 			// 因为是连续的两句话的时间轴,强制插入了一个点,那么就需要在这句话的 Start 部分向后延迟对应的秒数
-			oneSubStartTime = oneSubStartTime.Add(time.Duration(0.002 * math.Pow10(9)))
+			oneSubStartTime = oneSubStartTime.Add(time.Duration(addMoreTime * math.Pow10(9)))
 		} else {
 			for i := 0.0; i < needAddRange; {
 
@@ -116,6 +116,19 @@ func (s *SubUnit) AddBaseTime(addBaseTime time.Duration) {
 	s.baseTime = s.baseTime.Add(addBaseTime)
 }
 
+// SetBaseTime 设置基准时间
+func (s *SubUnit) SetBaseTime(setBaseTime time.Time) {
+	s.baseTime = setBaseTime
+}
+
+func (s *SubUnit) SetOffsetStartTime(realStartTime time.Time) {
+	s.offsetStartTime = s.RealTimeToOffsetTime(realStartTime)
+}
+
+func (s *SubUnit) SetOffsetEndTime(realEndTime time.Time) {
+	s.offsetEndTime = s.RealTimeToOffsetTime(realEndTime)
+}
+
 // GetDialogueCount 获取这个对白单元由几个对话
 func (s SubUnit) GetDialogueCount() int {
 	return s.subCount
@@ -357,3 +370,5 @@ func (s SubUnit) GetFrechetPoint(whichOne int) []frechet.Point {
 }
 
 const perWindows = float64(vad.FrameDuration) / 1000
+
+const addMoreTime = 0.002

+ 0 - 96
internal/pkg/sub_timeline_fixer/fixer.go

@@ -20,7 +20,6 @@ import (
 	"golang.org/x/net/context"
 	"gonum.org/v1/gonum/mat"
 	"os"
-	"path/filepath"
 	"strings"
 	"sync"
 	"time"
@@ -531,98 +530,6 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 	return true, outCorrelationFixResult.NewMean, outCorrelationFixResult.NewSD, nil
 }
 
-// GetOffsetTimeV3 使用 VAD 检测语音是否有人声,输出连续的点标记,再通过 SimHash 进行匹配,找到最佳的偏移时间
-func (s *SubTimelineFixer) GetOffsetTimeV3(audioInfo vad.AudioInfo, infoSrc *subparser.FileInfo, staticLineFileSavePath string, debugInfoFileSavePath string) (bool, float64, float64, error) {
-
-	/*
-		这里的字幕要求是完整的一个字幕
-		1. 抽取字幕的时间片段的时候,暂定,前 15% 和后 15% 要避开,前奏、主题曲、结尾曲
-		2. 将整个字幕,抽取连续 5 句对话为一个单元,提取时间片段信息
-	*/
-	subUnitList, err := sub_helper.GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerBase, SubUnitMaxCount, bInsert)
-	if err != nil {
-		return false, 0, 0, err
-	}
-	// 开始针对对白单元进行匹配
-	for _, subUnit := range subUnitList {
-
-		startTimeString, subLength, _, _ := subUnit.GetFFMPEGCutRangeString(ExpandTimeRange)
-		// 导出当前的音频文件适合与匹配的范围的临时音频文件
-		outAudioFPath, _, errString, err := s.ffmpegHelper.ExportAudioAndSubArgsByTimeRange(audioInfo.FileFullPath, infoSrc.FileFullPath, startTimeString, subLength)
-		if err != nil {
-			log_helper.GetLogger().Errorln("ExportAudioAndSubArgsByTimeRange", errString, err)
-			return false, 0, 0, err
-		}
-
-		audioVADInfos, err := vad.GetVADInfoFromAudio(vad.AudioInfo{
-			FileFullPath: outAudioFPath,
-			SampleRate:   16000,
-			BitDepth:     16,
-		}, false)
-		if err != nil {
-			return false, 0, 0, err
-		}
-
-		var subTimeLineData = make([]opts.LineData, 0)
-		var subTimeLineFFTData = make([]opts.LineData, 0)
-		var subXAxis = make([]string, 0)
-
-		var audioTimeLineData = make([]opts.LineData, 0)
-		var audioTimeLineFFTData = make([]opts.LineData, 0)
-		var audioXAxis = make([]string, 0)
-
-		subBuf := make([]complex128, my_util.MakePowerOfTwo(int64(len(subUnit.VADList))))
-		audioBuf := make([]complex128, my_util.MakePowerOfTwo(int64(len(audioVADInfos))))
-		for index, vadInfo := range subUnit.VADList {
-
-			subTimeLineData = append(subTimeLineData, opts.LineData{Value: vadInfo.Active})
-			baseTime := subUnit.GetOffsetTimeNumber()
-			nowVADInfoTimeNumber := vadInfo.Time.Seconds()
-			//println(fmt.Sprintf("%d - %f", index, nowVADInfoTimeNumber-baseTime))
-			nowOffsetTime := nowVADInfoTimeNumber - baseTime
-			subXAxis = append(subXAxis, fmt.Sprintf("%f", nowOffsetTime))
-
-			subBuf[index] = complex(float64(my_util.Bool2Int(vadInfo.Active)), nowOffsetTime)
-		}
-
-		for i := 0; i < len(subUnit.VADList); i++ {
-			subTimeLineFFTData = append(subTimeLineFFTData, opts.LineData{Value: real(subBuf[i])})
-		}
-
-		outDir := filepath.Dir(outAudioFPath)
-		outBaseName := filepath.Base(outAudioFPath)
-		outBaseNameWithOutExt := strings.ReplaceAll(outBaseName, filepath.Ext(outBaseName), "")
-
-		subVADStaticLineFullPath := filepath.Join(outDir, outBaseNameWithOutExt+"_sub.html")
-
-		err = SaveStaticLineV3("Sub", subVADStaticLineFullPath, subXAxis, subTimeLineData, subTimeLineFFTData)
-		if err != nil {
-			return false, 0, 0, err
-		}
-
-		for index, vadInfo := range audioVADInfos {
-
-			audioTimeLineData = append(audioTimeLineData, opts.LineData{Value: vadInfo.Active})
-			audioXAxis = append(audioXAxis, fmt.Sprintf("%f", vadInfo.Time.Seconds()))
-
-			audioBuf[index] = complex(float64(my_util.Bool2Int(vadInfo.Active)), vadInfo.Time.Seconds())
-		}
-
-		for i := 0; i < len(audioBuf); i++ {
-			audioTimeLineFFTData = append(audioTimeLineFFTData, opts.LineData{Value: real(audioBuf[i])})
-		}
-
-		audioVADStaticLineFullPath := filepath.Join(outDir, outBaseNameWithOutExt+"_audio.html")
-
-		err = SaveStaticLineV3("Audio", audioVADStaticLineFullPath, audioXAxis, audioTimeLineData, audioTimeLineFFTData)
-		if err != nil {
-			return false, 0, 0, err
-		}
-	}
-
-	return false, -1, -1, nil
-}
-
 func (s *SubTimelineFixer) calcMeanAndSD(startDiffTimeList stat.Float64Slice, tmpStartDiffTime []float64) FixResult {
 	const minValue = -9999.0
 	oldMean := stat.Mean(startDiffTimeList)
@@ -695,9 +602,6 @@ const FrontAndEndPerSrc = 0.15                        // 前百分之 20 和后
 const MatchPer = 0.7
 const CompareParts = 5
 
-const SubUnitMaxCount = 100 // 一个 Sub单元有五句对白
-const ExpandTimeRange = 10  // 从字幕的时间轴片段需要向前和向后多匹配一部分的音频,这里定义的就是这个 range 以分钟为单位, 正负 60 秒
-
 const FixThreads = 1 // 字幕校正的并发线程
 
 var mutexFixV2 sync.Mutex