posts - 0,  comments - 6,  trackbacks - 0

小节 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音频。

播放MP3Vorbis   /  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.

译:压缩音乐的缺点在于编码  MP3Ogg 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:

译:如果对你的游戏来说处理器不是问题,那么你还需要获得 MP3Ogg Vorbis的解码器java Zoom站上(网址 www.javazoom.net)你可以获得这两个解码器。该站点提供基于Java's Service Provider Interface 编写的插件,通过它可以获得解码MP3OGG 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个对象:SequenceSequencerSequence对象包含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.11MidiPlayer类是循环播放音乐的例子。它实现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 。这一切都在MidiPlayersetPaused()方法中实现。

创建自适应的音乐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 阅读(716) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航:
 
<2018年11月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

留言簿(2)

我参与的团队

文章档案(22)

搜索

  •  

最新评论