Steam Audio Tutorial

We will be building off of the Unity 4.1 Throw a Ball Tutorial so complete and/or open that project. If you are not using VR, you may ignore the VR Prefabs and any scripts. Instead create the same scene and follow the below instructions.

[Non-VR only] Interactivity

If you are not using VR, we will need to add a few scripts to make things interactive.

First add an empty GameObject and call it Player. Move your Main Camera to the Player to make it a child of the Player GameObject.

Now add a Character Controller Component to the Player and transform it such that it is just above the floor plane.

Now add the following new script to the Player and call it DemoPlayerController:

using UnityEngine;


[RequireComponent(typeof(CharacterController))]

public class DemoPlayerController : MonoBehaviour {

  public Camera mainCamera;


  private CharacterController characterController = null;


  private float movementSpeed = 5.0f;

  private float rotationX = 0.0f;

  private float rotationY = 0.0f;


  private const float clampAngleDegrees = 80.0f;


  private const float sensitivity = 2.0f;


  void Start() {

    characterController = GetComponent<CharacterController>();

    Vector3 rotation = mainCamera.transform.localRotation.eulerAngles;

    rotationX = rotation.x;

    rotationY = rotation.y;

  }


  void LateUpdate() {

#if UNITY_EDITOR

    if (Input.GetMouseButtonDown(0)) {

      SetCursorLock(true);

    } else if (Input.GetKeyDown(KeyCode.Escape)) {

      SetCursorLock(false);

    }

#endif  // UNITY_EDITOR

    float mouseX = Input.GetAxis("Mouse X");

    float mouseY = -Input.GetAxis("Mouse Y");

    if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) {

      mouseX = 0.0f;

      mouseY = 0.0f;

    }

    rotationX += sensitivity * mouseY;

    rotationY += sensitivity * mouseX;

    rotationX = Mathf.Clamp(rotationX, -clampAngleDegrees, clampAngleDegrees);

    mainCamera.transform.localRotation = Quaternion.Euler(rotationX, rotationY, 0.0f);


    float movementX = Input.GetAxis("Horizontal");

    float movementY = Input.GetAxis("Vertical");

    Vector3 movementDirection = new Vector3(movementX, 0.0f, movementY);

    movementDirection = mainCamera.transform.localRotation * movementDirection;

    movementDirection.y = 0.0f;

    characterController.SimpleMove(movementSpeed * movementDirection);

  }


  private void SetCursorLock(bool lockCursor) {

    if (lockCursor) {

      Cursor.lockState = CursorLockMode.Locked;

      Cursor.visible = false;

    } else {

      Cursor.lockState = CursorLockMode.None;

      Cursor.visible = true;

    }

  }

}

Then, attach the Main Camera to the script.

Now, to the Ball, add the following script called AudioDemoBallController:

using UnityEngine;


[RequireComponent(typeof(Renderer))]

public class AudioDemoBallController : MonoBehaviour {

  private Material material = null;


  void Start() {

    material = GetComponent<Renderer>().material;

    SetGazedAt(false);

  }


  public void SetGazedAt(bool gazedAt) {

    material.color = gazedAt ? Color.green : Color.red;

  }


  public void TeleportRandomly() {

    Vector3 direction = Random.onUnitSphere;

    direction.y = Mathf.Clamp(direction.y, 0.5f, 1.0f);

    float distance = 2.0f * Random.value + 1.5f;

    transform.localPosition = distance * direction;

  }

}

Lastly, create an empty GameObject and call it GameManager.

To this GameObject, attach the following script called AudioDemoManager:

using UnityEngine;


public class AudioDemoManager : MonoBehaviour {

  public Camera mainCamera;


  public AudioDemoBallController ball;


  void Start() {

    Screen.sleepTimeout = SleepTimeout.NeverSleep;

  }


  void Update() {

#if !UNITY_EDITOR

    if (Input.GetKeyDown(KeyCode.Escape)) {

      Application.Quit();

    }

#endif  // !UNITY_EDITOR

    Ray ray = mainCamera.ViewportPointToRay(0.5f * Vector2.one);

    RaycastHit hit;

    bool ballHit = Physics.Raycast(ray, out hit) && hit.transform == ball.transform;


    ball.SetGazedAt(ballHit);

    if (ballHit) {

      if((Input.touchCount == 0 && Input.GetMouseButtonDown(0)) ||    // LMB for desktop.

         (Input.touchCount > 0 && Input.GetTouch(0).tapCount > 1 &&   // Double-tap for mobile.

          Input.GetTouch(0).phase == TouchPhase.Began)) {

        ball.TeleportRandomly();

      }

    }

  }

}

Then attach the Main Camera and the Ball to the script.

Now you should be able to run the application, move around, and click on the ball to move it to a random location.

Begin by downloading Steam Audio. Extract the folder from the download and then navigate to Unity.

In your project, go to Assets -> Import Package -> Custom Package. Then navigate to the <folder you extracted>/bin/unity. Click on the Steam Audio Unity package file and click "Open". Accept everything for importing.

Steam Audio Setup

Navigate to Edit -> Project Settings -> Audio and under Spatializer Plugin select "Steam Audio Spatializer". Also select "Steam Audio Ambisonics" under Ambisonic Decoder Plugin

Now navigate to Window -> Steam Audio. Here make sure that the Audio Engine is set to "Unity"

You may also change your Simulation Preset here. I would recommend "High" but "Custom" will allow you to further enhance the audio simulation.

Optionally, you can add a custom HRTF (Head-Related Transfer Function) in the .SOFA file format.

Using Steam Audio

Now we are ready to begin using Steam Audio!

First, make sure that the your Camera has an Audio Listener component and add one if it does not (the Camera child object of the CameraRig object in the case of the Steam VR Tutorial).

Now to the Ball object, add an Audio Source Component.

Either download a sound clip from online or use one of the Steam VR audio files for the AudioClip field of our Audio Source.

Be sure that both Play On Awake and Loop are checked so that audio starts and continues while we are in VR.

Also make sure to set the Spatial Blend slider all the way to the right (value of 1) for 3D spatialization.

Then, under 3D Sound Settings, click to enable the Spatialize checkbox as well as the Spatialize Post Effects sub-checkbox.

Now also add a Steam Audio Source Component to the Ball.  You may change these fields as you wish but for the most realistic audio, I would recommend these settings:

Lastly, since this object will be a dynamic sound source, add a Steam Audio Dynamic Object Component to the ball.

Scene Export

In order for Steam Audio to work when we run the Scene, we'll have to export it.

Click on the Steam Audio Manager Settings object in the Hierarchy to open it up in the Inspector.

Now under Scene Export, select all three options (Pre-Export Scene, Export All Dynamic Objects, and Export to OBJ).

Application Testing

Now you are ready to test run the application!

Click run to start the application (make sure you have headphones or are using a headset built into a HMD if you are using VR).

You should be able to hear your audio coming from the ball!

If you are in VR, try moving/throwing the ball and holding it up to each ear. The sound should be varying spatially!

Changing the Environment

Now create four walls and a ceiling to the scene (either a small room or surrounding the whole scene).

To each of these, the table, and the floor, add both a Steam Audio Geometry Component and a Steam Audio Material Component

Feel free to change the material type for each object. The default material should be "Generic" but this can be changed in the Steam Audio Manager Settings object.

Now run the application again to see how the audio changes! Be sure to re-export your scene.

When the table occludes the ball, the audio source should become less pronounced (if you have the above settings).

Loudon Cohen