DirectMusic imposes several rules and limitations that you should keep in mind. We cover the more significant ones here and discuss more specific restrictions as they arise.
A DirectMusic Performance is somewhat analogous to a conductor and an orchestra; the conductor is only able to conduct at a single speed at any time (unless he is conducting some avant-garde piece of contemporary music!), and the orchestra as a whole needs to understand where those beats are. All pieces of music playing on a Performance must play at the same tempo — and a tempo change imposed by one piece of music will affect all other playing pieces of music. This becomes most interesting when using DirectMusic for playing sound effects and ambient sound in addition to music, as these sounds care nothing for tempo. SFX and ambience may inadvertently cut off because of musical tempo changes. There are several options that you may consider:
Author all content at the same tempo. This of course defeats the ability to change speeds based on various events.
Use clock-time Segments for sound effects. Every Segment file can specify whether it is meant to use music-time or clock-time.A music-time Segment bases its timing information on the tempo of the music. Notes will play for a specific number of measures, beats, ticks, etc. If the tempo changes, the note will be played for less or more time — desirable for music but not so much for other sounds. A clock-time Segment, by contrast, only pays attention to the system clock and absolute time. Generally used for Segments that only contain non-note-based wave information, a clock-time Segment uses millisecond accuracy for playback. A wave told to play for 5.12 seconds will play for exactly that amount of time, regardless of tempo changes that occur while it is playing.
Use multiple DirectMusic Performances. You can always run more than one DirectMusic Performance simultaneously. The amount of processing power used (i.e., the CPU overhead) for a second DirectMusic Performance is small, though of course there are now additional assets to manage and track. Consider playing sound effects, ambience, and other audio cues that do not respond to tempo on one performance (with constant tempo), while music-oriented sounds will be played on another performance (with variable tempo).
The next restriction to keep in mind is the differences between primary and secondary Segments. A Segment can be either primary or secondary. Only one primary Segment may play at a time; starting a new primary Segment will implicitly stop and replace any previously playing primary Segment. Primary Segments typically dictate tempo, groove level, chord progression, and other big picture (aka "global") performance-level events. By contrast, many secondary Segments may be playing at the same time. Secondary Segments typically layer on top of the primary Segment, picking up and using the primary Segment's tempo and other settings. However, if a secondary Segment plays as a controlling secondary Segment, rather than layer on top of the primary Segment, it will actually replace corresponding Tracks from the primary Segment. Controlling secondary Segments are typically reserved for more advanced usage (for instance, changing the chord progression of the primary Segment, say, when an antagonist enters the same room as the hero in the game).
Primary Segments are generally the main background music or ambience. Secondary Segments are often "one-shot" sounds or "stingers" that play over the primary — perhaps sound effects or musical motifs. Secondary Segments follow the primary's chord progression, so musically motivated secondary Segments can play with appropriate transposition and voicing.
Programmers and audio producers should note that crossfades are not a built-in DirectMusic function for transitioning between Segments. For now, it is a fact, and so you are going to have to fudge them. It's not all bad, as you do have options. These options include AudioPath volume manipulation, MIDI volume controller use, or authoring volume crossfades directly into content. Remember that only one primary Segment can play at a time, which precludes the possibility of using primary Segments exclusively for crossfades. Unless multiple DirectMusic Performances are used, at least one of the Segments we are crossfading between will need to be a secondary Segment. For ease of use, we suggest that both be secondary Segments. The one-tempo limitation we discussed above makes crossfades between two pieces of music with different tempos difficult. One of the pieces will be played faster or slower (unless multiple DirectMusic Performances are used). Of course, this limitation really only applies for sequenced music; prerendered wave files using different tempos play fine.
"Pause" is another feature not implicitly built into DirectMusic. However, a programmer can track the time when a Segment starts, as well as its offset when he stops that Segment. Using this information (and keeping in mind that the Segment may have been looped), the programmer can typically restart a Segment from the same location to create "resume" behavior. However, this only works for Segments that use music time. Note that content that includes numerous tempo changes may be less accurate in restart position than content with a single tempo.
While this works for waves, MIDI and DLS limitations do not allow this for sequenced note data. The MIDI standard for note information consists of a "note on" and corresponding "note off" event. Starting playback between the two events will not trigger the note. Even if it did, remember that DLS Instruments cannot be started from an offset; they can only be played from the beginning. This won't really be an issue for short notes in a dense musical passage. However, if you have long sustained notes (for instance, a string pad), keep this in mind if you want to be able to pause/resume your music. In that particular case, you might want pause/resume functionality to restart the piece of music at a position before the pad began or even the beginning of the Segment.
Memory is typically the most precious resource for games, whether on the PC or a console. The amount of memory taken up by the resources of a program or a particular component of a program is called the footprint. Making use of streaming wave data can help keep the memory footprint small; only a small amount of any playing wave is actually in memory at a time. DirectMusic supports wave streaming within Wave Tracks, with content-specified read-ahead settings that determine how much of the wave is in memory. However, the DLS format does not support streaming, so any DLS Collection instruments play entirely from memory. There are several optimizations available that we will discuss in Chapter 2 when we cover Bands (a DirectMusic file that stores DLS Instruments), but keep in mind that DLS Instruments will occupy a footprint as long as they are downloaded.
Again, this isn't a big deal if you are creating music for stand-alone listening. You'll have the free range of the system memory to work with for samples (normally 128MB of memory — more memory than any pro hardware synthesizer on the 2003 market) on top of all the streaming that the audience's PC can handle. But in games, you are very limited in the amount of memory you can use. Just keep that in mind.
|Note for programmers:|| |
Just using DirectMusic incurs a memory footprint, albeit a small one. The size does depend on which DirectMusic functions you choose to use in your application. For instance, if you use DirectX Audio Scripting with the Visual Basic Scripting Edition language (VBScript), that language requires several libraries of code to be loaded to the tune of almost 1MB of DLLs (dynamically linked libraries). Granted, other aspects of your program might depend on the same libraries, but to help keep the memory footprint more manageable, DirectMusic offers a tiny (~76KB) optimized DirectX Audio Scripting language (called audiovbscript) as an alternative to the fully featured VBScript.