小节 4.8播放音乐Playing Music
Although background
music isn't found in every game you play, it can play an important role in a
game. Music can set the mood—for example, an action game could play fast-paced
music, while slower music might be better suited for a game that requires more
thought.
译:虽然并不是每个游戏都有背景音乐,但背景音乐在游戏中的作用非常重要。音乐可以调动情绪,如动作游戏可以播放快节奏的背景音乐而智力游戏更适合慢节奏的背景音乐。
Also, music can
change the player's emotions toward elements of the game. Is the music happy?
Or is it dramatic? Happy music might be better suited for the easier levels,
such as the first few levels of a game. Dramatic music could be played for the
more difficult levels, such as when the player is fighting a powerful bad guy.
译:此外,音乐还可以改变玩家对游戏元素的情感,音乐是欢快的吗?是激烈的吗?轻松欢快的音乐更适合简单的关卡,如游戏的前几个关卡。而激烈的音乐可以再高难度关卡播放,如当玩家正在和强大的坏蛋战斗时。
When you've decided
on the type of music you want, the next step is to figure out where the music
comes from. Nope, it doesn't come from those voices in your head. Instead,
games typically play music in one of three ways:
译:当你已经确定想要的音乐类型以后,下一步就要解决的是音乐的来源。不要怀疑,绝不是来自你脑袋里想到的声音。游戏通常使用以下三种音乐中的一种:
·
Streaming
music from an audio track on a CD // 来自光盘音频磁道中的音乐流;
·
Playing
compressed music such as MP3 or Ogg Vorbis
//播放MP3 或Ogg Vorbis之类的被压缩过的音乐;
·
Playing
MIDI music // 播放MIDI(迷笛)音乐。
播放CD音频 Playing CD Audio
Some CD-ROM games
have plain old Red Book Audio (the standard audio CD format) right on the CD.
The benefit here is you get great-quality sound and it's easy to implement:
Just tell the sound card to start playing the CD, without any other involvement
from the game. The other cool aspect is that players can slip the game CD into
their audio CD player and groove to the game's tracks.
译:一些 CD-ROM游戏(光盘游戏)光盘中包含了符合红皮书标准(标准CD音频格式)的旧式音频,好处是音乐的音质好,而且容易实现:只要让声卡开始播放光盘,而不必让游戏参与任何工作。另一个好处是玩家可以将游戏光盘放进音频光盘播放器中,刻录游戏的音轨。
Unfortunately, CD
audio takes up a lot of space, typically around 30MB for a three-minute song.
If you have four three-minute songs, that's 120MB of space that could be used
for more graphics or bigger levels. In addition, the Java Sound implementation
doesn't support playback from a CD, so this option is out for you.
译:但是,CD音频占用空间比较大,通常时长三分钟的歌曲要39 MB。如果游戏中需要使用四个时长三分钟的歌曲,则会占用120MB的空间,而这些被占用的空间本来可以用于更多的图形和较大的游戏关卡。另外。Java Sound实现不支持播放CD音频,因此无法选择CD音频。
播放MP3与Vorbis / Playing
MP3 and Ogg Vorbis
The second option is
compressed music. MP3 and Ogg Vorbis formats are much smaller than that for CD
audio, typically around 3MB for a three-minute song, and have near-CD quality.
They've become increasingly more popular in games.
译:第二个选项是压缩音乐。MP3和 Ogg
Vorbis格式比CD音频小的多,通常三分钟歌曲只有3MB左右,而且音质接近CD,在游戏中越来越普及。
The drawback here is
that decoding MP3 or Ogg Vorbis files takes quite a chunk of processor power.
Sound cards can't play compressed music directly, so the music is decoded while
it's played. This means the extra processor use can interfere with other parts
of your game. On faster, modern machines, the decoding won't be noticeable, but
on slower, older machines, the decoding could take 20% to 40% of the processor
or more. That could make other parts of the game, such as animation, seem slow
or jerky.
译:压缩音乐的缺点在于编码 MP3和Ogg Vorbis文件需要占用大量处理器资源。声卡不能直接播放压缩音乐,因此要边播放边解码。过多的处理器资源被占用可能会影响游戏的其他部分的运行。在现代高速计算机上,解码的影响并不明显,但在老式低速计算机上,解码占用处理器资源高达的20%到40%,甚至更多。这就有可能使游戏其他部分看起来运行缓慢或闪烁,比如动画。
If the processor
time doesn't matter to your game, you'll need to get an MP3 or Ogg Vorbis Java
decoder. Java Zoom, at www.javazoom.net, has both. This site provides a plug-in
through Java's Service Provider Interface that enables you to get an AudioInputStream that decodes an MP3 or Ogg Vorbis stream.
Just include the necessary .jar file, and be sure to convert the AudioInputStream, like so:
译:如果对你的游戏来说处理器不是问题,那么你还需要获得 MP3和Ogg Vorbis的解码器。在java Zoom网站上(网址 www.javazoom.net)你可以获得这两个解码器。该站点提供基于Java's Service Provider Interface 编写的插件,通过它可以获得解码MP3或OGG Vorbis流得到的AudioInputStream 。你只需要将必要的.Jar文件包含到你的应用中,并确保将AudioInputStream进行如下转换:
名词解释:Service Provider Interface(服务提供商接口),满足某种服务标准的供应商提供的符合该标准的应用程序接口,SPI应该和该服务的API标准是兼容的,应用程序一般应该是基于API编写,除非是SPI中包含API中没有提供的功能而又必须使用。
// create the format used for playback
// (uncompressed, 44100Hz, 16-bit, mono, signed)
//创建播放采用的格式( 未压缩,44100Hz,16位,单声道,带符号,以little-endian字节顺序存储单个样本中的数据)
AudioFormat playbackFormat =
new AudioFormat(44100, 16, 1, true, false);
// open the source file //打开源文件
AudioInputStream source =
AudioSystem.getAudioInputStream(new File("music.ogg"));
// convert to playback format //转换成变成播放格式
source = AudioSystem.getAudioInputStream(playbackFormat, source);
Also, be sure not to
load the samples into memory. A compressed sound file might take up only 1MB
for each minute of music, but the uncompressed samples would take 10MB for each
minute. Instead, play any large sounds directly from the AudioInputStream, which streams the sound from disk.
译:压缩声音文件每分钟可能只有1MB,但解压缩后的样本则可能高达10MB。因此,一定不要把样本装载到内存中。相反,我们直接通过 AudioInputStream播放从磁盘打开的大体积声音。
But which one should
your game use, MP3 or Ogg Vorbis? Although MP3 is incredibly popular, Ogg
Vorbis is license-free and claims better sound quality. The people playing your
game won't notice or care, so go with whichever one suits your needs better. You
can find more information on Ogg Vorbis at www.xiph.org/ogg/vorbis.
Also, be sure to look into MP3 licensing issues at www.mp3licensing.com.
译:那么我们在游戏中选MP3还是Ogg
Vorbis呢?尽管MP3已经越来越普及,但是Ogg
Vorbis是无需可证的,而且音质更好。由于玩家不在乎音乐的格式,所以你可以选择更符合游戏需求的。你可以在www.xiph.org/ogg/vorbis 找到关于Ogg
vorbis 的更多信息。在www.mp3licensing.com可以了解MP3许可证的信息。
播放MIDI音乐 Playing MIDI Music
Finally, there's MIDI music. MIDI music
isn't sampled music like other sound formats; instead, it works more like a
composer's sheet music, giving instructions on which note to play on each
instrument. The audio system synthesizes to each note according to the pitch,
instrument, and volume, among other parameters.
译:最后我们来了解MIDI音乐。MIDI音乐不是样本音乐那样的声音格式,而是类似与作曲家的乐谱,通过指令指示乐器播放什么音符。音频系统会根据音调,乐器,音高和其他参数平,合成每个音符。
Because MIDI files
contain instructions instead of samples, MIDI
files are very small compared to sampled sound formats and are often measured
in kilobytes rather than megabytes.
译:因为MIDI文件包含指令而不是样本,因此比采样声音格式小的多,其大小通常都是以KB单位,而不是MB。
Because the music is
synthesized, the quality might not be as high as that of sampled music. Some
instruments won't sound realistic, or the music might sound a little too
mechanical. A creative musician can usually mask the deficiencies of MIDI music, however.
译:因为MIDI音乐是人工合成的,通常它的音质不如采样音乐。一些乐器听起来不够逼真,可能听起来有点儿过于机械。然而又创造力的音乐家通常能够掩盖MIDI音乐的缺陷。
The Java Sound API
synthesizes MIDI music through the use of a
soundbank, which is a collection of instruments. Unfortunately, although the
Java SDK includes a soundbank, the Java runtime does not. If a soundbank isn't
found, the hardware MIDI port, which has
unreliable timing in Java Sound, is used. For this reason, it's recommended to
use a soundban1k.
译:Java
Sound API 通过声音乐队(sound bank 程序模拟的一组乐器)合成MIDI音乐。不幸的是虽然Java SDK中包含声音乐队,而Java运行时环境却不包含。如果找不到声音乐队,则会使用硬件MIDI端口,它的定时功能不稳定。所以,建议使用声音乐队。
The Java SDK
includes a minimal-quality soundbank, and you can download higher-quality
soundbanks from http://java.sun.com/products/java-media/sound/soundbanks.html
and include them with your game.
译:Java SDK中的声音乐队效果很差,你可以到http://java.sun.com/products/java-media/sound/soundbanks.html下载高质量的声音乐队并将其包含在你的游戏中。
The Java Sound API
provides MIDI sound capabilities in the javax.sound.midi package. To play MIDI
music, you need two objects in this package: Sequence and Sequencer. A Sequence object contains the MIDI data, and a Sequencer sends a Sequence to the MIDI synthesizer. Here's an example of playing a MIDI file:
译:Java Sound API 在java.soundbaks.midi包中提供了MIDI声音功能。要播放MIDI乐音,需要这个包中的2个对象:Sequence和Sequencer。Sequence对象包含MIDI数据。而Sequencer能将一个Sequence发送到MIDI合成器中。下面是播放MIDI音乐的例子:
// open the midi file // 打开midi文件
Sequence sequence = MidiSystem.getSequence(new File(filename));
// open the sequencer //打打开序例化器
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
// play the midi sequence //播放midi序例
sequencer.setSequence(sequence);
sequencer.start();
By default, the Sequencer plays a Sequence once and
then stops. But in a game, you usually want to loop the music. To loop a Sequence, you need to be notified when the music is done
playing and start the Sequencer again.
译:默认情况下,Sequencer播放Sequence一次,然后停止。但游戏中通常需要循环播放音乐。要循环Sequence,就要在音乐播放完毕时重新启动Sequencer。
An example of how to
loop music is in the MidiPlayer class in Listing
4.11. It implements the MetaEventListener interface, which notifies the class when
the Sequence is done playing via the end-of-track
message.
译:清单4.11的MidiPlayer类是循环播放音乐的例子。它实现MetaEventListener接口,通过轨道末尾消息通知音乐播放已经完毕了。
清单
Listing 4.11 MidiPlayer.java
package com.brackeen.javagamebook.sound;
import java.io.File;
import java.io.IOException;
import javax.sound.midi.*;
public class MidiPlayer implements MetaEventListener {
// Midi meta event //Midi事件
public static final int END_OF_TRACK_MESSAGE = 47;
private Sequencer sequencer;
private boolean loop;
private boolean paused;
/**
Creates a new MidiPlayer object.//创建一个新的MidiPlayer对象
*/
public MidiPlayer() {
try {
sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.addMetaEventListener(this);
}
catch ( MidiUnavailableException ex) {
sequencer = null;
}
}
/**
Loads a sequence from the file system. Returns null if
an error occurs. 从文件系统中载入序例,当发生错误时返回null
*/
public Sequence getSequence(String filename) {
try {
return MidiSystem.getSequence(new File(filename));
}
catch (InvalidMidiDataException ex) {
ex.printStackTrace();
return null;
}
catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
/**
Plays a sequence, optionally looping. This method returns
immediately. The sequence is not played if it is invalid.
播放sequence ,可以循环或不循环。这个方法立即返回。不可用的sequence将不会被播放
*/
public void play(Sequence sequence, boolean loop) {
if (sequencer != null && sequence != null) {
try {
sequencer.setSequence(sequence);
sequencer.start();
this.loop = loop;
}
catch (InvalidMidiDataException ex) {
ex.printStackTrace();
}
}
}
/**
This method is called by the sound system when a meta
event occurs. In this case, when the end-of-track meta
event is received, the sequence is restarted if
looping is on.
发生元事件时,这个方法将被声音系统调用。当收到轨道末尾元事件时,如果处于循环播放模式,则sequence重新启动。
*/
public void meta(MetaMessage event) {
if (event.getType() == END_OF_TRACK_MESSAGE) {
if (sequencer != null && sequencer.isOpen() && loop) {
sequencer.start();
}
}
}
/**
停止sequencer,将其复位为0
Stops the sequencer and resets its position to 0.
*/
public void stop() {
if (sequencer != null && sequencer.isOpen()) {
sequencer.stop();
sequencer.setMicrosecondPosition(0);
}
}
/**
Closes the sequencer. //关闭sequencer
*/
public void close() {
if (sequencer != null && sequencer.isOpen()) {
sequencer.close();
}
}
/**
Gets the sequencer. //获得sequencer
*/
public Sequencer getSequencer() {
return sequencer;
}
/**
Sets the paused state. Music may not immediately pause.
设置暂停状态,音乐不一定立即停止
*/
public void setPaused(boolean paused) {
if (this.paused != paused && sequencer != null) {
this.paused = paused;
if (paused) {
sequencer.stop();
}
else {
sequencer.start();
}
}
}
/**
Returns the paused state. //返回暂停状态
*/
public boolean isPaused() {
return paused;
}
}
MidiPlayer also provides methods for opening Sequences and pausing the music. To pause, MidiPlayer calls the stop() method of the Sequencer object, which stops the Sequence without resetting its position. Calling start() resumes the paused sequence. All this happens in MidiPlayer's setPaused() method.
译:MidiPlayer还提供打开Sequence
和暂停播放音乐的方法。要暂停音乐,MidiPlayer调用Sequencer对象的stop()方法,在不复位的情况下停止播放Sequence 。调用Start()方法则继续播放暂停的sequence 。这一切都在MidiPlayer的setPaused()方法中实现。
创建自适应的音乐Creating Adaptive Music
Now that you can
play MIDI music, let's discuss one of its
advantages: easy implementation of adaptive music. Adaptive
music is music that changes based on the state of the game. For instance,
if the player is battling a large number of enemies, the music might be fast
and loud. Conversely, the music might be quiet when the player is walking
around exploring rooms alone.
译:现在你能够播放MIDI音乐了,接着让我们来讨论一下MIDI音乐的一个优点:很容易实现自适应的音乐。自适应音乐是根据游戏状态自动改变的音乐。如玩家正在与大量的敌人战斗,则音乐可能快速而激烈,相反,当玩家单独在房屋中搜索时,音乐声会非常小。
The change in music
could happen at any time—for example, the player could be strolling along one
second, and then 100 robots could be trying to kill him the next. So, changing
the music smoothly can be a challenge.
译:音乐的改变可能随时发生,例如玩家前一秒可能还没有遇到一个敌人,后一秒突然有100个机器人要杀他。因此,想要平滑地改变音乐是一个很大的挑战。
You can adapt songs
to the game state in two ways:
译:可以用2种方法在游戏状态中适配音乐:
·
Change
songs 改变歌曲;
·
Modify
the song currently playing 修改当前播放的歌曲。
Because the actions
of a player can change at any time, changing songs is a more difficult task.
The change can't be abrupt, or it will be distracting. Songs can be designed so
that they have "change points" to signify places where a song change
can occur.
译:由于玩家的动作可能随时改变,因此实时改变歌曲是一个非常困难的任务。音乐的改变不能太突然,否则会分散注意力。歌曲可以被设计包含一些 “变化点”,以指示一首歌曲在哪里可以发生改变。
Also, songs need to
transition smoothly. To do this, the first song can fade out while the next
song is fading in. Also, while the first song is fading out, its tempo could
change to match the tempo of the next song.
译:歌曲需要平滑地过度。为此,当切换音乐时可以让前一首歌逐渐退出,后一首歌逐渐进入。另外,在前一首歌逐渐退出时,其速度可以渐变成后一首歌的速度。
Or, you could just
take the easy way out and insert a sound of a scratching phonograph needle。
译:或者,你可以简单地取出和插入一个声音的一个刻痕留声机针。(这句翻不成,在网上翻译的,高手帮着看看)
The second option is
to simply modify the exiting song. You can do this by changing the tempo or
volume, or adding another instrument to it.
译:第二个选择是简单地修正在退出的歌曲。你可以改变歌曲的速度或音量,或添加另一个乐器到歌曲中。
Adding or taking
away an instrument is easy to do with MIDI
sequences. MIDI music is typically organized
into tracks, with each track playing a specific instrument. For instance, there
might be one track for guitar, one for keyboards, and so on.
译:MIDI sequence很容易添加和移除乐器。MIDI音乐通常由多音轨组成,每一个音轨演奏特定的乐器。例如,可以有一个吉他音轨,一个键盘音轨等。
You can mute or
unmute a track with one method:
译:可以调用一个方法开启或关闭某个音轨的声音:
sequencer.setTrackMute(trackNum, true);
Here, trackNum is an integer representing the track number you want
to mute. If you don't know what track belongs to what instrument in your MIDI file, you might have to experiment by muting each
track, one by one.
译:其中参数trackNum是整型,表示要静音的音轨号。如果不知道MIDI文件中那个音轨属与那个乐器,你可以将所有音轨一个一个地静音,来通过实验辨别。
Listing 4.12 MidiTest.java
import java.io.File;
import java.io.IOException;
import javax.sound.midi.*;
import com.brackeen.javagamebook.sound.MidiPlayer;
/**
An example that plays a Midi sequence. First, the sequence
is played once with track 1 turned off. Then the sequence is
played once with track 1 turned on. Track 1 is the drum track
in the example midi file.
一个播放 MIDI sequence 的例子。首先,sequence 在音轨1被关闭的情况下被播放了一次。然后,sequence 在音轨1被打开的情况下被播放了一次。音轨1是样例文件的鼓乐音轨。
*/
public class MidiTest implements MetaEventListener {
// The drum track in the example Midi file 鼓乐音轨
private static final int DRUM_TRACK = 1;
public static void main(String[] args) {
new MidiTest().run();
}
private MidiPlayer player;
public void run() {
player = new MidiPlayer();
// load a sequence 加载 sequence
Sequence sequence =
player.getSequence("../sounds/music.midi");
// play the sequence 播放 sequence
player.play(sequence, true);
// turn off the drums 关闭 鼓
System.out.println("Playing (without drums)...");
Sequencer sequencer = player.getSequencer();
sequencer.setTrackMute(DRUM_TRACK, true);
sequencer.addMetaEventListener(this);
}
/**
This method is called by the sound system when a meta
event occurs. In this case, when the end-of-track meta
event is received, the drum track is turned on.
当一个元事件发生时声音系统会调用该方法。当收到音轨末尾元事件,鼓乐音轨被打开。
*/
public void meta(MetaMessage event) {
if (event.getType() == MidiPlayer.END_OF_TRACK_MESSAGE) {
Sequencer sequencer = player.getSequencer();
if (sequencer.getTrackMute(DRUM_TRACK)) {
// turn on the drum track 打开鼓乐音轨
System.out.println("Turning on drums...");
sequencer.setTrackMute(DRUM_TRACK, false);
}
else {
// close the sequencer and exit 关闭 sequencer 并退出虚拟机
System.out.println("Exiting...");
player.close();
System.exit(0);
}
}
}
}
Just like when you
play sampled sound, you must explicitly exit the VM when you're done. MidiTest exits the VM when it receives the second end-of-track
message.
译:就像你播放样本音乐一样,你必须在播放完毕时明确地退出虚拟机。MidiTest 在收到第二个音轨末尾消息时退出虚拟机。
总结Summary
In this chapter, you
learned the basics of sound, sound filters, and music. You made real-time echo
and psuedo-3D filters, and you created a cool sound manager to handle game
sound effects. You also made some adaptive music and learned how to play back
MP3 and Ogg Vorbis sound files. Combining this knowledge with graphics and
interactivity from the previous chapters, you're ready to create your own game.
译:在本章中,你学习了声音基础、声音过滤器和播放音乐的相关知识,创建了实时回响过滤器和伪-3D过滤器,还创建了一个很酷的声音管理器用于处理游戏声效。你也创建了一些自适应音乐并学习了如何播放MP3 和 Ogg
Vorbis 音频文件。将这些知识结合前面章节学习的图形和交互性知识,你已经做好准备,可以开始创建自己的游戏了。
学软件开发,到蜂鸟科技!
超强的师资力量 、完善的课程体系 、超低的培训价格 、真实的企业项目。
网址:www.ntcsoft.com
电话:0371-63839606
郑州软件开发兴趣小组群:38236716
posted on 2010-11-27 01:37
whistler 阅读(909)
评论(0) 编辑 收藏