Version

menu_open
Wwise SDK 2023.1.2
Integrating Markers

Introduction

Markers are identifiers that are inserted in a WAV file and used to tag a position in the waveform. These markers are usually created in a WAV editor application, such as SoundForge®, Adobe® Audition®, or CueTool.

An application can use these markers to be notified when a certain position is reached during playback. For example, you could use this information to synchronize content drawing with the audio being played, or to know which file is being played by a random container so that the correct subtitles can be displayed in your game.

Note: Using Wwise marker notifications is usually the most efficient way to integrate a lip-sync or subtitle solution.

Working with the.wav File Format

Chunks are data storage units used to store cue points, or data about cue points. Cue points are points of interest flagged in .wav format files.

Cue Chunks

The cue chunk format is used to store marker positions that indicate points of interest in a .wav file.

Offset Bytes Description Value
0x00 4 Chunk ID "cue " (0x63756520)
0x04 4 Chunk Data Size Depends on the number of cue points
0x08 4 Num Cue Points Number of cue points in list
0x0c Cue Points
#define CueID 'cue ' /* chunk ID for cue chunk */
typedef struct {
ID chunkID;
long chunkSize;
long dwCuePoints;
CuePoint points[];
} CueChunk;
typedef struct {
long dwIdentifier;
long dwPosition;
ID fccChunk;
long dwChunkStart;
long dwBlockStart;
long dwSampleOffset;
} CuePoint;

List Chunks

A list chunk is a container inside the .wav file which contains subchunks. The associated data list chunk (adtl) format is used to store labels, notes, and text associated to a cue point.

Offset Bytes Description Value
0x00 4 Chunk ID "list" (0x6C696E74)
0x04 4 Chunk Data Size Depends on contained sub-chunks
0x08 4 Type ID "adtl" (0x6164746C)
0x0c SubChunks start here

Label Sub-Chunks

The label sub-chunk format is used to store a string associated with a cue point. It should be inside the associated data list chunk.

Offset Bytes Description Value
0x00 4 Chunk ID "labl" (0x6C61626C)
0x04 4 Chunk Data Size Depends on size of text
0x08 4 Cue Point ID Refers to cue chunk dwIdentifier
0x0c Label (variable-size text)

Working with Source Plug-ins

Source plug-ins can also generate marker notifications.

Within a source plug-in, AK::IAkPluginServiceMarkers::CreateMarkerNotificationService() can be used to create an instance of AK::IAkPluginServiceMarkers::IAkMarkerNotificationService. AK::IAkPluginServiceMarkers::IAkMarkerNotificationService::SubmitMarkerNotifications() can then be used to send marker notifications to the game using the AkAudioMarker structure.

{
AkUInt32 dwIdentifier; ///< Identifier.
AkUInt32 dwPosition; ///< Position in the audio data in sample frames.
const char* strLabel; ///< Label of the marker taken from the file.
AkUInt32 dwLabelSize; ///< Length of label read the from the file + terminating null character.
};

Marker Generator Source Plug-in Example

Below is an example of a source plug-in that generates marker notifications.

class MyMarkerGeneratorSourcePlugin : public IAkSourcePlugin
{
private:
IAkSourcePluginContext* m_pSourcePluginContext{};
IAkPluginServiceMarkers::IAkMarkerNotificationService* m_pMarkerNotificationService{};
AkUInt32 m_uElapsedSamples{};
static constexpr AkUInt32 g_uPayloadSize{ 64 };
char m_Payload[g_uPayloadSize]{};
// ...
public:
IAkPluginMemAlloc * in_pAllocator, ///< Interface to the memory allocator to be used by the plug-in
IAkSourcePluginContext * in_pSourcePluginContext, ///< Interface to the source plug-in's context
IAkPluginParam * in_pParams, ///< Interface to the plug-in parameters
AkAudioFormat & io_rFormat ///< Audio format of the output data to be produced by the plug-in (mono native by default)
) override
{
m_pSourcePluginContext = in_pSourcePluginContext;
m_pMarkerNotificationService = AK_GET_PLUGIN_SERVICE_MARKERS(m_pSourcePluginContext)->CreateMarkerNotificationService(m_pSourcePluginContext);
return AK_Success;
}
IAkPluginMemAlloc * in_pAllocator ///< Interface to memory allocator to be used by the plug-in
) override
{
AK_GET_PLUGIN_SERVICE_MARKERS(m_pSourcePluginContext)->TerminateMarkerNotificationService(m_pMarkerNotificationService);
return AK_Success;
}
void Execute(
AkAudioBuffer * io_pBuffer ///< In/Out audio buffer data structure (in-place processing)
) override
{
static constexpr AkUInt32 uNumMarkers{ 1 };
AkAudioMarker markers[uNumMarkers];
markers[0].dwIdentifier = 'mrkr';
markers[0].dwPosition = m_uElapsedSamples;
markers[0].strLabel = m_Payload;
markers[0].dwLabelSize = g_uPayloadSize;
const AkUInt32 offsetsInBuffer[uNumMarkers]{ 0 };
m_pMarkerNotificationService->SubmitMarkerNotifications(markers, offsetsInBuffer, uNumMarkers);
// advance the position of the markers
m_uElapsedSamples += io_pBuffer->MaxFrames();
}
// ...
};

How to Use Marker Notifications

Here are instructions on how to design your application so that it receives the marker notifications:

  • When posting a play event, you should add the AK_Marker flag to in_uiFlags. If you also want to have the end of event notification, you should use AK_EndOfEvent | AK_Marker since the flags are bitwise exclusive.
