- 积分
- 746
- 最后登录
- 1970-1-1
- 阅读权限
- 70
- 积分
- 746
- 帖子
- 精华
该用户从未签到
|
Ralf Hagen的音效教程《SMS文件揭密与领会》中文版
[这个贴子最后由todayhigh在 2006/02/18 09:09pm 第 2 次编辑]
SMS文件揭密与领会
Ralf Hagen(德国) 著
第一版 2002年6月20日发布
2002年10月10日由Yuri Sos自德语译为英语
2006年2月17日由Edgar Li(todayhigh)自英语译为汉语
简介
Kuju Entertainment曾经的作品Locomotive Simulator满足了所有人的口味,可在Windows, Linux及Solaris下稳定运行,享有盛誉。当微软来做模拟游戏时,这个作品也须遵从look and feel的微软名言。
其结果就是我们现在看到的MSTS。
闲言不表,.sms文件是MSTS中编写得最糟的配置文件,sms的官方释义为音效管理系统(Sound Management System),可是若解释不清就让人认为是S&M之类的东西。下文中将讲述我对其涵义的管见。
.SMS文件
机车:每台机车拥有2个SMS文件,xxxcab.sms用于机车视角音效,xxxeng.sms用于外部视角音效。
自行公务车与客运车辆:拥有xxxpas.sms用于乘客视角(切换键5)音效。
所有车辆:拥有xxxwag.sms用于外部视角音效。
SMS文件结构
文件头
要建立一个SMS文件,您必须定义一个文件头并标记其结束。
文件头格式为
SIMISA@@@@@@@@@@JINX0x1t______
Tr_SMS ( )
所有的指令行都要用Tr_SMS括号标记结束。
您可以用下列指令加入注释。
Skip ( )
或
Comment ( )
或
#
推荐您经常给自己的文件加入准确的注释。不幸中的万幸,虽然有的默认文件注释都含有错误,我们还算是有可参考。
伸缩性组Scalability Group (SL)
Tr_SMS小节分为3个部分,合称伸缩性组,关键词是ScalabilityGroup( )。其中包括所需的音效。
伸缩性组的3个部分分别称为SL5、3和1,定义了在不同音阶下播放的音效,SL5高、SL3中、SL1低。
为了明确标示出伸缩性组中的音频流,伸缩性组前面有一组注释。下面是一组好的注释示例:
Skip(** SL 5 sounds **)
Skip(** - One One shot Steam audio stream **)
Skip(** - Two looping audio streams, playing an pitch shifting loops by Speed {wheel rot} **)
Skip(** - One Whistle audio stream **
Skip(** - One Bell Toggle audio stream **)
Skip(** - One Injector 1 audio stream **)
Skip(** - One Injector 2 audio stream **
Skip(** - One Sander audio stream **)
Skip(** - One TBrake audio stream **)
Skip(** - One Water Trough Loop audio stream **)
Skip(** - One Fire box Loop audio stream **)
Skip(** - One Fire box shovelling stream **)
Skip(** - One Control audio stream with individual Control sounds **)
Skip(** - One Coupling audio stream **)
它们是对G lsdorf 380机车SL5组的正确注释格式。每一个音频流都有一个注释。
我们来看一下伸缩性组的开头。其中一些项目我还没弄清楚。
一个典型的cab.sms文件开头如下:
Activation (
CabCam ()
Distance (100)
)
Deactivation (
ExternalCam ()
PassengerCam ()
Distance (100)
)
Stereo ()
...
eng.sms文件的:
Activation (
ExternalCam ()
Distance (1000)
)
Deactivation (
CabCam ()
PassengerCam ()
Distance (1000)
)
...
pas.sms文件的:
Activation (
PassengerCam()
)
Deactivation (
ExternalCam()
CabCam()
)
Stereo()
还有wag.sms文件:
Activation (
ExternalCam ()
Distance (55)
)
Deactivation (
PassengerCam ()
CabCam ()
Distance (55)
)
我将尝试解释各项的涵义,也欢迎所有人从其他角度给出解释。
激活Activation () 与失活 Deactivation ():指示了哪一个声音文件在给定的视角(外部、机车、乘客)中播放。
ExternalCam ()指外部视角(切换键2、3、4)。
CabCam ()指机车视角(切换键1)。
PassengerCam ()指乘客视角(切换键5)。
举例如下:如果想在通过平交路口的时候在车厢里听见铃声,您需要在crossing.sms文件(控制平交道口的音效)中将cabcam()一行从deactivation ()下移到activation()下。如下所示,修改前是绿色,修改后是蓝色。
Activation (
ExternalCam ()
Distance (100)
)
Deactivation (
PassengerCam ()
CabCam ()
Distance (100)
)
Activation (
ExternalCam ()
CabCam ()
Distance (100)
)
Deactivation (
PassengerCam ()
Distance (100)
)
距离Distance ()指示了在距列车多远的地方能听到音效,比如外部视角下您可以在一定范围内听到机车的声音,即使在列车的另一端也是同样的。
立体声Stereo ()指出所需的.wav文件应是立体声的。Stereo ()参数必须设定,括号里面可以为空白。没有的话那么所需的文件是单声道的。如果弄反了,即.sms文件中设置为立体声而实际上为单声道文件或反之,声音文件会以错误的速度播放。当出现第一种情况时,速度降为一半,如果设置是单声道而声音文件是立体声,速度会加倍。那样的对话听起来很搞笑!
对于其他的文件头项目您可以自己实验,请把结果发给我。我说过有些项目是没有用的。您可以使用上面的例子做模板,它们在\380\Sound文件夹里。
看过了文件头,我们来到了实际音效部分。这一小节的开头是
Streams ( )
Streams ( )的意义相对简单,括号内是音频流的数目和相应的单个音频流,类似于Lights()在.Eng/.Wag文件中的作用。
音频流Stream ()
下面的内容开始变得有趣,终于接触到真正的音效了。
一个简单的音频流定义如下:
Stream(
Skip( **** Whistle sounds. **** )
Priority( 6 )
Triggers( 2
<...>
)
首先是Skip()注释描述了这个音效,本例中是380机车的汽笛。下一行指出了优先级,这个我还没有实验过,但是我猜优先级是越大越高,比如优先级为Priority(6)的音频流比Priority(5)的占上风。音效在Trigger ()小节中混合。每个音频流对应着一个音效。如果您想让若干个音效同时播放,就必须定义同样多的音频流,例如您想同时鸣笛、响铃还要听到引擎噪音的变化时。
触发器Trigger ()
Streams ()和Lights ()中是一样的,先标出触发器数目,后面定义出各个独立触发条件。触发器有2种:离散触发器和变量触发器。
离散触发器实例:
Discrete_Trigger ( 8
StartLoopRelease ( 1 File( "a380_whistle1.wav" -1 )
SelectionMethod ( SequentialSelection )
)
)
Discrete_Trigger ( 9
ReleaseLoopReleaseWithJump ()
)
离散触发器需要一个事件来解除触发状态。这些事件预先编了号,详见本文附表。下面讲述具体音效的播放方法。在上面的例子中,第一项(Discrete_Trigger 8)在开始鸣笛时执行,第二项(Discrete_Trigger 9)在结束鸣笛时执行。
简单吧?那我们来看个难的。
变量触发器Variable_Trigger与初始触发器Initial_Trigger
380cab.sms中的相关小节如下:
Triggers ( 3
Initial_Trigger (
StartLoop (
1 File ( "a380_power_cruise0.wav" -1 )
SelectionMethod ( SequentialSelection )
)
)
Variable_Trigger (
Speed_Inc_Past 2.0
ReleaseLoopRelease ()
)
Variable_Trigger (
Speed_Dec_Past 2.0
StartLoop ( 1 File ( "a380_power_cruise0.wav" -1 )
SelectionMethod ( SequentialSelection )
)
)
)
VolumeCurve (
SpeedControlled
CurvePoints ( 4
0.0, 0.25
0.4, 0.2
1.6, 0.1
2.0, 0.0
)
Granularity ( 0.01 )
)
您看下来了吗?好样的!
初始触发器Initial_Trigger很容易解释,它不需要任何相应事件触发就处于激活状态,但必须由一个事件来解除这个状态。不然这个音效就会反复循环播放。
变量触发器Variable_Trigger需要由事件触发,这就是变量的来意。变量详见下述。
我们来看这个变量Speed,即MSTS中的行车速度。在Variable_Trigger一节中有2个变量是Inc_Past和Dec_Past,Inc意为增加Increase,Dec意为减少Decrease,Past意为“达到”。
在上例中Speed_Inc_Past 2.0意为“当加速到或超过2.0时执行某动作”,Speed_Dec_Past 2.0意为“当减速到或低于2.0时执行另一动作”。
随机触发器Random_Trigger会间断地自行解除。它的应用实例是在蒸汽机车中产生司炉铲媒的音效。这个我没有深究。
里程触发器Dist_Travelled_Trigger和驶过的里程有关,单位可能是米或英尺。它用于wag.sms,某些列车停在站内时仍然发出行车的音效,或许就是它的原因。这个也没有深究。
变量Variables
速度Speed 如上述,MSTS中行车速度,单位米/秒。
距离Distance 与列车的距离,单位是米,我没有实验过。
变量1Variable1 它应该有用,可惜实际上似乎没有。它是轮子的线速度,单位米/秒,和轮子直径有关,好像也和模型中动画帧数有关。我没有弄明白。
变量2Variable2 计量了列车循环数目和/或载重。对蒸汽机车的行为影响显著,但是没有什么作用。
变量3Variable3 蒸汽机车中指“铲煤速度”,单位百磅/小时。内燃机车中可计量动力制动的程度,取值从0.0到1.0,0.0代表关闭,0.5即50%应用,1.0为100%应用。
曲线Curves
在变量触发器Variable_Triggers的例子中,可见音频流Stream()小节中的曲线Curves,它直接跟在触发器Triggers ()一项之后。曲线有2种,音量曲线VolumeCurve和频率曲线FrequencyCurve。先讲点声学课,声音由空气的振动传播,包含2个属性,频率和响度。各种不同振动合起来就成了噪音。在MSTS中我们用到2个值,频率指出了音调(例如标准A大调频率为440赫兹),响度指定了音量Volume。音量曲线和频率曲线让您能够调节这2个属性。
每条曲线可以为2个变量(X轴)控制,速度或者变量2。
下面是一个简单的音量曲线实例:
VolumeCurve (
SpeedControlled
CurvePoints ( 4
0.0, 0.25
0.4, 0.2
1.6, 0.1
2.0, 0.0
)
Granularity ( 0.01 )
)
首先,曲线中落在VolumeCurve ()或FrequencyCurve ()中括号之间的部分才会被播放,详见下述。这定义了Y轴。第二,X轴上由速度或变量2(例如)决定取值。CurvePoints ()括号内指出了曲线上几个点的位置。如例子中所示,点的定义方式和音频流Streams, 触发器Triggers, 灯光Lights中的格式一致。点本身以X,Y的格式列出,最后关闭CurvePoints括号。
下一个属性是梯度Granularity (),它指示了计算机计算X值时的步长。
不熟悉高等数学的人可能第一眼看不懂。其实很简单,如果我们要作一条曲线,首先要找到相关的值,在一个坐标系中转换为相应的点。然后我们就知道了曲线的形状并通过各点绘出这条曲线。
计算机不会绘图,但它可确定这个函数,并作出取值表。在计算机从最小到最大依次为X取值并计算相应的Y值时,梯度Granularity指出X值的步长。在上面的例子中,计算机从X=0.00, 0.01, 0.02, 0.03…, 1.96, 1.97, 1.98, 1.99, 2.00依次取值计算。
音量Volume与频率Frequency
在上一节中我们看到音量和频率可以改变,本节讲述其具体方法。
音量Volume
想来音量取值范围应为从0到1,但有人用大于1的值实验并获得成功。我以为该值的意义是相对于.wav文件的原始音量,0.5为其一半,1.0不变,2.0加倍。
频率Frequency
这点比较难懂。下面是gp38cab.sms中的频率曲线部分。
CurvePoints ( 8
0.000 12025
0.150 12025
0.450 13000
0.500 13000
0.501 12025
0.550 12025
0.850 13000
1.000 13000
)
Y值初看起来难以理解,但了解到MSTS中要求.wav文件为11025赫兹以后问题就明朗了。大于11025的值会使音调高于原始.wav文件,小于的相反。因为存在限制,取某些值时可能不能得到满意的音效,需进一步实验。
播放指令(循环looped或简单simple)
现在我们已经知道如何调节要播放的.wav了,但还缺少播放的技艺。
MSTS播放指令如下:
播放一次PlayOneShot ()
例如:
PlayOneShot ( 1 File ( "a380_reverserf.wav" -1
SelectionMethod ( SequentialSelection ) )
该指令会从头至尾播放.wav文件一次。
循环开始StartLoop ()
例如:
StartLoop ( 1 File ( "a380_power_cruise0.wav" -1 )
SelectionMethod ( SequentialSelection ) )
该指令会启动一个循环来反复播放某.wav文件。其中的.wav文件不需要剪接标记(详见下述)。
循环结束ReleaseLoopRelease ()
终止由StartLoop启动的循环。
曲目内循环开始StartLoopRelease ()
例如:
StartLoopRelease ( 1 File( "a380_whistle1.wav" -1 )
SelectionMethod ( SequentialSelection ) )
该指令可启动一个循环,反复播放某.wav文件中首个与末个剪接标记之间的部分。典型实用见于机车鸣笛和撒砂的音效。
曲目内循环结束并跳转ReleaseLoopReleaseWithJump ()
终止由StartLoopRelease启动的循环。若此指令不出现,循环将无限进行下去。
注:目前看来 ReleaseLoopRelease()和ReleaseLoopReleaseWithJump()的作用是一样的,也许在MSTS的更新(加强)版本中会严格区分。这些指令的用法参见下一节。
播放指令(文件播放)
最后来看看播放指令本身。MSTS的所有配置指令都已在/Utils/ffedit下的loadstr.hdr文件中列出(不幸的是没有解释),其中包括文件File()和文件列表FileList()。我没有见到FileList()用于任何地方,File()则用于StartLoop、StartLoopRelease或PlayOneShot等播放指令中。
这些指令的固定格式如下:
StartLoopRelease (
1
File( "a380_sandf.wav" -1 )
SelectionMethod ( SequentialSelection )
)
第一个左括号后首先是文件的数目,然后是文件的名字。-1我认为指示循环播放文件中首个与末个剪接标记之间的部分,没有-1时则循环文件开头与首个剪接标记之间的部分,为-2时会导致音效错误。也有报告说取-1以外的值都会使计算机死锁。
最后讲选择方式SelectionMethod。有两项可选:顺序选择SequentialSelection依次播放各个文件,随机选择RandomSelection每次播放其中任一个文件。显然当只有一个文件时就无所谓了。而下面的例子中:
PlayOneShot ( 3
File ( "a380_airb_auto1.wav" -1 )
File ( "a380_airb_auto2.wav" -1 )
File ( "a380_airb_auto3.wav" -1 )
SelectionMethod ( RandomSelection )
)
计算机会从3个文件中选1个播放。
编写.sms文件
我推荐您特别留意如下的指南:
与带括号的指令打交道时,一定要立即把它写完,再往括号内填东西。例如
PlayOneShot (
)
不然很容易就漏掉右边括号或找不到指令的结尾了。
要让人家易于弄明白括号的内容和指令的起止点,例如
Instruction(
SubInstruction(
DoNothingLoop ()
DoSomethingLoop(
SubSubInstruction()
)
)
AnotherSubInstruction(
AnotherSubSubInstruction()
YetAnotherSubSubInstruction()
)
)
这样子就很容易看出某个部分属于哪一条指令,一条指令在何处结束同时下一条指令开始;这对您查找错误是一个极大的帮助,因为MSTS遇到括号丢失或错误时只会打电话回家(发送错误报告——中译者注)。
注释!我跟您讲过一定要多写注释吧?
在伸缩组中,为每一条音调流排好序并写一行注释(在为机车引擎编定2条重叠的音频流时,可把注释写在一起以避免把它们隔开)。
注释每条音频流的用途。
遵循MSTS的文件命名原则:
车内(立体声)文件:型号_功能.wav
type_function.wav (如gp_sand.wav)
车外(单声道)文件:外_型号_功能.wav
x_type_function.wav (如 x_a380_whistle1.wav)
坚持命名的连续性,同一型号的文件使用一致的文件名,不要起下面的一组名字:gp_horn.wav、gp38_sander.wav、 x_diesel_horn.wav。
波形声音.WAV文件
如果您打算在MSTS中使用原创的音效,不仅要编好.SMS文件,更重要的是录音的技术。您首先需要一个好的音频编辑软件,它们价格不菲,如友立媒体工作室(Ulead Media Studio)。共享软件和试用版软件可以到http://www.tucows.com下载,MSTS中广受欢迎的还有GoldWave (http:www.goldwave.com).。
用于MSTS的.wav文件必须是下列格式的:
外部视角音效x_type_function.wav
取样率11,025Hz/16位/单声道
内部视角音效type_function.wav
取样率11,025Hz/16位/立体声
用于StartLoopRelease() / ReleaseLoopReleaseWithJump()循环的文件必须包含剪接标记(Cue-Marker)。
剪接标记Cue-Marker
当机车鸣笛时,笛声可以远长于或短于原始.wav文件,这归功于剪接标记。剪接标记由音频编辑软件生成,有自己的编号和名字,编号由00000开始,名字就叫做标记(Marker)。MSTS原版文件的标记命名格式为Marker mm:ss:hh(标记 分:秒:时),正是友立媒体工作室(Ulead Media Studio)的默认命名格式。
"为什么在一个复杂系统中使用这么简单的方式呢?"在.wav文件中使用编号00000将导致MSTS崩溃,所以当编辑.wav文件时,先在最开头编上第一个标记,完工后再删除00000号标记。
警告:再次编辑.wav文件时,如果没有编号00000的首位标记,编辑软件会自动设置首位标记的编号为00000,因此当您要进一步编辑.wav文件时,务必在文件最初加入一个标记。
编号00001的标记是循环的起点,类似于乐谱中的重复开始符号"||:"。
下一个是中位标记,取值比较随意,从1到16号的标记都可以用。与它有关的事实是,应用ReleaseLoopReleaseWithJump指令播放到中位标记后,MSTS会跳转到末位标记。这个测试我还没有完成(和/或正确结果还没有得出)。
文件尾部设置有末位标记,对应着乐谱中的重复终止符号":||"。在文件播放时,如果发生了开始事件StartEvent则跳转至标记00001处播放,如果发生了结束事件ReleaseEvent则跳转至本标记处,并播放此后的部分直到文件结束。
这里有一个技巧是把标记做在一组紧邻的相同频率之中,那么您可以随意划分标记出的各个部分,而在回放时听不到跳音。
所以一个.WAV文件中包含:
音效的起始部分,如风笛开始渐强的声音;
一个开始标记;
音效的中央部分,包括几个反复、可连接的中位标记;
一个结束标记;
音效的末尾部分,如风笛渐弱渐远的声音。
结论
您现在已经看到了.SMS文件的庐山真面目。其中有一个空白标题我也不解其意。如果您有什么新发现或要修订本文请发邮件至aranea-diademata@gmx.net。
愿这篇文章成为德国(也是国际的——英译者Y.S.注)MSTS音效事业繁荣的起点。借助本文您应该能够通读并反复领会原始的.sms文件。文中用不同颜色标出的文本有助于辨识音频流和理解文章大意。
Kuju的人士没有坚持统一文本格式(这和出色的编程有关),令人失望。但是您检查了原始的文件以后就会认识到坚持这一点有多么重要。
本文尚未完成,其实才写了几天。我把这个半成品发布出来希望起个抛砖引玉的作用,让更多的免费音效得以问世。请把您的建议或疑问发到我的邮箱aranea-diademata@gmx.net。
我会劝说Sebastian Frey开放一个音效论坛。开版之后您可以通过http://train-simulator.sebastianfrey.de访问。
致谢
本文的问世离不开下列朋友的无价援助!
atze - 感谢他的建议;
beekay - 感谢他的建议;
Blade - 感谢他对伸缩性值的建议;
knopi - 感谢他的建议和贡献;
MadMike - 感谢他的建议(特别是剪接标记方面)和贡献;
Manfred - 感谢他对取样率的建议;
Volker_Bollig - 感谢他的建议;
Train-sim.com音效设计论坛提供了很多现成的建议,特别是变量和剪接标记编号方面;
http://train-simulator.sebastianfrey.de/论坛和聊天室提供了大量技巧、乐趣与动力。
版权声明
Ralf Hagen(2002)版权所有。
对本文的修改、转换或收录入其他文章须先经本人许可。
在公开发布之前须先将发布之位置告知本人。本人拥有随时取消该许可的权利。
本文是免费的。用于商业用途(或打包提供下载)的许可费用为1500欧元起。
附件
离散触发器Discrete_Trigger
此数据不保证精确
编号 涵义
1 ~
2 ~
3 ~
4 撒沙器开Sander On
5 撒沙器关Sander Off
6 刮水器开Windscreen Wiper On
7 刮水器关Windscreen Wiper Off
8 鸣笛Horn On
9 停止鸣笛Horn Off
10 响铃Bell On
11 停止响铃Bell Off
12 风泵开Compressor On
13 风泵关Compressor Off
14 列车制动(制动音效)Train brake applied (brake sounds)
15 换向器置前进位Reverser Forwards
16 换向器置后退位Reverser Reverse
17 列车制动闸柄动作Brake Handle forwards (Train brake)
18 机车制动闸柄动作Brake Handle forwards (Loco brake)
19 ~
20 动力制动闸柄动作Dynamic Brake Handle forwards
21 列车制动缓解Release locomotive brake
22 列车制动Apply locomotive brake
23 ~
24 ~
25 忽略警报器追踪(?)Vigilance Alarm tracer (?)
26 撒沙器开关Operate Sander (toggles)
27 第一喷汽阀开Steam Ejector 2 on
28 第一喷汽阀关Steam Ejector 2 off
29 ~
30 第二喷汽阀开Steam Ejector 1 on
31 第二喷汽阀关Steam Ejector 1 off
32 ~
33 副风机开关Auxiliary blower Toggle
34 汽缸阀开关Cylinder Cocks Toggle
35 ~
36 炉门开关Firebox Door open/close toggle
37 头灯开关Light switch toggle
38 淘水Water Scoop
39 ~
40 炉门开Firebox door open
41 炉门关Firebox door close
42 ~
43 ~
44 中央暖气阀门Central heating Steam Valve
45 升弓Pantograph Up
46 降弓Pantograph Down
47 受电弓操作钮Pantograph toggle
48 电控制(?)Econtrol
49 ~
50 ~
51 机车制动操作Locomotive Brake Operate (EB Brake)
52 ~
53 列车常用制动Apply train brake, normal application
54 列车紧急制动Apply trainbrake, emergency
55 ~
56 忽略警报器生效Vigilance Alarm On
57 忽略警报器复位Vigilance Alarm Reset ("Z" key)
58 挂钩Couple
59 挂钩Couple
60 挂钩Couple
61 摘钩Uncouple
62 摘钩Uncouple
63 摘钩Uncouple
64 ~
65 ~
|
|