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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑
; Q8 ]6 J  K, Y/ `3 g& d3 y
7 w  ~/ u; w- c3 f该游戏是scummvm支持的少数几款FMV AVG。
8 S& d$ F7 v& }: Z视频采用了一种叫做RL2的格式。
! X, G8 x* @, g0 @7 ~/ ]% K参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav," ?' g2 x$ T7 C/ D3 t
然后用whisper语音识别之后就能配上字幕了。7 q9 H  X1 b: H# y0 ]3 m
此外,rl2格式用potplayer也能直接播放。! d( q7 Q1 r6 V" t

5 ]6 n$ f" P) }) i8 d  D文件格式
" I, G6 s$ n+ U/ n3 ]https://wiki.multimedia.cx/index.php/RL2% g; l. G+ b# M' R  u+ O

  1. ' U. A8 E% ^, C  x( w9 D* o
  2. +  0  dword  Header                -- "FORM"4 Q3 H$ `: e0 _( F
  3. +  4  dword  BackSize              -- size of the background frame7 _" Z, }2 `  m4 p$ Q
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"' I) T. l& m) Y0 v& \
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN
    : O) C: ^  r, d3 h9 Y9 w, Q6 W
  6. + 10  dword  NumFrames             -- number of frames
    ! S/ Y8 F$ f4 }" u: P& }: y
  7. + 14  word   Method                -- encoding method. ignored, zero) K: `) U& f' E0 T
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound" Q% _; ?- K- P9 s5 L8 |( o
  9. + 18  word   Rate                  -- sound sample rate in Hz# x6 q& B% h8 G4 C) u
  10. + 1A  word   Channels              -- number of sound channels
    $ R6 L  E7 a6 G6 a  y9 d" R
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    ! v2 \- I% F2 l
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport
    2 }- G& l$ e/ m' o' y$ q0 U
  13. + 20  dword  ClrCount              -- number of used colors  _0 p- r" V( i% r$ p6 L. \- B
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    4 g3 u# o1 ~% i, I4 c* Y7 X
  15. -- if Signature == "RLV3" AND BackSize <> 0
    + s. u& m- d% g. o2 W
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding( D  l0 e; U, s
  17. --
    - W+ ^  g) O( a
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video). }0 g0 U1 q* {3 P  ~
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file; K  t3 {' \# M9 h) ]
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk% U4 S- y7 `$ |! U0 D/ v
  21. -- for each frame --
    # \; K4 T# H! z8 G$ o
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    ( _- d8 F, `0 |7 `
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
8 R: P  V2 v  o5 Y% v" i
参考代码(有问题,但可参考)
  1. using System;; N1 K6 B) F6 j. s
  2. using System.IO;
    4 T  v3 Y8 {9 V4 j- c, w2 t( s/ I- |
  3. using System.Text;
    9 e7 A1 g* ^4 b
  4. & d8 z% F/ S  l4 h3 Q- ]( R
  5. public class RL2ToWavConverter$ _1 H2 v, P; q
  6. {6 \, b/ u* M1 P
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    ' x, P& \- |1 A- R( _$ i! I
  8.     {1 n1 w6 @! Z* y8 K
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))% M* b* k3 q4 W- {1 t  ?
  10.         using (BinaryReader reader = new BinaryReader(fs))" V1 n( x/ H$ ?4 ?+ l* M" v$ Z7 n
  11.         {8 u8 m- U  S% ^4 b$ V+ j8 c! u( l
  12.             // 读取头部
    ' g$ K' a7 [0 u0 H
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    . D$ q2 p) k7 G* N" b
  14.             if (header != "FORM")
    ( i5 m7 ~6 L: o- K9 ~
  15.             {
    : e0 u5 [' J4 \2 M3 w$ |# b: ~
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    : ]' T$ E- E) w2 W
  17.                 return;5 A# @% B$ k1 v; S" ]
  18.             }
    ) [. |8 Q9 j8 Q; x" [! o' |- P
  19. 8 r  t+ W( _" u
  20.             uint backSize = reader.ReadUInt32();
    , e3 v8 I' d: }# a5 F$ }
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
    + F$ \) q* R8 ]; V; t$ C
  22.             uint dataSize = reader.ReadUInt32();
    % Y9 d$ m3 l: t4 Y$ i0 b' J  ]
  23.             uint numFrames = reader.ReadUInt32();7 K7 q1 @3 v, D9 u9 R+ J1 Z7 b
  24.             ushort method = reader.ReadUInt16();
    2 g+ ^* s) M- P+ R; [0 c3 \  X7 A
  25.             ushort soundRate = reader.ReadUInt16();8 w+ E/ g/ {4 f# C2 z
  26.             ushort rate = reader.ReadUInt16();
    - b  r9 w/ @/ g$ S9 j
  27.             ushort channels = reader.ReadUInt16();
    $ ^) y2 n4 {8 y) s1 U! Q' a# Q2 k
  28.             ushort defSoundSize = reader.ReadUInt16();
    2 I0 w/ I- g- M4 P9 F; r! B
  29.             ushort videoBase = reader.ReadUInt16();
    2 E2 y& V! t: Q! b* U9 u9 `
  30.             uint clrCount = reader.ReadUInt32();0 V4 S: [- G! K7 |3 u, V
  31.             uint[] chunkSize = new uint[numFrames];; w: p, {( Q. g, d
  32.             uint[] chunkOffs = new uint[numFrames];' m/ n/ a+ C! S! I, T- |9 y" |
  33.             uint[] soundSize = new uint[numFrames];4 d, O, ?% B+ a+ }
  34. 7 V. m# f# D: Z; \5 z5 h
  35.             if (signature != "RLV2" && signature != "RLV3")' h% C8 I4 x8 d9 o& y( J! @8 K8 N
  36.             {
    % q  o8 L! l: C( i) f( I
  37.                 Console.WriteLine("不支持的签名。");
    5 [2 x7 u2 Z: S' P& Q1 S8 Z0 c
  38.                 return;7 ~( R+ w* T3 r/ {4 N8 o
  39.             }
    8 v* b+ W6 O# M' @0 ?& {4 H' P
  40. 0 h/ b2 ?3 K) h8 ^4 T3 j" I' N
  41.             // 读取块信息/ t; {, ?* Q. b' h) g
  42.             for (int i = 0; i < numFrames; i++)
    ; R3 h' g/ J3 K3 P$ l! Y+ b  [
  43.             {$ }& r( |& I5 w+ c) }6 z
  44.                 chunkSize[i] = reader.ReadUInt32();
    / j; ^; R' E) i0 k! K
  45.                 chunkOffs[i] = reader.ReadUInt32();( s  P* \0 C! j: c3 E( T
  46.                 soundSize[i] = reader.ReadUInt32();
    2 b  N# P5 ~4 e( o% R
  47.             }
    7 \. j% D" h3 ~1 Q' A
  48. : ~1 D9 p2 Y# q  V7 H, _" E
  49.             // 如果存在背景帧,请跳过它
    9 ^+ Y1 n/ c4 U: q8 V3 a, d5 ^
  50.             if (signature == "RLV3" && backSize != 0)
    / B- C. r" Z: S+ |& W
  51.             {' O- c) c6 @5 ^
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);* \" T# P# g2 h9 H
  53.             }
    8 d! V% g; u0 F7 n  R& `- \

  54. ( @& \! R5 J0 o
  55.             // 创建一个WAV文件并写入音频数据" M: |5 }8 z5 t4 \/ i; w6 Y  W
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))# l4 T% `% O+ S8 D. Z% I+ ^
  57.             {" K+ C! ?. ?  Z8 d
  58.                 // 写入WAV头部
    + \6 W, x/ \3 z3 c+ w" x
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    / l+ r  v% b4 u9 M7 b
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8) M2 C' P7 N+ e2 t7 u: Q
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    ! D5 ]3 m( q( W
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));
    ; O7 G" |9 J: b# v
  63.                 wavWriter.Write(16); // fmt块大小% n9 Z% Q$ h& x, K( L  c6 ~
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)
    5 O8 M! f( x. R* N4 K
  65.                 wavWriter.Write(channels); // 声道数1 o* L! e( C- E- `" m+ v! V
  66.                 wavWriter.Write(rate); // 采样率
    # y5 [1 }; q- Y! [
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数, [9 ^; y3 t6 d2 g/ {! |
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数$ D7 ~  G$ l- g
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度2 c) S5 {; H! s4 |- s9 [
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));
    . y+ j/ b3 _6 |& K# P0 ?2 _
  71.                 wavWriter.Write(dataSize); // 数据大小3 V/ u# e! V+ D& ~# H
  72. # n3 N$ f! A" h% N
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    4 d# f$ \, n7 h1 h4 Q' ~
  74.                 for (int i = 0; i < numFrames; i++)
    " T( T& D& \0 x' n( f' i
  75.                 {- R& i; \9 O5 G. T
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);
    7 L- K" b$ y3 K! |' U
  77.                     wavWriter.Write(audioData);5 y& V# K9 B7 g) ]
  78.                 }
    / N/ J& ?1 p' D1 e2 l" T1 o
  79.             }( F, D" H; W' X, @
  80.         }
    ; H# l* i$ V$ T4 k/ R; z5 V1 h
  81.     }) c7 I7 v# Q2 }; y/ ~3 g5 Q' M
  82. }! {* I3 F5 m) F4 q
  83. # D* D& R7 t( |+ _) D& Z7 h4 j
  84. class Program  c. v% n7 G+ q9 c# \7 S
  85. {
    ' k  T7 h7 b# H  F& R  w
  86.     static void Main(string[] args)
    % m1 p. B: `. _2 r6 L5 ^
  87.     {
    8 g  y% L( t# G5 G- B+ Q
  88.         string inputFile = "N1275510.RL2";
    # C, P) O. ~' {% r* q$ ]* P
  89.         string outputFile = "output.wav";
    / F& O" T$ x" r; P0 x
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);
    2 _( V5 N' g6 J& q8 t
  91.         Console.WriteLine("转换完成。");  [9 R; S3 g5 q$ s+ c
  92.     }  o' _. w: h8 h5 M8 {
  93. }
    1 m1 n: m$ W4 C
复制代码

2 {4 o" l' [! _4 S2 E5 Q/ q/ q) R* P& l; W5 w7 i/ A
$ [7 B, h7 X! p5 @7 I: J' w0 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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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