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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑
& |9 M5 R7 w. p4 o
' f( J. }! G0 o  h3 S该游戏是scummvm支持的少数几款FMV AVG。/ `2 z: R6 U; v. m& t0 \8 S
视频采用了一种叫做RL2的格式。
" b7 |7 B5 t6 g4 l' e参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,) F* [6 t0 B4 F/ ~2 q6 z' `
然后用whisper语音识别之后就能配上字幕了。- N5 \2 \* _/ f* r
此外,rl2格式用potplayer也能直接播放。
' q. T3 G2 N9 r, q$ S7 P# i6 d7 K, A( r3 R$ q, ^" R+ |
文件格式8 u1 X$ ~9 g) j
https://wiki.multimedia.cx/index.php/RL2
9 _$ g% \$ G6 ?2 m' O: }$ M* k! g

  1. . `$ z3 W6 S9 ~; a% q
  2. +  0  dword  Header                -- "FORM": d9 k& ?% p0 \3 D0 N$ \
  3. +  4  dword  BackSize              -- size of the background frame
    + E% J- R+ h4 t8 G# G. d  q
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    + L9 s, E6 J7 n; y2 b" Q# G7 [
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN1 m4 {% I8 G9 l. A" {
  6. + 10  dword  NumFrames             -- number of frames' O4 M: P' L4 {! i
  7. + 14  word   Method                -- encoding method. ignored, zero
    # R  f4 B: I6 w
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    1 f9 ?* Y3 K9 U: ~$ N
  9. + 18  word   Rate                  -- sound sample rate in Hz; [3 z: R! s) _
  10. + 1A  word   Channels              -- number of sound channels) m" l3 Z# K  x3 {! m& ?
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    7 I. m; D% I( u' {
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport
    5 _& B8 H; {! V
  13. + 20  dword  ClrCount              -- number of used colors: R( E" V: J4 I$ t" C9 S& |
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries& m/ n# L6 ]( |) f& s% Y
  15. -- if Signature == "RLV3" AND BackSize <> 0+ J; G  ?. r' s$ M
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    ( e7 m) b9 t+ Z9 k  f
  17. --
    # @/ t4 {+ a( w6 i' g
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)+ _) T* i$ ~( X3 b* V; @
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file) _' p  p) g; @+ Y
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk3 d( f/ e+ B+ Z% x8 {" C
  21. -- for each frame --6 x: ~( n9 |: y# u
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    & {9 D' k1 l& S& p0 l4 z9 ~
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
6 l  j- e  K  ^! g2 r( z* y' N) x0 P
参考代码(有问题,但可参考)
  1. using System;
      i  v7 o- E0 w# ~- `
  2. using System.IO;9 Z! C. R# T8 C) W$ o7 ^& Z: b8 p
  3. using System.Text;
    8 \( L& n. V- V
  4. 8 M; a5 T3 B! a2 c
  5. public class RL2ToWavConverter
    4 B& T5 x0 t4 c) Z% c- H
  6. {
    % Y" F/ D8 q6 p. X
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    1 Q9 ?, A. c1 N8 k0 p' T. X
  8.     {$ k5 E% t: K/ {- m: ?$ L9 f% D
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    / K9 w6 Z" o) n, a9 k
  10.         using (BinaryReader reader = new BinaryReader(fs))
    1 }; n9 \9 L. ~4 v; Z1 D% T
  11.         {
    ; \) B5 O/ o. Z0 A: d$ {
  12.             // 读取头部
    ! d: \' {' C2 w! ~
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));; H0 v. J5 F( h
  14.             if (header != "FORM")9 S0 t, ^7 ~+ T3 {8 g& a7 B
  15.             {
    1 {9 _; G, a* n6 d8 C, U
  16.                 Console.WriteLine("无效的.rl2文件格式。");
      T! }' }- R$ b/ |
  17.                 return;
    % `. {5 g8 a0 Y9 T, Q
  18.             }
      k6 m% B& @5 Q! s* r, a

  19. " ?0 \" \9 b* _0 L8 y6 z: j" c& D
  20.             uint backSize = reader.ReadUInt32();- \1 P4 X6 S, j( c9 _
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));2 Q+ h1 w! Q9 }% i7 u: N9 x
  22.             uint dataSize = reader.ReadUInt32();
    & p% Q' H7 ]  r" o: C. f4 o. B# E
  23.             uint numFrames = reader.ReadUInt32();$ L9 m" Y9 T. K3 Q
  24.             ushort method = reader.ReadUInt16();
    - x$ P0 V" Y: N! V. d' o* _
  25.             ushort soundRate = reader.ReadUInt16();9 v9 N; ]1 u! a
  26.             ushort rate = reader.ReadUInt16();9 W% c( u) c' d) _7 u6 `; d. U
  27.             ushort channels = reader.ReadUInt16();
    / f% T% P: Q, H4 [- P! k7 V( t' ?7 W
  28.             ushort defSoundSize = reader.ReadUInt16();
    ) w  H. [# r4 M4 \
  29.             ushort videoBase = reader.ReadUInt16();
    5 a' h) \8 L5 `' D% ]
  30.             uint clrCount = reader.ReadUInt32();
    " r0 u  |& h5 e; d" p
  31.             uint[] chunkSize = new uint[numFrames];
    0 K6 M1 T3 R* q, F+ `" k5 G# N
  32.             uint[] chunkOffs = new uint[numFrames];
    ( E6 _+ C3 `+ J! ?1 a
  33.             uint[] soundSize = new uint[numFrames];4 T7 W& k4 E0 M
  34. & m! [- ~5 [. _" ?# d, K
  35.             if (signature != "RLV2" && signature != "RLV3")7 u% V+ J1 b* U" {* c
  36.             {
    4 o* e$ O! _: V" l+ H5 P. B9 d
  37.                 Console.WriteLine("不支持的签名。");
    * k7 E; n. V; ^2 B% i0 r
  38.                 return;# p7 {* k& ?+ ~- c/ W
  39.             }0 p8 J* S6 j/ l0 m  u
  40. ) o- Q( v& ?1 f; n8 p! H# }* U/ b
  41.             // 读取块信息! d) Y: A. n/ u+ j: q
  42.             for (int i = 0; i < numFrames; i++)
    - z' |. N) D7 c  f$ K5 r
  43.             {
    . z$ D$ i% \0 O' e8 S3 p! W9 N5 I) R; d
  44.                 chunkSize[i] = reader.ReadUInt32();
    0 {& P1 h( \3 I+ O* R
  45.                 chunkOffs[i] = reader.ReadUInt32();
    8 M; ^5 t8 d8 ~( K. ~/ l* Q
  46.                 soundSize[i] = reader.ReadUInt32();
    ! W3 X, l) U9 K3 b1 K& Z. J
  47.             }. T, h/ O$ z0 g4 A3 ]  ]+ v" g
  48. ( N+ m: `+ E* O4 N5 P3 k/ G
  49.             // 如果存在背景帧,请跳过它
    1 O' s4 t) p3 U6 }+ i5 q1 q
  50.             if (signature == "RLV3" && backSize != 0)+ c' c" n/ Z/ |0 F/ B
  51.             {5 Y  _' P& {5 D- A( h3 \
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);! R. I/ H! q& w! H0 x, O
  53.             }
    " G' i) S& V+ T6 {; ?8 J$ z
  54. " T" C7 g' a& G' }
  55.             // 创建一个WAV文件并写入音频数据* g! }6 |; C- W8 v( X  ~7 j! _
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))
    * Y3 g& X& c/ |) B% p
  57.             {
    2 k6 `6 k; I9 k2 [$ Q5 s9 l  S
  58.                 // 写入WAV头部" D' S3 @- o: r. K9 t5 C. O6 ~! ?
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));5 J: r+ w. O  B& e
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    2 s( t' k# s8 g7 B
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));: R! K2 P9 o! s# P* [% Y
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));# C! b. X3 J1 _4 R5 P+ Q( [7 x" [
  63.                 wavWriter.Write(16); // fmt块大小1 m4 B9 ]2 w  C/ |# p+ ]( q6 V/ y
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)2 w; P' x1 k9 z  ^- A; X6 O
  65.                 wavWriter.Write(channels); // 声道数. f( c# U* J5 I7 F& [
  66.                 wavWriter.Write(rate); // 采样率5 p4 v8 y  s% K2 E7 N9 b% R
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数* \( U1 _' h2 l# w  {! b
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
    ( b- C- a8 m( J0 c$ ~, f7 D; S
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度
    1 o) e( E& u3 p
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));" I; O$ W+ _2 i! v9 n% J
  71.                 wavWriter.Write(dataSize); // 数据大小, Z0 x/ w& P0 }" i/ W  c
  72. 2 F) D3 Y  X$ Y: c" Y
  73.                 // 从.rl2文件中读取并写入PCM音频数据) ^5 o+ H% S% Q' F+ ?
  74.                 for (int i = 0; i < numFrames; i++)
    ! w! v3 |+ E2 I* u) M4 @9 L$ |
  75.                 {. K4 h, S2 x/ U# [$ k: C7 k+ v4 R# a1 D
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);
    9 ]8 ]+ [4 E% M2 i/ p" D/ ~9 B2 s
  77.                     wavWriter.Write(audioData);9 D2 }& q/ a- j7 j
  78.                 }( h$ ^9 V' D8 l: f
  79.             }
    % o* K1 C# l4 N% ^+ Y9 e, K; ?
  80.         }4 _' x, N3 Q8 d9 g
  81.     }# L% }& E2 u7 u
  82. }* B3 c0 u( w5 W+ c4 k
  83. ' j8 e0 a4 K* k& b
  84. class Program
    ' B4 {) P1 j& _  E/ J9 q
  85. {  N6 x( x2 X7 Y, C, H. K
  86.     static void Main(string[] args)
    4 |% N5 ^! I4 E( b% E
  87.     {
    ) `  D9 H7 P, L
  88.         string inputFile = "N1275510.RL2";9 [% @# k) V1 s5 S+ Z' S  |2 s7 e7 O
  89.         string outputFile = "output.wav";
    1 W1 `% ?$ H( E2 [9 ^2 @. D
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);2 H/ A# q# P+ m# K8 f: j
  91.         Console.WriteLine("转换完成。");
      N: R) a5 H6 q" K
  92.     }* u% A! ?$ I0 t1 R' ]4 K
  93. }, F( S) b% y9 q9 G2 t3 I
复制代码

! }6 n  F" ]( H: t
' M1 u- c' ?9 m$ |$ y! N2 o/ M" }5 h/ P  f
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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