Table of Contents

Integrating Wwise Motion

Motion is a feature allowing users to control the haptic feedback of a control interface. With Wwise, you can manage motion using the same feature set that you use to manage the audio in your application. Internally, motion data is no different from audio data. This means that all the features available for audio are also available for motion. Two types of haptic feedback are available using the Wwise motion feature. You can either use any audio signals in your project and transform it into motion or generate dedicated motion signals using the Motion Generator source. This feature can be tested directly in the Wwise authoring tool on Windows with a supported controller.

Motion components

Motion uses the Wwise Sound Engine plug-in system in order to work in an application and can be subdivided into two modules: the audio source called Motion Generator and the Audio Device called Wwise Motion. Although the Motion Generator is optional, it remains a powerful tool to create accurate and flexible motion designs.

Motion sink plug-in

The Motion sink plug-in can be seen as the link between the sound engine and a motion-ready device. Just like any sink plug-in, it receives data from a set of Listeners and is in charge of "presenting" this data to a device. This plug-in is inside a separate library and needs to be included in both the authoring tool and the application. Refer to the Set up Motion section for more information.

Motion Generator source plug-in

The Motion Generator source plug-in is a very useful and accurate way to design the behavior of haptic feedback effects. Just like any audio source, you can add the Motion Generator to a Sound SFX node in your Wwise project to generate curve-based haptic feedback. Make sure that the Sound SFX nodes have an Output Bus set to a motion-ready bus.

Set up Motion

In order to use motion in your application, you need to properly set up each component. Note that all the concepts applicable to the audio workflow are also applicable to motion. It uses the same busses, Listeners, and Emitters (see Integrating Listeners).

Wwise Authoring setup

To be able to send either sound or motion data to a device, you need to add the licensed Wwise Motion ShareSet to the Audio Device folder of your Wwise project. The Audio Device folder is located in the ShareSets tab of the Project Explorer. The Wwise Motion ShareSet is the Audio Device plug-in used by the sound engine to interface with a motion-ready device. It is also crucial to assign the Wwise Motion ShareSet to a top level Audio Bus. The term motion bus denotes, for simplicity's sake, a top-level Audio Bus with a Wwise Motion ShareSet assigned to it. Good practice is to use a single motion bus hierarchy in your project for easier troubleshooting and monitoring. You can now set the Output Bus of any Sound SFX to a motion bus to create haptic feedback. Usually the Sound SFX elements using a motion bus are also using a Motion Generator source. To simultaneously have audio and motion, a Sound SFX needs to have at least one motion bus and one Audio Bus, either as the Output Bus or as an Auxiliary Bus.

Game setup

On the game side, the first thing that you will want to do is make sure to link with the separate library called AkMotionSink. This library provides support for the standard controllers of supported platforms. You also need to include the AkMotionSinkFactory.h file located under SDK\include\AK\plugin. Including this file is really important because it will automatically register the plug-in.

Note.gif
Note: In Unity, plug-in libraries are managed automatically. You don't have to add AkMotionSink manually.

Refer to the following table for the list of supported controllers and additional requirements.

Platform Device

Additional requirements

Android

Android device with vibration support

iOS

Not supported. The various haptic feedback APIs on iOS devices do not meet Audiokinetic's requierments to support the Motion feature due to specification restrictions from Apple.

Linux

Not supported.

Mac

Not supported.

PlayStation 4

DUALSHOCK 4
PlayStation Move

Switch

Joy-Con

Windows Xbox One controller
Xbox 360 controller
DirectInput Controllers
XInput.lib
Dinput8.lib
Winmm.lib
UWP UWP Gamepad

C++/CX

Xbox One

Xbox One Controllers

A dedicated output needs be added for each device your application wishes to use motion with. For example, a split-screen game with four players connected would need to add four different outputs for the controllers to receive haptic feedback. To add an output device, use the Wwise API function AK::SoundEngine::AddOutput and specify the ShareSet name (as defined in your Wwise project) in the AkOutputSettings parameter. Additionally, since multiple devices may be connected, you need to provide a device ID. Refer to the following table for more information on device ID. To simplify the setup when using a single controller, a default device ID is supported. By using "0", the Motion sink will target the first connected device that supports motion.

Platform Device

Information

Android Android device with vibration support

Use 0.

iOS Not Supported

-

Linux Not supported.

-

Mac Not supported.

-

Windows XboxOne controller
Xbox360 controller
Use the player index between 0 to 3.
Windows DirectInput Controllers Use the guidProduct stored in a DIDEVICEINSTANCE. Hash the guidProduct by using an AK::FNVHash32.
UWP UWP Gamepad

