设为首页收藏本站官方微博

建议 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)

[复制链接]
查看: 669|回复: 0
打印 上一主题 下一主题

[建议] 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)

跳转到指定楼层
楼主
发表于 2023-9-4 11:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)

本帖最后由 shane007 于 2023-9-4 12:57 编辑
+ w( J' u1 Q: r& L7 {7 j9 d
  W/ u" [; q3 k 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
4 H8 I- R# P& l1 B: y 使用时需要輸入语言,源文件路径和目标文件路径7 k7 ~& s. Z! d, Z
最后是输出srt文件
' }% e/ q4 E6 o9 k& w- |* R4 ]+ c/ B
代码如下
5 w% @, |* a/ w0 Z以下这句用多线程可以增速,否则很慢
; v( a0 ]: E* v5 U( U3 P/ t9 A+ }以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。7 p% h) e" T2 {! s# n$ b- x

4 v0 |1 U7 O1 ?$ X+ G
( r3 i$ O, d9 f: X1 u
  1. var builder = factory.CreateBuilder(): O3 ]3 U! A/ I6 O* t2 w
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

# B/ S/ S7 j- [0 Z: V  a- W- \" L9 [- D5 D/ }; l0 u. }
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT: k5 L, U; g; k/ [6 A  ~
  2. . V& N, @5 m: H  p  \2 R4 j
  3. using System;
    5 d9 \& k: T% S6 }. D; z, L
  4. using System.Diagnostics;7 C( ~) ]% q3 M- A6 m
  5. using System.IO;
    8 l; m. L) u& h5 p
  6. using System.Threading;
    $ S; z% R+ h. n# b8 u
  7. using System.Threading.Tasks;
    % a# q. X! |. a/ U" a7 q
  8. using CommandLine;" G+ o) O  P* ]' b
  9. using Whisper.net;
    1 a6 k$ T: h8 ~$ b0 @1 G% T, w8 s
  10. using Whisper.net.Ggml;9 A5 J3 W# |" g& B$ s/ c; C& N
  11. using Whisper.net.Wave;+ a! s: |5 d* Z* ?; ^; F

  12. ( _# F( Q# H9 S2 }; V4 o6 I. a
  13. await Parser.Default.ParseArguments<Options>(args)
    0 v- L+ k* F# {1 h
  14.     .WithParsedAsync(Demo);
    . m: g8 t7 M9 C( E6 o3 ?

  15. 8 q% D# @& y8 L) q# p& I
  16. async Task Demo(Options opt)
    3 @/ {% }# b9 E. z( b. M$ [/ v: n
  17. 9 D/ J) s: H  U3 b- W  I) W
  18. {
    1 C, H' L' @3 V: D# w- O& r+ u
  19.     if (!File.Exists(opt.ModelName))
    ' ^! K, `+ w( V$ K
  20.     {3 g- N8 L$ j. i4 E$ \
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    % e5 c% H5 R/ e$ e) W' m( z
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
    ) u( y: A1 I6 u2 ?; _0 X
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);7 E3 G6 H3 K, v6 N- `
  24.         await modelStream.CopyToAsync(fileWriter);3 B2 d: f3 w  H% B0 p5 U
  25.     }
    # a5 v( g( }6 k& J) \8 ]

  26. + o9 e3 W/ Y5 J6 a+ }8 c; G* n
  27.     switch (opt.Command)
    & l0 F2 p0 F) _& S2 g! [6 b
  28.     {
    / c3 ~, f' j) j. }+ x( r6 J
  29.         case "lang-detect":" [% \9 K9 I9 s
  30.             LanguageIdentification(opt);
    & D% O' N* X# i9 x4 G* {- B+ [- e  P
  31.             break;( Y7 F& H& r! [# I) I/ i
  32.         case "transcribe":
    : W, j3 y) V8 W# x- Q( |4 [1 L% b
  33.         case "translate":  Q. ~) R8 c- O9 ~! {' N8 R
  34.             await FullDetection(opt);3 c/ A  Z) `4 ~& a1 c  d' }' M2 \, s
  35.             break;
    * W) w9 r& t: h# g3 ]9 @( u
  36.         default:; z! K" t+ |& h7 H9 b
  37.             Console.WriteLine("Unknown command");
    0 o' u" P& I5 |6 J! Z7 y
  38.             break;
    ; I7 C. Y% V. K; N6 ?
  39.     }! G1 ~! m7 v# |
  40. }
    , U! h+ s7 p2 F" e: B) I

  41. 1 m5 {3 K- c8 B
  42. void LanguageIdentification(Options opt)
    : S/ u( n  T& ?1 S
  43. {; b, V1 Q3 w" v  i* w( x4 q8 ^4 k
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    ' Y" \: @* P+ p! U
  45. # m( Z5 n1 q4 J6 C" ^* X3 X+ {
  46.     // Same factory can be used by multiple task to create processors.6 a2 f3 j: \- X3 S! X# _
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);* a' z3 K" y. I. H

  48. 5 ?7 ?$ S2 f8 K. q
  49. /*    var builder = factory.CreateBuilder()% D2 G8 e, Z2 z  X, g  q
  50.        .WithLanguage(opt.Language);*/8 y2 T+ k5 |+ d. ~  a7 c
  51.     var builder = factory.CreateBuilder()8 A9 n9 c, l& p; G  d! E! H
  52.    .WithLanguage("english");
    0 P3 J6 `/ k  ]# S  h: r
  53.     using var processor = builder.Build();
    4 Z0 t# C$ G5 e* n/ t& }; @

  54. 1 }3 `# w4 H5 Z  p( t3 d( k5 d, N
  55.     using var fileStream = File.OpenRead(opt.FileName);$ S5 a$ G7 W' b) L6 j

  56. ) p' S. z; B9 q. ?; D7 H: `
  57.     var wave = new WaveParser(fileStream);
    4 M4 w3 T$ o6 X3 W2 H( o  m+ |; v" [
  58. 0 A. i* a8 G1 O& D( P3 R
  59.     var samples = wave.GetAvgSamples();
    7 E2 f9 a# {& F  Y
  60. & V$ }( i% a+ W" x0 ?" d- Q
  61.     var language = processor.DetectLanguage(samples, speedUp: true);; j) G* |6 y8 U, Z9 {9 V* S3 M
  62.     Console.WriteLine("Language is " + language);
    / r: O+ ~: t  @+ Y
  63. }( G3 _6 s7 n; J
  64. 3 t. ]9 ~; U+ o6 ?) z) e
  65. async Task FullDetection(Options opt)$ a& b8 G0 S, o2 G
  66. {5 h4 ]  s( ?* g+ U
  67.     // Same factory can be used by multiple task to create processors.
    * u0 w& N; z2 B1 n  ]" Q6 U
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);: K& J& u! i2 }" t! @% r1 {5 Z: w+ p
  69. 2 z3 S' G  S) t1 ]. z
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);0 ^( E" X6 Y) k; x  B5 ]) Z
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");+ e: O2 v: h% ?$ b8 U% ?
  72.     string languageOption = Console.ReadLine();0 O5 A/ [; s9 v3 o0 N2 i( c/ {
  73.     var builder = factory.CreateBuilder()
    ( _# g4 g/ \  Y5 C& r( w
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    - ~  `; r, [0 F! Y# H" J0 y
  75. 6 v6 [/ B, `2 t4 l
  76.     if (opt.Command == "translate")
    & R/ w# u* d/ i
  77.     {+ [# s0 {) W) g/ ^" Y+ i" A) y
  78.         builder.WithTranslate();4 a* f3 k3 o1 h
  79.     }' a6 M) x' L9 \( i3 L2 A
  80. ' Q2 v4 Z) A* b
  81.     WhisperProcessor processor = builder.Build();3 j8 H" W& |& _
  82.    
    4 b/ V6 r# R0 j3 E5 x" M  ^
  83.     Console.WriteLine("请输入wave源文件目录:");
    2 W% U* ]3 g1 F$ R: ~
  84.     string sourceDirectory = Console.ReadLine();
    ! M. _4 G' R1 q$ r
  85. ; v2 W7 }! j$ z
  86.     Console.WriteLine("请输入目标文件目录:");6 `) c7 c$ X( @6 S4 g% N6 o; Z/ r
  87.     string targetDirectory = Console.ReadLine();
    . }( `8 I& R% r! S' j- N
  88. - P' z' ]9 s2 ~$ O% `: Q
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))- {3 H, w( k/ m5 V, v# @7 O  o# P
  90.     {
    ) m: D( `" s: n/ `
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    9 J( S! f* v# T0 n8 _: H
  92.         return;. G0 o! l4 A. ]5 J8 k1 m
  93.     }% {' p% u( r3 @5 H3 X# f# G5 f

  94. ; r4 J% r1 _* m5 G2 o* q5 z9 c
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);" k* D% Q& T% m: s

  96. * Z$ y% O! @2 W
  97.     Console.WriteLine("处理完成!");
    $ I5 w* O  b% Y' j/ O
  98. : [+ ^3 p. v& g9 f9 e9 V
  99. }
    6 i# Y. i- t$ h+ F% z7 D8 l$ m( _+ \
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, 2 l7 J1 J( H; n, Z5 v! V4 h' j
  101.     string sourceDirectory, string targetDirectory)  `; C8 M: m- D2 D* U9 k
  102. {
    2 E$ D! }' f' h3 A3 h
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);& j6 q& d: f, t, j* o
  104. 7 G8 P% `' y0 F/ Y* G
  105.     foreach (var sourceFilePath in files)
    ( S4 X2 e  Q3 l, n1 U
  106.     {0 g. C9 d: X- P8 i9 M7 g5 p0 o
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    * F) Y8 Y. i3 Y$ I0 S
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    " U, P; w+ m) K  J0 e
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    6 S5 v5 N  P' ^9 F7 t

  110. , U) [" D* @" g2 {- ~4 d# d
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    6 b( y+ H, Y/ L

  112. # K, L2 C0 U( N5 a
  113. + d/ Y+ P; R+ M- ?$ P& T" f
  114.         if (!File.Exists(destinationFilePath))9 }8 s# t2 R1 z, N7 D, e3 J( w/ j
  115.         {
    9 g4 s6 l; a  v. d; {% ]
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");' U1 S' B, x+ w# ~1 S# J) }

  117. % S& _! z2 _0 ^3 J. E0 k
  118.             using var fileStream = File.OpenRead(sourceFilePath);' G* q$ c& ]: k0 A' N
  119.             var segmentIndex = 1;
    , |* P$ {: w0 h0 B" `" c
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    4 o9 P- L% {8 _
  121.             var startTime = DateTime.Now; // 记录开始时间. b9 e) h1 L0 V

  122. 4 |1 }% r: E. g) P6 r0 h
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    . ?% Z/ T$ a/ u: t' G: {0 N. _
  124.             {# ~! @! X- t; j( ?; n
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");: }2 a1 R0 J6 h- C
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    : _9 Q# A- K9 O
  127.                 Console.WriteLine(segment.Text);, x, M2 H! p# h* P; b% O  E
  128.                 Console.WriteLine();9 R6 A8 s9 _. P" Q2 p2 }* a
  129. 4 L1 K6 P, z6 c. t
  130.                 // 将srt内容写入文件
    ! m$ _4 M& ~8 k/ \* }! B
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");/ s5 L3 Q9 b( Z9 y. N
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");5 _6 ^. m: \8 F* B
  133.                 await writer.WriteLineAsync(segment.Text);
    $ ]9 G0 j$ _# I: ~% \/ k2 o* @0 y/ V
  134.                 await writer.WriteLineAsync();
    1 i1 W# R) h- y. `2 U
  135. % q2 V2 A9 ~2 N6 S5 r& S
  136.                 writer.Flush(); // 立即保存srt文件% {0 M" d$ r/ p

  137. / v: j5 l" x: M$ j# R
  138.                 segmentIndex++;
    ) ]4 v8 E! X: I  l9 V
  139.             }
    ' r  c; ~- ~3 T, u' ^7 u1 o
  140. ( s$ {1 o- a3 q; t
  141.             var endTime = DateTime.Now; // 记录结束时间1 F6 d/ I4 v& \* ?* R5 a
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    # e& Z6 N6 ]" l& Z8 c- ^# }
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");/ Y" |  o$ y) ~$ \, l- ?. m2 Q3 V
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");3 L( `0 {" l# N% i
  145.         }1 Z- x" }" e7 o) c; a  D: ^
  146.         else {
      A3 x3 ~" j  a& v: Z
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");5 \. v1 E, v+ G7 L' {- V( s/ ]
  148.         }
    3 v( k8 B( g( U% g  U$ x8 a
  149.     }: L& J( K, q! |& k! ?2 Y/ B
  150. }
    ( q/ K+ O5 D( A8 x
  151. public class Options0 z/ E3 R8 Q& z  x( z' h/ \/ m5 [
  152. {/ \, e; X! t% d; H# Y  N  `3 t
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    ! j  ?& t6 U* a$ o( J$ x% U: t& B
  154.     public string Command { get; set; }- f4 H# r" f0 }- G  J* S
  155. 8 o$ [; {8 k: Q
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    9 ?; [. E5 u: X2 X% R) D" F
  157.     public string FileName { get; set; }
    0 u8 D; T) O0 t* C0 s) m, W9 k
  158. 8 R2 n, r+ h3 ^5 Z7 ?( N
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]; j9 {5 F/ D6 x1 [/ U$ I
  160.     public string Language { get; set; }* c- W0 H/ l4 I  [4 \

  161. ! d, L$ X0 i/ G
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]. h& ?% Y# g( l8 m6 \' j3 D/ u
  163.     public string ModelName { get; set; }
    $ f) u3 R5 Z' {) Y* T
  164. ) A& c7 Q- x1 [- e( F# }3 t% U
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    ; F3 J% f+ l# J( e) M
  166.     public GgmlType ModelType { get; set; }; X9 c' g# `, ]
  167. }
    % j# g; g- U$ }; i0 t% {3 t9 a8 Y
复制代码
. l6 K' S# {  x+ t+ S; v/ v
7 U& Y) e' M; L+ x
, h: e9 j5 R  R9 s

* f7 e. Q& K0 ^  Q+ F; G! N) H$ s
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

冒险解谜游戏中文网 ChinaAVG

官方微博官方微信号小黑屋 微信玩家群  

(C) ChinaAVG 2004 - 2019 All Right Reserved. Powered by Discuz! X3.2
辽ICP备11008827号 | 桂公网安备 45010702000051号

冒险,与你同在。 冒险解谜游戏中文网ChinaAVG诞生于2004年9月9日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

快速回复 返回顶部 返回列表