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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 8 M  O& S: s2 z6 |" Q( C8 y% Q; Z

; G5 P% x: B0 S7 V( z) M; Q该游戏是scummvm支持的少数几款FMV AVG。% A+ f1 G( Y3 d: Q: E5 i
视频采用了一种叫做RL2的格式。% i' X8 l  T  G5 H8 m+ w) e- r$ a5 v
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,8 L- z; x  {# f$ }  L7 _% l. z
然后用whisper语音识别之后就能配上字幕了。2 s/ t2 o9 \) E: j9 M
此外,rl2格式用potplayer也能直接播放。
0 H* G  k9 \& Q% f# Y$ ?! Y; S$ I9 u! o$ r  Q: f" r5 o
文件格式. Q4 t4 T# Z% m7 b
https://wiki.multimedia.cx/index.php/RL26 [! W# [6 U0 q' q

  1. 0 S3 o8 x0 |: N
  2. +  0  dword  Header                -- "FORM"
    9 d9 |7 I- Q3 l% D; X5 `& M; i3 h
  3. +  4  dword  BackSize              -- size of the background frame
    9 J1 b: d: m) o4 r' |' |
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    8 P0 z( v" Q. ]. K+ g
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN7 p9 Z  G8 E( n% o3 j6 z: l
  6. + 10  dword  NumFrames             -- number of frames
    3 D, A4 k$ N: E5 ]# `8 u/ [% {
  7. + 14  word   Method                -- encoding method. ignored, zero
    6 R; `$ F2 O* }# x
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    & ?% F1 w. g4 y8 z' R& d% M8 }
  9. + 18  word   Rate                  -- sound sample rate in Hz
    4 c4 y0 s" u( J; z' v. s6 e
  10. + 1A  word   Channels              -- number of sound channels
    8 B  R( H- {  c7 d* y/ c, Z
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below0 i5 l# {  U2 W5 V" t
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport3 X0 g5 h0 b$ p1 O; L: X4 P+ p
  13. + 20  dword  ClrCount              -- number of used colors: F+ F, j# l- I3 B" r4 _% y
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries! q  g4 a- u5 K. o
  15. -- if Signature == "RLV3" AND BackSize <> 0
    - \) w! q2 r& {
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding9 ^; I4 ^5 c1 ^2 J9 T
  17. --
    & E0 D4 j" A& ^1 [( e% j; h
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    - H4 ]8 ]- L% M) K  M1 D+ ]2 h
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file. w$ _- x9 P8 p, I
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    : X6 ]4 {8 O9 T! W1 f' u
  21. -- for each frame --9 P: H' _. @* `: W6 a
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio8 R0 K) |) O4 q% x; V7 p2 U1 N1 N
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
* L! x; [! N) z. C7 H
参考代码(有问题,但可参考)
  1. using System;1 N$ u( O- P% D1 F+ [
  2. using System.IO;+ q6 ~* t2 |# f: z5 m8 G) [
  3. using System.Text;
    ) r" ]% X. r$ }8 c

  4. ' u2 N# x  W) F* W2 D* V
  5. public class RL2ToWavConverter
    2 T+ f5 D5 `9 o5 g# ~' [8 |% J
  6. {
    2 T/ w3 O2 Z/ w1 o6 Q
  7.     public static void ConvertToWav(string inputFile, string outputFile)+ g% }& Z; n3 Z: \4 H4 |, [
  8.     {
    ) I" q6 {( ]- j
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))/ G7 |2 c) a2 X; T
  10.         using (BinaryReader reader = new BinaryReader(fs))) e0 `" l" Q* ^2 b  n
  11.         {
    ! k0 q+ l1 w$ {2 H
  12.             // 读取头部
    * {9 E$ n3 U& B! y) h- b
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));  {' [4 `& h& e
  14.             if (header != "FORM")6 o4 L! Z2 x! S" _  u
  15.             {
    9 l) e- k2 T; N) z
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    8 Y8 m3 ^/ \/ T$ }; w/ b* L: F
  17.                 return;
    + a' J$ k6 {  |# \- A# G
  18.             }+ b4 t6 S; L+ I2 P
  19. 7 o+ G( O* F* e
  20.             uint backSize = reader.ReadUInt32();
    # u/ q8 q2 F' ?
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));! q" o' a8 }# S6 x3 i" Z% R
  22.             uint dataSize = reader.ReadUInt32();; _1 E' N9 l& o! n2 O& m
  23.             uint numFrames = reader.ReadUInt32();
    # {! G* S: D2 I, }4 K* K4 v) u4 [! X
  24.             ushort method = reader.ReadUInt16();
    ; U9 E3 _4 `' @4 p; }0 e
  25.             ushort soundRate = reader.ReadUInt16();$ n  _: g& D* z& _/ F4 a
  26.             ushort rate = reader.ReadUInt16();
    3 Z2 [! r  R% ?. b* }# v! ^8 y+ p. D
  27.             ushort channels = reader.ReadUInt16();
    ' W; |$ g8 V! p* h3 G
  28.             ushort defSoundSize = reader.ReadUInt16();
    " W8 ^2 y) W6 S0 V
  29.             ushort videoBase = reader.ReadUInt16();
    3 X% d2 ~7 N  N* C
  30.             uint clrCount = reader.ReadUInt32();
    : Q6 W0 e! }. A. m/ }/ A2 W
  31.             uint[] chunkSize = new uint[numFrames];4 C' j( B) C8 M
  32.             uint[] chunkOffs = new uint[numFrames];1 U# C2 \4 L6 T0 G' o
  33.             uint[] soundSize = new uint[numFrames];
    6 y  h: I& {" t5 v

  34. * e5 ~: V& d1 m% [* o6 p5 f
  35.             if (signature != "RLV2" && signature != "RLV3")  J( l& T3 _! x0 f  C6 D: J) [
  36.             {
    7 Q; F3 c7 b& ^' d% k4 O% E1 ]2 B* r" L
  37.                 Console.WriteLine("不支持的签名。");
    5 y" e, L6 a4 G8 S
  38.                 return;) B2 q( @8 e. N3 T4 m( }
  39.             }
    ! M1 E1 S) V$ g9 f2 p

  40. ! \7 ^5 @% u0 T- W" c
  41.             // 读取块信息
    7 z) j+ ?' h$ r3 I7 O
  42.             for (int i = 0; i < numFrames; i++)
    ! I2 U6 o4 I# r7 K; f1 b
  43.             {
    2 P- v+ c$ y  h' a  A2 f
  44.                 chunkSize[i] = reader.ReadUInt32();
    $ u/ y3 m. m  }: J. r2 Z
  45.                 chunkOffs[i] = reader.ReadUInt32();
    0 a8 u  S- a9 P. l
  46.                 soundSize[i] = reader.ReadUInt32();
    * t6 l: w; L5 S
  47.             }' z. {1 Q( J, @) h% I7 R
  48. 7 L2 I; D, C2 z
  49.             // 如果存在背景帧,请跳过它# n: Y' f4 [2 v9 c
  50.             if (signature == "RLV3" && backSize != 0)
    ! a. H/ `' X# j) q% w& r3 F
  51.             {
    9 {' I( F$ [# Z: U
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);  z! K- ^) _* p$ A! \8 @" `% W" o
  53.             }& G0 h: N! l& d! K" X
  54. 0 ?: `& x, L- G( b7 _5 a
  55.             // 创建一个WAV文件并写入音频数据, D3 H$ u2 V/ b. i" Z
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))& n$ C: _9 Q* n% y' n1 x
  57.             {# d% C. _' w( b  ~, V
  58.                 // 写入WAV头部) g( V) l7 T1 y: u8 D; g( E2 I9 @# g
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));2 G8 W' c1 |) N- y: [' J) L
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8) N; y* ]* ?' A/ V6 c5 Q1 C* ]1 M
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    . o0 ]) s- ]9 r  J! U
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));
    ; _! |" p; i' s( u  ]) s! K' d
  63.                 wavWriter.Write(16); // fmt块大小: _+ {8 ?. z' ^' K2 G# V; w
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)/ K; C2 R9 b  e
  65.                 wavWriter.Write(channels); // 声道数
    0 r2 O! c! r$ F
  66.                 wavWriter.Write(rate); // 采样率
    6 ?! h# q1 ]( P
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数. V+ o: J/ U% m9 [/ ]% U
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数+ M3 Q# r, P8 O2 ]
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度* Y$ B5 T3 _; K1 C; L
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));
    & A: W* P& l! c1 h1 u5 ~$ Z# }
  71.                 wavWriter.Write(dataSize); // 数据大小
    7 M0 J% k' }& u% Z/ }8 l& W6 v+ E

  72. : ?% m; J* g. ]7 J3 ?7 ^6 D
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    * `7 _. v+ e4 [1 ~' X
  74.                 for (int i = 0; i < numFrames; i++)5 H3 g2 g: z# u  }3 |+ S( o
  75.                 {3 _  K* c1 f! G# X
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);& j" w/ p) `" ^* N( [4 v
  77.                     wavWriter.Write(audioData);
    % l+ X6 F! a$ Y. S$ T/ d& y5 ]  j
  78.                 }
    # j. P" O7 j( B! m' u$ k
  79.             }
    , o, F1 n! Y$ r3 [' v% F
  80.         }
    # i9 }3 x1 M. e, ?
  81.     }
    # a4 A- ]: }, n' Y5 e. j
  82. }. C) j& ]4 O" A2 f5 |2 t5 F# u

  83. 4 \& p% ~+ O% H- H
  84. class Program
    5 l9 o+ r+ Z6 @6 [& [
  85. {
    6 a' @3 S' l' [( n
  86.     static void Main(string[] args)
    " F1 s9 z  V: ~
  87.     {
    3 _" i: M6 I8 g5 F
  88.         string inputFile = "N1275510.RL2";/ }- U$ ~" X, F4 j$ g* v* ]
  89.         string outputFile = "output.wav";, r& g+ N5 a1 r9 B* z
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);# n* ?! ]5 T; G' v$ H( ]
  91.         Console.WriteLine("转换完成。");; I& m4 H- |# S8 E6 X; l
  92.     }1 M- }4 b$ d2 B8 P! a
  93. }
    8 v( [3 F; ?0 K; p: ^; K% q
复制代码

& _4 a2 T2 _8 \3 B9 P7 ~6 k
1 \0 l6 [  E" E1 Z/ S
1 r6 C- ?$ N  c: A% B9 z6 O
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好1 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2025-4-4 01:08 | 只看该作者
学习学习一下
回复 支持 反对

使用道具 举报

高级模式
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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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