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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑
4 N! P5 E/ N; J1 C0 D& t5 K; B' C+ ?/ i# R. P8 |+ Z0 G4 A
该游戏是scummvm支持的少数几款FMV AVG。
/ m, Y% n* ]7 A) x: h视频采用了一种叫做RL2的格式。
. b; t7 C, _9 F0 ^参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,' M) ?# b2 F1 ~) H+ j
然后用whisper语音识别之后就能配上字幕了。
* c0 [& ]) t" r- w% J  t. O此外,rl2格式用potplayer也能直接播放。& S, s5 k: E- w2 i1 J# j7 o- q
5 A3 O: A. m( o9 R$ D
文件格式0 C, J7 B8 |1 H; z; s) e
https://wiki.multimedia.cx/index.php/RL2
5 Z0 W7 O" j/ d# r# z" m
  1. % E& _; i# g, ~. z$ |
  2. +  0  dword  Header                -- "FORM"
    . K- }& i' i4 K$ I8 w/ v, T
  3. +  4  dword  BackSize              -- size of the background frame) q6 _! ]3 y$ Y+ V' J6 Z
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    4 H/ k$ l9 _' v3 h- N# T3 I/ {
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN
      X1 u& ^$ i! L8 {7 m0 X
  6. + 10  dword  NumFrames             -- number of frames" P& H1 n" [& Y/ T4 p- Q0 ~
  7. + 14  word   Method                -- encoding method. ignored, zero+ @: A% c- b  m$ P1 z4 k) B5 r
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound% U8 y' d7 C& k3 c( w, O1 Y- ~
  9. + 18  word   Rate                  -- sound sample rate in Hz
    ; e/ i3 l0 \0 l' W# ?+ M
  10. + 1A  word   Channels              -- number of sound channels0 `2 `& u+ D) q. n, x
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    ( Q% v5 X, H" h# z$ Q7 {) E# a# z
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport; n6 }7 b6 U: Q4 J
  13. + 20  dword  ClrCount              -- number of used colors
    * ?& k, f; S8 B7 p  }) e
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries9 A% B+ l" ~" |6 w8 Q! T  L+ {! A
  15. -- if Signature == "RLV3" AND BackSize <> 0/ S1 g6 p% o1 S; k# n6 a# P
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    + p7 |+ X2 J5 u4 h# \8 F( T
  17. --
    4 A- H) t. U  R/ T* }) P
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)' T, k- M, v% H; o0 }
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file, V, z1 C$ O% B9 I2 ~& P: b
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk4 ~( W" y9 P0 R0 P
  21. -- for each frame --
      r* x! o; r6 s0 ~6 F* j4 S# f$ Y
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    * L, p3 }8 }2 Y: S! V- s
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

  V! m# |1 a% z) s8 N1 ]5 q/ ?% H( i( c参考代码(有问题,但可参考)
  1. using System;, v4 D$ ]3 B9 q+ ~
  2. using System.IO;& Q6 r, t6 d3 _6 |- v$ h' v
  3. using System.Text;$ }+ |1 W" l; ~7 K
  4. 9 x7 x4 O4 d+ I9 C; ?( }5 P+ E
  5. public class RL2ToWavConverter
    2 n) \, C6 [6 p. I( y+ M; t) }& ]6 c
  6. {
    # \+ }1 a- o9 [3 S
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    / g2 e0 x( v# g8 K/ Y
  8.     {
      N9 W4 Q( o# H. b& T6 e
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))! q6 i- h4 }0 k/ D; ?- c2 L
  10.         using (BinaryReader reader = new BinaryReader(fs))
    * E( m! u. l6 j
  11.         {4 `6 n, K$ H! t6 j7 z7 M7 v
  12.             // 读取头部3 F7 u# @$ e" \. a' s/ ]; I9 o
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    , Z+ u9 _: m! G, V
  14.             if (header != "FORM")" l+ r) X* w4 c; w' Y
  15.             {- ?- n3 D1 I) _* `+ t6 P! X
  16.                 Console.WriteLine("无效的.rl2文件格式。");( y) N; i, z. ^4 p# E
  17.                 return;" ^# @& e2 U; |, d+ N
  18.             }! Q5 r0 n5 L  U* N; a; N- K

  19. $ Z( W% [5 g: ~5 B
  20.             uint backSize = reader.ReadUInt32();
    - d" f3 V1 n8 Z7 x( q" p
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));4 Q# A6 y) a) L! l) K2 B) A
  22.             uint dataSize = reader.ReadUInt32();( B4 h' l1 \5 O2 r; F! Z
  23.             uint numFrames = reader.ReadUInt32();
    + T2 G8 P" W! q
  24.             ushort method = reader.ReadUInt16();$ q/ F8 A! D: F2 @1 X: [
  25.             ushort soundRate = reader.ReadUInt16();
    8 ]5 h( \- q2 h8 y5 S: J/ }) m
  26.             ushort rate = reader.ReadUInt16();
    , {4 m: b. X) h! ^! g1 l% z' i# v
  27.             ushort channels = reader.ReadUInt16();
    " q( ^: M4 F- F% Z3 B9 S3 R
  28.             ushort defSoundSize = reader.ReadUInt16();
    , d: @# ^- o9 _* M) `; d
  29.             ushort videoBase = reader.ReadUInt16();+ y/ k( z: |3 d0 u. c
  30.             uint clrCount = reader.ReadUInt32();$ ~+ P1 C) F& N' B: @' _* l
  31.             uint[] chunkSize = new uint[numFrames];
    ; o5 S5 g& }( v  @6 F4 I2 e
  32.             uint[] chunkOffs = new uint[numFrames];
    ( C( c# e8 O0 u; h4 O! l1 g
  33.             uint[] soundSize = new uint[numFrames];) T6 U3 ~- Z' ]$ I. F/ x3 r4 @2 d
  34. $ U( y* X8 n$ b' E% u, P0 Y
  35.             if (signature != "RLV2" && signature != "RLV3")
    , `* G5 K$ Y1 r# w! A
  36.             {
    " p$ Q2 Z9 [: I# @  a7 W0 S
  37.                 Console.WriteLine("不支持的签名。");
    " o2 P- _3 I8 `" W
  38.                 return;
    ' j9 c  j% U2 Q0 P* G; H* j! f) D
  39.             }
      y1 f+ W5 }2 q. s3 t

  40. 1 ^; [8 Q* ]2 p! }$ i* ~( @
  41.             // 读取块信息
    , ]( L! |4 r1 j1 q3 ^3 o7 t# R
  42.             for (int i = 0; i < numFrames; i++)
    3 [* v# I  [, d/ M
  43.             {
    $ B0 q6 K; ~( z+ z
  44.                 chunkSize[i] = reader.ReadUInt32();" O5 D2 W$ M' X# N& K
  45.                 chunkOffs[i] = reader.ReadUInt32();
    / ?; R: p2 r$ L* S6 k* @" r
  46.                 soundSize[i] = reader.ReadUInt32();
    2 O+ \6 f5 J! I9 y6 X3 k* c
  47.             }
      [# M! [" {, R' u3 F9 P2 z
  48. ( p/ }( v4 F/ s  a  z6 S3 _' u% I
  49.             // 如果存在背景帧,请跳过它( D5 S* b) C6 I) K5 A+ k9 b
  50.             if (signature == "RLV3" && backSize != 0)4 }4 x% ?, L. A+ z6 o! S2 ?' {" |
  51.             {9 E- Z1 u7 n, b1 D. G
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);& H: a5 M7 a5 e1 m
  53.             }
    2 [1 v* }: M. g; h8 B

  54. ) o$ W( E- o& X
  55.             // 创建一个WAV文件并写入音频数据
    * s) k$ f% M& t2 m/ |
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))7 ?2 }8 o- H4 j+ J3 ?9 {; W
  57.             {
    / A1 f' i3 E) u# _: A
  58.                 // 写入WAV头部
    ; V" U7 J9 D; J
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));- ^1 r, B1 Z4 B" {
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    ! Z7 L( P4 y  f* H# C" c- }
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));' \* P! M+ I  @- `9 b" E
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));
    , G9 o, H* U8 |
  63.                 wavWriter.Write(16); // fmt块大小
    2 z4 h! f- ]; E1 f
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)1 c; c% f& h0 A( A8 T; D
  65.                 wavWriter.Write(channels); // 声道数
    ' d2 ^1 Z( r" D1 F% H# j# o- D, P
  66.                 wavWriter.Write(rate); // 采样率* a) V' _8 {( y9 I( c# x
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    " a4 H" Z1 m4 s, d9 P; _& z; O
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数+ Y, T9 @1 {& I3 r4 h( Z
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度. h2 o$ M, N7 }0 t4 q/ _! F6 a
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));
    ! ~1 e3 I4 E/ i6 D, ?: G
  71.                 wavWriter.Write(dataSize); // 数据大小
    / }1 |9 O1 J. C4 j
  72. 9 t; x- {" K+ A0 u4 w% S' U1 l# I
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    + a( t* q9 B$ M* i4 w
  74.                 for (int i = 0; i < numFrames; i++)
    5 _) r* L2 {* q( h# L/ f
  75.                 {
    . q; Z/ X/ N1 N2 X/ L% z" ?; `* m
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);( F9 {4 g5 a. v6 T, \2 x( V/ H  p
  77.                     wavWriter.Write(audioData);1 P5 U, y3 K6 Z- e1 t: c3 V7 |
  78.                 }# P* X8 M1 R) |. W! D/ [
  79.             }8 q0 p3 M2 ^9 I* m; Y& J: I
  80.         }% V# M- u% A( X) z" m, M
  81.     }1 |' k9 Q) @& x/ ]) K
  82. }
    # z% ], z- O8 [
  83. 9 j. W& h7 v4 |7 [
  84. class Program
    8 v8 V6 [) u& \" z7 d; Z- K
  85. {
    6 L  @1 h; B7 x$ ~1 i2 E
  86.     static void Main(string[] args)5 C; R9 C4 W; _2 K3 K1 T8 G
  87.     {8 x' ^) i0 g3 Z, j- i3 S
  88.         string inputFile = "N1275510.RL2";
    " `8 o; A) x) Z- _% E" K9 P8 j! C
  89.         string outputFile = "output.wav";
    ' G5 a; ~* X8 S' T
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);
    % v5 n5 f) f: P; w! W( z5 c! g) [
  91.         Console.WriteLine("转换完成。");0 t4 W+ _# Q* d/ Q
  92.     }8 q! w* V% ?" W/ F- z
  93. }
    $ f. j2 c% i/ e* F3 p% b! E8 X! H
复制代码

" a; |% S7 }4 d1 ?' F; T! G' P! J
2 a( `% }. F$ L6 j/ a& ]) {
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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