Using Fmod Doppler on Unity without a rigidbody

As I mentioned on this article, Fmod includes a built-in doppler feature but unfortunately it requires two things in order to work on Unity:

  • A rigidbody on the game object where the emitter is.

  • The game object needs to be moving via the physics engine, like for example using Rigidbody.AddForce or just using gravity.

This limitation has prevented me from really using the doppler effect since, on the games I have worked on, we usually move objects by code or using animations which means that Unity’s physics engine has no clue what the object’s velocity is, so in turn, Fmod doesn’t know either.

Additionally, we would also need to know the listener’s velocity, since in nature the doppler effect always takes into consideration the relative velocity between the listener (you and your ears driving in a car) and the emitter (another car’s horn).

So let’s jump into Unity and try to find a solution for this problem. I took most of the code from this thread on the Fmod forums.
Note: this work was done on the following versions so as time goes by, it could get more and more outdated:

  • Fmod Studio & Fmod Unity implementation plugin version: 2.02.04

  • Unity version: 2020.3.19f1

You can get this project on GitHub so you can copy the code more easily or play around with it. Here is the zipped project in case you prefer that.

Using Doppler with a rigidbody and the physics engine

Before we do anything else, let’s see how the system was intended to be used by default. As you can see in the video below, I have a very basic setup: I created a new, clean Unity project, integrated Fmod into it and created an Fmod project.

The Fmod project simply contains a 3D event with a looping testing sine wave tone. On the Unity project I just have a camera with the Fmod studio listener, a plane with no collisions and a cube. On the cube, I added a rigidbody and an Fmod emitter. As you can hear, at first we hear no doppler effect but activating the doppler feature on the event macro section and re-building banks makes the doppler effect work.

So now that we can see that Doppler is working when using gravity, let’s try switching the movement to just animation. As you can see, I disabled gravity, added an Animator to the cube and made an animation so it falls in a similar way as it does with the physics engine. You can clearly hear that there is no doppler in this case and we only get it back when we switch the gravity back on and disable the animator. So this is basically the problem we need to solve.

How Fmod receives velocity information

If we look at Fmod’s documentation, we can see that: “The Doppler property requires velocity in order to calculate how much Doppler adjustment needs to be applied. Velocity can be provided by the game engine or by calling EventInstance::set3DAttributes. In the case of the Unity and Unreal Engine integrations, this is usually set automatically to match the velocity of the associated Rigidbody or RigidBody.”

So this is how we are currently sending the velocity to Fmod, via the rigibody. But as the docs say, we can also provide this information manually which means we need to calculate the velocity ourselves but at least we don’t depend on the physics engine anymore. Let’s call this manually calculated velocity, “kinematic velocity”, since it doesn’t care about the forces applied, just the movement itself.

Let’s adapt the default Fmod emitter. I personally don’t use it since I have my own emitters but the default one is a good example to learn what’s going on.

Modifying StudioEventEmitter

First, let’s think about when we want to use kinematic velocity. In theory, everytime there is no rigidbody, we want to potentially use it but it would be a waste to do it if the event in Fmod is not even using doppler. On the other hand, sometimes we will have a rigidbody and we still want to use kinematic velocity since the object could be moved by just animation or code.

First, I thought about reading the event description to see if the event in question had doppler activated and turn on kinematic velocity based on that. The problem with this approach is that sometimes we may have doppler turned off, but we still want to send kinematic velocity information to Fmod to use it as a parameter for other things.

So my solution was to add a new option to StudioEventEmitter where you can set if you want to calculate kinematic velocity. This would be independent of having a rigidbody and also independent of the event having doppler activated. So firstly, let’s add a new bool variable to the public settings within StudioEventEmitter:

Since this class uses a custom made editor, we need to modify the editor class too:

As you can see, the class now has an additional option on the inspector.

We then declare a couple of variables on StudioEventEmmiter that we need to calculate the game object’s velocity:

As you can see, I’m using a VelocityVector3 class that is new to both Unity and Fmod. Let’s create this class on RuntimeUtils:

Next, let’s create a method to calculate the velocity on a given frame and update our velocity related variables:

On Update(), we want to call the previous method, but we only do it if we are using kinematic velocity for this particular event:

We are almost finished with StudioEventEmitter. The last thing we want to do is make sure that we attach the Fmod instance to the gameobject in a slightly different way when we want to use kinematic velocity. This is done within the PlayInstance() method.

