DirectMusic Producer supports any ActiveX scripting language for creating scripts, but the two most commonly used languages are Visual Basic Scripting Edition and AudioVBScript. AudioVBScript is a DirectMusic-optimized language, specially geared toward music content playback and occupying a very small memory footprint. Alternatively, a composer could use the full Visual Basic Scripting Edition language ("VBScript" for short). While this language occupies more memory and potentially could take more processing power, it is a fully featured language, providing added flexibility and additional features, such as string concatenation (the ability to merge several pieces of text for display or script usage). Generally, start with AudioVBScript and move up to VBScript if you find that you need additional power. All scripts written in AudioVBScript will work in VBScript, but the opposite is not necessarily true. Of course, don't forget that the programmer can also step in for more complex scripting usage to perform some operations in lower-level DirectMusic code.
The language that a specific script uses can be selected from that script's properties page.
Figure 7-5: The Script Properties window.
A full list of differences between the two languages can be found in the DirectMusic Producer help documentation under the topic AudioVBScript Limitations.
Basic Scripting Usage
Let's create our first scripting routine. Click in the Source frame of the Script Designer window. A cursor appears, and we can type away. Routines follow this format:
Sub [name of routine] [things to do when this routine is triggered] End Sub
For instance, we're going to create a routine that introduces a new character.
Sub IntroduceCharacter End Sub
If you click anywhere else in the Script Designer window (or in the project tree), notice that IntroduceCharacter pops up in the Routines frame at the top right of the window.
Figure 7-6: IntroduceCharacter in the Routines window.
You could double-click on this routine to trigger it (though of course, it doesn't do anything yet). By the way, if our routines ever disappear from that Routines list, it means that our script has some kind of typographical error in it. We talk about that more when we get to debugging in a bit.
Playing a Piece of Audio
Okay, now let's make our routine do something. The simplest function is probably to play a wave or a DirectMusic Segment. Let's play our Hello wave.
Sub IntroduceCharacter Hello.play End Sub
The period (.) is how DirectX Audio Scripting separates the object that we're using (in this case, a wave) from the function that we want to call on it (in this case, playing it). Remember, the script only knows about objects that were dragged into its embed or reference folders; if we tried to play a Segment or wave that wasn't in those folders, we would get a syntax error. The above routine will play Hello using all default properties; it will play as a primary Segment, and it will play at the default authored boundary (most typically, immediately, but this could be set in the Boundary tab of the Segment's properties page). Again, we could try this routine out by double-clicking on it over in the Routines frame. Now it makes noise!
Making scripts as readable as possible by placing comments helps when you might later need to return to the script to make edits. Any line of a script that begins with an apostrophe (') is effectively ignored when that script is played back and typically used for, among other things, describing what the routine does.
Sub IntroduceCharacter 'We trigger this routine whenever our character meets 'other characters. Hello.play End Sub
Let's make this routine do something a bit more complex; a routine that only does a single thing doesn't really save us much over having the programmer implement it. We've got these other two waves that we wanted to string together into a more complete introduction, so let's add them to the script. We wouldn't want to just sequentially call Hello.Play, MyNameIs.Play, and Bob.Play — that would fire off all three waves at the same time. Worse yet, they would each be played as the primary Segment, which means they would cut each other off. Instead, we want to use one of the transition boundaries that DirectMusic provides, the ability to queue Segments to play one after the other.
Sub IntroduceCharacter 'We trigger this routine whenever our character meets 'other characters. Hello.play MyNameIs.play (AtFinish) Bob.play (AtFinish) End Sub
Our code now introduces one of the several parameters available when you tell a Segment to play. Parameters can be optionally enclosed in parentheses, which often helps for readability. They are required to be in parentheses when they're on the right side of an equation, as we see a bit later on, so it's often easiest to simply always use parentheses.
The first parameter that can be used to modify our play call consists of flags that we can use. The AtFinish flag says that this Segment should wait to play until the previous primary Segment has finished playing. So our routine is now firing off "Hello" and queuing up "my name is" and "Bob" to play afterward.
Be aware that this kind of dialog "stitching" (piecing together dialog fragments to reassemble whole sentences) involves many challenges beyond implementing queued playback in an application. Writing dialog, coaching, and recording voice talent to get appropriate and believable inflections present significant challenges that are beyond the scope of this book. These difficulties are shared by many applications — sports titles that use stitching for their commentators in particular.
You can see the list of parameters for playing a Segment by looking in the DirectMusic Scripting Reference guide, under the topic Segment.Play. When the Script Designer window is open, a shortcut to the guide can be found in the Help menu and is also available via the Ctrl+F2 shortcut. Parameters are separated by commas, though if you don't use all of the parameters, their default settings will be used. Therefore, for these early examples, we will just stick with the first parameter.
For the flags parameter of Segment.Play, multiple flags can be combined simply by "adding" them (using the + sign between them). For instance, we can create a new routine that starts our room ambience when we enter the room. If any music is playing, we want the ambience to sneak in at a measure boundary. We play it as a secondary Segment so that the background score continues to play. (Recall that only one primary Segment can be playing at a time.)
Sub EnterRoom RoomAmbience.Play (IsSecondary + AtMeasure) End Sub
Granted, our dialog example has the same issue; we probably don't want our dialog to become the sole primary Segment. Since it becomes a bit more complex to solve this problem for dialog stitching, we come back to that in a moment.