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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑
: m& t4 w9 j+ S2 C
. R8 v6 E# U0 J/ c  Q该游戏是scummvm支持的少数几款FMV AVG。( `6 o- _' {0 U/ Q5 E
视频采用了一种叫做RL2的格式。
( ]8 f9 [2 M$ h2 `+ f3 c/ U: A  j参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,
, z9 A  z& a& K& i( i: U然后用whisper语音识别之后就能配上字幕了。" Y) x: I# L: y/ W; y; l
此外,rl2格式用potplayer也能直接播放。1 e. B2 i9 ^+ p0 W7 M0 n! A

7 q( p  K  T2 i  K( M文件格式+ r% ~# R/ t8 P4 ^8 D# @" @4 j6 f0 N
https://wiki.multimedia.cx/index.php/RL2% L9 j* G  |: P9 @- A& X. i( ^
  1. ; Q. p3 }; R# y; T
  2. +  0  dword  Header                -- "FORM"
    9 b3 M- x4 l8 M4 |( Y
  3. +  4  dword  BackSize              -- size of the background frame  R) e8 _. A: V! t* P* q; U
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    * `' j4 @' q9 n. ?) W
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN  t# z; Z! u$ t$ `, L; T  A- O
  6. + 10  dword  NumFrames             -- number of frames; u6 e/ E. N3 z) b
  7. + 14  word   Method                -- encoding method. ignored, zero: d/ u$ P: z0 b* O+ w( d* H4 h
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound' X& T1 _5 r$ \& J
  9. + 18  word   Rate                  -- sound sample rate in Hz  W) A1 w8 J) h# e2 A* J" l
  10. + 1A  word   Channels              -- number of sound channels2 m- e$ A" O; f' e
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below! s) L! T6 L# H6 K# N5 V( U
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport) W0 r" S7 u: R  d( u( i: S' u
  13. + 20  dword  ClrCount              -- number of used colors* x. m# E) [& P$ d
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries( W- r. d4 e2 P
  15. -- if Signature == "RLV3" AND BackSize <> 0
    + x" k' g+ U: s3 Y" B
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    & j( `: l+ i. Q5 U. ?2 x
  17. --
    % F0 S- K) J. p7 Z9 P! K5 F
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    / p* u4 |& x0 n; f0 v, v: p
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file
    , K+ Q5 I6 h* y; A
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    2 d6 d+ t2 g& A/ F
  21. -- for each frame --0 @9 t* @  a1 U+ \9 H- m% m
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    9 k0 m+ K2 C  f, d8 z' S
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
& |: a' h4 i' {8 Q+ G- w. v
参考代码(有问题,但可参考)
  1. using System;
    2 h2 I1 H7 O5 A7 T: E- J
  2. using System.IO;, T* X( \/ T# x( H" F
  3. using System.Text;
    " A- O+ P3 }1 N2 `6 g) R
  4. 2 B# w9 A/ z' _! J/ `$ @7 @
  5. public class RL2ToWavConverter
    ) @) f% e/ U2 i
  6. {% A5 e4 Y3 U5 Y" O
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    * Z: z; |1 t) K' k# _
  8.     {. q3 v3 a2 `  k* S8 ], s  `
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    ' H5 o- n2 ~8 z& W, ]: K8 e  o
  10.         using (BinaryReader reader = new BinaryReader(fs))7 R& w6 B/ J# b, s8 g6 s7 s5 X
  11.         {
    $ B% S* \2 C1 w2 b1 S8 E
  12.             // 读取头部
    : r7 C/ p9 a) T0 T/ C
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    : V. }9 r' T* Z# q; b
  14.             if (header != "FORM")- D4 J6 _7 o( a5 f7 l- K
  15.             {
    4 m$ T9 I6 P% n
  16.                 Console.WriteLine("无效的.rl2文件格式。");1 c4 q1 Q3 v/ I' |6 |! s2 B- y
  17.                 return;& i3 R. @  Z. @) w8 i
  18.             }
    9 m/ u8 Z1 j8 q+ n) X+ O9 }  ^

  19. : y1 l1 Z/ Q" q6 l' `5 m( ^0 h
  20.             uint backSize = reader.ReadUInt32();
    ) C1 r* ~, Z# U2 b! y+ Z
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
    ( _* h& M8 j4 ?
  22.             uint dataSize = reader.ReadUInt32();7 I6 R- {9 @! a
  23.             uint numFrames = reader.ReadUInt32();
    $ V- h8 k$ Z+ c/ D0 w# g4 {8 [
  24.             ushort method = reader.ReadUInt16();
    # F+ L. H  M, X- ^4 g
  25.             ushort soundRate = reader.ReadUInt16();
    0 a0 I: e2 B  W3 e+ o
  26.             ushort rate = reader.ReadUInt16();. |; Y: A, e2 a
  27.             ushort channels = reader.ReadUInt16();5 |, i9 X6 h; v! I* {5 k4 B
  28.             ushort defSoundSize = reader.ReadUInt16();
    3 l9 p. L1 Z5 b7 r" e3 z+ b
  29.             ushort videoBase = reader.ReadUInt16();9 p  v1 w& D* K9 \1 d
  30.             uint clrCount = reader.ReadUInt32();
    % [4 e: i5 ^* B
  31.             uint[] chunkSize = new uint[numFrames];
    1 f8 F, U/ L8 W( \5 Y0 {6 R7 E6 d
  32.             uint[] chunkOffs = new uint[numFrames];
    # R: b4 r& d7 E5 \" W! q9 W/ h
  33.             uint[] soundSize = new uint[numFrames];2 p$ v9 l5 \, z' {3 V: Z( v5 o
  34. " z- Z) }3 e; q$ p
  35.             if (signature != "RLV2" && signature != "RLV3")7 N4 {& c3 ]2 m& Y, a  ?
  36.             {# g2 ]' a6 ?; w" a/ V
  37.                 Console.WriteLine("不支持的签名。");
    : W% ^! A0 a2 w
  38.                 return;5 b- k9 |/ M+ l+ x4 |9 b
  39.             }: Q' t$ a& d- K9 C0 {7 L  f5 T
  40. - S( R2 S" Y& F* H; V# V3 }0 [- }
  41.             // 读取块信息) e' {/ l  U' `% c: H/ |
  42.             for (int i = 0; i < numFrames; i++)
    2 G3 R4 t- N! K' h  f1 [5 r5 J
  43.             {$ O# f' P6 D7 f( Q" G2 ~, [: T
  44.                 chunkSize[i] = reader.ReadUInt32();: I1 x- c* `% _$ B& U9 b
  45.                 chunkOffs[i] = reader.ReadUInt32();! d& B' v3 r1 c+ V5 w
  46.                 soundSize[i] = reader.ReadUInt32();2 X# Z; M# m1 G
  47.             }: M$ a4 o+ q: C- ^, `
  48. 0 [4 s( j. y* E5 c  B& r
  49.             // 如果存在背景帧,请跳过它
    , |1 M9 ^4 s, F$ d$ ~
  50.             if (signature == "RLV3" && backSize != 0)
    . Y% b3 [& Y1 w& A8 @- Y3 B( K
  51.             {: [+ e, u3 O$ x% J
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);* E9 Q8 x! M" W2 V9 ?( M
  53.             }# {# N! J4 Z6 M" d3 ?, z
  54. 3 e) L* s. D: P4 t* r7 _
  55.             // 创建一个WAV文件并写入音频数据6 d* X2 L+ L$ b  B" m- N
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))! e9 X, Z: k- Z& C6 \
  57.             {
    - j4 X  I5 K' C/ i$ s8 F: i
  58.                 // 写入WAV头部
    . g, Y' ~7 ~3 C( X
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    : R& N; W, K( c0 v
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    5 @0 ^# h) F) d
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    ) W8 u# B7 U" ?, R1 ^$ A
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));
    7 P0 F7 ~- q9 J  z- E# V
  63.                 wavWriter.Write(16); // fmt块大小& b9 a' Q' @3 ]4 @
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)# d" o$ u, t. X7 ]- s% A, {3 E- E( n
  65.                 wavWriter.Write(channels); // 声道数
    + @1 j+ q. i9 |8 b! u8 t
  66.                 wavWriter.Write(rate); // 采样率# U8 l9 J, o0 d% H" N/ ~
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数5 H+ d6 C( m4 V
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
    , g3 O$ b2 P! U, t- R. m% o: s1 r
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度& y- N) O: T0 @3 u  Y. i4 K* I
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));4 g& t  Z7 P- k5 F$ ~6 A
  71.                 wavWriter.Write(dataSize); // 数据大小  z+ @6 P7 F5 J6 o

  72. ' D# t) Y1 Y5 n: e9 e
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    ' y7 w+ {! A8 k9 s7 v) b3 B* x
  74.                 for (int i = 0; i < numFrames; i++)
    ! K/ O7 k+ K, X# F. R$ U# }; M
  75.                 {
    - D! ^( y, [/ S% L/ R1 k6 F, \
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);
    5 j% [4 N; o: D  _
  77.                     wavWriter.Write(audioData);
    : @5 ], L: Q  L7 Q
  78.                 }" G) ~& h, B4 @8 ?0 Q* D
  79.             }
    8 i; u  W0 u9 u9 `& m2 u
  80.         }
    % d) ?. l# s2 K
  81.     }7 N6 }  z3 i% g% ~2 w2 p1 i* `
  82. }
    6 \" G1 i( _, O, t

  83.   ^( W7 w: V2 m1 V9 j
  84. class Program7 F- Z8 ^3 M/ w* ]1 p
  85. {7 Y0 `8 m9 _- b0 O2 W
  86.     static void Main(string[] args)1 ?* f* f) o& M8 g* `! C% t/ q" H
  87.     {
    + s: {( ?0 R# \  S3 d! ?) j7 ~" c
  88.         string inputFile = "N1275510.RL2";
    0 b: |9 F% Z* i9 o: Y
  89.         string outputFile = "output.wav";
    ' P0 W0 F# K+ z' A1 `, c3 N0 u$ G
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);! T" K9 p7 ^; X; I
  91.         Console.WriteLine("转换完成。");
    , |$ w! U9 t( I& O. u- ^0 ]0 [: Z: r
  92.     }
    # e3 F0 c9 s. |
  93. }2 ]3 A. j6 g  n8 @+ K$ Y$ P2 _, l
复制代码
4 J! n) F7 U, i: w1 \1 y) U

0 J, @: X# }) \6 g
3 y0 c6 ]% B! F& L8 u! R3 k! C% q( J
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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