So we modify the code to be:

As you can see, we are making sure we only attach the rigidbody if it exists AND we don’t want to use kinematic velocity. Otherwise, we use our new kinematic velocity. Here we are using a new overload on AttachInstanceToGameObject() that we don’t have yet. We will fix this in the next section.

RuntimeManager

This script takes care of updating things at runtime. We need to do a few modifications for our kinematic velocity to work. We first add two new variables to the AttachedInstance class. We do this so we can keep track of the velocities without a rigidbody.

Next, we create the overload we were missing before. As you can see, this attaches the Fmod instance to the game object and uses our kinematic velocity class instead of a rigidbody.

We now need to make sure we are updating the values on each frame. As mentioned earlier, this is accomplished by setting the 3D attribute by hand. So we look for the Update() method and we modify it like so:

Essentially, we are making sure we only update the attributes based on the rigidbody when it exists AND we are not using kinetic velocity. Otherwise, we update the values including kinetic velocity.

Notice that to be able to do this we need to overload the To3DAttributes() method on RuntimeUtils like so:

StudioListener

The last thing we need to do is also modify the Fmod listener. We need this since the Doppler effect is always based on the relative velocity of the emitter and listener. So we need to tweak StudioListener (or you could also create a child from it) to be able to measure its kinematic velocity.

We first add the same variables we added to StudioEventEmiiter. We also make sure we initialize the kinematic velocity variable if no rigidbody is found. You may need to modify this if your listener lives on a game object that has a rigidbody and you still want to use kinematic velocity.

We now copy the same method we used before for calculating speed in real time and we make sure we call it each frame if we are using kinematic speed.

The last thing we need to do here is to modify SetListenerLocation() so we can also use kinematic velocity as an option:

To make this work, we also need to overload SetListenerLocation() on the RuntimeManager:

And that’s all the code work finished!

Final Results

If everything went well, we should now be able to hear the doppler effect with no rigidbody and just moving the object via animations. As you can see, Fmod can now also get velocity values, which could also be useful to modify the audio based on them.

Success! These modifications could be done in many different ways depending on your needs so take my take as inspiration. If this doesn’t work for you or you have questions, feel free to contact me.

Remember that you can get this project on GitHub to play around with. Here is the zipped project in case you prefer that.

Brief Source Control guide for Audio Peeps

Here is a summary of ideas and concepts about Source Control or Version Control that I wished I knew when I starting out in game audio since they can get a bif confusing.

What is Source Control?

Basically, It is a system used within software development to share and keep track of code and other assets. Since many people will have access to the same files, you can see how this can create conflicts if two people try to change the same thing at the same time. Source Control has features and workflows to allow people to safely work without conflicting with each other.

It also allows you to work with different versions of the same application which share some parts of the code. At the same time, in functions as an advanced backup because all the work is both locally on every developer computer and on a server somewhere. Because of this, is easy to go back to a previous version if needed, like if something breaks, for example.

So imagine something like Google Drive or Dropbox but far more advanced so multiple users can seamlessly work at the same time and with different partial collections of files from a common pool in the cloud.

In summary, Source Control is a fancy way of sharing files between people in a way that allows for multiple versions and conflicts can be minimized and/or resolved when they arrive.

Git

This is one of the most popular pieces of software to do Source Control and you will probably see it all around. Since it was developed by Linus Torvalds (yeah the guy who is the reason Linux is called that way), it is a free and open source so anyone can use it.

As far as I can see, Git was 87.2% of Source Control software in 2018 so it is clearly the King.

What can be confusing at first, is that Git, more than an application itself, is a system or protocol. Git can be used on the terminal but more usually people use a Client, which is a dedicated App with a GUI (Graphical User Interface) so it is easier to use.

Fundamentally, you can use Git purely locally but usually it is hosted online so many people can access the same repository. So you need some server somewhere to do this.

In conclusion, Git seems to be the most used Source Control software and it is really a protocol that can be used by different clients and using different online services for hosting. Let’s see these:

Git Hosting & Clients

GitHub: This is a company owned by Microsoft which offers free online hosting for Git repositories. Many important open soruce projects are on Github, like Bitcoin. For commercial and more complex projects, Github also have paid options.

GitHub Desktop: This is a client, a software with a GUI that uses the Git protocol and can be used with Github hosting or really any other Git hosting (Even local).

