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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑
7 O4 R! ]) @. w" L  ]; F7 j: q' Z! u7 x$ ~; M! M7 C) x1 q+ L
该游戏是scummvm支持的少数几款FMV AVG。
7 M% d8 C6 L9 N3 P; W0 `- P% Z视频采用了一种叫做RL2的格式。6 A/ U- l% n* }2 Y3 h7 @5 \! \
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav," A/ K2 @% ~! F9 a6 t, f% Q6 J
然后用whisper语音识别之后就能配上字幕了。
. R8 l- o9 y0 D此外,rl2格式用potplayer也能直接播放。
2 r- o' p- k6 ]  _! [
' ?) S( u% L' c4 |% e6 k! B2 ^# g1 {文件格式6 C3 A8 w3 E0 P( _
https://wiki.multimedia.cx/index.php/RL29 c# |+ F! @2 [/ t9 A6 ]  f, M" q
  1. 1 L% K7 k' p  z4 j8 U2 j
  2. +  0  dword  Header                -- "FORM"
    7 ^; ]$ g$ |0 m3 K$ f- i
  3. +  4  dword  BackSize              -- size of the background frame
    % t# V9 W# C* Q' n8 _# f
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    0 s- G0 f, `2 m$ s3 Y9 z2 Z
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN5 h9 g: ?/ O- h' ]6 I% _
  6. + 10  dword  NumFrames             -- number of frames$ C2 j- |' ?1 ^! Q8 j
  7. + 14  word   Method                -- encoding method. ignored, zero! I8 E" q$ s* E6 U6 L( D" P
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound6 S- n3 l2 U  v  m! }
  9. + 18  word   Rate                  -- sound sample rate in Hz
    ' ~3 q& _# j# ^4 i9 T9 k
  10. + 1A  word   Channels              -- number of sound channels
    ( K& |9 N  M3 \1 I% ], Y5 H
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    2 F, R8 i" u6 Z: {7 G% y8 s
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport: v$ q! f( s3 k# B7 d9 J, q+ r
  13. + 20  dword  ClrCount              -- number of used colors
    # b  e' k; f7 E' p& H1 n$ ^# V
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    3 P/ x) f( A4 P+ A: F
  15. -- if Signature == "RLV3" AND BackSize <> 0; S, B, T) W7 `  x2 F% ^
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    9 f) S* U. G0 ^1 q
  17. --
    . d' V, s. p: j
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    " M4 G1 S  U6 m  k! Q
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file5 N1 J6 q) _+ j" ^5 Q- B
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    + n0 y, d; {; k- t! O/ ?) Y2 C
  21. -- for each frame --
    8 [1 N; W  w' i1 L: A! {
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio7 a1 E; y$ }) L
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
* i# C, D2 {+ `8 U. g0 n' A
参考代码(有问题,但可参考)
  1. using System;, H6 J; |' @- k2 t3 p
  2. using System.IO;" R: b/ U2 b* s( w0 H; s8 ?! b
  3. using System.Text;5 r7 s+ a- R$ D! C0 D

  4.   A' K: |7 f6 a3 h! \
  5. public class RL2ToWavConverter
    ( M" n+ X  K# _' K: k
  6. {
    * v; l/ ?( U8 p) s6 G
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    7 ]# ^+ y1 X0 D3 J0 s: U
  8.     {
    9 |% V6 V* Y4 e, C' I: k, b. ^& C3 H
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    " R7 ^3 R& [' h( k. `, d# z. D
  10.         using (BinaryReader reader = new BinaryReader(fs))' |8 R5 R; a- F% R" i  [
  11.         {: _4 P; j8 ]; C/ t" e. y
  12.             // 读取头部& v; X, t! F, p& h- P# |0 u+ ~
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));, L# R" K" J9 S) }
  14.             if (header != "FORM")
    & G) {/ I% ?: c3 F$ c; ^
  15.             {4 H9 J" z5 R9 I5 z. H
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    : {3 j, j7 y; f
  17.                 return;
    5 V) w! ^5 t3 b% ^- U
  18.             }) o$ V6 I9 h% H* ~+ A/ `

  19. : n. D& V' y# \, A" B  W
  20.             uint backSize = reader.ReadUInt32();0 y2 y3 y( t; M" O
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));! I+ b8 `* W% C8 j
  22.             uint dataSize = reader.ReadUInt32();
    . ?! \" w* C, S& O0 H* |  Q: _) u
  23.             uint numFrames = reader.ReadUInt32();; h, `/ L. n' x$ ]6 y
  24.             ushort method = reader.ReadUInt16();0 S* `) `  v- U% Q7 z( j- \+ z
  25.             ushort soundRate = reader.ReadUInt16();
    # t+ B3 T2 F/ }3 W  o0 Y5 c
  26.             ushort rate = reader.ReadUInt16();  u  Q" v& U& }' E3 r% c7 d
  27.             ushort channels = reader.ReadUInt16();
    " h! Z9 Y3 ?" T; S" a
  28.             ushort defSoundSize = reader.ReadUInt16();( ?  V  k8 v7 G% v6 @
  29.             ushort videoBase = reader.ReadUInt16();( @+ i/ x" ?5 o7 s- Z
  30.             uint clrCount = reader.ReadUInt32();1 H0 n( ~0 B" {5 \
  31.             uint[] chunkSize = new uint[numFrames];7 n4 P# N7 j1 {2 W1 {7 B
  32.             uint[] chunkOffs = new uint[numFrames];
      E$ g/ E1 n1 U6 B$ n( C3 G
  33.             uint[] soundSize = new uint[numFrames];
    $ ~( h' e- M+ z. e: d
  34. 6 i; K4 y) o; v! ?( {/ }$ z
  35.             if (signature != "RLV2" && signature != "RLV3"), i: A6 d6 `% \  P
  36.             {. |0 `9 S) ?5 H# |' i5 Y9 x" @( {
  37.                 Console.WriteLine("不支持的签名。");
    0 M! ~8 z2 b! k' ~( z+ B& V" D
  38.                 return;
      h# N, n% t5 w6 \
  39.             }
    6 W, a7 t4 f5 j6 W
  40. & a6 O7 u" @5 @
  41.             // 读取块信息
    * {  h0 v0 \! l$ a+ t
  42.             for (int i = 0; i < numFrames; i++)% O+ H4 x. }1 J, _
  43.             {8 \9 q: _$ S4 m0 l
  44.                 chunkSize[i] = reader.ReadUInt32();0 u' I* C) _4 ?! W: r0 o  `
  45.                 chunkOffs[i] = reader.ReadUInt32();
    ' }2 K) T, H- F; l0 z/ k& Z
  46.                 soundSize[i] = reader.ReadUInt32();
    9 j  m0 M6 J% t# q% h  C0 X& Y; t
  47.             }" A' S0 V# D- a8 T* }5 Q3 o

  48. 9 B$ D% Q  K7 B; E' Q
  49.             // 如果存在背景帧,请跳过它
    2 f1 n. Q7 \2 D3 v: d
  50.             if (signature == "RLV3" && backSize != 0)# {8 S! ~" Y  ~7 A3 b  u
  51.             {+ s* Q1 W2 S- c* g: D# w
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);9 q& p2 O( P5 T
  53.             }: q+ N0 x4 v' `+ C2 H* E

  54. " j- y9 [9 W4 z5 i( n# {" R; [
  55.             // 创建一个WAV文件并写入音频数据
    2 n/ [7 G+ h; K: J9 c# `! f" a- U% _
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))
    + J8 y9 }1 [% f9 P; g
  57.             {
    7 a5 V' x/ N$ N. M" v
  58.                 // 写入WAV头部
    ; @8 }" ~4 M5 k8 _
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));3 O) D* J6 q0 F, V/ ?
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    5 d" \: H- }/ _; _& n
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));2 P; _" r* W: M/ _* }! l4 L
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));
    6 a1 R) `4 @- h* k# r1 {) z
  63.                 wavWriter.Write(16); // fmt块大小
    1 t4 v4 q$ e# _
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)5 s4 B: G) r) I& N8 D
  65.                 wavWriter.Write(channels); // 声道数
    0 m( `, ^( t' E5 x7 U
  66.                 wavWriter.Write(rate); // 采样率
    7 F" D! o' t9 D, M
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    1 c( |; U$ g8 C+ ], B
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
    : l: \- H6 {3 r% _2 m
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度
    # A% m$ X1 F# O; _" C3 j# |
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));
    7 l* D7 g/ C3 g3 E: U2 L- U* o
  71.                 wavWriter.Write(dataSize); // 数据大小
    ( [4 b, c' ~6 b- d

  72. 5 a& R2 n& l3 E8 t
  73.                 // 从.rl2文件中读取并写入PCM音频数据' ^1 N. [" p5 H* O
  74.                 for (int i = 0; i < numFrames; i++)
    - b+ A' H& O! m' y
  75.                 {
    8 @8 w3 R" V  J. A" ~. @; h
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);- O# Q" O+ W) x9 O( z7 f
  77.                     wavWriter.Write(audioData);6 C* R6 C$ z. C6 i% p
  78.                 }) a$ ~! z7 s) C9 h* j' f5 M% l
  79.             }
    , n) w- n5 x* k" `! @0 @3 e: |2 Y
  80.         }5 ~- B$ l9 o1 j) x4 P
  81.     }. v: R: {: G. @0 {2 v& w! w
  82. }
    & r+ J1 J5 w4 h

  83. ( J+ T% @0 \: |- g
  84. class Program1 {8 H, @  u8 M4 }& Y' A
  85. {9 Y0 N6 U, J* S( ^1 G, z
  86.     static void Main(string[] args)* R( Q1 D: {! b: r% _
  87.     {: \' b# e- a0 y: a- ^! A8 @' ^9 x8 n, p
  88.         string inputFile = "N1275510.RL2";3 Y, B& L! e1 X/ J! Y
  89.         string outputFile = "output.wav";
    8 m, m. f$ R6 p/ `3 F
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);( r8 v- ^& Q+ ]) }( |2 X; `5 E
  91.         Console.WriteLine("转换完成。");+ a+ W5 }3 f4 K8 P
  92.     }
    ) B" Q! J8 |; T8 Q
  93. }, G, Q( v2 O: I: w# O0 U3 i; Z
复制代码
1 R9 A3 c: Z# j

  O7 m9 m. C. k* v: h. h
2 I; f, y, Y! v( O# S0 M5 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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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