Table of Contents

Integrating External Sources

External Sources are a special type of source that you can put in a Sound object in Wwise. It indicates that the real sound data will be provided at run time. This is very useful to manage a large amount of dialogue lines that would otherwise need a Sound and an Event for each, that would in turn need to be included in banks that would need to be properly divided and managed. It is also very useful if the dialogue lines are already managed through another system such as an AI-driven speech generator.

The external source is created in Wwise the same way as other source plugins, through the Add Source button, allowing it to be part of complex structures if desired. On the game side, playing an event with a external source is done through AK::SoundEngine::PostEvent and AK::SoundEngine::DynamicSequence::Playlist::Enqueue, like any other sound. The WAV file(s) to play to replace the external source will need to be provided when the Event is posted. The decision of which file(s) to play is left entirely to the programmer. This also means that the file management for the source files is done external to the Wwise sound engine. While this involves more work, it also gives more flexibility.

Conversion of external sources

The wave data that the Sound Engine uses is in a proprietary format; you will need to convert your input files in order to pass them to the sound engine at runtime. This is done through the External Sources File List in Wwise. This is a very simple XML file that contains all files that you need to convert along with the conversion settings you want to use. To specify the WSOURCES file, go in the Project Settings in the External Sources tab. Here is an example of this file:

<?xml version="1.0" encoding="UTF-8"?>
<ExternalSourcesList SchemaVersion="1" Root="d:\TestProject\ExternalSources">
    <Source Path="kaaboom.wav" Conversion="VeryCompressed" />
    <Source Path="SomeOtherFolderInTheProject\working.wav" Conversion="PCM"/>   
    <Source Path="d:\FolderOutsideTheProject\out.wav" Conversion="PCM" Destination="out.wav"/>  
    <Source Path="..\RelativeOutsideTheProject\relative.wav" Conversion="PCM" Destination="relative.wav"/>  
    <Source Path="MyHdrSound.wav" Conversion="PCM" AnalysisTypes="6"/>
</ExternalSourcesList>

The Root attribute specifies the root path for the Source entries. If omitted, the project directory is considered the root. The Root path can be a fully qualified path or a path relative to the project directory.

The Source item specifies one file to convert:

  • The Path is always relative to the Root path.
  • The Conversion attribute is the name of the Conversion Setting ShareSet to be used to convert the file. If not specified, it will use the Default Conversion Setting of the project.
  • The Destination attribute is optional and allows you to specify a different destination filename and path. The path is relative to the output path specified in the Project Settings or command line. You may rename the file with this attribute as well. Note that you cannot use only a file path: you need to specify a file name also. Furthermore, the extension of the converted file will be ".wem", regardless of the extension of the Destination attribute. The hierarchy of folders inside the Root directory is always replicated in the output path if the Destination attribute is not specified. You must specify the Destination attribute if you use a file outside the Root directory.
  • AnalysisTypes is used to determine what kind of analysis meta data should be included in the header of the converted file. There are currently two types of analysis usable by the sound engine, loudness and HDR. -- Loudness is used for loudness normalization, so if you should add it to your external source if it is used by a sound structure that has the "Enable Loudness Normalization" check box ticked. Set AnalysisTypes to 2 in order to include it. -- HDR solely consists of the envelope of the sound. Include it if you plan to use this source inside an HDR system, in a structure that has the "Enable Envelope" check box ticked. Set AnalysisTypes to 4 in order to include it. -- Set AnalysisTypes to 6 (that is, 2 + 4) in order to include both types.

Conversion of the external sources is automatically done when bank generation occurs, along with all the other file conversions. Note that files that are already converted are not reconverted needlessly.

Caution.gif
Caution: To avoid reconversion, Wwise saves some data in a Wwise.dat file in the output directory. This file is not necessary for your game, so you should not include it in your final files. If this file is deleted, all wave files will be reconverted.

The directory structure of the input directories will be replicated in the output directory, relative to the root path. In the example above, the output directory would contain a "ExternalSources" folder and a "Lower Tests\Originals\SFX" folder. Note that paths that contains ".." will be stripped and start at the first real folder.

Command-Line Conversion

It is also possible to convert only the external sources of a project through the command-line tool. For example, this will convert the external sources without generating the banks for the Xbox One.

"%WWISEROOT%\Authoring\x64\Release\bin\WwiseCLI.exe" "C:\Project name.wproj" -ConvertExternalSources XBoxOne

For more information about the command line tool (WwiseCLI), see Using the Command Line

Streaming vs In-Memory