GitLab: This is another popular online hosting service for Git projects.

Bitbucket: This is yet another online hosting service for Git owned by Atlassian, who also owns Jira (a task management) and Confluence (wikis) which are also popular in the game development industry.

Sourcetree: This is a popular client with a GUI to work with Git repositories and it is also owned by Atlassian.

Fork: Yet another client to use Git with.

TortoiseGit: One more Git client which integrates with the Windows File Explorer.

There are many, many more hosting services and clients but those above are some of the most popular.

Apache Subversion (SVN)

This is a completely different ecosystem and procol for source control. It uses similar concepts as Git but on other aspects is quite different. I’ve seen SVN used for larger files like art and audio within game development.

TortoiseSVN is a popular SVN client which integrates with the Windows File Explorer.

Perforce or P4

This another Source Control protocol software, quite popular in software and game development.

Terminology & Workflows

Now that we know a bit about the ecosystem, let’s see some of the concepts that Source Conctrol uses. This can be applied to any system but is mostly oriented towards Git.

repository is like a project that you create withing the Git system. So an app or a game will generally be one repository that is then shared by all the users.

When you want to get the repository in your local computer this is called Clonning. When doing this, you choose a folder in your drive and the Git client will download all the content. Once you do this, you have access to all the files, or to be precise to a version of all these files from the moment you did the clonning.

Although you are at first clonning the whole repository, while you work you are always dealing with branches. These are different versions of the software or game that are used by the team. Usually, there is a stable main branch called master or develop which functions as the principal branch where all other branches usually eventually point to.

After you clone the repo, if someone else updated it later, you will get “behind”. Source Control doesn’t usually work like Drive or Dropbox, where things are automatically updated. In contrast, you have update it manually. This may seem like a weakness but it is actually a strength. You need to have full control of when you are behind, ahead or just in sync with the server’s repository, depending on the situation.

Generally, if you are not working on anything at the moment, you want to be up to date with the master branch. For this, you switch to that branch (you check out the branch) and use the Pull action, which just pretty much checks if there is new stuff on the server and downloads it. In the case of SVN, this is action is called Update, which makes sense.

Keep in mind that when getting the latest version, you don’t get the whole thing again, just whatever is new or was changed, which makes things much faster. But what happens of you are the one who makes the changes? In this case, the simplest thing to do is to just send your changes to the server. In order to do this, git has two different steps which can be confusing. Before we go into those, we need to find whatever files we have changed and select them to make sure those are the changes that we want to upload. This part is important because usually there will be other local changes that we don’t really want to get into the server.

So after making sure that we have chosen the correct changes, we need to do these two step which are usually done at once but is important that you know the difference between them. The first is a Commit. This is just saying to the repo, hey I want to change these files and here is a brief description of what this change does. Once you do a commit, you have updated your local version of the branch where you are working on, but the server (or your co-workers) still have no idea that this change has occurred. The next step is a Push and that’s just the action of uploading your changes to the server for everyone to see.

As you can see, in the heart of this Commit and Push workflow is the isea of a Change, that is, the files that you have modified in respect to the server version that sits in the repo. Sometimes, you will make unintended changes which will break things. Since you are working with Source Control, you can always revert these changes, which will change the file back to its original state, which should be the same that exists in the server so no harm done.

Something else that it is important to know: You don’t usually work directly on the master or develop branch. This branch is usually reserved for an estable version of the game or software so people shouldn’t directly push things to it. That’s why we use branches. You would usually do your work in a branch you create, check that all works as intended and then push your changes to a server version of your own branch. Once that is done, you will create a Pull Request, from your branch to the estable one and usually someone with more seniority will check that all looks good and then accept the pull request. Once done, the result is sometimes called a Merge, since your branch is merging into the master branch.

And that’s all I have, it was quite a lot at once if you are new to this but I hope this works as an introduction from which you can expand as you get more and more into game development.

Tutorial Wwise en Español - Parte VII: Optimizacion

Note for my english readers: Sorry this article is not in your language but I wanted to write something for the spanish speaking community since there aren’t many resources on game audio in my native tongue. If I see that there is demand, I would be happy to translate this into english although most of the content can be found in Audiokinetic’s official resources.

Introducción

Llegamos ya a la ultima parte de esta serie, espero que te haya servido de ayuda para entender Wwise un poco mejor. En esta última entrega vamos a ver como podemos optimizar el uso de memoria y CPU para que el sonido de nuestro juego sea lo más eficiente posible.

