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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 / a! r/ [  k$ g4 c% _% c( U

/ Y' Y6 b9 O0 ]% V+ A该游戏是scummvm支持的少数几款FMV AVG。5 J; K! H  b7 W
视频采用了一种叫做RL2的格式。* K3 X: ^  s3 Y3 l
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,
: _6 E/ w3 K, b" s5 I" o, z然后用whisper语音识别之后就能配上字幕了。
6 ~0 Q& q4 v) g+ k' j此外,rl2格式用potplayer也能直接播放。, }% l* V$ a- y4 y$ |

  g; Z) V; `3 U: z文件格式
$ A0 ]1 M9 m& n' u5 S  o& w+ Jhttps://wiki.multimedia.cx/index.php/RL2
  y, F, \0 P$ `  L

  1. 8 }, X: @/ Z8 R% M4 r2 i) g9 @) _7 ^
  2. +  0  dword  Header                -- "FORM"# o) ~  ^3 E7 m, \  Z, m- f
  3. +  4  dword  BackSize              -- size of the background frame
    9 W; D% ~' E1 \
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    ' ]3 e5 L8 g, |1 {6 z
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN% A3 _4 _, m4 c- Y- Y* ^4 ^# t
  6. + 10  dword  NumFrames             -- number of frames* q- u, M" C. [. Q$ s
  7. + 14  word   Method                -- encoding method. ignored, zero, q% L4 w" s- K7 j5 S8 m
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    & }; }. y  O8 h: n
  9. + 18  word   Rate                  -- sound sample rate in Hz# X/ i# U9 q/ D& C2 A
  10. + 1A  word   Channels              -- number of sound channels
    * l5 }# w" t0 R
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    3 H3 x! `! K  V& s$ }2 R: z5 ^
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport5 g% r- e( Y( |$ Z+ P3 T
  13. + 20  dword  ClrCount              -- number of used colors6 l; E/ Z" f' e. D5 h- q1 Y: q5 J8 R
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries5 o) R+ C' r. ~) l6 d: r9 O2 e
  15. -- if Signature == "RLV3" AND BackSize <> 0
    4 n3 f+ ]5 e7 f
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding7 N/ ^  `! h$ g: O! K; x. w7 k
  17. --
    7 [9 {  \+ F. G; |" t3 z: q
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    3 Q4 O" X9 u- ]5 @
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file/ X. @2 x' F' \+ f$ F5 R
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk. X' G3 Z. [) i4 ~
  21. -- for each frame --7 D' E$ o! A, x7 [  |: I3 f
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    4 S7 {6 u% `3 y* [/ Z* B
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

, O1 a% Y8 J9 A: a参考代码(有问题,但可参考)
  1. using System;
    7 o0 f6 w! [+ o- o
  2. using System.IO;
    : s7 ^0 Y; D: B2 {! B
  3. using System.Text;
    % Q+ |0 J; r. G3 }
  4. . Q( k3 V# \# [/ ]# V
  5. public class RL2ToWavConverter  {/ J, V) R1 Y1 y. c
  6. {
    4 N: n. X5 U$ y2 N* \. h  v% d+ t
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    ! _3 O* j9 ^& y  x/ X8 k
  8.     {
    + `$ |+ c4 ^( z) k2 F
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
      R: j8 ]/ a* i3 ]" I" t
  10.         using (BinaryReader reader = new BinaryReader(fs))
    8 w8 @- ?" `. x2 h- i& z) c
  11.         {; n: A$ _8 {. ~* c6 ]* v
  12.             // 读取头部& S1 f5 h5 X; Z0 x2 r: R8 n  \9 h
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));/ ?0 e6 {; c7 h4 `
  14.             if (header != "FORM")! q4 Y9 f5 o9 J/ h# k
  15.             {
    & j: c/ |' d9 U' a3 u7 ]
  16.                 Console.WriteLine("无效的.rl2文件格式。");
      m4 h) O5 G0 a& D
  17.                 return;' m$ N; @/ S5 \3 c
  18.             }0 V+ V) M' f) v- I" }5 b) Q4 ~
  19. 3 A- y5 d! N: i% ~& L
  20.             uint backSize = reader.ReadUInt32();
    8 |0 ^/ R4 D) S
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
    + y- [% ]5 f; \- u8 l
  22.             uint dataSize = reader.ReadUInt32();7 Z& n  _/ Z. i* Z4 k
  23.             uint numFrames = reader.ReadUInt32();+ @8 v* F9 }2 z0 ]
  24.             ushort method = reader.ReadUInt16();
    & R0 |' e9 z2 v, I% ^* X/ n
  25.             ushort soundRate = reader.ReadUInt16();3 Q; M5 z2 j( i4 [+ ^
  26.             ushort rate = reader.ReadUInt16();# P, p; \+ _2 H
  27.             ushort channels = reader.ReadUInt16();
    , F6 q, F" W- A+ x9 A
  28.             ushort defSoundSize = reader.ReadUInt16();8 g1 ?3 t2 \7 }. M& n) z
  29.             ushort videoBase = reader.ReadUInt16();
    7 d) z( ?1 N! q  w& `
  30.             uint clrCount = reader.ReadUInt32();' k1 U. j, y2 u( q. l0 M( r
  31.             uint[] chunkSize = new uint[numFrames];  u5 P( Z5 M/ }, Q1 x
  32.             uint[] chunkOffs = new uint[numFrames];
    ( _2 W* m2 D& {0 C' u" t0 i' L3 j
  33.             uint[] soundSize = new uint[numFrames];3 @" r, U" v; a. j
  34. : i9 o4 Z0 v, o' S
  35.             if (signature != "RLV2" && signature != "RLV3")
    2 u' D$ \. {, Z( [7 ]+ F
  36.             {
    0 R. R* M/ \: _9 i. o$ I0 u
  37.                 Console.WriteLine("不支持的签名。");) G8 Q% f) b/ j/ [3 ?, L/ v. _8 B5 @
  38.                 return;" C8 ~1 U0 Q9 ^. G$ }2 t0 N; S( R
  39.             }0 e* F; [/ l6 ~- {  J/ |
  40. ( m' ^) q( c4 ?
  41.             // 读取块信息, ~; T9 S6 x9 e
  42.             for (int i = 0; i < numFrames; i++)0 Z) S4 \8 Y# S6 o! b
  43.             {
    7 X" R* a: ?9 G( u, X1 N& A
  44.                 chunkSize[i] = reader.ReadUInt32();; F1 U4 j; t9 j' X0 ]( V
  45.                 chunkOffs[i] = reader.ReadUInt32();
    " H8 R, n, H3 X3 ~; V  z
  46.                 soundSize[i] = reader.ReadUInt32();& \- B! ?  a. v) k
  47.             }
    2 v3 A6 X: B7 V( w7 @

  48. 6 U; T6 y5 V7 R/ Q( c4 C: O$ y
  49.             // 如果存在背景帧,请跳过它: {3 L3 c& y" l/ W* W. u
  50.             if (signature == "RLV3" && backSize != 0)3 F2 l2 j! f  `8 G8 @$ g) S
  51.             {$ ]. e9 t* w; z" r! F
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);; ~# F0 I3 a8 n; M4 H
  53.             }
    ) q# V* S0 G3 a! i8 L- O

  54.   _) R" {& H! c
  55.             // 创建一个WAV文件并写入音频数据
    ; [0 e) ]: k& Q+ ^) e: ?
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))
    - X5 r+ A( P% }# i, L% j7 H" {: K) P
  57.             {
    6 B. J* O; U& J+ o) L2 Z. a! h: y/ g
  58.                 // 写入WAV头部7 T4 J0 N- E) M" Z. w' y
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    9 z% z8 I( C8 P" x* k) |& ^
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8# a& ?6 S5 q: v' E. g4 V. l/ h
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));; q: R& c" d$ G: B
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));
    3 |6 }; s! y) X! r+ i0 @6 j7 }% j
  63.                 wavWriter.Write(16); // fmt块大小4 W0 k5 f* z$ |% P6 |, \# V+ b
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)
    " ?: b9 p- j8 b* i9 I- u0 J  n
  65.                 wavWriter.Write(channels); // 声道数) p) o( o# b4 V- T" e' u8 ^
  66.                 wavWriter.Write(rate); // 采样率- m2 s. A/ e4 z8 K, e% L
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数0 g. w; [, l+ n, r  z) G4 a" t3 b
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数! K; r' W+ z, Y: K6 j4 p8 s
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度
    , O  ~/ |! q' o. q3 Z, @' q  U
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));. l7 U' a0 L% A! L! p" S
  71.                 wavWriter.Write(dataSize); // 数据大小4 N1 |( z  e. A  s2 f* b4 `3 x6 y
  72. * _, l$ w/ e/ y; W) i: S4 _. h" j
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    8 y; ^  N+ |# s
  74.                 for (int i = 0; i < numFrames; i++)
    ! M7 s  A) h$ p$ w& b
  75.                 {
    3 M/ Y5 l: m& Y( x
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);% r( m7 n: ]3 ]7 I# i- v# g
  77.                     wavWriter.Write(audioData);
    : |6 P; s# J4 }  d0 j
  78.                 }
    ; A3 _% c& {8 o" P, C7 R0 L$ n
  79.             }
    9 q, {8 A1 b3 p$ G
  80.         }
    * L$ T( A( x! J8 X! L( \: m4 [* l% M
  81.     }8 n  J1 g6 p, x% Z
  82. }$ F; F# K+ d7 |' U+ P

  83. 1 w5 u$ @1 t- r
  84. class Program, m, l& e& q+ w+ y! C& k2 q. l
  85. {" V' F- a2 h$ m
  86.     static void Main(string[] args)* a# b8 Q5 U6 R8 ?8 U( j6 V; G* i
  87.     {
    2 S9 L) R3 J: T$ K4 }3 v0 X; M8 i
  88.         string inputFile = "N1275510.RL2";
    7 Q6 ^( g( R& d$ N% R  i
  89.         string outputFile = "output.wav";- m0 z- @  t! ^
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);& ^  W) A9 `, b" ~3 g
  91.         Console.WriteLine("转换完成。");; C' g" G' w- B  O* s. `( c
  92.     }- [( e% ]- D" F7 ~' n4 }4 m
  93. }% w0 {5 [) J+ }6 [/ o
复制代码

" T2 m$ O$ p3 m5 K; F
6 \% g* f  M9 y9 ^0 |9 z1 R5 v* J
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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