Retrieve the ID of a Gamepad reference by calling AK::GetDeviceIDFromGamepad.

PlayStation 4 DUALSHOCK 4 Use the handle of the device returned by scePadOpen or scePadGetHandle.
PlayStation 4 PlayStation Move

Use the handle of the device returned by scePadOpen or scePadGetHandle.

XboxOne XboxOne Controllers

Use the Id stored in a IGamepad object.

Switch Joy-Con

Use nn::hid::NpadId with the desired index

Keep in mind that a game controller can be disconnected either physically or through communication problems. It will not have any adverse effects on the sound engine other than using some resources uselessly. If you think a device has been disconnected for a long period of time, you should call AK::SoundEngine::RemoveOutput and provide the AkOutputDeviceID returned by the corresponding AddOutput() function call. This will free up resources.

Multiplayer considerations

Motion outputs are just like any other Secondary Outputs, therefore have the same restrictions and requirements. If you are making a single-player game, meaning only one player is controlling the game locally, the Listener/Game Object setup is very simple. In normal cases, the new motion output will re-use the same default Listener as the main audio output. In short, you rarely have to manage Listeners in a single player setup.

If making a multiplayer game, you will need to create one Listener/Game Object per motion output. This is necessary so that players each have their own mix of haptic feedback, depending on the in-game situation. The Listener associated with a device must be initialized at the same time as the output is initialized by AK::SoundEngine::AddOutput(). Specific Listeners provide an additional layer of routing for sounds or motion. You can target a specific player if you play an Event on a Game Object that is uniquely associated with that player's Listener. This association can be done by calling AK::SoundEngine::SetListeners. See Integrating Listeners for more information about Listeners and Game Objects. Note that you can also associate multiple listeners with the same game object, resulting in a "broadcast" effect on all listeners.

Note.gif
Note: A sound needs to be routed into the motion bus hierarchy even if the Emitter as a Listener set to a motion output.

Examples

The following examples will provide information on how to set up your application to use motion. You can also refer to the Demo Motion of the Integration Demo (DemoMotion.cpp) included in the SDK samples. It provides working examples for all the supported platforms.

Setup for a single player

First, some general plug-in management: as with any other plug-in, you need to include the corresponding file and link the library. (This is for Wwise native development, only. Ignore this on Unity.)

#include "AkMotionSinkFactory.h"            //Link to AkMotionSink.lib, implements the output to ga
#include "AkMotionGeneratorSourceFactory.h" //Link to AkMotionGenerator.lib, implements the Motion Generator source.

Then add an additional output with the Motion ShareSet name you gave in the Wwise project, in this case "Wwise_Motion". We use 0 for the output ID because we want to use the first connected game controller.

AkOutputSettings outputSettings("Wwise_Motion", 0); 
AK::SoundEngine::AddOutput(outputSettings);

Then play an Event, as per usual. In the Wwise project, the "Play_Explosion" Event would point to a Sound SFX that is routed to a bus that has the "Wwise_Motion" ShareSet assigned as its Audio Device.

AkGameObjectID explosionGO = 100;
AK::SoundEngine::RegisterGameObj(explosionGO, "Explosion");
AK::SoundEngine::PostEvent("Play_Explosion", explosionGO);

Setup for multiple players

To be clear, the multiplayer case means "multiple players on the same console", and not a "networked multiplayer game". In multiplayer scenarios, the mix for motion, or any player-specific output, needs to be different to represent the player's perspective in the game world. To do so, players will each need their own Listener.

int NUM_PLAYERS = 4;
const AkGameObjectID OBJ_FOR_PLAYER[MAX_PLAYERS] = {100 ,200, 300, 400};    // Game Object IDs are arbitrary.
for(int i = 0; i < NUM_PLAYERS; i++)
{
    AK::SoundEngine::RegisterGameObj(OBJ_FOR_PLAYER[i]);                    // Register a GameObject to use as Listener.
    AK::SoundEngine::SetListeners(OBJ_FOR_PLAYER[i], &OBJ_FOR_PLAYER[i], 1);    // Make the Game Object listen to itself.
}

Then add an output for every player. You don't need multiple ShareSets; each ShareSet can be used multiple times. You need to provide a real device ID for every controller. This example is for Xbox controllers on Windows. Refer to the table in Game setup for information on how to retrieve device IDs for specific platforms.