Como la optimizacion sólo tiene sentido cuando tenemos un proyecto de mayores dimensiones, vamos a usar uno de los proyectos del curso oficial de Wwise. Los puedes encontrar en este link. Una vez lo descargues, abre el proyecto de Wwise de la leccion 7. Echa un ojo al proyecto e intenta entender para que sirve cada cosa y como funcionan los distintos eventos y objetos sonoros, con todo lo que has aprendido ya deberias poder moverte por aqui con comodidad.

Usando diferentes bancos

Una de las formas mas obvias de optimizacion es el uso de bancos. Hasta ahora, hemos puesto todos los sonidos en un mismo banco, pero para un juego completo esto no es una solucion muy eficiente. Una buena opcion podria ser tener una banco “master” o “main” que siempre cargamos y luego bancos específicos por cada nivel o area del juego. En general, siempre que en un juego haya una pantalla de carga, esta es una buena oportunidad para cargar bancos.

En el caso del proyecto que tenemos, no hay creado ningún banco todavia por lo que empezaremos por crear un banco “main” o principal que alojará los sonidos que queremos siempre disponibles. También vamos a crear otro banco para un nivel concreto del juego. Vamos a ello.

Dentro del Layout “Designer”, ve a la pestaña “SoundBanks”. Verás que bajo la “Default Work Unit”, no existe ningún banco. Crea dentro de ella un banco llamado “Main” y otro llamado “DCP_the_core”. Te recuerdo que estos nombres deben ser exactos puesto que el juego está llamándolos desde el código.

Una vez creados, ve al layout “SoundBanks” (o pulsa F7). Si despliegas la “Default Work Unit”, verás los dos bancos que hemos creado. Por ahora están vacíos, ya que debemos especificar qué eventos queremos asociar con ellos. Por ello, bajo la columna “Data Size”, aparece un tamaño de “0”. Fíjate también que podemos determinar un tamaño máximo por cada banco (“Max Size"), aunque por ahora el tamaño no está limitado por lo que aparece como infinito.

En algunas ocasiones, especialmente en juegos para consolas, sabremos mas o menos con cuanta memoria contamos para el audio del juego por lo que podremos espcificar el tamaño máximo de los bancos, o al menos hacer una aproximación. Vamos a establecer un tamaño de 9.000.000 para el banco “Main” y de 6.000.000 para el “DCP_the_core”.

Ahora podemos asignar los eventos a cada banco. En la parte inferior izquierda de este layout, verás que podemos ver todos los eventos del proyecto. Si te fijas, verás que todos los eventos del nivel que estamos construyendo (“DCP_the_core”) tienen un prefijo “DCP” que nos indica que pertenecen a este nivel. Esta es una forma muy conveniente de nombrar a los eventos ya que de esta manera, queda claro que solo son usados en este nivel. Arrástralos al banco. El resto de eventos pueden ir al banco “Main”.

Verás que por ahora, el tamaño no ha cambiado. Esto es por que necesitamos construir los bancos primero. Selecciona la plataforma e idioma y haz click en “Generate All” para construirlos. Una vez hecho esto, como puedes ver, nuestros bancos son demasiado grandes para el límite que habíamos puesto. Ten en cuenta, que esto no nos impediría en ningún caso usar estos bancos en el juego. El límite de tamaño es simplemente una constricción que nos hemos puesto nosotros mismos para que sea más fácil mantenernos en el gasto de memoria que nos hemos propuesto. Veamos entonces cómo reducir el tamaño de nuestros bancos.

Ajustes de conversion (calidad de audio y incluir/excluir audio)

He comentado varias veces en entregas anteriores que es importante usar en Wwise audio en su calidad original (a ser posible sin comprimir y en wav). El principal motivo es que cuando construimos nuestros bancos, Wwise no usa los archivos tal cual, sino que los convierte en un formato comprimido dependiendo de la calidad que le indiquemos. Por ello, esta conversión es uno de las formas más fáciles de reducir nuestros bancos.

Desde el layout “Designer”, ve a la pestaña “SharedSets” que recordarás de cuando vimos las curvas de atenuación. Verás que una de las secciones aquí es “Conversion Settings”. Bajo la “Default Work Unit” vamos a crear un nuevo ajuste de conversión llamado “SFX”.

Este será el ajuste que usemos para nuestros efectos de sonido. Primero, vamos a ver a qué elementos en concreto queremos aplicarlo. Volvemos a la pestaña “Audio” y verás un Actor-Mixer llamado “Weapons”. Selecciónalo y ve a la pestaña “Conversion”. Esta es una de las pocas pestañas que nos quedaba por ver en este panel.

Una vez aquí, podemos cambiar la configuración de conversión para este Actor-Mixer en concreto. Verás que por defecto, de usa el “Default Conversion Settings” que es el SharedSet que se crea en cualquier proyecto de Wwise vacío. Pero nosotros queremos usar el nuestro por lo que haz click en el botón con las dos flechas (>>) y elige el que acabamos de crear (“SFX”).

Una vez elegido, haz click en “Edit…”. En esta ventana podemos ver los ajustes de conversión y todos los objetos que ser verían afectados. Hay muchas cosas distintas que se pueden aplicar para reducir el tamaño de los archivos. Podemos convertir archivos stereo en mono, bajar la frecuencia de muestreo o cambiar el formato de compresión. Verás también que podemos elegir distintos ajustes para cada plataforma (windows, mac, consolas, etc…) Esto es muy útil ya que ciertas plataformas pueden ofrecernos más espacio que otras y así podemos estar listos para cada una de ellas desde el mismo proyecto de Wwise.

En nuestro caso, lo que más rápidamente va a reducir nuestro tamaño es el formato, Por ahora, verás “PCM”, lo cual significa que no estamos aplicando ninguna compresión al audio. Cambia esto por un formarto “Vorbis”, que es un formato comprimido como lo es mp3.. Esta opción nos permitirá construir bancos más ligeros sacrificando sólo un poco de calidad de sonido. Por defecto, la calidad es “4” y este valor es un buen compromiso entre tamaño y fidelidad, pero se puede cambiar si es necesario. Una vez listo, haz click en “Convert…” en la parte central derecha.. Elige tus plataformas (si ves mas de una, elige todas) y “OK”. Ahora podemos ver el tamaño original de cada archivo de audio y el convertido. Verás que los archivos son ahora notablemente más ligeros.

Para ver el impacto que esto tiene en nuestros bancos, vuelve al layout “SoundBanks” y construye de nuevo. Nuestro banco “Main” ya cumple con los requisitos que habíamos establecido mientras que nuestro otro banco especíco del nivel es aún demasiado grande. Esto los solucionaremos en breve pero mientras hay un par de conceptos con los que es importante que te quedes.

Por un lado, este SharedSet de conversión que hemos creado se pueden aplicar a cualquier otro conjunto de sonidos por lo que esta sistema es muy cómodo a la hora de asignar distintos niveles de compresión a distintos elementos. Por ejemplo, podríamos usar unos ciertos ajustes para nuestros efectos sonoros, otros para el diálogo del juego y finalmente otros para la música.

Por otro lado, ten en cuenta que en todo momento, puedes elegir si prefieres monitorizar un objeto sonoro con sus archivos sonoros asociados originales o ya convertidos. Al reproducir cualquiera de estos objetos, verás que el transporte tiene un botón que dice “Original”. Si el botón está encendido (como en la imagen inferior) esto implica que estás monitorizando el audio sin ninguna compresión. Si lo apagas, estarás oyendo el audio ya comprimido lo cual te puede dar una mejor idea de cómo sonará realmente en el juego.

Streaming

Normalmente, mientras se juega, los archivos de audio se cargan el la memoria RAM de forma que se pueda acceder a ellos de forma muy rápida. Esto es una buena solución para archivos pequeños ya que los necesitamos muy rápido (sonido de pasos, disparos, etc…) pero no ocupan demasiado espacio en al RAM.

En el caso de archivos de sonido grandes como ambientes o música esta solución no es tan adecuada ya que llenaremos la RAM demasiado y ten en cuenta que también la necesitamos para los gráficos. Por ello, en el caso de estos archivos grandes podemos llamarlos directamente desde el disco duro y así liberar RAM.

Hagamos esto con la música de nuestro juego para ahorrar memoria. Si recuerdas cuando construimos el banco de nuevo, aun nos pasábamos de nuestro límite ya que este representa a la memoria RAM del usuario final.

En el layout “Designer”, busca la musica (“Cube Main Theme”). En la pestaña general del “Property Editor” verás a la derecha “Stream”. Selecciona esta opción. No es necesario cambiar los ajustes. Una vez hecho, vuelve a contruir los bancos y ahora si que estamos dentro de los límites de memoria que nos hemos marcado, ya que el objeto no se cargará en RAM.

Optimizando gasto en CPU

Hasta ahora, todos los ajustes que hemos hecho nos han permitido usar menos memoria pero otro aspecto que podemos usar es el uso de la CPU. Cuando el juego está funcionando hay una serie de cálculos constantes que se hacen como la distancia entre objetos, transformar sonidos usando EQ o reverbs o simplemente reproducir un objeto sonoro.

Cada uno de estos objetos ocupa una “Voice” o voz. Cada una de estas voces es la unidad mas pequeña posible que canaliza un determinado sonido. Como te puedes imaginar un juego usará muchas voces, cientos de ellas, pero siempre tendremos un límite físico a cuantas de ellas podemos usar a al vez. Esto dependerá de la potencia de la CPU del usuario, que puede ser no muy grande, por lo que nuestro trabajo consiste en crear el mejor sonido posible usando una carga mínima en la CPU.

Algo que podemos ajustar para limitar el uso de voces es dejar de usarlas si el sonido contenido en ellas está demasiado distante a la jugadora y por lo tanto apenas se oye. Vamos a ver cómo podemos controlar esto. Haz click en “Project > Project Settings” o Shift + K. Verás dos opciones importantes “Volume Threshold” y “Max Voice Instances”

La primera controla a qué volumen dejará de existir cada voz mientras que la segunda especifica cuantas voces pueden existir a la vez. Como puedes ver, esto es ajustable por plataforma, permitiéndonos de nuevo optimizar el gasto de CPU para usuarios en consolas o móviles. Vamos a cambiar el umbral de volumen a -50 y las voces máximas a 40.

Como puedes imaginar, con esto estamos reduciendo el rango dinámico de nuestro juego. Ahora la diferencia entre el sonido más fuerte y el más débil será de 50dB como mucho. Reducir el numero de voces también reduce drásticamente el gasto de CPU aunque esto puede ser un problema por que en el momento en el que Wwise se quede sin voces puede dejar de disparar sonidos que son muy importantes como los diálogos. Por otro lado, ciertos eventos como una ametralladora van a usar montones de voces y esto puede hacer que nos quedemos rápidamente sin ellas.

Ve al Actor-Mixer llamado “Weapons” y a la pestaña “Advanced Settings” (que por cierto es la última que nos quedaba por ver).

Verás que aqui podemos establecer un límite para el número de instancias que queremos de un sonido o conjunto de sonidos. Haz click en “Limit sound instances to:”, elige 25 y “Globally”. Esto significa que en el juego nunca habrá más de 25 instancias de objetos sonoros de este Actor-Mixer lo que nos garantiza que no acapare procesamiento de CPU.

Por otro lado, podemos también querer darle una prioridad alta a ciertos sonidos como la música. Para ello, ve al objeto que contiene la música y en la misma pestaña, dale una prioridad de 80. Con esto le decimos a Wwise que si necesita voces para nuevos sonidos que se están disparando, la música nunca sea parada.

Sumario

¡Y esto es todo! En esta séptima y última parte, hemos visto cómo optimizar el uso de CPU y memoria, lo cual es crucial para que nuestro juego funcione lo mejor posible en cualquier plataforma.. Si tienes dudas o cualquier problema, puedes escribirme a contactme [ arroba ] javierzumer.com. Mientras tanto, dejo por aquí un glosario con todos los conceptos que he ido introduciendo en esta parte.

  • Conversion Settings: Objeto de tipo “SharedSets” que nos permite elegir cómo queremos compirmir el audio en nuestros bancos.

  • Stream: Cuando un objeto sonoro se repoduce en este modo, no se está cargando en la RAM sino que se llama directamente desde el disco duro, lo cual nos permite ahorrar espacio en memoria.

  • Voces: La unidad mas pequeña que canaliza un determinado sonido. Cada objeto sonoro que reproduce en el juego usa una voz.

  • Prioridad: Valor que podemos establecer para un objeto sonoro o un conjunto de ellos y establece cuándo un sonido será eliminado para dejar espacio a otro nuevo. Los objetos sonoros de más alta prioridad serán eliminados los últimos.