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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 / |3 l1 E, S: o# b( U! c$ j. \0 f
- t+ b' G2 R1 j" x8 ?: L
该游戏是scummvm支持的少数几款FMV AVG。/ h" n# T2 k6 v8 I0 z" u, A
视频采用了一种叫做RL2的格式。
( M& W% J( y* D0 _参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,0 ]& I5 v1 R7 E# D4 j- J
然后用whisper语音识别之后就能配上字幕了。, A! S/ W, n6 o# X. r6 D
此外,rl2格式用potplayer也能直接播放。
3 w# h% N/ o/ s/ V! L0 r2 u
7 E( m1 W; K3 B( t2 h) Q2 B文件格式0 r9 P& Y/ i8 r8 L0 S# D/ \
https://wiki.multimedia.cx/index.php/RL2
* z9 J' E# a4 {0 Z1 O+ p* }' j

  1. * I2 G1 P! Q+ g( e% G
  2. +  0  dword  Header                -- "FORM") s& w9 Q" t% H  o
  3. +  4  dword  BackSize              -- size of the background frame+ v9 m' w! J' [* S  W
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"- F8 z/ q8 o7 D9 J9 E5 C6 n) T
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN
    / b9 W4 b; C- h! X
  6. + 10  dword  NumFrames             -- number of frames: [; q7 @3 }) C: s8 A% c2 D" F+ L0 G% V
  7. + 14  word   Method                -- encoding method. ignored, zero
    6 M7 ^' n% ?' Z0 c4 D
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound' ]% B+ r# x3 x0 w; F; X
  9. + 18  word   Rate                  -- sound sample rate in Hz* G6 y( `9 Q- x# k
  10. + 1A  word   Channels              -- number of sound channels- C; z- v; Z& }& `& l' m# G
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    5 n8 \" k' M0 }- q4 e4 x
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport
    1 u" z% _& b/ ~7 y5 F( M, D: n$ l: e" P$ l
  13. + 20  dword  ClrCount              -- number of used colors
    ' `. D6 v/ c1 Z! \  I6 [5 {
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries4 b3 Z" ~" ^4 ?+ r6 |  @
  15. -- if Signature == "RLV3" AND BackSize <> 02 i0 b4 h: `$ r6 `7 C0 V% i
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding3 F+ R, X) I/ V. L1 Z0 [
  17. --5 y1 V& r$ y) K. N  N/ y% m
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)2 k1 T8 K: y9 k" G) ?
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file' R7 m: V1 d: ]0 r+ O# u2 C
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk! c% l1 K- t' o5 Y9 L( Z" W
  21. -- for each frame --
    ! D. ]* L. S# J0 d* h
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    " L+ @3 y$ @2 K( [
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

