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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑
5 b  Y, Z7 g9 m' z: ]
& k2 {6 g# M; V" c3 \4 h9 G: F该游戏是scummvm支持的少数几款FMV AVG。
8 d4 t" h1 r( \  w' P视频采用了一种叫做RL2的格式。5 d. O- E4 T! m5 U& d
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,
8 {' U  k; G2 D  q3 T) [* l然后用whisper语音识别之后就能配上字幕了。9 c' t- N1 ^3 b3 t+ O9 u
此外,rl2格式用potplayer也能直接播放。
) j( C' `+ X3 e* ]/ ~: P1 T
( t; u% u3 f1 C. e文件格式
0 n' L4 D* D* l3 Ohttps://wiki.multimedia.cx/index.php/RL27 G$ @7 R+ e5 n& R! o( S- l

  1. 0 g/ q& n4 ~& ~% d6 m: h. k
  2. +  0  dword  Header                -- "FORM"
    9 k' _; d+ X% a8 s( D% L
  3. +  4  dword  BackSize              -- size of the background frame& O' M$ K8 ^" g4 I7 ]6 T/ n
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"4 A# @. o9 |$ L. w/ r* k: J5 s5 }
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN
    ' z& i) _: Z8 D; O; ^& M
  6. + 10  dword  NumFrames             -- number of frames  @* {! n. S  o+ u2 d
  7. + 14  word   Method                -- encoding method. ignored, zero2 Q: F' W" ]' j
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    ; G* D6 U( Y( @  c
  9. + 18  word   Rate                  -- sound sample rate in Hz9 {" Z! U+ f, q4 X
  10. + 1A  word   Channels              -- number of sound channels
    * ?1 M6 e" V# o. U0 X
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    4 k' {; M' q4 t  s( r, M
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport
    ( o8 U1 i! E6 a! H9 v% T
  13. + 20  dword  ClrCount              -- number of used colors
      ?6 C+ a3 K2 |) f& f
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    - b8 U( K+ [: a( x+ u
  15. -- if Signature == "RLV3" AND BackSize <> 0/ s, R; S( i* V4 [, q
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    ; M+ E( E3 ~+ O2 A
  17. --, m& ]+ A) S- Y  [7 A, k- M0 ]
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    5 e* E* B8 E9 L7 S, \
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file; h* s& O0 w% f7 o& a& ^* c
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    2 ]* H" I/ c' U7 p9 T4 Q
  21. -- for each frame --
    4 S. J% D. C; T1 V  c
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio5 Z  Y; }2 s, N
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

7 Q$ L3 m/ c# G参考代码(有问题,但可参考)
  1. using System;
    ) I( _; N% A& _% L
  2. using System.IO;
    9 E" W+ ?% Q4 [. B2 A8 x5 L
  3. using System.Text;
    ! t. p3 x. J$ X: [; A( B0 T# y

  4. 2 @9 ~1 U- U% u9 n: W/ E7 a6 B8 f
  5. public class RL2ToWavConverter# E$ B2 a. N  Y0 J1 P3 L
  6. {7 j& @& N! U/ c% M
  7.     public static void ConvertToWav(string inputFile, string outputFile)7 ?4 q4 j' B8 ]6 l
  8.     {
    . r9 Y; {, D% U% E" `, K
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    . q, z' j1 S4 ?% q* e
  10.         using (BinaryReader reader = new BinaryReader(fs))
    9 J5 g- i% U! ?& _
  11.         {
    3 `+ g" H# G* T- a/ S! m1 I
  12.             // 读取头部& p/ @8 n7 |' s7 z0 i
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));( y& N* l6 z, K7 W2 i. d) H
  14.             if (header != "FORM")
    3 u% ]& I+ [# s
  15.             {
    + i* A% F( ^2 Q- @
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    3 K! v( t- I$ S1 Y- b" _! b
  17.                 return;
    - k. q" E  Y) [( ~3 O/ G1 K
  18.             }% i4 }& k3 n/ P( p1 u6 B3 t$ q

  19. 8 W  S. y9 j+ O) d0 v7 ]4 a
  20.             uint backSize = reader.ReadUInt32();4 t( ]% r4 A2 P0 X
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
    6 o% _4 ]- Q& L4 a
  22.             uint dataSize = reader.ReadUInt32();' O% e: a+ S- q$ f2 A) I: B  |
  23.             uint numFrames = reader.ReadUInt32();
    / n3 X# }/ \9 ?! ?
  24.             ushort method = reader.ReadUInt16();
    8 U( R- B7 Y( b3 Q; a% h2 [' \
  25.             ushort soundRate = reader.ReadUInt16();
    8 K, A! ?- `. Z7 o* J: m
  26.             ushort rate = reader.ReadUInt16();
      r. l8 G8 L& p8 M, _
  27.             ushort channels = reader.ReadUInt16();! ^4 A0 q6 V: a' [
  28.             ushort defSoundSize = reader.ReadUInt16();
    / @3 j3 R$ G$ \) m& _1 S" {
  29.             ushort videoBase = reader.ReadUInt16();
    ) r9 Z9 f# n! ]9 v7 J1 L8 O% K
  30.             uint clrCount = reader.ReadUInt32();4 N# Z1 j' Z% ?
  31.             uint[] chunkSize = new uint[numFrames];# c! M" S% q( ~; @7 ?' y3 C
  32.             uint[] chunkOffs = new uint[numFrames];
    ( W: ]1 }% x+ l
  33.             uint[] soundSize = new uint[numFrames];8 h; A! m: s) Q6 J+ R' i

  34. " h" N, [3 ^! a3 _2 p  ]
  35.             if (signature != "RLV2" && signature != "RLV3")! W+ X: e* m+ y" f2 r% Q3 ?; k
  36.             {
    & |+ L3 E) z+ p5 @; r
  37.                 Console.WriteLine("不支持的签名。");4 n7 \" Q6 M3 P5 N
  38.                 return;
    / F5 [- T5 i" y" n9 I
  39.             }! _$ n; u; T9 n0 l- Q- |# D
  40. $ P$ b" H6 ]3 v
  41.             // 读取块信息
    6 m# F/ ]# F& k# p& [: q; }
  42.             for (int i = 0; i < numFrames; i++)
    ' [3 k: h# v, s* U1 m; M$ o1 ]* x
  43.             {% u, X9 Z; B! F7 T  Q2 s0 r
  44.                 chunkSize[i] = reader.ReadUInt32();# c; E6 R& a& n. R) i2 a
  45.                 chunkOffs[i] = reader.ReadUInt32();
    * [9 D( w" t( Y" S
  46.                 soundSize[i] = reader.ReadUInt32();
    ; |9 C+ m2 j. H; i6 [; j
  47.             }0 E! I7 G! h. _' G* A, Q( P

  48. & ~9 b$ p' \; ~; f- I1 ~
  49.             // 如果存在背景帧,请跳过它& A- E# c  z8 b" u% [  D! b( o# w. i
  50.             if (signature == "RLV3" && backSize != 0)/ j9 G( g* j: w$ G- j
  51.             {# a* e# Y. j2 j) ]$ D' w/ t1 W
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);
    , Z, }* \8 t# A6 L
  53.             }( O5 v. ], ~) ^4 u/ A. ~/ ?

  54. " h  Y/ [  \1 ^* d4 p
  55.             // 创建一个WAV文件并写入音频数据
    $ T$ M3 M% a0 c8 h1 ]' e5 \- C. p
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))
    / _( _" }0 V% O3 D. e
  57.             {
    7 e/ F, v3 _, {7 s
  58.                 // 写入WAV头部
    3 E5 y  @6 |5 h
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));& x1 R: B  h* I: y% X
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    % e5 j6 L9 `2 e' _9 j
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));% X! a+ X- _( \# z
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));- o% ^( i% a$ t& D) K+ o! V
  63.                 wavWriter.Write(16); // fmt块大小$ |. S* M' B8 ^- V- a9 E$ Y0 L. s
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)
    - B9 ?% z1 z9 ]
  65.                 wavWriter.Write(channels); // 声道数% j- s1 Y: D. ]& k
  66.                 wavWriter.Write(rate); // 采样率$ @. {  D6 `, h7 I2 b
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    7 r, }+ c6 \+ C
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
      i# I9 I, j& h
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度
    1 S3 }8 o0 G  B4 M- b1 I+ C
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));, q; E6 b$ ?& i; p& R- |1 q
  71.                 wavWriter.Write(dataSize); // 数据大小
    % e' v. M9 C4 u; l
  72. % R% ], ^; O. t: M8 a  z
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    % l5 y+ T: z9 D: B" \( z
  74.                 for (int i = 0; i < numFrames; i++)$ h' G; d6 K$ E
  75.                 {
    # s! ^. P9 r3 F/ J
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);
    ' w0 c! j! O1 u
  77.                     wavWriter.Write(audioData);& o' }! i- M+ P4 R
  78.                 }
    / [% v2 g/ B. X
  79.             }5 p1 l' F3 h" d' }2 |. t
  80.         }2 Z$ j0 G6 U2 `/ ]3 L
  81.     }
    $ ^8 F$ L, t8 b$ g% ]: H
  82. }/ \% |( n+ R" j' Q" }

  83. 1 p6 B5 ~4 {2 a/ ]( @, A$ ]) G
  84. class Program! ~5 s4 q( N' F7 U1 O4 i& P
  85. {
    - T- v9 _3 m+ `7 W/ m$ q7 F
  86.     static void Main(string[] args)
    / d9 C9 T' B+ J( S4 c  j  t4 |
  87.     {' ?0 ~4 K% B$ ]* }: J6 N
  88.         string inputFile = "N1275510.RL2";0 b5 t0 E1 u2 X- ]+ `! z
  89.         string outputFile = "output.wav";
    % D, Q9 T% U9 |2 K; a! ^
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);0 O7 y7 r* C* L4 l# N
  91.         Console.WriteLine("转换完成。");) L' Y" p; {# t4 K! h4 K
  92.     }4 ^/ ~- m  o5 [2 z
  93. }
    4 ^$ m5 s* ?+ J' x/ e
复制代码
0 E  X/ o/ w- c2 ?1 B3 k. ~

0 }$ v4 U1 Y0 O; Y2 N+ k( |* T6 N% U! w+ }& [+ k5 \
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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