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

建议 【Scummvm汉化 #6】 Voyeur (CD - DOS) 偷窥 音频分析

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

[建议] 【Scummvm汉化 #6】 Voyeur (CD - DOS) 偷窥 音频分析

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

【Scummvm汉化 #6】 Voyeur (CD - DOS) 偷窥 音频分析

本帖最后由 shane007 于 2023-9-2 00:06 编辑
9 x, g2 y) O9 u: U( w5 S  t8 t, F* s
6 k7 |2 M' ?- F- l7 Z该游戏是scummvm支持的少数几款FMV AVG。
1 e- f; ^2 s0 c$ A% M( @视频采用了一种叫做RL2的格式。8 L& w9 s4 }/ c! h8 j& e
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,7 Q. |! D) r2 s2 M
然后用whisper语音识别之后就能配上字幕了。
+ x$ K, {+ Y4 ?此外,rl2格式用potplayer也能直接播放。
: }  J2 x9 j) m) n' X5 q- }  E. g8 Y4 O, G+ I) A2 g" [" ~$ y
文件格式
) V. s" n1 [; A5 y3 phttps://wiki.multimedia.cx/index.php/RL2/ a4 L6 w5 A* V# Z& @
  1. & V+ T! ^) e0 @
  2. +  0  dword  Header                -- "FORM"! B' \" n' V' Q6 u* F
  3. +  4  dword  BackSize              -- size of the background frame# P2 f$ u; Q; o1 w% G% F, [  a- @
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"0 k0 q1 w/ s$ w* D
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN9 G/ q7 W1 S2 \# O( w. g' T# J( U( [4 N
  6. + 10  dword  NumFrames             -- number of frames
    . e& x# J* n  F  L: G1 q) Z, _& l; w3 l
  7. + 14  word   Method                -- encoding method. ignored, zero
    & x* W6 C/ [8 J6 g6 H, r) M: V
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    ( w6 X. z0 T# P  J
  9. + 18  word   Rate                  -- sound sample rate in Hz
    9 j, S' G2 v0 W  S0 R& F3 r
  10. + 1A  word   Channels              -- number of sound channels& q- `6 X/ s( a
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    % z2 P$ @: g. }& y
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport# }% B  A8 x0 S8 i# G
  13. + 20  dword  ClrCount              -- number of used colors
    6 a2 K6 E& Q5 \) _
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    0 R, u# X' ^& `# E3 I  V+ g
  15. -- if Signature == "RLV3" AND BackSize <> 0
    5 C  ^  V+ H- j! F! G
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding" e9 K9 ~' W' A3 `: V8 U
  17. --4 z& [' `" [  e# z& F' `
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
      ?5 |5 S& K6 z
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file1 _6 X- g' S- a# w5 Q1 Q, H, c
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    0 B8 z# }  c0 ~4 M, j
  21. -- for each frame --5 s4 {! M( }* |1 a
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio( V0 a+ G! j6 x
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

6 Z( o) D, n0 |) j) w参考代码(有问题,但可参考)
  1. using System;8 x- b; S8 z  e- ~( J, H% U
  2. using System.IO;+ [- R3 z: e& q. e' U2 Y( r
  3. using System.Text;
    # u6 k. d' A$ X4 l- r8 a1 q

  4. ! q8 f/ T/ V  s2 e% b# |
  5. public class RL2ToWavConverter; Z7 G; p" O/ _$ z8 h  o
  6. {
    ' C5 a; K3 O8 y8 V' d/ F% H' ^
  7.     public static void ConvertToWav(string inputFile, string outputFile)
      q' r4 e- s1 I8 z# [2 K" X
  8.     {
    0 [) H0 ]/ d$ z( R: H* y/ J6 y
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))  L' t/ p" G$ R. w% N; U5 b
  10.         using (BinaryReader reader = new BinaryReader(fs))
    2 M( W6 ?3 E2 {" x3 \' }& Y
  11.         {
    1 G7 f/ e: X+ w
  12.             // 读取头部+ U9 j8 Q9 |3 q$ @" e8 t
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    ) d4 G, r: I* J- U
  14.             if (header != "FORM")
      w& J2 z9 A" z/ g1 z  v. C
  15.             {9 K4 H) _# X% _$ y
  16.                 Console.WriteLine("无效的.rl2文件格式。");7 N% s8 ?, v! ^; @. {
  17.                 return;
    , f6 N. d- p" E- M. Q7 ?& `* K
  18.             }
    " T. w; A. \1 G
  19. 1 h/ Q9 u  `1 w1 `
  20.             uint backSize = reader.ReadUInt32();% x5 B& m, @1 E% B- U3 a+ F
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));. y. ?, v+ a4 m6 v4 O( E7 `; l
  22.             uint dataSize = reader.ReadUInt32();  m; ~0 j$ j! o
  23.             uint numFrames = reader.ReadUInt32();# N& o' F1 `* r# j- H! `; P. H
  24.             ushort method = reader.ReadUInt16();  Y) a* E+ C8 t' U
  25.             ushort soundRate = reader.ReadUInt16();
    2 }7 H. {& ~0 Z2 {) L: s
  26.             ushort rate = reader.ReadUInt16();1 O' [0 ^9 G" v+ m( N3 h6 H2 h8 d- S
  27.             ushort channels = reader.ReadUInt16();
    - S5 A+ `" V. q7 Z+ X6 h3 H& ?9 E
  28.             ushort defSoundSize = reader.ReadUInt16();
    1 `0 v3 i( n% [  ?( y
  29.             ushort videoBase = reader.ReadUInt16();
    2 b# f$ |  d4 ?9 Y) w9 |
  30.             uint clrCount = reader.ReadUInt32();
    3 q6 n! P! I1 m7 s9 s$ h1 v2 |+ U
  31.             uint[] chunkSize = new uint[numFrames];. B* Y* i' X2 t
  32.             uint[] chunkOffs = new uint[numFrames];
    4 ]  ?# S* _1 T* `1 `, e8 z
  33.             uint[] soundSize = new uint[numFrames];" _- M# O$ E) ]6 k8 a! R

  34. * v, O4 I* B- H8 G/ }, V: {
  35.             if (signature != "RLV2" && signature != "RLV3")
    1 z! U7 b) s; g, V3 N8 q7 j0 A+ [7 H
  36.             {8 _+ t' V+ p' h0 d. S9 {* v8 {" X
  37.                 Console.WriteLine("不支持的签名。");6 r; T7 \9 K+ i% L2 e3 j
  38.                 return;
    7 k& v9 P+ s5 Q& `0 v" d1 }
  39.             }
      Y2 v% y$ k; E4 @. q; m
  40. ) n1 B) y; F# i, u/ X5 P5 v. F
  41.             // 读取块信息
    $ d) k8 K% _* k2 s# L" J$ J( O' u8 H0 q
  42.             for (int i = 0; i < numFrames; i++)
    $ |; l, @8 Z/ U
  43.             {; v' X4 k" b( o" b
  44.                 chunkSize[i] = reader.ReadUInt32();
    : m' Z+ e% j( ^% u. b$ d6 `" o3 ]
  45.                 chunkOffs[i] = reader.ReadUInt32();6 W6 Q- |9 [: {# D: E- @7 Q  R  [
  46.                 soundSize[i] = reader.ReadUInt32();
    ; j2 J+ ^; ]' L
  47.             }* u7 b* g: Q" h: a+ D8 n
  48. 7 E2 _+ s; c# [+ q
  49.             // 如果存在背景帧,请跳过它
    9 y+ n. u3 j3 P) v
  50.             if (signature == "RLV3" && backSize != 0)
    % Q  g1 p( Q: X8 s" I6 j( _
  51.             {, c; c2 e% ]" Q
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);: }: [0 Z' |: V; T
  53.             }  m  \& H% X0 {+ E! v
  54. - a' K7 i: t( y* H
  55.             // 创建一个WAV文件并写入音频数据8 y! i0 K; p: K6 q# X! ?' D
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create))); ~8 I& ?4 [, p; A
  57.             {
    * s6 o. g$ E, B, x7 T% S
  58.                 // 写入WAV头部, J( w& s% y0 \& }9 N( l
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    - L# B! M# e, v& m7 D  R! ^
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 88 A. c. [3 C2 O1 [, K4 I
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    0 L8 Z& q* V, E7 E+ r
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));7 b* f& ], e$ a4 B% T" B/ U% C* M
  63.                 wavWriter.Write(16); // fmt块大小
    ! _& H  k; b. T" Q
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM). H. [5 Y- r$ W2 K5 C
  65.                 wavWriter.Write(channels); // 声道数* |" W" |+ B" J
  66.                 wavWriter.Write(rate); // 采样率  {8 o4 h- F3 _
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    . Y1 J4 h  s, ]- M
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数# D3 a3 B9 _+ W+ H6 J# J9 E  s
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度3 T4 ], `( d/ z; P0 L
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));
    . h2 g5 j2 F, k/ D3 Z1 r# @
  71.                 wavWriter.Write(dataSize); // 数据大小
    ( T  {0 Z& m: \! K, u4 W& g' M

  72. 1 Y/ B' }/ p. r% i! y- a0 {
  73.                 // 从.rl2文件中读取并写入PCM音频数据- R& Z# l4 \8 i3 ]7 \& V2 i. m
  74.                 for (int i = 0; i < numFrames; i++)
    ) [' i; ^) m3 V$ x! l
  75.                 {
    7 D1 c& W. S/ |6 n3 ]
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);: A1 c  g" w) S2 H4 B
  77.                     wavWriter.Write(audioData);
    2 ^- w) N) K6 w! f" E  g
  78.                 }
    0 k3 j9 R6 G" f0 a/ b- b6 u
  79.             }
    4 G2 o4 X/ k! |, |& {. c
  80.         }
    7 t  D. ^# a; P, c
  81.     }( S8 m, R4 N1 C+ Y# S, A
  82. }
    + a6 J7 \4 u+ Q  y# @

  83. : H; d5 r% H6 x
  84. class Program
    - E1 _( X& g2 e/ k  g; @& P' m
  85. {
      i/ S% M4 {# E, |5 F
  86.     static void Main(string[] args), |) t; i# o/ y8 f- q  h
  87.     {
    % I( P; X( a" K& _3 G
  88.         string inputFile = "N1275510.RL2";7 I- m- x; N4 b5 T4 S& i2 C' ~" {
  89.         string outputFile = "output.wav";
    2 }& Y" r0 c* j5 T5 f! S/ B
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);
    4 `4 f, E: L: ]& W& L$ D
  91.         Console.WriteLine("转换完成。");; h4 ~! G- X; J& D
  92.     }: Q' P( A  u! A  g% [2 p1 [
  93. }" w5 W; \+ D3 v3 m
复制代码

" N( I8 @) ]# x9 }- W- G
  w/ ?7 j( a2 ]. f' }( S- J+ K5 ^5 |
5 |4 d* q+ p. f
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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