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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 1 @/ _$ E7 D2 I8 D1 v

/ T5 Q! z  \  u- E' x* m. M该游戏是scummvm支持的少数几款FMV AVG。
. V/ A0 e6 r7 `0 g) }视频采用了一种叫做RL2的格式。
" i  [. M3 Y+ a" L# F参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,2 n9 p( h& g% s! D# z, Z, O
然后用whisper语音识别之后就能配上字幕了。  |* Z; S1 d4 K' Z8 B
此外,rl2格式用potplayer也能直接播放。) Z: R1 c% T1 [, A
. T  S: f( i+ G& l" X
文件格式+ Y$ k$ E1 N) {! ?" W6 c
https://wiki.multimedia.cx/index.php/RL2, {$ |0 `! a2 `% @9 T) y. a7 H

  1. 5 O5 H+ p0 p4 V# D4 }8 y: {. A
  2. +  0  dword  Header                -- "FORM"
    - M8 V0 J8 t# v4 e. W2 u
  3. +  4  dword  BackSize              -- size of the background frame
    . n! N( }8 q  X' {& k. Q2 w# M7 Q
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"
    6 i1 u; M; W2 U! ^
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN
    2 l+ W/ S3 J; j3 [& n! e* n3 V
  6. + 10  dword  NumFrames             -- number of frames4 ]6 r* L  L& b5 c( n
  7. + 14  word   Method                -- encoding method. ignored, zero) Z# @/ K/ }7 \8 X6 W" U, {
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound) \0 e  L3 X' G8 E" {
  9. + 18  word   Rate                  -- sound sample rate in Hz' M$ J( h7 I* B6 }0 n4 S) f
  10. + 1A  word   Channels              -- number of sound channels
    3 K6 H3 t7 `* S$ |
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below$ G. [8 S' n  W) U& v4 m
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport
    / |9 \  M( U' @  |7 `
  13. + 20  dword  ClrCount              -- number of used colors6 L* X+ c6 d0 x6 N
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    ; e8 i" ]. A$ p
  15. -- if Signature == "RLV3" AND BackSize <> 0
    7 H2 ?2 y) ]1 d1 b
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    " m9 `) w7 W1 I0 e3 A
  17. --
    - ^9 x7 j, H2 h" Q
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    3 ?% ?. z* d+ s5 u7 ~) a/ w
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file
    4 x" ?/ ^0 b& W$ K4 `
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk' |# I- u" ]) F/ H9 [2 k$ J+ }
  21. -- for each frame --
    : k: k4 T& O1 Y# R: |0 R! b
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio/ \" L" a9 u8 n$ @7 b7 G
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
4 v, o5 z" f( u1 l7 K' j6 |
参考代码(有问题,但可参考)
  1. using System;
    ) r! |/ D* y) `0 t
  2. using System.IO;
    % T( {2 `% X- m! H2 q+ f$ U1 |
  3. using System.Text;
    % r9 d# ]4 X& F8 ]# q
  4. 6 K7 l. J' {( N7 `9 [5 m% }0 |  C
  5. public class RL2ToWavConverter
    8 M8 A/ f+ p  N( R  e7 @; g, z
  6. {
      x' K6 Y$ O4 a  m  D3 e. n
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    6 `, P9 ^2 U3 [# c9 X
  8.     {
    . Q. R: o$ n1 ?, W
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    1 I$ L) V7 B% F1 K, U9 }
  10.         using (BinaryReader reader = new BinaryReader(fs))9 X3 X: `& e6 S7 a6 F* T, U3 T; ^
  11.         {
    1 K0 b+ @( ^0 S4 x
  12.             // 读取头部. R' Q7 A+ A2 f
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));, m4 D$ x3 J6 l7 x( I' z$ H$ o5 {
  14.             if (header != "FORM")' E2 c; |/ g/ X/ o1 [: {; m4 I+ E
  15.             {! y" G  }0 O3 T, x7 ]! l5 l9 f
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    ' x0 ~  x% T& c6 |
  17.                 return;" e  k9 u: V; X5 J; K& v( B; j! `
  18.             }
    4 I0 D3 k( Q1 v
  19. , g) b4 X4 T7 r. O1 E
  20.             uint backSize = reader.ReadUInt32();. v$ x/ r8 ]/ q' g0 R& W0 M5 o
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));% [- n# E* s1 K7 E3 Q
  22.             uint dataSize = reader.ReadUInt32();
    $ c/ D5 Q. Q. j! [8 u: h
  23.             uint numFrames = reader.ReadUInt32();
    # x& B7 n6 p! K9 V! _* S" B# A
  24.             ushort method = reader.ReadUInt16();
    # g# p) X2 V4 q) l$ O7 T0 X* q. X$ |
  25.             ushort soundRate = reader.ReadUInt16();
    ( n; _3 j! B* O6 ]; i0 C" [7 O
  26.             ushort rate = reader.ReadUInt16();
    , N7 n$ d' V5 T6 y+ }. ]0 n% b  z
  27.             ushort channels = reader.ReadUInt16();
    - r. ~7 Z  R& A0 C) Z6 r
  28.             ushort defSoundSize = reader.ReadUInt16();
    + W0 _: ^8 Y* o1 N) I
  29.             ushort videoBase = reader.ReadUInt16();
    $ N- J9 k, D' ]7 D
  30.             uint clrCount = reader.ReadUInt32();7 b5 I; @+ M' `4 z8 V+ G
  31.             uint[] chunkSize = new uint[numFrames];
    3 k5 p; R& @. p; Q) z
  32.             uint[] chunkOffs = new uint[numFrames];" L% g5 h; E/ ^  \8 {  ?" V. Z
  33.             uint[] soundSize = new uint[numFrames];
    ! l- ^% s: W5 i, O' L

  34. 4 d/ p8 H9 c6 ?
  35.             if (signature != "RLV2" && signature != "RLV3")
    & A% ~$ p5 p' \: Q. |
  36.             {' Q' w$ N& I  [; z6 c: r  j& L
  37.                 Console.WriteLine("不支持的签名。");; f, A" U6 G/ `' [7 z
  38.                 return;8 \, V" k, Z/ p4 l' `1 Q
  39.             }  Q+ e3 m% t* q4 s

  40. * _6 z$ @! V/ D/ g
  41.             // 读取块信息
    $ a$ d$ K8 C* j# e/ C1 ~* t8 I
  42.             for (int i = 0; i < numFrames; i++)0 E+ r1 G4 [8 y; E9 S# `
  43.             {
    , q5 C7 o9 x5 S$ a+ A
  44.                 chunkSize[i] = reader.ReadUInt32();
    ' U. E6 D3 T- W0 |
  45.                 chunkOffs[i] = reader.ReadUInt32();& U6 ]% g1 z& Y* A+ v
  46.                 soundSize[i] = reader.ReadUInt32();6 b- {% _2 p+ g6 J) X
  47.             }  ~) @0 V* o% s, g! h
  48. : Y5 k/ |  t& R( Q5 n8 o# b0 D# b
  49.             // 如果存在背景帧,请跳过它
    - w5 L; Y( ?* D  L
  50.             if (signature == "RLV3" && backSize != 0)9 i  O% \" d+ i
  51.             {" W! W, W, X' ~/ i
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);( Y) j, [4 k9 h! E; P& U
  53.             }
    - B' s* U2 ^# Q, Q2 a- c3 D
  54. : A+ Z0 y/ p, P6 Q, R1 @2 I4 K
  55.             // 创建一个WAV文件并写入音频数据( ~2 K2 F* m, `/ f9 h: H
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))8 H* u0 h) D6 S9 p5 R/ y2 k
  57.             {
    $ ^6 X5 |2 t. A+ Q9 n
  58.                 // 写入WAV头部, i6 c1 E$ C3 ^  y: c
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    5 P3 u  a& ^( F2 x# ^  I* t
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    $ f4 U& N$ F5 z3 ^! m
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    * T3 X4 {4 z3 x* v) D! n
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));7 k% n  p; Z8 |; e# w4 f/ L) n8 E' ~' R9 K
  63.                 wavWriter.Write(16); // fmt块大小
    & `; K" A0 ?  c7 a
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM)+ e) M% y0 }& U# N5 j! `
  65.                 wavWriter.Write(channels); // 声道数. O8 g8 d: d. _$ i1 W) z- H
  66.                 wavWriter.Write(rate); // 采样率$ j* q. Q  H+ X) l3 p" G
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数" Z$ m4 Z; H+ S- t
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
    5 s- i$ p& r# P( F) Y  n
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度
    * Q4 N& R1 p! N$ s. V
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));5 @1 J! t' p1 F; _" u& b3 f
  71.                 wavWriter.Write(dataSize); // 数据大小
    ( a5 j4 Z4 b2 U6 @$ d$ w& m0 h
  72. # a+ X$ l# |$ E/ y' r7 O' r4 l( b& X
  73.                 // 从.rl2文件中读取并写入PCM音频数据5 S4 G2 ]* A8 w8 i" W
  74.                 for (int i = 0; i < numFrames; i++), e; `( p8 i7 L: L/ i
  75.                 {/ {2 l0 ?3 @  ~$ O, k
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);
    . {& p1 T% d  n4 y* o3 h
  77.                     wavWriter.Write(audioData);
    ! ?3 y" l; a0 o; k
  78.                 }) V( y' Q0 z0 e# y1 J0 y- O) _' J4 o
  79.             }
    : X# Z2 K% I' ~5 x$ B2 `5 V. z: r9 w
  80.         }2 d3 A5 j* |3 @& ]1 [& w9 ?
  81.     }2 z; I1 W0 R0 a0 m6 ~3 T
  82. }
    5 m/ }1 T" b9 c5 \% b' Y
  83. . D1 ^9 w, p" n# K! \: O" L4 X
  84. class Program" I5 G- N9 z) @4 t
  85. {
    * z7 @$ l, b1 b6 ~# l0 i
  86.     static void Main(string[] args)* s+ L9 B! l2 ^3 W% H
  87.     {
    * P% t+ K# R9 Q  j4 @* R9 z
  88.         string inputFile = "N1275510.RL2";
    1 l- e" ?  f9 g# l! ]
  89.         string outputFile = "output.wav";
    + P8 A! }" ^- [2 q
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);( m8 m' q4 p6 m8 K8 g6 T
  91.         Console.WriteLine("转换完成。");
    - c; q4 n- ~- g& }
  92.     }9 L' Z% ]( ~7 ^6 Q, k/ A2 L
  93. }
    2 X% q3 }2 |) S$ H
复制代码
1 N) K" z# b( S* }# l! {
$ T. V3 g4 v3 H
' F/ b/ o0 S* W
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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