const AkUInt32 DEVICE_SPECIFIC_ID[MAX_PLAYERS] = {0, 1, 2, 3};  // For Xbox controllers on Windows, device IDs are simply 0 to 3. Other platforms have different requirements.
for(i = 0; i < NUM_PLAYERS; i++)
{
    AkOutputSettings settings("Wwise_Motion", DEVICE_SPECIFIC_ID[i]);   // Use the "Wwise_Motion" ShareSet to drive device DEVICE_SPECIFIC_ID[i]. 
    res = AK::SoundEngine::AddOutput(settings, &motionOutputIDs[i], &OBJ_FOR_PLAYER[i], 1);  // Add the output, link the appropriate Listener to it.
}

Then play an Event, as per usual. In the Wwise project, the "Play_GunFire" Event would point to a Sound SFX that is routed to a bus that has the "Wwise_Motion" ShareSet assigned as its Audio Device.

AK::SoundEngine::PostEvent("Play_GunFire", OBJ_FOR_PLAYER[0]);  // This will play only on player's 0 controller because of the Game Object-Listener relation.

To play an Event that would be affecting multiple devices, you need to set up a new Game Object that would be listened by all the player-specific Listeners.

AK::SoundEngine::RegisterGameObj(explosionGO, "Explosion");         // Register a Game Object to play an explosion.
AK::SoundEngine::SetListeners(explosionGO, OBJ_FOR_PLAYER, 4);      // Attach all 4 listeners of the players to the Game Object, so all can receive the Motion Effect.
AK::SoundEngine::PostEvent("Play_Explosion",explosionGO );          // Because all 4 listeners are tied to the explosionGO, the Play_Explosion Event will be broadcast to all of them.

You can also refer to the DemoMotion class in the sample IntegrationDemo. It provides an example of a multiplayer setup.

Checklist and Troubleshooting

So, in order for a specific device to receive motion with one device you must:

  • Add the Wwise Motion ShareSet to the Audio Devices of your Wwise project.
  • Create a top level Audio Bus and set its ShareSet to the Wwise Motion you just added.
  • Create Sound SFXs and route them to the motion bus hierarchy.
  • In the game, link to the AkMotionSink library by including AkMotionSinkFactory.h and link with the AkMotionSink library.
  • Create a Game Object to call and receive motion Events using AK::SoundEngine::RegisterGameObj.
  • Call Ak::SoundEngine::AddOutput with the Wwise Motion ShareSet and a device ID. If multiplayer, provide a Listener object for each.
  • Trigger your Events the same way you do for audio Events.

To have Motion in the Wwise project:

  • Add the Wwise Motion ShareSet to the Audio Devices of your Wwise project.
  • Create a top level Audio Bus and set its ShareSet to the Wwise Motion you just added.
  • Create Sound SFXs and route them to through the motion bus hierarchy.
  • In the Audio Preferences, locate the busses you want to use motion with and, from the list, set their device to the motion device of your choice.

Profiling

To troubleshoot problems, it is recommended to profile your application. In the authoring tool you can profile your application by connecting to it and using the Profiler layout (F6). Several tools can help you understand the source of a problem. The Capture Log view will let you see error codes, which will appear in red. The Graph view displays a visual representation of the sound engine pipeline. You should be able to see the motion devices at the end of the pipeline. If not it means that the sound engine was not able to find the device you specified. Another really helpful view is the Emitter/Listener tab. It will show you all the Emitter-Listener pairs. If the Motion Effect does not work, it can be because the Emitter is not associated with the Listener you specified to your motion device.

If you trigger a Motion effect but it doesn't work, do the following:

  • Make sure that you don't have a registration error with the plug-in, by looking in the Capture Log. If so, check if you included the AkMotionSinkFactory.h and linked to the AkMotionSink library.
  • Make sure that the sound engine was able to initialize the device. If not, you should see an error in the Capture Log when AddOutput is called from the game.
  • Make sure the Sound SFX you play is routed to a bus that leads to a motion device. You can check this with the Audio Bus property of the Sound SFX, and the Audio Device property of the bus.
  • From the Voices Graph tab, identify which Emitter triggered. Make sure that there is an associated Listener in the Emitter-Listener tab. It can be the same Game Object that emits and listens. If not, review your calls to RegisterGameObj, SetListeners, and AddOutput.
  • Make sure that the Listener is the one associated to the desired output device.
  • Also pay attention to the results of any API calls you made. Make sure that none return an error.

For Android devices, don't forget to add the permission in the application AndroidManifest.xml file like so:

<uses-permission android:name="android.permission.VIBRATE"/>