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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 9 B: v. @  O$ ?' D% ]9 P, V
! I+ B; Q# V7 b" ]- [1 h
该游戏是scummvm支持的少数几款FMV AVG。
; Y* m+ `* ~5 H! O0 {4 y$ e# U视频采用了一种叫做RL2的格式。
8 B& Q* }' g0 H0 k+ d# L0 p8 C参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,
: r; \8 X' ]/ V, C然后用whisper语音识别之后就能配上字幕了。0 E' X1 Z( a% b/ C. q" o
此外,rl2格式用potplayer也能直接播放。
1 w* ?+ j) e' q. j1 Q/ ]6 d& H( ]9 I3 Y
文件格式
( A$ a4 d( A2 S4 ~7 @- xhttps://wiki.multimedia.cx/index.php/RL2$ q- G) @( c9 l/ W) U0 ]

  1. 1 N9 N  I) \5 L  A7 ~+ G$ n
  2. +  0  dword  Header                -- "FORM") Y% X, R2 R+ _( e, R4 A* ]0 K
  3. +  4  dword  BackSize              -- size of the background frame8 K& H+ m. m4 u* S( [9 w
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    9 U6 q- p" I* m( L
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN% I( x" o$ b5 k9 l  j
  6. + 10  dword  NumFrames             -- number of frames4 f" Q, w& w& A" J
  7. + 14  word   Method                -- encoding method. ignored, zero
    * m: ]! `( T) ]  g: e; {3 N
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    4 |6 O# `7 t8 e0 A$ S* O! `
  9. + 18  word   Rate                  -- sound sample rate in Hz2 ]  W2 H8 B# \5 s* D0 n' E( c
  10. + 1A  word   Channels              -- number of sound channels- b% @' R0 x  p: C/ B
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below9 A! d2 h8 `5 }3 S! X2 ?
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport
    & n2 k3 t, h! i0 e. ^. u7 U; n
  13. + 20  dword  ClrCount              -- number of used colors
    : \7 _/ ]% A+ D: g
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    8 c9 f# h( _: u, W" ^
  15. -- if Signature == "RLV3" AND BackSize <> 0
    : B" q. u  w2 f. o" c
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    4 j, t4 v1 O4 ~5 {
  17. --: R4 _8 G2 s4 y1 _! W2 p
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    ( d0 i1 A5 Z+ J: w+ k; H- W
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file
    9 ?% v6 n& u- a9 {0 F8 E6 J1 M
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    6 ?; Y6 p* P( V0 e' f
  21. -- for each frame --
    & X  I" v# d+ q( {( w
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio+ L- u  a+ X3 j+ T
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

6 _! ~( D1 q( F* V参考代码(有问题,但可参考)
  1. using System;
    ! b% }" N  E( @8 r0 e' t6 x8 z
  2. using System.IO;  J; l& _/ d! f# R8 z
  3. using System.Text;
    6 f2 `% z5 Z- F

  4. - `2 z. b8 y. Z" u2 f; q: C
  5. public class RL2ToWavConverter: `' R/ T. y- I- A8 ]
  6. {
    * u- T& C% A" i8 \4 s- e8 p
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    ) }# N% S+ B# C4 t  B; D
  8.     {% _! x! p6 f3 A: x3 r1 w4 B) O
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read)); b2 y& G% b7 u: H  Z
  10.         using (BinaryReader reader = new BinaryReader(fs))
    0 F1 t2 y2 f+ p% @; {
  11.         {/ @! b. R* m* K6 X1 o
  12.             // 读取头部
    . n0 h1 V; U8 X4 D: x6 E' q. G
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));* q7 [4 M! I  o& C  d9 B
  14.             if (header != "FORM")+ _  e- b3 d+ ^2 @7 V0 P
  15.             {
    ' r" F9 f* G4 w
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    7 A( n, ^+ ?, s* {  `+ s4 r
  17.                 return;
    1 ?2 {& y3 [, y4 b' i, ~& D4 D
  18.             }0 x  q) U4 i' w3 s: f+ S4 X

  19. * ~' R: }5 G8 r& B. H
  20.             uint backSize = reader.ReadUInt32();! J" C4 T# e  {" u6 ]9 z4 M
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));  E# M' B: {' p7 r5 K7 u  u
  22.             uint dataSize = reader.ReadUInt32();
    ; [+ z6 I: p/ r( c  C& `1 M. @
  23.             uint numFrames = reader.ReadUInt32();
    2 n; _5 P; }7 ~
  24.             ushort method = reader.ReadUInt16();6 m& s3 L( h* x$ b1 y7 b. {' t& [6 y
  25.             ushort soundRate = reader.ReadUInt16();4 A6 t$ J/ l- g; f
  26.             ushort rate = reader.ReadUInt16();" u- p$ X! P1 v, H/ w
  27.             ushort channels = reader.ReadUInt16();
    9 {/ u4 e" P+ s4 X  L8 R" m
  28.             ushort defSoundSize = reader.ReadUInt16();& e- J* r# ^9 g! ^2 _4 w& G: q& x
  29.             ushort videoBase = reader.ReadUInt16();
    ! W3 i' Z) N8 E1 q2 Y
  30.             uint clrCount = reader.ReadUInt32();
    1 c4 c) A- g* b" `
  31.             uint[] chunkSize = new uint[numFrames];5 F2 L' R, R/ E! h0 p& s3 r
  32.             uint[] chunkOffs = new uint[numFrames];
    $ i5 [1 p& L5 Y* @+ W' C: @; @
  33.             uint[] soundSize = new uint[numFrames];
    4 B! F( L$ z5 E; e- w( W: a( o

  34. - _- r! U4 i  Z7 \1 V
  35.             if (signature != "RLV2" && signature != "RLV3")
    4 O! K, n7 k: u- }2 s
  36.             {
    . R) r6 v- V+ t
  37.                 Console.WriteLine("不支持的签名。");
    " K3 _9 T9 A2 M; T9 V
  38.                 return;
    ) ~7 x. f. ?* b6 Y
  39.             }
    8 a: P7 L8 N8 u" R

  40. " G3 |- T2 \# K5 }
  41.             // 读取块信息
    % ~5 n  G8 ]# i0 ^3 ^" C8 \7 R+ s
  42.             for (int i = 0; i < numFrames; i++)/ r8 w" }- H9 r3 d: V' m' r! d! ~3 B* O
  43.             {" E+ @4 ^- Z8 M
  44.                 chunkSize[i] = reader.ReadUInt32();5 F0 e/ h3 L+ [: }8 u3 f
  45.                 chunkOffs[i] = reader.ReadUInt32();, t: ], T9 j' d  B
  46.                 soundSize[i] = reader.ReadUInt32();
    7 @2 S. b4 j  k0 ?! q; J
  47.             }
    ( x; @8 n" {+ Q4 z: ?5 X" t

  48. & r' Y6 G# X% C/ I
  49.             // 如果存在背景帧,请跳过它* b0 @+ y- S6 |
  50.             if (signature == "RLV3" && backSize != 0)
    % Y2 K/ {1 r4 |& b2 o
  51.             {
    5 w1 ?& A/ i" C+ f1 y2 H2 M
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);+ G  z1 s. l  e1 i( f) t  n
  53.             }
    & Z/ B* P  E$ ]' |* L
  54. 4 Y4 C6 I% o% p( K, `" \; ]
  55.             // 创建一个WAV文件并写入音频数据. M5 s5 O+ o7 M0 B3 E; W
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))% G% }0 s1 z& A. [/ S
  57.             {; t9 ]/ n+ R' b* G) U4 ]
  58.                 // 写入WAV头部. N2 b! C$ ], v7 Z9 Q) C) i3 e2 z) `
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));7 e" y# \! j* e; ^
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8; G1 o) z* O9 \. I$ U/ w7 p9 k, J
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    . g: n, s# ^% U8 v0 {" b7 [
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));( O0 Z. f! B, N8 K; [- |  T
  63.                 wavWriter.Write(16); // fmt块大小/ k( G4 E% a+ K/ \2 k- G
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)1 Z% p6 w9 f- D
  65.                 wavWriter.Write(channels); // 声道数
    ( J. K' u8 k7 e
  66.                 wavWriter.Write(rate); // 采样率
    $ s' V9 a# E2 u) F/ I! \
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数' d( ^3 b) G0 r$ D. E
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数' e1 z) {" s) b# U4 P, l- x# D
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度2 z- `" A! E) {  r. D
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));
    " K' v5 Y4 T/ H4 E: s6 |3 U
  71.                 wavWriter.Write(dataSize); // 数据大小' ~7 f; Y! Q0 d
  72. + N3 Y% k, K( X' @# N; ?% U
  73.                 // 从.rl2文件中读取并写入PCM音频数据1 L: Q* k9 ?( D! O" ~' I$ h/ O
  74.                 for (int i = 0; i < numFrames; i++)
    ) \8 k7 T. N  ~: _
  75.                 {
    . f* W& J  W, ]: i8 Z
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);
    1 G& `) `$ J* H2 j; }
  77.                     wavWriter.Write(audioData);& A  h+ c% {( e2 B# V# \
  78.                 }
    * [% s- a/ S# U
  79.             }. W2 y0 M$ P0 w9 `7 x7 J
  80.         }
    8 b2 L# F' q+ _; M
  81.     }+ z0 Y/ u, E! K) H
  82. }
    + O' O; H5 j+ W& s1 C  L+ D/ m3 X

  83. 1 C1 \% z& a: S" }
  84. class Program
    - u/ R, [& Q( j
  85. {# }6 z4 v0 }2 Z1 j1 M( [/ z
  86.     static void Main(string[] args)
    ! m/ H. g, N: l) `  n& X5 M
  87.     {
    / V7 q& x' D, K6 o
  88.         string inputFile = "N1275510.RL2";& b7 B& a; H3 e; u( V) M
  89.         string outputFile = "output.wav";+ m1 ]; \8 j+ e5 W3 T6 Q7 n
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);- w+ R: S/ Y% c" g' x0 @4 O, ^" r
  91.         Console.WriteLine("转换完成。");8 H/ `3 T8 \, A: L6 W$ z
  92.     }
    5 ]8 y: R- B( r
  93. }
    & Z% y3 x0 t, F; D* X
复制代码

, `2 N0 D! i1 o8 e+ q. H. c( n( P$ R8 C# B

, Y0 w" m( N) I  ~" ~  V( m
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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