To provide the audio data to the sound engine, you can either specify a file name or a data pointer in the AkExternalSourceInfo structure. This completely overrides the Streaming check box that is on the Sound object in the Wwise project. When using a data pointer, you are responsible for the memory management and ensuring that the data will stay in memory for the entire length of the playback.

When you specify a file name, the file is opened and streamed from disk exactly like a normal streamed file would. Its location on disk has to be resolved inside your implementation of the File Location Resolver in the Low-Level I/O subsystem. Refer to Low-Level I/O for more details on the Low-Level I/O subsystem.

The default File Location Resolver services are implemented in CAkFileLocationBase, and are provided as a sample in the SDK (see Default Low-Level I/O Implementation). This implementation does not support subfolders; it assumes every external source streaming file is at the same place as the "standard" streaming files.

The Wwise Stream Manager passes flags to AK::StreamMgr::IAkFileLocationResolver::Open() in order to help you resolve file location correctly (AkFileSystemFlags). At this level, you may distinguish external sources from standard streaming files with the "company ID" (AkFileSystemFlags::uCompanyID). Wwise passes AKCOMPANYID_AUDIOKINETIC for soundbanks and standard streaming files, and AKCOMPANYID_AUDIOKINETIC_EXTERNAL for streaming external sources. You may therefore use this value to search external sources in another location on disk.

Note.gif
Note: AkFileSystemFlags::bIsLanguageSpecific is always set to false with external sources, even if the external source was included in a "Voice" sound structure. In fact, we recommend that you use external sources inside language-independent SFX instead of Voices. Localization has to be handled right from the start, when specifying the file name or ID in AkExternalSourceInfo.

Example: Playing a single sound through the external source mechanism

The project must contain:

  • A sound called MySound with a External Source also named "MyExternal" (added through the "Add Source" button)
  • A play event "Play_MySound"
  • A bank with the event included
  • An external source list in the Project Settings (see example above)
  • The external source list must define the source "One.wav" and "Two.wav" (implicitly converted in "One.wem" and "Two.wem" respectively).
    AkExternalSourceInfo source;
    source.iExternalSrcCookie = AK::SoundEngine::GetIDFromString("MyExternal"); //The cookie is a hash of the name of the external source object.
    source.szFile = AKTEXT("One.wem");      //The file we're going to play. 
    source.idCodec = AKCODECID_PCM; //The file is in PCM.
            
    AK::SoundEngine::PostEvent( "Play_MySound", 2, 0, NULL, 0, 1, &source );
        
    source.szFile = AKTEXT("Two.wem");      //Let's play a different file with the same event/source
    AK::SoundEngine::PostEvent( "Play_MySound", 2, 0, NULL, 0, 1, &source );
Note.gif
Note: The extension of the external file has to be ".wem". In the External Sources File List file, you may rename the destination file, but cannot change its extension. Once converted, a file's extension is always ".wem". If you package a converted file into a File Package, you also need to refer to it in your code with the extension ".wem": the File Packager generates lookup IDs by hashing the full name, including the extension.

Example: Playing an event with multiple external sources

You can replace many wave files in one single event. For example, you could setup a sequence container with 3 external sources. If an event triggers the playback of more than one external source, they must be named uniquely in the project (therefore have a unique cookie) in order to tell them appart when filling the AkExternalSourceInfo structures.

The project must contain:

  • A Sequence Container called MyExternalSequence with 3 sounds and one External Source each(added through the "Add Source" button)
  • The name of the sources should be 1, 2 and 3 so we can replace them separately.
  • A play event "Play_MyExternalSequence"
  • A bank with the event included
  • An external source list in the Project Settings (see example above)
  • The external source list must define the source "One.wav", "Four.wav" and "Five.wav" (implicitly converted in "One.wem", "Four.wem" and "Five.wem" respectively).
    AkExternalSourceInfo sources[3];
    
    sources[0].iExternalSrcCookie = AK::SoundEngine::GetIDFromString("Extern_1st_number");
    sources[0].szFile = AKTEXT("Five.wem");
    sources[0].idCodec = AKCODECID_PCM;
    
    sources[1].iExternalSrcCookie = AK::SoundEngine::GetIDFromString("Extern_2nd_number");      
    sources[1].szFile = AKTEXT("One.wem");
    sources[1].idCodec = AKCODECID_PCM;         
        
    sources[2].iExternalSrcCookie = AK::SoundEngine::GetIDFromString("Extern_3rd_number");      
    sources[2].szFile = AKTEXT("Four.wem");
    sources[2].idCodec = AKCODECID_VORBIS;  //The codec can be different for each source, if needed
    
    AK::SoundEngine::PostEvent( "Play_MyExternalSequence", 2, 0, NULL, 0, 3, sources );