Version

menu_open
Wwise SDK 2023.1.8
Integration Details - MIDI

Introduction

The SDK API provides functions to post MIDI events to the sound engine. The types of MIDI events that may be posted are:

  • note-on event.
  • note-off event.
  • and continuous controller (CC) event.

For MIDI events to produce sound they must have a target synthesizer. The synthesizer is a collection of Wwise objects created by the Wwise user in the project's Actor-Mixer hierarchy. Note-on events will typically play the targeted Actor-Mixer object or one of its descendants. If played, the Actor-Mixer object will stop once it has:

  • reached the end of its source if it is not set to loop,
  • or a corresponding note-off event (same note and channel) is sent to the same target.

Integrating MIDI Events in Your Game

The AK::SoundEngine::PostMIDIOnEvent "PostMIDIOnEvent" function queues MIDI events in the sound engine. The function takes as arguments:

  • the MIDI event.
  • an Event ID.
  • a Game Object ID.
  • a Playing ID.

The sound engine groups posted MIDI events into sequences. Each sequence is identified by the following:

  • a Game Object ID; a function parameter,
  • a Playing ID; a function parameter,
  • a Wwise Object ID; obtained from the target object of each play action in the event corresponding to event ID. See Integrating Events for more details regarding Events.

Thus, it is possible to post the same MIDI event(s) to multiple targets simultaneously. For example, suppose we have:

  • event EV1, which has play actions for both Wwise Objects W0 and W1,
  • event EV2, which has a play action for Wwise Object W0.

If we post MIDI event ME1 to EV1 with Game Object GO, then the sound engine will add MIDI event ME1 to the MIDI sequences W0-GO-PID1 and W1-GO-PID1, where PID1 is the Playing ID returned by PostMIDIOnEvent. If we then post MIDI event ME2 to event EV2, the sound engine will add MIDI event ME2 to the MIDI sequence W0-GO-PID2.

Calls to AK::SoundEngine::PostMIDIOnEvent add MIDI events to the MIDI sequences. However, no processing is done until the AK::SoundEngine::RenderAudio function has been called. Each call to AK::SoundEngine::RenderAudio processes the message queue, and may produce any number of audio frames; depending on how much time has elapsed since the previous call to RenderAudio. For each frame processed by RenderAudio, the sound engine advances all MIDI sequences by one frame.

MIDI Event Timing

The moment at which a MIDI event is executed is determined by the following factors:

  • the moment at which it was queued (via PostMIDIOnEvent),
  • the event's member AkMIDIPost::uOffset,
  • the argument in_bAbsoluteOffsets provided to the call to PostMIDIOnEvent.

If in_bAbsoluteOffsets is false, the MIDI event is executed uOffset samples from the time the PostMIDIOnEvent message is read from the sound engine's message queue (see Updating MIDI Sequences). If in_bAbsoluteOffsets is true, the MIDI event is executed uOffset samples in absolute time. The current absolute time is obtained via a call to AK::SoundEngine::GetSampleTick.

Note: The duration of a sample can be determined from the sound engine's audio settings, via a call to AK::SoundEngine::GetAudioSettings.

MIDI Event Sequences - Playing ID

A call to PostMIDIOnEvent combines all posted MIDI events into a MIDI sequence. As mentioned previously, a MIDI sequence is identified by:

  • a Playing ID,
  • a Game Object ID,
  • an Event ID. A sequence's Playing ID is created by a call to PostMIDIOnEvent with in_playingID set to AK_INVALID_PLAYING_ID. The Playing ID is used in subsequent calls to PostMIDIOnEvent to add MIDI events to the sequence. The sequence is as follows:
  • A first call to PostMIDIOnEvent creates the MIDI sequence. The function argument in_playingID is set to AK_INVALID_PLAYING_ID. The function returns the Playing ID PID.
  • A subsequent call to PostMIDIOnEvent is made to add events to the sequence. The function argument in_playingID is set to PID.

The Playing ID returned by PostMIDIOnEvent determines if the events were posted to the intended sequence. If the returned Playing ID:

  • matches in_playingID, then the events were added to the intended sequence.
  • does not match in_playingID, then the events were added to a newly created sequence.
  • is AK_INVALID_PLAYING_ID, then an error occurred, and the events were not added to any sequence.

A new sequence, different from the one specified, may be created if:

  • the sequence (Playing ID) did not exist,
  • the sequence was created using a different Game Object or Event,
  • the sequence no longer exists because all MIDI events have been executed and all playing sounds have ended.

Updating MIDI Sequences

It is important that each a MIDI sequence be played by the sound engine at the exact time intended by the application. There are two ways a MIDI sequence may be posted to the sound engine.

If the entire MIDI sequence is known, and it is known that the timing of the MIDI sequence will not change, then the entire MIDI sequence may be posted with one call to AK::SoundEngine::PostMIDIOnEvent.

However if that is not the case, then the MIDI sequence will have to be updated at each frame. The AK::SoundEngine::PostMIDIOnEvent function may be called at any moment, and anywhere in the application. However, calling this function in a thread other than the main audio thread may lead to synchronization issues. Calls to AK::SoundEngine::PostMIDIOnEvent only post the events in the sound engine's message queue. The message queue is processed during a call to AK::SoundEngine::RenderAudio, and such a call may lead to any number of processed audio frames. To ensure proper synchronization, it is recommended that the application register a global callback function as follows:

  • AK::SoundEngine::RegisterGlobalCallback( &MyCallbackFunction, AkGlobalCallbackLocation_PreProcessMessageQueueForRender );

The registered function will be called by the sound engine at each audio frame. The application can use the callback function to keep track of audio frames processed by the sound engine. Thus, posting MIDI events in the callback function will ensure proper synchronization.

Stopping a MIDI Sequence

Call the AK::SoundEngine::StopMIDIOnEvent "StopMIDIOnEvent" function to stop a MIDI sequence. The function accepts a Playing ID, an Event ID and a Game Object ID as parameters. Any of these parameters can be set to their invalid values to act as wild cards. Thus, if all arguments are set to invalid then all MIDI sequences are stopped.

A call to this function will clear the MIDI sequence(s) and stop any playing sounds.

For examples of integrating MIDI, refer to Quick Start Sample Integration - MIDI.


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