AkUniqueID in_eventID, // Unique ID of the event
AkGameObjectID in_gameObjectID, // Associated game object ID
AkUInt32 in_uFlags = 0, // Bitmask: see AkCallbackType
AkCallbackFunc in_pfnCallback = NULL, // Callback function
void * in_pCookie = NULL // Callback cookie that will be sent to the callback function
// along with additional information
);
  • Your callback function must have the following form:
static void MarkersCallback(
AkCallbackType in_eType, // Type of callback reason, in this case AK_Marker on
// reception of a marker event.
AkCallbackInfo* in_pCallbackInfo // Pointer to callback information structure, in this case
// AkMarkerCallbackInfo*.
)
  • When your callback function is called, you first need to check what type of notification is passed. For example, if you only want to process AK_Marker notifications, you should return when any other event type is received.
  • Based on the type of notification, you can typecast in_pCallbackInfo into the appropriate information structure type. For AK_Marker notification, it is AkMarkerCallbackInfo.
// Callback information structure corresponding to AK_Marker.
{
AkUInt32 uIdentifier; // Cue point identifier
AkUInt32 uPosition; // Position in the cue point (unit: sample frames)
const char* strLabel; // Label of the marker (null-terminated)
AkUInt32 uLabelSize; // Size of the label string (including the terminating null character)
};
  • Make sure you copy the contents of the strLabel string member if you plan to reference it later, as the pointer can be invalidated after the callback returns.
See also
Quick Start Sample Integration - Events

Notification Latency

Currently, notification is sent when the buffer is passed down to the hardware. This means that there is a certain constant delay between when the notification is sent and the marker is encountered. This gives your application enough time to gather the information on the marker and process it before the sound associated with that marker is really played.

Note that this delay is platform-dependent.

Callback Thread

The callbacks for markers, as well as for the end of event notification, are done from the sound engine's main thread. This means that your application should gather all the information it needs from the notification and return immediately. If any processing needs to be done, it should be performed in a separate thread once the relevant information has been copied from the notification.

If the application holds the thread for too long, the sound engine might fall into an underrun state and the output might stop playing.

Note
The label string from the callback function should be copied because the referenced data will be released by the sound engine after the callback function returns.

Wwise Capture Log and Markers

The Wwise Profiler can display marker notifications from the sound engine. In order to do so, you must ensure that the Markers Notification Data option in the Profiler Settings dialog is enabled. When a marker is reached and a notification has been requested, a new line will appear in the Capture Log. Note that these notifications can be filtered out if needed by clearing the Markers Notification Data check box in the Capture Log Filter dialog.

See also
Integration Details - Events
Defines the parameters of a marker.
Definition: AkAudioMarker.h:16
const char * strLabel
Label of the marker (null-terminated)
Definition: AkCallback.h:119
AkUInt32 dwIdentifier
Identifier.
Definition: AkAudioMarker.h:17
AkUInt64 AkGameObjectID
Game object ID.
Definition: AkTypes.h:142
AKRESULT
Standard function call result.
Definition: AkTypes.h:213
AkUInt32 dwLabelSize
Length of label read the from the file + terminating null character.
Definition: AkAudioMarker.h:20
AkCallbackType
Type of callback. Used as a bitfield in methods AK::SoundEngine::PostEvent() and AK::SoundEngine::Dyn...
Definition: AkCallback.h:48
AKSOUNDENGINE_API AKRESULT Init(const AkCommSettings &in_settings)
#define NULL
Definition: AkTypes.h:46
@ AK_Success
The operation was successful.
Definition: AkTypes.h:215
AKSOUNDENGINE_API void Term()
AkUInt32 uIdentifier
Cue point identifier.
Definition: AkCallback.h:117
AkUInt32 AkUniqueID
Unique 32-bit ID.
Definition: AkTypes.h:134
AkUInt32 uLabelSize
Size of the label string (including the terminating null character)
Definition: AkCallback.h:120
AkUInt32 uPosition
Position in the cue point (unit: sample frames)
Definition: AkCallback.h:118
Type
IDs of temporary memory pools used by the sound engine.
Definition: AkMemoryMgr.h:336
void(* AkCallbackFunc)(AkCallbackType in_eType, AkCallbackInfo *in_pCallbackInfo)
Definition: AkCallback.h:266
const char * strLabel
Label of the marker taken from the file.
Definition: AkAudioMarker.h:19
#define AK_GET_PLUGIN_SERVICE_MARKERS(plugin_ctx)
Definition: IAkPlugin.h:1756
uint32_t AkUInt32
Unsigned 32-bit integer.
AkUInt32 dwPosition
Position in the audio data in sample frames.
Definition: AkAudioMarker.h:18
AKSOUNDENGINE_API AkPlayingID PostEvent(AkUniqueID in_eventID, AkGameObjectID in_gameObjectID, AkUInt32 in_uFlags=0, AkCallbackFunc in_pfnCallback=NULL, void *in_pCookie=NULL, AkUInt32 in_cExternals=0, AkExternalSourceInfo *in_pExternalSources=NULL, AkPlayingID in_PlayingID=AK_INVALID_PLAYING_ID)
Defines the parameters of an audio buffer format.
Definition: AkCommonDefs.h:63
AkUInt32 AkPlayingID
Playing ID.
Definition: AkTypes.h:137
AkForceInline AkUInt16 MaxFrames() const
Definition: AkCommonDefs.h:643

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise