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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 + D3 X0 u; p* }" e) Q' u

/ Y. ]/ j; _$ z( w该游戏是scummvm支持的少数几款FMV AVG。
- @9 H% E- @5 C- J: \视频采用了一种叫做RL2的格式。' @( R  ~' _4 a* b. j/ n( {
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,
8 X& |9 u% ^$ K3 k3 w0 S  Z# o然后用whisper语音识别之后就能配上字幕了。
0 w3 k/ k! R, ?" U此外,rl2格式用potplayer也能直接播放。
# }5 Y6 B1 p! p2 x8 J; O* b8 x: G& C* I: E0 A9 g8 H
文件格式
: u2 C9 q! R. D2 c8 i1 `6 bhttps://wiki.multimedia.cx/index.php/RL23 a6 |( `" I5 V

  1. 4 U1 c! }8 A/ E' M% G
  2. +  0  dword  Header                -- "FORM"
    7 v) U% y' v( Y9 C4 C6 J
  3. +  4  dword  BackSize              -- size of the background frame
    & I# C6 @9 C4 }9 N: L3 R- M5 R
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    5 n9 ^1 t" E$ I% \" V$ f
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN
    9 ]4 `" l. i% D1 [2 o' U) r8 t
  6. + 10  dword  NumFrames             -- number of frames7 Y: m  F, Z- T. e8 b
  7. + 14  word   Method                -- encoding method. ignored, zero
    * Q. ]+ U4 [' A& v
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound
    " h$ C8 ?' K" H& N& Q( ~7 G
  9. + 18  word   Rate                  -- sound sample rate in Hz% e2 E5 k/ H' Y# h  {2 c
  10. + 1A  word   Channels              -- number of sound channels/ B! e% v9 T& R! a4 A
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    + R$ s/ l  F3 q! d8 H& M& ^0 y
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport: d( y2 n( v5 }
  13. + 20  dword  ClrCount              -- number of used colors1 i/ q* O" i' C8 n9 J' }
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    + j$ ?+ Y9 k- k
  15. -- if Signature == "RLV3" AND BackSize <> 0, t6 N/ O$ C, U7 y
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding& m$ M$ B1 x/ d& ?+ m4 L6 x: |7 |
  17. --" u+ S, _: o7 d, E7 }$ d
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    7 g* N5 a9 m% p' r' q! e: Y+ s
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file/ }7 f( H, j; J' G, s* P2 E( \) h$ W
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk
    & q9 O- ^& d0 [
  21. -- for each frame --3 }4 J7 @5 K; j% m3 M! F4 l
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio# w4 k+ i7 e9 L  O: @* \# j% s( S
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码

- j4 _( P+ M0 x  v  g参考代码(有问题,但可参考)
  1. using System;
    ' g) V# W# ~" R" B" u4 a$ s9 H" J
  2. using System.IO;1 }9 W0 I$ r7 P5 J5 k( ^1 x
  3. using System.Text;
    3 s; P. P$ b, [' E3 j6 _
  4. 1 I$ `! S: u+ F2 h7 e2 C3 j' J% f7 |
  5. public class RL2ToWavConverter/ b; t+ [  Z' \
  6. {, m+ m  l# V3 O) u
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    ( l4 R2 g2 [- O
  8.     {
    7 u3 x: d2 B3 `# }" G
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    1 o" a$ [0 d1 Y, q. Y) @* {' y
  10.         using (BinaryReader reader = new BinaryReader(fs))! b0 `/ \4 x8 H
  11.         {
    , T/ g; Y4 {* I* E0 s/ A& }- @0 |
  12.             // 读取头部; d9 C9 ?+ o0 D$ ~0 j
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    0 f# [1 o+ v6 [8 N$ l- {; |: w
  14.             if (header != "FORM")
    6 B1 D! t" a- }
  15.             {
    5 D3 \  @, |  g# B
  16.                 Console.WriteLine("无效的.rl2文件格式。");1 m: H( s' V& Z
  17.                 return;
    9 C7 Y, c$ c, f1 W; t0 d6 `
  18.             }
    " B4 ~9 k; Q4 E+ j

  19. + @; o. v8 ^. q0 y
  20.             uint backSize = reader.ReadUInt32();
    2 ?, j; p; T. Y' j. W
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
    3 L3 u$ B' a/ ?) {! R5 r& e, ?9 y
  22.             uint dataSize = reader.ReadUInt32();
    0 e4 O0 b' n' Y$ F0 b( C) M
  23.             uint numFrames = reader.ReadUInt32();/ {' c4 y' i2 A7 y
  24.             ushort method = reader.ReadUInt16();1 S: o( D" d: b5 y9 t4 k; g+ N
  25.             ushort soundRate = reader.ReadUInt16();
    ! J: u& H8 v& ~
  26.             ushort rate = reader.ReadUInt16();
    - ]/ {2 V: q$ M( F* @. u
  27.             ushort channels = reader.ReadUInt16();
    + z' b$ Z9 F# k( |% Q
  28.             ushort defSoundSize = reader.ReadUInt16();7 f% Z: |$ {, S7 ^  N1 e
  29.             ushort videoBase = reader.ReadUInt16();; b6 D0 }5 L+ _1 f
  30.             uint clrCount = reader.ReadUInt32();- d  r. k% ~( w5 R. g% X" h( `* r7 n
  31.             uint[] chunkSize = new uint[numFrames];5 r5 e  c9 ^7 \) g6 ]; L2 J
  32.             uint[] chunkOffs = new uint[numFrames];
    " g2 h7 f7 Y: H5 J. {
  33.             uint[] soundSize = new uint[numFrames];1 j. i, }! r2 Y9 W+ b& s0 @" g) [

  34. , h+ i) b9 ]3 ]8 I0 A
  35.             if (signature != "RLV2" && signature != "RLV3")5 a' u+ O2 O7 A2 U' N; `* w
  36.             {8 r' a* A2 N* A3 f. `  v  M' Q
  37.                 Console.WriteLine("不支持的签名。");
    ; R/ {2 ?) U, p& p3 A! i. F
  38.                 return;4 p' N3 e  A) {% I8 d" Z
  39.             }% m% O+ V1 Q6 g- _/ `$ d
  40. 6 W, W  @6 A3 y
  41.             // 读取块信息3 @& s  J# `( A0 o& w8 S! C
  42.             for (int i = 0; i < numFrames; i++). F% {4 [" J0 b" A
  43.             {& ~0 t3 W5 P0 j/ ]' X
  44.                 chunkSize[i] = reader.ReadUInt32();$ M: d/ a" a9 |+ S/ n" R
  45.                 chunkOffs[i] = reader.ReadUInt32();
    0 u# _2 o2 k! t: ]4 H
  46.                 soundSize[i] = reader.ReadUInt32();
    ; N, P" r; u2 H$ l
  47.             }
    9 o) F% I# ~/ G1 h* j" N) n4 M1 R

  48. 8 |5 }8 i- I6 \9 b: `9 ?. f
  49.             // 如果存在背景帧,请跳过它$ }4 {5 x- h3 _+ I# `
  50.             if (signature == "RLV3" && backSize != 0)6 ?4 |/ E- p' y9 ]
  51.             {
    6 a8 i7 P& F* J! \
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);# t- j+ @9 ]  v7 a
  53.             }/ l3 T! A. t! V0 H
  54.   `, k4 `! E+ {/ ?4 _7 s% }
  55.             // 创建一个WAV文件并写入音频数据2 g- V; _) E: s8 b7 \' q
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))
    ) W8 `: o9 p% J5 f9 f# }/ J  R  e9 j
  57.             {+ F, a9 ^/ F% k# K1 c2 e0 C
  58.                 // 写入WAV头部
    . @0 K8 ^0 \- B5 O
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    " O$ y6 u  M: z
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 83 I! [* ]  J$ F' |5 A  D
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    # S1 h- l9 Y  w( D& h
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));$ p% {5 L1 o2 I# D
  63.                 wavWriter.Write(16); // fmt块大小" `) ]$ M. z' J' ~
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)* Z0 J' q" `1 R- D1 h) j' H
  65.                 wavWriter.Write(channels); // 声道数" ?! ^6 P2 d3 f# N( _. A
  66.                 wavWriter.Write(rate); // 采样率6 k# ]  w- M3 |( Z- ^$ b( ?
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    ' _3 T# v5 _% }6 |3 w, O8 {
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数. u7 X7 L' j" ^% V' U
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度9 ?" T$ o& q+ D8 T; {$ K
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));; L' h- r! n( k+ I7 d
  71.                 wavWriter.Write(dataSize); // 数据大小1 ^* h- T" ]( }* b# k% W3 z7 k

  72. / P" t$ `9 L8 z; l
  73.                 // 从.rl2文件中读取并写入PCM音频数据1 S' c3 I$ E, \4 ~
  74.                 for (int i = 0; i < numFrames; i++)
    1 Q2 l; \, j' u# R
  75.                 {6 y  s3 Z6 e! c3 t, v
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);1 g- ]8 |  l0 J8 H
  77.                     wavWriter.Write(audioData);3 G! p( e  E9 B# Y$ {7 N) z
  78.                 }0 R7 _/ B+ P. t. g
  79.             }
    / S1 w  N1 T2 F+ I2 y# o4 r4 `
  80.         }
    ( J+ r, e5 ?2 A% X; T
  81.     }
    - D% P/ Z( ~! u7 S9 P6 y+ u
  82. }% j2 b* q# A1 I' {5 q
  83. $ H0 I% ?7 z0 l0 |
  84. class Program% ~: z! x2 F5 U
  85. {
    5 I$ H. O9 w; d% T3 u+ M
  86.     static void Main(string[] args)1 E3 N  I3 p2 {' `  R: U& L
  87.     {6 X, o- s# n4 v1 t! S4 s
  88.         string inputFile = "N1275510.RL2";6 c, Z0 O9 J. E  L
  89.         string outputFile = "output.wav";9 t+ y. [+ d: s
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);3 u  z  l9 v  O! ?
  91.         Console.WriteLine("转换完成。");
    ; ]" `( N+ m/ H5 I
  92.     }% ~( G" c1 k. G" f
  93. }
    9 C. w  J: D( b. P+ C- Y
复制代码

" }/ m3 g6 |; |0 u" R( B5 ?9 m) m9 O' C

& j* n0 K0 ?& _. @" X
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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