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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-2 00:06 编辑 0 L+ E7 h) g" t. R% E+ S
" e2 F5 C8 ^  G/ u" v) X: Y  A$ u9 ^. {
该游戏是scummvm支持的少数几款FMV AVG。
+ ]" }9 v$ ~8 _  Q2 @/ ^! j0 O" t, \' K视频采用了一种叫做RL2的格式。! b  C/ x5 `; R5 h# M9 _2 s* Y2 E
参考以下格式和Scummvm中的代码,可以想办法将RL2中的raw data部分转换为wav,
4 _+ `- ~+ X; D9 m/ N- m( a然后用whisper语音识别之后就能配上字幕了。
9 J; b3 ?# K" t% g此外,rl2格式用potplayer也能直接播放。
; {0 X7 V/ S: a4 o
; T+ P+ Y+ K( S& u8 c) @文件格式$ M4 q; ^' P6 {' S$ C% O- T
https://wiki.multimedia.cx/index.php/RL2: w4 ]6 O2 x, w

  1. ' D9 P% m9 i  ^% n6 w0 |; {
  2. +  0  dword  Header                -- "FORM"
    + \6 Y% O7 _: b& y! |
  3. +  4  dword  BackSize              -- size of the background frame/ t. B0 L5 H" s, y  ]/ T, N8 n* L
  4. +  8  dword  Signature             -- "RLV2" or "RLV3"5 X7 k. X$ v* Z2 A: r, m5 ^
  5. +  C  dword  DataSize              -- size of the data past this point BIG-ENDIAN& i1 c% A! h+ e7 ^3 I$ E
  6. + 10  dword  NumFrames             -- number of frames
    2 ?; x% h9 p6 U) Z/ R* N
  7. + 14  word   Method                -- encoding method. ignored, zero
    2 f0 O8 E* Q7 }! e
  8. + 16  word   SoundRate             -- sound sample rate in some obscure format. zero means no sound4 A! o  G; i- Z1 M: r8 G5 [
  9. + 18  word   Rate                  -- sound sample rate in Hz: `2 u& o& ?: r: y- u2 M
  10. + 1A  word   Channels              -- number of sound channels
    8 N  l" x) F# g# L
  11. + 1C  word   DefSoundSize          -- size of the single sound chunk. see notes below
    % Q) O: a9 R3 k7 \" }/ i( j/ }
  12. + 1E  word   VideoBase             -- initial drawing offset within 320x200 viewport! z+ q2 m8 n3 {# c* j5 h
  13. + 20  dword  ClrCount              -- number of used colors8 q8 u6 d1 \% [
  14. + 24  RGB    Palette[256]          -- 256 RGB triplets. full 8-bit entries
    2 s5 I3 `" ]% A
  15. -- if Signature == "RLV3" AND BackSize <> 0
    ( a, b) k+ }9 r2 c& Y& i
  16.   +324 byte  BackFrame[BackSize]   -- encoded background frame. ignore VideoBase during it's decoding
    , A( ~; A4 j' ]5 {; ~
  17. --1 x! X3 D6 j# J0 \; {$ z
  18. +xxx  dword  ChunkSize[NumFrames]  -- complete size of the chunk for each frame (audio+video)
    * t# A% a& z6 u1 N
  19. +yyy  dword  ChunkOffs[NumFrames]  -- offset of the each frame chunk from the start of file
    ( ?; f* j; Z' S0 H/ ]# N+ p
  20. +zzz  dword  SoundSize[NumFrames]  -- size of the audio portion in the frame chunk! h3 Y( z- U4 g4 n' ^
  21. -- for each frame --. J6 u7 v' C: w5 h0 r0 d0 }; e
  22. +xxx  byte   Audio[SoundSize[frame_nr] & 0xFFFF]  -- raw 8-bit audio
    0 }( _4 t4 H6 u. F2 O
  23. +yyy  byte   Video[...]                           -- compressed video stream
复制代码
9 V1 W7 _+ }3 o1 j+ d
参考代码(有问题,但可参考)
  1. using System;% Q; W7 R$ }  O: @3 ]( D
  2. using System.IO;
    9 y, A; b+ H2 i5 g
  3. using System.Text;
    7 ?! X4 p& N0 L/ O% F

  4. & h' @2 d: I0 v* w
  5. public class RL2ToWavConverter
    0 ]& C" _! m9 v9 H$ u
  6. {
    / a2 Z6 C) O1 a4 x
  7.     public static void ConvertToWav(string inputFile, string outputFile)
    9 ^+ R. d4 v3 `" O$ _: @+ s
  8.     {( Z; X; J2 B3 a5 g4 V
  9.         using (FileStream fs = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
    ' B- @' n* Z6 i8 Y9 m$ Y. V6 B0 F( U
  10.         using (BinaryReader reader = new BinaryReader(fs))0 [9 L1 Y  ]- `9 J! @) D
  11.         {
    * l! |4 ?1 s5 [4 \( y
  12.             // 读取头部. K; S) r9 M+ k9 H2 h
  13.             string header = Encoding.ASCII.GetString(reader.ReadBytes(4));
    $ U  m! T3 e- R; F; N1 T* }
  14.             if (header != "FORM")% B$ X7 R* N5 S% s: [0 |# r
  15.             {
    ( S& e0 p% S1 W; o" j( l3 [4 ~
  16.                 Console.WriteLine("无效的.rl2文件格式。");
    ! A7 z( {7 Z; M" E6 k
  17.                 return;" C9 v! r, n! p, t( |% W
  18.             }
    & A' D, f# S  f# u& m( B* ^
  19. ) O  l! S7 D6 z( V$ @, }. `2 j
  20.             uint backSize = reader.ReadUInt32();! J; x) g7 n: n! }# p' M% W
  21.             string signature = Encoding.ASCII.GetString(reader.ReadBytes(4));* \  c, b) F( |0 T* |, L- p
  22.             uint dataSize = reader.ReadUInt32();& y! e: A) A$ @: [" S- j
  23.             uint numFrames = reader.ReadUInt32();
    % M1 J- o  {  P. L$ Z
  24.             ushort method = reader.ReadUInt16();  N' c' g) q- _% R# K
  25.             ushort soundRate = reader.ReadUInt16();
    9 N% b& I* w% G0 c0 ^, i3 O- S- ]
  26.             ushort rate = reader.ReadUInt16();6 n& W9 j2 P, E3 g" q' R2 s" O
  27.             ushort channels = reader.ReadUInt16();% O. D+ e( t9 ~! f
  28.             ushort defSoundSize = reader.ReadUInt16();
    * u+ b& j: P9 y/ o) O9 V/ @; n
  29.             ushort videoBase = reader.ReadUInt16();
    8 z5 ?- w" r" k# F  W
  30.             uint clrCount = reader.ReadUInt32();
    * V% Y; d/ ^$ w% e# `7 [1 D8 [9 y
  31.             uint[] chunkSize = new uint[numFrames];
    3 v) u; s! F9 d1 T
  32.             uint[] chunkOffs = new uint[numFrames];: M3 y8 S; n- R) G' X
  33.             uint[] soundSize = new uint[numFrames];
    7 n5 g" S2 X: D- k) L! [
  34. ' w' g  w0 E* J( A8 K% [2 L7 Z
  35.             if (signature != "RLV2" && signature != "RLV3")
    & J: G: Z; L2 R/ K+ m
  36.             {, W7 b# ?: o9 f1 K: u  K1 }
  37.                 Console.WriteLine("不支持的签名。");5 B; L4 a  A) J2 [; a* m' g
  38.                 return;
    0 @  P- ?0 x: Z4 m& ~4 G- u
  39.             }/ J8 z* w5 o+ F! C

  40. 1 E2 G* h& @4 s+ ^
  41.             // 读取块信息4 U# P& i! @) k  T- @% L) |3 `
  42.             for (int i = 0; i < numFrames; i++)
    ( k* v+ q0 ]/ [( b% O+ Y
  43.             {
    * Q  H5 B( j8 Y
  44.                 chunkSize[i] = reader.ReadUInt32();
    + `- K5 h3 p+ F" f8 z/ R. H
  45.                 chunkOffs[i] = reader.ReadUInt32();/ D# h( E, ]+ z, |
  46.                 soundSize[i] = reader.ReadUInt32();, k" j/ b9 V, o; A$ o5 R
  47.             }, B( I* k  A7 H3 }/ o* ^# v- i
  48. & B' R3 ]- l1 Z! ^- n: M6 p4 h
  49.             // 如果存在背景帧,请跳过它
    ' z+ s4 b7 }. b. t' I1 K
  50.             if (signature == "RLV3" && backSize != 0)9 E: r5 |- _2 f9 ^0 r4 d
  51.             {
    . {$ t& G; [& ?+ `# O- H/ n/ I
  52.                 reader.BaseStream.Seek(backSize, SeekOrigin.Current);
    . b4 x8 Q1 U+ i- d9 w; @/ f
  53.             }9 i. o) H8 R( B5 h
  54. # e9 F7 g' C! c6 V7 A% G0 q! O( h
  55.             // 创建一个WAV文件并写入音频数据
    7 n# i' [9 a6 u9 K2 J* `$ \9 j! P( l
  56.             using (BinaryWriter wavWriter = new BinaryWriter(File.Open(outputFile, FileMode.Create)))+ k2 T6 P. ]7 r& w) L
  57.             {) D6 T# y% Z: N: D: ]4 i
  58.                 // 写入WAV头部! a9 H" o. _. \% U- Y
  59.                 wavWriter.Write(Encoding.ASCII.GetBytes("RIFF"));
    * Q$ b* R! n8 y6 \' T
  60.                 wavWriter.Write(36 + dataSize); // 总文件大小 - 8
    7 U) w9 `7 u% N. @. H# F; ~
  61.                 wavWriter.Write(Encoding.ASCII.GetBytes("WAVE"));
    3 Q5 P% W0 L6 X" T
  62.                 wavWriter.Write(Encoding.ASCII.GetBytes("fmt "));& Z9 J1 @5 |! P) @2 y
  63.                 wavWriter.Write(16); // fmt块大小
    9 D& Z$ h/ s6 P' [# G
  64.                 wavWriter.Write((ushort)1); // 音频格式(PCM), g* d0 _" Y) z, I, q8 S; B
  65.                 wavWriter.Write(channels); // 声道数
    " K6 Z) D. O! {4 F. j' W, U6 j# R; u
  66.                 wavWriter.Write(rate); // 采样率
    % _2 j. Y( W( d$ t
  67.                 wavWriter.Write(rate * channels * defSoundSize / 8); // 每秒字节数
    + a0 {8 Q6 x2 K, [3 R' q" ~
  68.                 wavWriter.Write((ushort)(channels * defSoundSize / 8)); // 每个采样点字节数
    2 V+ Z. ^5 R% |5 Z* t
  69.                 wavWriter.Write(defSoundSize); // 每个样本的位深度# }+ l6 Q  p3 ~5 r7 P
  70.                 wavWriter.Write(Encoding.ASCII.GetBytes("data"));: J; u/ x- ]4 K- c% v. Q
  71.                 wavWriter.Write(dataSize); // 数据大小1 x. @4 Q$ ~3 b
  72. 8 V5 Q3 [8 k8 a
  73.                 // 从.rl2文件中读取并写入PCM音频数据
    / h# y1 X3 ^6 t6 Z% Z
  74.                 for (int i = 0; i < numFrames; i++)
    ; [* D/ Z  R8 A* M
  75.                 {4 H  d4 J( M4 r( H! R. X
  76.                     byte[] audioData = reader.ReadBytes((int)soundSize[i]);: E$ s0 a1 G7 j( g3 l: @
  77.                     wavWriter.Write(audioData);
    : c8 c* [/ N1 g6 ]( N* v
  78.                 }
    - {# s( }- Q, e0 G* E
  79.             }, z' ]) F% E" h; g( a
  80.         }! I1 P# ?- E) f8 C
  81.     }% c8 P( L* Z3 o4 q$ f% G
  82. }
    1 L4 x! ^* }% N) t% |$ w1 l

  83. 3 \1 N2 A- U- v' g& {
  84. class Program
    ; j: {+ |" y3 c" Z
  85. {
    ( n$ }8 i; B  l7 R1 d. p
  86.     static void Main(string[] args)
    " R0 j0 \4 B) X# o$ J/ |
  87.     {
    0 t. x/ L- [9 z) q( h0 T$ Z4 }
  88.         string inputFile = "N1275510.RL2";3 f- X! @  e2 G' g
  89.         string outputFile = "output.wav";  w- s; s# t! ]: `
  90.         RL2ToWavConverter.ConvertToWav(inputFile, outputFile);
    $ I; [! @7 P! F& [8 P9 M2 M
  91.         Console.WriteLine("转换完成。");! z( W4 f3 s' R1 U$ [
  92.     }* L$ ]# o8 G& p& s% L# i& z
  93. }
    ( J' j' i' R( v7 p
复制代码

. z5 \( a' _6 W+ G+ j' Y$ z7 ~
/ \7 O  T' `! A  B8 l& `; t! U' w! S& u: v
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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