8 l, Y; W) h; \# w5 P: D1 c参考代码(有问题,但可参考)
  1. using System;& q" e1 t! U* X  R' m( g
  2. using System.IO;
    . W4 a# `; X' P
  3. using System.Text;
    6 i7 G8 e8 V. g. q0 c! S5 K  t

  4. , M+ U1 P5 B' {+ Q9 \. C( k2 N2 F
  5. public class RL2ToWavConverter. L9 z* m& q) x
  6. {
    5 c  ?6 }5 \: m+ G! p
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    % f% K" `) b$ s$ ]
  8.     {
    2 V; e4 j+ l' J
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    $ k" z4 O2 ], `% M
  10.         using (BinaryReader reader = new BinaryReader(fs))" }' u4 q3 b. E
  11.         {
    " C; w, n: y  I3 B7 c- f
  12.             // 读取头部4 W. d( ]% F- V# C$ ]  M
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    & z7 B/ Y9 C. X# P
  14.             if (header != "FORM")! c8 t+ d2 I( [7 h4 B
  15.             {( @! p: ^$ J5 b
  16.                 Console.WriteLine("无效的.rl2文件格式。");& g) @" w6 p! i* M) ~7 D3 h+ g
  17.                 return;
    - F5 `$ V5 `1 m" V5 k9 O' K
  18.             }
    , w  O4 w3 `8 N& B& I/ _
  19. & b4 z6 j7 h0 U7 ^" O
  20.             uint backSize = reader.ReadUInt32();
    " \6 u# O, A9 p7 R, a9 |' l5 n
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
    0 i: Y0 P* x. c( W: g/ `
  22.             uint dataSize = reader.ReadUInt32();
    # N- A9 M4 x$ W, w! k0 t
  23.             uint numFrames = reader.ReadUInt32();. c2 ]2 `! ]+ W" q9 N
  24.             ushort method = reader.ReadUInt16();
    ! S3 w) |' U, l* }  @
  25.             ushort soundRate = reader.ReadUInt16();. o8 g+ S) w7 @
  26.             ushort rate = reader.ReadUInt16();/ ?+ V7 Q, Q6 _# R' ^$ ^
  27.             ushort channels = reader.ReadUInt16();6 F0 D, ?( f2 t# m
  28.             ushort defSoundSize = reader.ReadUInt16();$ w. q- g% G' s% \( P
  29.             ushort videoBase = reader.ReadUInt16();% s5 w/ Q& t" U: P$ w1 F2 ~! x
  30.             uint clrCount = reader.ReadUInt32();; x1 \( h1 _1 t% `' T
  31.             uint[] chunkSize = new uint[numFrames];2 x& ~3 j8 B& G4 X$ X( ?* x& e( Y$ [
  32.             uint[] chunkOffs = new uint[numFrames];
    + U' C: P0 Q  ?! Z0 p3 \& H
  33.             uint[] soundSize = new uint[numFrames];
    % K; d! r* u1 C3 F8 m

  34. ; t2 @5 Q; L1 m& \4 ^) V
  35.             if (signature != "RLV2" && signature != "RLV3")
      O' [' E2 b9 A& z0 Z8 G' |
  36.             {. E  P% }' L- Q$ W1 ~- M  d8 i1 g
  37.                 Console.WriteLine("不支持的签名。");& U. c$ Q" e5 V4 Z
  38.                 return;
    6 e7 C6 x" _$ m3 o( K! f( v1 w9 b, B6 `
  39.             }
    9 j8 Y) V7 y+ l1 N5 w. u
  40. 4 g  d( L1 L: R9 b8 q# M- r
  41.             // 读取块信息
      ?  b8 T& A2 q& o3 v8 d6 p
  42.             for (int i = 0; i < numFrames; i++); U* I" Q6 ^9 Z* r3 q) {& N' d( q
  43.             {1 ~% M: A( d$ v, N$ {( e$ u# E4 U
  44.                 chunkSize[i] = reader.ReadUInt32();
    5 R! v9 ]- d' S) z
  45.                 chunkOffs[i] = reader.ReadUInt32();2 B8 M+ R# X/ K2 O$ Z
  46.                 soundSize[i] = reader.ReadUInt32();
    ' O: J  c3 X5 `5 G
  47.             }, C  C2 X! k- b" M+ Z1 ?
  48. , w  {: K) W( K0 [5 }' }) K
  49.             // 如果存在背景帧,请跳过它
    ; k9 q/ c. p1 K# B1 O
  50.             if (signature == "RLV3" && backSize != 0)
    1 S- W+ {8 r% I
  51.             {4 b6 A# x. Q2 W  Q
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);$ t: y; @! u- H" I0 s
  53.             }
    3 F! n& e& W; t) E$ T

  54. 9 X5 _0 Y9 B; J4 ]) @
  55.             // 创建一个WAV文件并写入音频数据3 C0 V- v6 \/ L: M, @
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))8 J( y( w' X9 n. d, L
  57.             {
    ( K8 v5 C5 h4 b, y- {2 U+ Z: B
  58.                 // 写入WAV头部# z; @" G0 j5 d3 C) N: n! D
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));; g1 K7 L& }  \# `  _
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
      e/ P9 c7 N- q( t7 j
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    ( T5 z, P; v6 H; Y. f' v. {4 {" `
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));) y( j' ]- b. |9 `+ H% X
  63.                 wavWriter.Write(16); // fmt块大小
      [3 k  [+ ]! b7 {
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)8 z& I8 @5 d' `
  65.                 wavWriter.Write(channels); // 声道数
    & e6 C& ?5 m+ p2 U: e5 g
  66.                 wavWriter.Write(rate); // 采样率# J4 U  l2 u6 x2 V  X
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    ! T2 Y  w4 ]7 [/ p! G+ J
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
    ) b8 L/ M, L8 L1 D6 W' l
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度
    3 U+ n" E. w; d" D
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));: A5 K2 n9 W5 |* B7 y
  71.                 wavWriter.Write(dataSize); // 数据大小
    & s7 q& |' l8 h3 a% z/ ]- ^

  72. : z4 W8 U) Q, p9 q% N0 b7 p2 Z
  73.                 // 从.rl2文件中读取并写入PCM音频数据( `. e7 I% p" ?' J5 A' f
  74.                 for (int i = 0; i < numFrames; i++)
    3 V  O4 }# x$ U+ S+ O
  75.                 {7 N" f* ?# [' j& X# h! a! g
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);+ p; e; J, O3 p: ~6 D# s  W8 t8 N0 ?
  77.                     wavWriter.Write(audioData);/ i# V* `9 t$ m7 {) N
  78.                 }) ?$ {3 ?7 A. W" z+ r& Q* o) O
  79.             }
    * w( z4 {# Q6 H, q9 \
  80.         }- q+ Y2 u  L1 `0 M3 z6 P
  81.     }* t  U# s) q2 v, X
  82. }
    # T. f2 x. g0 B/ i$ B/ s8 F
  83. 2 N/ U5 o1 w* K: H( F2 K1 l
  84. class Program
    / U+ w9 f" G, `" C3 N
  85. {2 e0 z8 _: j7 G* B" I
  86.     static void Main(string[] args), o9 Z  s& r; d+ H. _, ~
  87.     {" L# Z, }: \! E; Y  W: k' W: t
  88.         string inputFile = "N1275510.RL2";
    ) t! q$ v  g. d6 V
  89.         string outputFile = "output.wav";8 h# w6 ~9 `: H8 |  w2 P; }( I
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);! H# ~/ K/ i1 ?7 M1 C; x
  91.         Console.WriteLine("转换完成。");
    0 h  t- X, k( ?' K9 A
  92.     }
    : J: X: h- J; s. O7 @3 }
  93. }
    % _* o8 Z, @/ X
复制代码
9 e8 l$ ?! ^- Q, k. l
8 W' T- u5 Q, e) ]

8 n6 ?9 o8 A' _5 V
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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