Graphics and Media • 56:28
Looking to create thrilling multi-channel 3D audio experiences in your application? Check out OpenAL, a multi-platform audio API that is perfect for games and advanced media applications. Leveraging the power of Core Audio, Tiger's built-in OpenAL implementation provides high-quality, low-overhead environmental audio that is compatible with a wide-range of audio devices. Learn how easy it is to integrate OpenAL into your application and take your audio to the next dimension.
Speaker: Elliot Sedegah
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. Welcome to 3D Environmental Audio with OpenAL. My name is Elliot Sedegah, and I'm going to give you a brief overview to OpenAL. And hopefully by the end of this session, you have a great understanding of how OpenAL works and how you can begin integrating it into your application so you can get great surround sound for your 3D environment.
So, what is OpenAL? OpenAL is a cross-platform 2D and 3D audio API. The API is originally designed for games but can be used in many other applications as well. It's a great companion to OpenGL, so if you have existing OpenGL code out there, it's a great API choice that you can take and integrate into your code, and then you're off and running with great surround sound for your 3D environment.
It's also open source, so you can go to the OpenAL website, download the latest sources, and take a look and see how it's supported for all the existing platforms that it's out there for. And another little bit of good news is it's now shipping as a pre-installed framework for Tiger, so it's going to be there for all your users using 10.4. And if you're looking for support earlier than that, it goes as far back as 10.28, so that's pretty good news.
Let's talk about some of the main features of OpenAL. With OpenAL, you get stereo and surround sound. This is great for your 3D environment, so you're not limited to just a stereo with the right and left channels. You get surround sound using all your speakers up to 5.0. And you get positional audio, so you can localize sound in three-dimensional space.
For example, if you had an object on the right side of your screen and you wanted your user to experience sound coming from the right speaker, you can easily do that by supplying coordinates to OpenAL. And if you can move this object around from right to left, and then you get a panning-like effect moving from the right speaker to the left speaker.
And you can move it back and forth in a distance, and depending on the distance it is from a listener, the sound will be attenuated. So it will be sounding a little bit softer or louder depending on the distance. You can change the pitch, too, and you can do all this while it's playing without much work at all.
OpenAL uses the same exact coordinates as OpenGL. So OpenGL uses a 3D Cartesian coordinate system using the X, Y, and Z planes. So if you look at the chart on your screen here, you can see a point in three-dimensional space at 0.5, 5, and 0. If you wanted to specify this point using OpenGL code, many of you might be already familiar with OpenGL, and you would use a GL vertex command with the floats 5, 5, and 0.
In OpenAL, if you wanted to attach a sound source to this object in three-dimensional space, this could be an explosion, this could be a plane flying overhead, it could be a car driving by, whatever you want it to be in your game, you can use the AL source command and use the same exact coordinates that you're using in OpenGL space, so you can see how your variables can be reused and you can add sound and integrate it into your game or your application.
Another interesting thing to point out here is that OpenAL also uses the same API conventions as OpenGL. So you can see the three F here in GL space. Most of you guys are familiar with it, knowing that this is supposed to specify you needed to add three floats to this method. The same exact thing is done in OpenAL, and this convention is followed throughout. So it'll be easy for you GL programmers to pick up on this, and you'll be up and running in no time.
OpenAL is built with Core Audio for Mac OS X. So it's built entirely with Core Audio. Core Audio is used to interface to all of the user's audio devices, so FireWire, USB, stereo or surround sound, everything that the user can support, OpenAL is going to get that. And it's combined with the power of audio units, the 3D mixer audio unit, which is used to localize your sound in three-dimensional space. So you can have your objects just mixed, and you don't have to worry about all the hard work there.
The OpenAL implementation is going to do that for you, because the 3D mixer handles the localization and it handles speaker configurations, sample rate conversions, a lot of the really difficult work that it takes to get a good sound engine up and running. And it's packaged inside a nice, easy-to-use API, so you can just use that code and you're up and running.
It's also cross-platform. So the code that you write for us, you can use it other places as well. Mac OS X's implementation is done in Core Audio, and that same code can be used in other platforms that you care about, such as Windows and Linux, other game platforms as Sony PS2, GameCube, Xbox, just to name a few. There's a large listing of platforms that are supported, and if you're interested in what their underlying implementation is, you can go to the OpenAL website, and it has details on the website, So you can make that in your decisions when you're making your game.
Here's a list of a few games that we have that are running OpenAL. I mean, there's a longer list than this, but we just took out a few just to illustrate a point. And as you can see, these are major titles. Really big. The list has been growing over the past year. You can see on here that a lot of these are also cross-platform. And OpenAL is a big reason for this.
Because of the cross-platform code nature, you really had to make maybe a few changes just to get it running on several different platforms. And if you look on here, you can see Blender 3D. And that's not a game. And you can see that this is not limited just to games. So if you have an application that's 3D and you want 3D sound, OpenAL is a great choice.
Game engines and libraries are also hopping into the action, too. Many popular ones that I'm sure many of you could be using, Agent AE, Torque, and Unreal, they're all adopting to use OpenAL now, mainly because of their cross-platform nature, some reasons because of the performance, many different reasons why you should use OpenAL. Now that you know how OpenAL works, just the overall 30,000 feet view of, hey, this is what it does, I'd like to invite Ryan Gordon, freelance software developer on the stage, give you a brief story about how his experience is using OpenAL.
Can you hear me? Okay, good. Hi, my name is Ryan Gordon. I'm a freelance game developer. Mostly I specialize in porting games from Windows to Mac OS and Linux and things like that. So what we're going to show you on the screen back here is a game called Feeding Frenzy.
The OpenAL is a game piloted by the talented Rich Hernandez, who is a feeding frenzy ninja. Basically, this game is very simple. What I want to talk to you about is mostly we talk in OpenAL in terms of positional audio, 3D space, and...
[Transcript missing]
So, what we're looking at here with Feeding Frenzy, it's very simple. You've probably already picked up the rules of this game.
You move a fish around the screen, you eat smaller fish, you avoid the bigger fish, and as you get bigger, you eat the bigger fish too. It's a little bit of Darwinism in your video game. But it's simple, it's non-intrusive, it's non-threatening. You could give this to your grandmother and she would love it. And by the way, it's on sale now at gamehouse.com. So, this was originally a Windows title.
When we first started working with this, it was Windows that used DirectX. Specifically for audio, it used 2D direct sound, not even direct sound 3D. And looking at options to move this to the Mac, we thought about Core Audio, we thought about SDL, we thought about SDL Mixer, you know, higher-level things. And we found that OpenAL was actually the best choice for a number of reasons.
When you look at the original game, as you are now, when you look at this, it only wanted to do things at the source code level at a high level, in higher-level stuff. For example, they wanted to do, you know, play this sound, just fire this sound off and forget about it. We want to stream music, but we don't really want to do anything but play it in the background, nothing fancy like that.
At most, in terms of positional audio, it wants to pan things left and right on stereo speakers, but it doesn't really want to think about it beyond that. In that sense, OpenAL worked incredibly well. Because that maps very closely to the API. Instead of talking about a 3D thing, you just talk about things on one plane.
But otherwise, you use the API exactly as you would in a 3D sense. So when we started working on this, we moved it from direct sound to OpenAL. And instead of trying to re-engineer stuff, anyone who's ever reported a video game, reported any software, knows you don't want to touch the original source any more than you have to.
Okay, maybe you haven't done that. So we started working on this. Instead of trying to re-engineer things, say, how can we make this work best with an alien audio API and such, we moved it over. We just copied the file one, you know, just directly copied the C file that implemented all the direct sound stuff and just went through it line by line, cutting out the direct sound stuff, leaving the higher level structure there and just replacing it line for line with OpenAL. So we did a word count, a line count on this the other day to see just where this turned out, you know, now that everything's done and debugged.
Changing it from direct sound to OpenAL took about a day, and that's to write it and debug it and play it and be done with it. That worked out incredibly nicely because no one wants to spend time working. I don't, I don't know. So after that was done and after spending a day on it, I looked at the line counts, and the direct sound code... Went from about 3,500 lines of C code, just straight, no-nonsense C++ code, 3,500 lines. When we were done with the OpenAL version, it was about 1,000 lines. So literally, it was three and a half times less code to deal with, which is wonderful in terms of debugging and maintenance and such like that.
So, some of the other basic benefits here, just to run down this very quickly, and you're going to hear some of these things again and again throughout this session, but it was cross-platform. The exact same OpenAL code, when we were done replacing the direct sound code, ran on Windows, Linux, and Mac OS. Out of the box, there was exactly zero if-defs in the code. There's none at all. Just the exact same code worked everywhere. Now, to be fair, there are zero if-defs in the direct sound code as well, but that's only going to run on Windows for obvious reasons.
So, that worked out incredibly well. In terms of maintenance, there's less to look at, less to figure out. There's no corner cases in it where you think, you know, geez, did I set up this primary direct sound buffer to be in cooperative mode? And what happens if they change users on me? Will it stop playing music and such like that? And those things became a non-issue.
We never had to look at this in terms of a byte-wise buffer. We never had to think, okay, we have 10 bytes left in this buffer, then we have to wrap around the beginning and start writing stuff there. You know, with OpenAL, you just say, "Hey, I have this much more data.
Please play it when you get a chance." With the buffer queuing mechanism, and it works great. Another benefit, and this is true in the direct sound version too, is that the Windows version is stereo only. And, you know, like I said, we're not using positional audio, but it's always nice to know that on a Mac, when you're using OpenAL, if you have eight speakers hooked up to your machine, if you have a five-speaker setup or whatever, if you have more than two speakers, it's just going to work right. I don't have to be like, "Well, all but your first two speakers are going to be quiet. Sorry, there's nothing we can do about it." That was a huge benefit for that.
Um, That's pretty much it. Otherwise, it was just in terms of man-hours and maintenance and code size and readability and usability, all of those things. OpenAL was just incredibly better for us than DirectSound. And to be fair, if you look at most APIs out there, you're going to find that if you'd moved it to any other API such as SDL, you're going to find a lot of these same benefits that OpenAL gave you. You find that you'd have these same fights. I don't want to blame DirectSound specifically, although I know it's easy to do at a Macintosh conference.
But in those senses, it worked out very well for us. I would definitely use it. This is the first 2D game I'd used OpenAL on. I didn't expect it to be this easy. I thought it worked out really well. Mostly before now, my OpenAL usage was on 3D games for obvious reasons. But even on a 2D game, it worked out great. So don't be intimidated to use this API, even if you don't have a big, grand-scale, multi-million-dollar, 3D, immersive, complicated game.
Even for independent developers or small-scale developers or puzzle game developers, it works out wonderfully. I'd highly recommend it to anyone. So that's what I have to say. Thank you, Rich, for helping us out here. I'm going to give the microphone over to Bob now, who's a core audio engineer, and he's going to talk some more about the specifics of OpenAL. Thank you. Yeah, that was great. Thanks. Good afternoon. My name is Bob Aaron, and I work at Apple as a Core Audio engineer. And I'm gonna talk a little bit about how to use OpenAL. So if we can get back to the slides, please.
Okay, so the main thing I want you to take away from my part of the session really is an understanding of what the OpenAL architecture looks like and how the APIs are used. And secondly, as Ryan and Elliot have already alluded to, to see what the benefit really is for you to use OpenAL in your application. By letting OpenAL do all the difficult audio work, such as optimized audio processing and dealing with the devices on your user system and multi-speaker configurations.
So if we take just a top-level view of what the architecture looks like, we can see that OpenAL basically is divided up into five components. And the first thing you'll want to do when you're adding OpenAL into your application is you have to do a little bit of initializing. And so the first component we'll talk about is the OpenAL device. Now the OpenAL device is the component that basically is going to deliver your rendered audio data out to some hardware.
And on Mac OS X, this device is the default output device that your user sets up in their system preferences or in the audio MIDI setup. And what's really nice about this mechanism is, again, your application doesn't have to know anything about the hardware on your system or the speakers or anything. It's just going to work and render out to what your user has already selected.
Now the next component you'll need to do-- to look at when you are doing some initializing is the OpenAL Context. Now this is your rendering context. It's basically your virtual space, or your environment for your game or your application. Now it contains some objects that are moving around in space, making sound. An object that moves also around in space that it can observe all those sound making objects. And it defines some parameters on how all of those things are rendered. And then ultimately delivers the rendered audio out to the OpenAL device.
So these are what the APIs look like, basically, for opening and closing devices and creating and destroying context. But instead of walking through the APIs parameter at a time, let me just show you a little bit of code. So I'm going to run a small demo in a little bit, and I'll show you all the OpenAL code that's needed to run this. And so we'll start out here. The first line there that the arrow's pointing to is a call to ALC OpenDevice.
Now, you notice that it's passing null. The reason we're doing that on Mac OS X is null, this is the device name string, but since we're always using the default output device, we can just pass null. That sort of indicates to use the system device or the default device for the user.
Now, once we actually have that device back, we need to pass it to a create context call. And the context call, you can have multiple contexts, and they always render to that device, so you have to pass the device in. Now, you notice that there's a second parameter, zero. That's actually an attribute list. On Mac OS X, you don't have to pass any attributes. You can just pass zero there.
And then lastly, as I mentioned, you can have multiple contexts or multiple spatial environments, but you have to have one that's designated as the current context. That's the context that will receive changes. You have to have it defined already so that as you make changes to parameters, the API knows which context you're talking about.
Okay, so now that we have our device and our context, the next object we'll talk about is the OpenAO listener. Now, the listener is implicit to your context. Each context has a single listener, and it can be moved around in space, just like the objects that are making sound. And it's really the object that represents how your user is going to experience your application when they're running it, and so for you GL programmers, it would equate, basically, to a camera. It's, again, the way that your user is going to experience this.
So one of the most important attributes you'll be setting for your OpenAL listener is the orientation. Now again, in GL terms, your orientation is like making a call to GL you look at. It defines which way your listener is looking in your virtual space. And so it's defined as two vectors, an at vector and an up vector.
And those are XYZ vectors, and they must be orthogonal to each other. That's defined in the specification. And if you look at the little code box at the bottom, again, you're going to see some conventions that are similar to GL. We have an AL listener FV, F for float, V for vector. And we're going to pass in those at and up XYZ vectors.
Now to demonstrate sort of how the orientation works, let me just show you a diagram. So on the left-hand side there, we have a virtual space, and it contains some objects. And in the center is our listener. And then the circles, the blue and the red circles, are some graphical objects that you may have in your application. And then the text there for car horn and dog barking sort of represents some objects that may be making sound in your environment.
This is a top-down view on the X and Z coordinates. If we look on the right-hand side of the screen, this would represent the user sitting in front of their monitor. They can experience that blue object, they can see it in their monitor, but they can localize the car horn and the dog barking appropriately in front and to the rear right.
I just wanted to point out one more thing. This is the default orientation for your listener when your context is created. It's looking down the negative Z axis. So if we wanted your listener to experience, be able to experience the other graphical objects, we can now turn around your, the sign on your Z axis, and now he's looking this way.
And so now if we see what the user is looking at in front of this machine, you can now see that red circle. But you notice that the audio objects now are being localized in a different place. The dog barking is now to their front left, and the car horn is to their right.
And the reason I wanted to show this is there's one sort of main difference, I think, between graphical objects and audio objects. And that's that graphical objects you're only experiencing while you're viewing them with your camera or however you're representing those to the screen. But the audio objects can be rendered and experienced all the time. So it's really important that they're localized correctly in your user's speaker configuration.
OpenAL is a great way to create a multi-channel audio experience for your application. OpenAL is a great way to create a multi-channel audio experience for your application. And there are several attributes to change on the listener so that they can all be rendered, you know, appropriately for what they are. And I'll walk through a few of those as we go along here.
So here are the APIs for generating and deleting a source. Now you'll notice that both of them-- except the first parameter is a size parameter. That's to indicate how many sources do you want to create, how many sources do you want to delete. And the second parameter for both of those APIs are integer arrays, appropriately the same size as whatever you've passed into the size parameter. And when you're creating sources, basically upon the call returning, that array will be filled out with some integer names representing the source names that you'll be using to reference as you want to change attributes for those sources.
And then the second, the delete sources call, you'll see you pass in an array, and you fill that in with the sources that you want to delete, telling the library, OK, I don't need these anymore. So in that case, we filled it in with 100 and 102, tell the library we don't need these anymore, and the library will delete them.
So an important attribute for both sources and listener is the AL position attribute. This is the way that you move your objects around in your virtual space, and they can be applied both to listener and source, as I said. And they're defined in world coordinates, x, y, z coordinates, where 0, 0, 0 is your center.
And they're just like OpenGL, they use a right-handed Cartesian coordinate system. So if you do that trick with your right hand and you pass, you point your thumb to your right and your index finger straight up and your middle finger toward you, that'll tell you the positive directions on the x, y, z axes, if you want to know that little trick.
So one of the things that you'll want to do, possibly, since you can now position your objects around in space, is have them behave as they would in a physical world. In other words, they should attenuate as the distance changes from your listener. And so there's two parts to doing that in OpenAL. First, we set a distance model on the context.
And what that means is we're going to set a model that will be applied to all the sources that are moving around and rendering audio in your context. I'll talk about the inverse distance and distance clamped models in just a second on some subsequent slides. But just to point out, the AL none, if you use that distance model, basically you're just telling OpenAL, don't do any distance attenuation for the sources in this context.
Next, you have to set some parameters on the source itself. And so those first three, the reference distance, max distance, and roll-off factor, I'll talk to those again in the next following slides. If you want to have a source, not have any distance attenuation, then you would use the AL source relative token, and you can turn distance attenuation on or off.
So let me show you the slide. So what you're seeing right here is an inverse distance square log curve. And this is the default curve that distance attenuation will be using for your source. Now you'll see there's a green line on the left-hand side. That's the reference distance.
And what the reference distance is, you'll see how it crosses 0 dB, where it crosses 0 dB with the orange curve. That's the point where, that's the distance at which your source will have no amplification or attenuation. And that's set, that's a settable attribute. You can set it to whatever's appropriate for the units of measurement in your game or on a per-source basis.
So here's an example of how we would get that. Since you can change it on a per-source basis, you may want to change that. And so here's an example of how you would get it. In this case, we're going to get back a value of 1.0. This happens to be the default setting when your source is created.
Okay, so the next thing we'll talk about here is the maximum distance. So the curve as it is right now, your sound will continue attenuating and approach out toward negative infinity, but long before it would ever get way out there, your source is going to stop being heard because you'll get a decibel level of attenuation that's quite low. So you may have a source in your application that you want always to be heard.
Now, you may want some attenuation to occur as you're moving around, but you may always want it to be heard, say, a generator in another room or whatever. And so you may want some attenuation. Well, the way that we do that is by setting the maximum distance property.
So if I executed this line of code that's in the box there to 16, you'll see how the code, how the curve would change. And that's now how your attenuation is going to be. So you can see that the distance property is going to be the same as the distance that you're going to be hearing. All distances past 16 now will be stuck at that, I think it's a negative 30 dB attenuation.
OK, so we've talked about some source settings. Now let's look at the distance model. The curve, as you're seeing it right now, has been using the inverse distance model. And the difference between that and the clamped model that you see in the code box is the clamped model will actually disallow any amplification between a distance of 0 and your reference distance. So by executing this line of code, where we change the distance model, you'll see how the curve is going to change. And there's a clamping there.
Now to be fair, on OS X, that clamping's happening in both distance models. We don't actually do any amplification from 0 to the reference distance. But you should still set that if that's how you want to behave, just in case you're running on a different implementation on a different platform where that amplification may occur. So make sure that you set that.
Okay, so now one last thing that you'll want to do to make each source behave differently is potentially change the curve itself. So what we've been looking at is just a straight inverse square law, but you may want your source to attenuate either faster or slower as it moves out towards maximum distance.
And so we're looking at the default setting of 1.0, but for instance, if we changed it now to 2.0, you'll see how the curve changes, where attenuation occurs more quickly, and then when it reaches that maximum distance, you'll also notice that its attenuation is actually at a lower level. And so those are all the attributes and properties you'll be changing for setting your distance attenuation behavior.
Okay, so the next thing we'll talk about is AL gain. AL gain is just an attribute for scaling the amplitude of the audio samples themselves. Now, 1.0 just basically is saying don't do any scaling, play the audio samples just exactly as they are, and a zero basically means play silence.
Now, it's important that since you cannot go above 1.0, it's important that you make sure that when you create your audio for your game or your application that you use the full bandwidth. You can always scale down, but you can't scale up, so it's important really to use the full bandwidth that you can use for those audio samples.
Now, setting listener gain, listener gain also, what that basically does is it will affect the gain of all the sources that are being rendered. And then you'll see also that there's a min and max bounding properties that you can use on a per-source basis. Now, the API is quite simple for setting this. You use the AL source F call, indicate the source that you want to change and the token. pass it in a float value, and off you go.
Okay, so the next one we'll talk about is AL pitch. This is the property that Elliot mentioned before, how you can change pitch for your sources. Again, this is just a rate scaler. 1.0 indicates do not do any pitch change, and it's settable while you're rendering. And so here's an example of how you could double the pitch of a particular source's audio data just by setting it to a value of 2.0.
Okay, so now you have your source, your context, your listener, your device. Your sources need some data to play. And so here's the last of those five components, and that's the OpenAL buffer. Now, OpenAL buffers are just buckets of data. They can be whatever data is supported by the implementation.
And the library actually makes its own copy, so once you pass it in, you can dispose the copy that you've passed in. And I'll show you how that works in just a second. Also, they're reusable. So in other words, you can generate a buffer, fill it with some audio data.
Sometime down the road in your application, you decide, "Oh, I don't need that anymore. Let's reuse this." Pass it some new data. The library will purge the old data and then copy in the new. And unlike the OpenAL sources, the buffers are not attached to a particular context. They can be shared by all available OpenAL sources across any application. across any number of OpenALE contexts.
So here are the APIs for the OpenAL buffers. You'll notice they look very similar to the generate and delete source APIs. Again, they take a size indicating how many buffers you want to create or delete, and then an array of integers, both either to be filled in upon creating or to specify the buffers that you no longer need. Now, once you've created some buffers, you need to add some data to them, and we use the AL Buffer Data API to do that.
So the first parameter there is the buffer, of course, that you're adding the data to. And then the next one is the format. The reason I want to point out the format is this is actually a constant that would be defined in your header files or possibly by an extension, and I'll talk about extensions in a little bit, to define what type of data you're actually handing to the library. Now, the box there that just popped up shows the formats that are required to be supported by OpenAL, any OpenAL implementation, and these are integer-- these are integer PCM files. formats.
Next, you pass in a buffer of data and how big it is. And then lastly, there's a frequency parameter. That's the sample rate of your audio data. One other note about your audio data. If you're passing in stereo data, stereo data won't be localized in your virtual space. It always gets rendered to your front left/right speakers if you have a surround system, or it's going to be in your left and right speaker of your stereo system.
So there are a couple of different ways typically that Open-AL sources will play buffers. Either kind of a one shot or play this sound on this event, or maybe a particular buffer that just loops through. Or you may actually want to have a queue of buffers chained together that can be modified as you're going along, maybe changed as events are changing in your application. And so there's a couple of different ways to do that.
The Open-AL--the AL buffer token's typically used for a one shot-- a one shot sound when you're adding that to your source. And then the queue buffers are for manipulating that. And I'll walk through an example of how you would use those calls. Now if you are manipulating a queue, there's also a couple of tokens for identifying some state about your queue.
Both one for finding out how many buffers have been processed or actually how many buffers are in the queue. And then, like I said, you can also use a single shot buffer to loop continuously. And so there's a property for turning that on and off. And then lastly, you may want your queue or even your single shot buffer to loop continuously.
So here's an example. Let me just walk through a little usage of how you can manipulate your buffer queue. We'll start out with a source that has a couple of buffers in it, buffers 1 and 2. And then it's playing along and you've decided, "Oh, I need to add some more buffers." So you use the AL Source Queue Buffers API, and you fill in an array with the buffer names that you want to append to the end of your queue.
Now, in this case, we've added three-- buffer 1, buffer 3, buffer 4-- and I wanted to point out, too, that you'll notice that buffer 1 is being used twice. There's no limitation on which buffers can be in there. It's just going to play these buckets of data in a sequence.
Okay, so now this is the way that you would check your queue length. You've added some buffers. Maybe you're not keeping that state yourself. You can query to see how many buffers are in your queue. And in this case, we have five, so that's the value we're going to get back from that call.
And your buffer cue's been playing along, and the gray boxes there denote some buffers that have already been played. Now we're playing the third one there. And you want to find out which ones have been played so that you can find out which ones can be deleted off the front of the cue. So you're going to get back a value of 2, and this lets you know I can take off one buffer or I can take off two buffers with the un-cue call.
And so here's an example. We're going to remove one buffer from your queue using this AL source on queue buffers call. And we pass in an array of size 1, since that's how many we're deleting, and when the call completes, that array gets filled in with the buffer name that was just removed off the front of your queue. So in this case, that would be buffer 1. Okay, so there's nothing really special here about the playback control calls. I'll just let those speak for themselves.
Okay, so back to our initializing routine. Again, this is some code we're going to run in just a second. Other than setting up your device in your context, typical usage might be that you would generate some buffers and some sources at some non-critical time in your application, either when you're knitting at the beginning or maybe between some levels or at some non-critical time. So here we have usage of the ALGenBuffers call. We happen to be generating four buffers in this app. And then a call to ALGenSources. Again, we're going to put one buffer in each source, so you'll see how that works.
Okay, so now that we have our buffers, we need to initialize-- need to do some initializing of them by passing them some data. Now, the reason that the line is in gray here next to the red arrow is this is not an open AL call. Your application will have to have some way of getting your audio data either out of a file or maybe you've stored it in some other fashion, but ultimately you have to get a buffer of data to then pass to the library. So you get your data, then you call "aobuffer_data" and pass the-- pass the data in. And then again, to reiterate, you don't need that data anymore. The buff--the open AL library has made a copy of it, so it's going-- you can release your copy now.
Okay, now lastly, we need to set up some attributes on our sources. So in our example here, we need to attach a buffer to each source. We need to turn looping on because we want all of our sounds to play continuously. We need to set a position in our space.
We need to set a reference distance that is appropriate for the virtual space that we've created. In this case, we're setting it to 5.0. And then we need to start playing. So if we could switch to Demo Machine 2, let me run the code that I've shown you in those three methods.
Okay, so also the code for this app, I think, can be found on the WWDC web pages and, you So you can check that out. There's just very little bit more OpenAL code than what I've just showed you. Basically, the only difference, the only thing I haven't showed you are the set calls that we're going to make as we manipulate the sources and the listener. So what we have right here right now is four sources denoted by the red.
By the red dots, these are four different sources. We can move them in space. And in the center we have a blue dot that denotes our listener. And you can see that there's an arrow there pointing out. That tells you which orientation our listener has. And again, this is a top-down view, an XZ plane view of this thing.
Alright, so we have our things, we should be hearing those all around the room. And if we change the orientation, We ought to be hearing all of those particular sources move around. And this is just by making one single orientation call. "And the library does all the rest of the work for you." Okay, so we have that, and so we can move the orientation. Now all those sounds are behind your listener, so they all ought to be in the back of the room. So maybe we want to bring them up to the front. And so we'll orient this way, and here they are up front.
Now let's say we have some, maybe we don't like the sound of that monkey, let's turn him down. That's an AL gain set call. And we want the electric sound to be a little higher pitched, change the pitch. So these are just calls to AL pitch, AL gain, orientation, and we can turn all the sources down by setting the listener gain to zero. And then these are just, moving these around are just calls to AL position, either for the listener.
"Or for the source. Oh, we've got that one down. So we can see how we can move that around the room. So that's all there is to the app. It's kind of a simple app, but it should get you started if you want to take a look at that code.
So if we can go back to the slides, please." One last thing about the OpenAL architecture is that there is an extension mechanism so that if you could check out the sources, they are available at the Creative site, and add a feature that you may need that maybe isn't in the Core APIs. And the way that you would do that is by adding an extension and defining a name for that extension and some names for your function pointers, if that's appropriate. And then there are some APIs for querying at render time whether your extension is present or not.
Now, there are some common extensions out there, and typically what would happen is you may propose an extension to the OpenAL community, and there may be some documentation on the OpenAL website, and so you can get information about that in that fashion. And then there are occasions where that extension may be rolled into the OpenAL Core APIs via a new specification.
That's actually happening in the Core APIs. So we're running right now with the 1.1 specification that's being developed at this time, and it's rolling in some capture APIs that were only available as an extension before. And so these are what the APIs look like. Again, they both take const strings, one for querying whether the extension is present, and if it is, then you can go and get function pointers into that extension.
Okay, so I've talked about the Core APIs, and you've heard the great story of why it makes your life easy, but it's still really important for you to have an efficient audio system. Many of you are developing games that have really highly computational graphic work and things, and you don't really want to be spending a lot of time doing audio. And the way we've done that in the Mac OS X implementation is by using these Core Audio pieces. And I'll talk about these three, the 3D Mixer Audio Unit, the Default Output Audio Unit, and the Audio Converter APIs one by one here.
So the 3D Mixer Audio Unit sort of equates to your OpenAO context. It's the piece in the implementation that is doing all the mixing of your audio sources. It's doing all the spatial rendering work. And it's been optimized, so it's quite efficient. And the other thing that it does for the implementation is it defines which speaker configurations your user can use. So currently, the 3D Mixer Audio Unit supports stereo, quadraphonic, and 5.0 rendering. So if there is some point in the future where 7.1 was appropriate and the 3D Mixer might support that, the OpenAO library would just work. You wouldn't have to do any changing on your part.
Now, the next piece are the audio converter APIs. These sort of--these equate, basically, to your OpenAO sources. Each source has its own data that it's going to be rendering, and eventually, it has to get the data that you've passed to the library into the native data format for Mac OS X, which happens to be 32-bit float samples.
So it's really important for you to have efficient into-float glitters, and that-- you'll get that with the audio converter APIs. The other side benefit is, since it's--the audio converter APIs can decode as well, it's--it'll be a trivial to add support to decode any particular formats that are supported on the Mac OS X platform.
Now, the last Core Audio piece is the default output unit. Now, this is the piece that does all the tracking for your user's audio device that they're rendering to. And what's nice about this setup is your application, again, doesn't have to know anything about the hardware or the state of the hardware or what speakers are connected to the hardware.
You're basically, you're, the default output unit is going to do the tracking for which device is being used, whether that's your user has changed it or possibly they're using a FireWire or a USB box, maybe it gets unplugged by accident. OpenAL, the library's just going to keep rendering because the default output unit's going to find a new device and then start rendering to that.
The other thing that can change on your user's device are its stream formats. So there could be a change in the amount of channels that you're going to be rendering. There could be a change in the amount of channels available to render to or the sample rate. Maybe your user's changed the sample rate in some software application or flipped a switch on their box. So, again, the default output audio unit does all that tracking and does all that work for the implementation.
So we've been talking about performance. This is a little piece of information here that shows you just really how much the Core Audio implementation is a win for you. On the right-hand column are some CPU load numbers for running a test in OpenAL while we've been playing 64 PCM sources simultaneously.
And as you can see, the numbers are quite low, and that's for running both in stereo and 5.0, on maybe a low-end G4 PowerBook platform or a 2.5-gig G5. And so you can see that those CPU loads are not going to be a real bad problem for your game. Now, on the left-hand side, you can see what we were using before we had added these 3D mixer and the Core Audio implementation that we have right now.
So there's a couple other things that we've added. Since we have this Core Audio implementation, we thought it would be good to expose some of these pieces through the OpenAL APIs. And so let me talk about a couple of these. First, the spatial rendering quality. The 3D Mixer actually has the ability to have a setting for how good the quality that you render to is.
And so there's a tradeoff between how good is the quality and how much CPU does it take versus you want something that sounds good but doesn't take as much CPU. And so we've added some rendering quality settings, a low and a high. Now the default is the low setting, which is an equal power panning.
And it sounds great. But you may have a case where your user's on a real high-end system, maybe they're using-- yeah, they're on a high-end system and you can afford some CPU hit to give them a better audio experience. You could then give them that high quality HRTF.
And so this-- this feature only works when you're rendering to stereo. Whenever you're rendering to a multi-speaker configuration, the 3D Mixer always uses the sound field setting. So this might-- the high quality HRTF may be appropriate for a headphone setting when your user has a powerful platform system.
So you see the blue boxes. Those are the numbers that we saw on the previous slide. Now I've added one more platform there, a G5 iMac, that's sort of in the middle in terms of speed and what's available. And so you can see on the right-hand column what the HRTF numbers look like. Now 33% on a G4 is probably a little intimidating. Maybe you're not-- maybe you're not going to want to use that. But again, this is rendering 64 sources. That may be more than you're actually rendering anyway.
But if we--if we start looking at the numbers for 48 sources and 32 sources, you can see that we're getting to a number now where rendering 32 sources on a high-end system, you can probably still afford to use that HRTF and really give your users a good audio-- an even better audio experience.
Okay, the next thing we'll talk about is the render channel count. Now, the render channel count is there so you can force a stereo rendering. And the reason you might want to do this is the way that the OpenAL implementation works is the default output unit discovers how many channels are available on the hardware device your user has set up and then tries to render to the richest number. So in other words if there's five or more channels available to render to, the OpenAL library is going to try and then render to 5.0. If there's four channels available on your device, it's going to render to quad. Otherwise it'll render to stereo.
Well, your user may have a nice 5.1 system that they're using, but maybe it's late at night and they have to turn down. But they don't want-- and so they plug some headphones in. So by using this, you can allow your user to just render to stereo. You don't have to do anything other than set this property and your user does not have to go and reconfigure how many speakers they have.
You can also set how many speakers they're rendering to in their default settings when they set up their multi-speaker configuration. And so we do that by using the AL_SET_INT and the GET_INT calls. And just by turning, you can force it to be stereo or render to the richest, the multi-channel, which is the richest amount of channels possible.
Okay, and lastly we'll talk about the mixer output rate. The mixer output rate is here, and this is really a mileage may vary property. It just depends on how many sources you're rendering, what the sample rates of your sources happen to be at, what the sample rate of the hardware your user is rendering is at. And so it's a little easier to describe in a diagram, so I'll do that in the next slide. But just so you see, you use the AL set double and get double APIs in order to set it. In this case, we're setting it to 22K.
And so I can show you a little more clearly what this really means is here we have an example where when the default output unit and the 3D mixer audio unit are set up at a Nib time, what happens is the default output unit goes and discovers the sample rate of the user's hardware.
And that sample rate gets propagated down into the 3D mixer. And so what the 3D mixer will do by default is take all of that incoming data, all those red boxes at the top-- in this case, they all happen to be 22K-- and what it does is it upsamples to that 48K rate before it does any mixing.
And the reason you may want to change this is, since we've gone from a 22K to a 48K, you're now pushing around more than twice as much data as is necessary in order to deal and process with those samples. So by setting the property at the 22K, as we saw on the previous slide, now what happens is there's no sample rate conversion. And by the way, the sample rate conversion that gets done is a cheap linear conversion. It's not expensive, but still, the case really here is more about how much data you're pushing around in the 3D mixer.
So by setting it to 22K, what we do now is do all our processing at 22K, and then the mixed data is then passed to the default output unit and then upsampled at that point instead of beforehand. And so that's my part of the talk. I would like to bring up Glenda Adams from Aspire Media, and she's going to talk a bit about Doom 3 and OpenAL.
Let's see if we can switch over to the demo machine here. Okay, there we go. I'm Glenda Adams, I'm the Director of Development with Aspire Media, and I'm really excited to be here today to show you a first kind of public unveiling of Doom 3 running under OpenAL.
We don't really need to see that. Oops, did we disappear? It's demo two. We were on there for a second, I think. I don't know if we lost our video signal because we switched resolutions. We can hear it at least. Maybe that's all we need for an audio demonstration. Do you want me to switch it back to the other? Yeah, I can switch it back to the other resolution.
There we go. Okay. So when we shipped Doom 3 about three months ago, it actually shipped with only stereo output because there really wasn't any good way for us to do 5.1 output, even though the game came from its original platform with a full 5.1 environmental audio. So we shipped it, and it really just didn't sound that, I mean, it didn't sound bad, but it didn't sound nearly as good as it could have. Now that OpenAL is available under Tiger, we decided to go ahead and move it to OpenAL so that we actually could do full 5.1 audio.
So we're going to jump into the game here. This is a later part of the game. If you don't know anything about Doom 3, you're actually kind of chasing demons through a Mars base and then eventually down into hell. And this is later in the game where you've actually gone down in to chase the demons back to their homeworld. And this is the game where you've actually gone down in to chase the demons back to their homeworld. And this is the game where you've actually gone down in to chase the demons back to their homeworld.
You really can tell it, as much as the graphics are quite amazing in Doom 3, the audio really adds a lot when you've got a full environmental sound that's going all around you. And as you're running through the levels, it really adds to the immersive experience of the game.
It's a little bit dark, but we can kind of go up into here. As we jump down into this level, this is a good place where you're sinking down into a lower level, and you can kind of see some of the positional audio as this cage kind of flies out and hits you and surrounds you as you're falling down into this pit.
Now we'll actually get to see a little bit of the bad guys that we've been chasing around here. And this is the point where you can kind of tell that the positional audio actually really makes an effect in playing the game. Because now you can kind of hear somebody sneaking out from behind you and realize that you better pay attention or you're going to be in bad shape.
As you basically run around the game and it's using OpenAL to play all these positional sounds, we're letting basically OpenAL and Core Audio do all the audio mixing for us so we don't have to actually try to figure out where we want to pan and move all the sounds around.
So that was our little demo of that. We actually were able to port OpenAL from the Windows code for Doom 3 relatively quickly because it's an open standard. There really wasn't much we had to change. It pretty much just came up and running on the Mac. And it really was a nice addition to the game. It makes it a much more immersive experience. They spent a lot of time really making the audio fit in with the story and give you a much more immersive feel to the game.
It makes it a much scarier game. I couldn't play it at night before with stereo and I can't play it any at all now with the 5.1 during the day even. It's too scary for me. So we're really excited about having OpenAL in Tiger and it's really a great addition. We're looking forward to using it for future games and we're going to release a patch for Doom 3 that enables OpenAL for everybody. Hopefully shortly in the next few weeks. Thank you.
Back to slides, please. Thanks. Well, we can thank Glenda for that great demo with Dune 3, showing you the power of what you can do with OpenAL. If you're looking for more information, though, so where you get started, how to get started, and how you can get up and running with this, you can get some documentation up on the WWDC website.
And you can also come to tomorrow's lab at noon in the Graphics and Media Lab right around the corner, and if you're working on your game already and you got started and you want some help, like right now, you can go over there tomorrow around noon. We'll be there from noon to 6.
Stop in there, talk to me, Bob, or any of the Core Audio engineers, and we might be able to help you. Here's some contact information. Here's my email. Rich Hernandez, marketing games engineer. And Bob Barron, the Core Audio engineer. You heard much about how to use the OpenAL implementation.
And you can also contact Garen Herbert from Creative Labs. This is the CVS repository owner. If you're writing games using OpenAL, contact him and let him know that, hey, I wrote a game using OpenAL, and he'll add you to the long list of growing games using OpenAL. Here's a list for the OpenAL website, and we also have an OpenAL mailing list.
When you start with your implementations and you have API questions that, hey, I'm doing this, and am I supposed to use this buffer with this method, this is a great list. It's very active, so you can get a lot of help that way. You can also contact DTS if you need specific help with your game, too.