AAX SDK  2.4.1
Avid Audio Extensions Development Kit

How to route and process MIDI in AAX plug-ins.

Midi Overview

DirectMidi is Avid's protocol for communication of MIDI and other timing-critical plug-in information. It is a cross-platform solution to tightly integrate the host application, audio engine, and plug-ins.

MIDI node types

There are four kinds of nodes an AAX plug-in can create. See AAX_EMIDINodeType for additional details about these node types:

Adding MIDI functionality to a plug-in

Plug-in may access MIDI data in its algorithm or data model. If plug-in needs MIDI in both places or just in the algorithm, it should add a MIDI node to the algorithm context, i.e. call AAX_IComponentDescriptor::AddMIDINode() with the appropriate node type.

//==============================================================================
// Algorithm context definitions
//==============================================================================
// Context structure
struct SMy_Alg_Context
{
[...]
AAX_IMIDINode * mMIDIInNodeP; // Local input MIDI node pointer
AAX_IMIDINode * mMIDINodeOutP; // Local output MIDI node pointer
AAX_IMIDINode * mMIDINodeTransportP; // Transport node
[...]
};
enum EDemoMIDI_Alg_PortID
{
[...]
//
// Add the MIDI node as a physical address within the context field
,eAlgPortID_MIDINodeIn = AAX_FIELD_INDEX (SDemoMIDI_Alg_Context, mMIDINodeP)
,eAlgPortID_MIDINodeOut = AAX_FIELD_INDEX (SDemoMIDI_Alg_Context, mMIDINodeOutP)
,eAlgPortID_MIDINodeTransport = AAX_FIELD_INDEX (SDemoMIDI_Alg_Context, mMIDINodeTransportP)
[...]
};
#define AAX_FIELD_INDEX(aContextType, aMember)
Compute the index used to address a context field.
Definition: AAX.h:323
Interface for accessing information in a MIDI node.
Definition: AAX_IMIDINode.h:40
// ***************************************************************************
// ROUTINE: DescribeAlgorithmComponent
// Algorithm component description
// ***************************************************************************
static void DescribeAlgorithmComponent( AAX_IComponentDescriptor * outDesc )
{
[...]
// Register MIDI nodes
err = outDesc->AddMIDINode(eAlgPortID_MIDINodeA, AAX_eMIDINodeType_LocalInput, "DemoMIDI", 0xffff); AAX_ASSERT (err == 0);
err = outDesc->AddMIDINode(eAlgPortID_MIDINodeOut, AAX_eMIDINodeType_LocalOutput, "DemoMIDIOut", 0xffff); AAX_ASSERT (err == 0);
err = outDesc->AddMIDINode(eAlgPortID_MIDINodeTransport, AAX_eMIDINodeType_Transport, "DemoMIDITrnsprt", 0xffff); AAX_ASSERT (err == 0);
[...]
}
int32_t AAX_Result
Definition: AAX.h:337
#define AAX_ASSERT(condition)
Asserts that a condition is true and logs an error if the condition is false.
Definition: AAX_Assert.h:268
@ AAX_eMIDINodeType_Transport
Transport node.
Definition: AAX_Enums.h:1020
@ AAX_eMIDINodeType_LocalOutput
Local MIDI output.
Definition: AAX_Enums.h:992
@ AAX_eMIDINodeType_LocalInput
Local MIDI input.
Definition: AAX_Enums.h:972
Description interface for an AAX plug-in component.
Definition: AAX_IComponentDescriptor.h:47
virtual AAX_Result AddMIDINode(AAX_CFieldIndex inFieldIndex, AAX_EMIDINodeType inNodeType, const char inNodeName[], uint32_t channelMask)=0
Adds a MIDI node field to the plug-in's context.

If MIDI data is needed in the plug-in's data model only, plug-in should describe MIDI node with AAX_IEffectDescriptor::AddControlMIDINode().

// ***************************************************************************
// ROUTINE: GetPlugInDescription
// ***************************************************************************
static AAX_Result GetPlugInDescription( AAX_IEffectDescriptor * outDescriptor )
{
[...]
// Register MIDI nodes
err = outDesc->AddControlMIDINode('linp', AAX_eMIDINodeType_LocalInput, "DemoMIDI", 0xffff); AAX_ASSERT (err == 0);
err = outDesc-> AddControlMIDINode('lout', AAX_eMIDINodeType_LocalOutput, "DemoMIDIOut", 0xffff); AAX_ASSERT (err == 0);
err = outDesc-> AddControlMIDINode('tran', AAX_eMIDINodeType_Transport, "DemoMIDITrnsprt", 0xffff); AAX_ASSERT (err == 0);
[...]
return err;
}
Description interface for an effect's (plug-in type's) components.
Definition: AAX_IEffectDescriptor.h:50
Note
These two types of MIDI nodes can't be used together in the same plug-in's effect.

Using MIDI in a plug-in algorithm

Like with other algorithm context ports, data in MIDI nodes is directly available in the plug-in's algorithm process function. Here is an example from the DemoMIDI_NoteOn sample plug-in:

template<int kNumChannelsIn, int kNumChannelsOut>
void
DemoMIDI_AlgorithmProcessFunction (
SDemoMIDI_Alg_Context * const inInstancesBegin [],
const void * inInstancesEnd)
{
[...]
// Setup MIDI In node pointers
AAX_IMIDINode* midiNodeIn = instance->mMIDINodeP;
AAX_CMidiStream* midiBufferIn = midiNodeIn->GetNodeBuffer();
AAX_CMidiPacket* midiBufferInPtr = midiBufferIn->mBuffer;
uint32_t packets_count_in = midiBufferIn->mBufferSize;
// Setup MIDI Out node pointers
AAX_IMIDINode* midiNodeOut = instance->mMIDINodeOutP;
AAX_CMidiStream* midiBufferOut = midiNodeOut->GetNodeBuffer();
AAX_CMidiPacket* midiBufferOutPtr = midiBufferOut->mBuffer;
uint32_t packets_count_out = midiBufferOut->mBufferSize;
// Setup MIDI Transport node pointers
AAX_IMIDINode* midiTransport = instance->mMIDINodeTransportP;
AAX_ITransport * transport = midiTransport->GetTransport();
bool transport_is_playing = false;
if (transport)
transport->IsTransportPlaying(&transport_is_playing);
if(transport_is_playing)
{
//
// While there are packets in the node
while (packets_count_in > 0)
{
midiBufferOutPtr = midiBufferInPtr; // Copy the packet from the input MIDI node
// to the output MIDI node
midiBufferOutPtr->mTimestamp = timeStamp; // Set the MIDI time stamp
midiNodeOut->PostMIDIPacket(midiBufferOutPtr); // Post the MIDI packet
midiBufferOut->mBufferSize = packets_count_in;
midiBufferInPtr++;
packets_count_in--;
}
}
[...]
}
#define AAX_CALLBACK
Definition: AAX.h:285
Packet structure for MIDI data.
Definition: AAX.h:637
uint32_t mTimestamp
This is the playback time at which the MIDI event should occur, relative to the beginning of the curr...
Definition: AAX.h:638
MIDI stream data structure used by AAX_IMIDINode.
Definition: AAX.h:662
AAX_CMidiPacket * mBuffer
Pointer to the first element of the node's buffer.
Definition: AAX.h:664
uint32_t mBufferSize
The number of AAX_CMidiPacket objects contained in the node's buffer.
Definition: AAX.h:663
virtual AAX_ITransport * GetTransport()=0
Returns a transport object.
virtual AAX_Result PostMIDIPacket(AAX_CMidiPacket *packet)=0
Posts an AAX_CMidiPacket to an output MIDI node.
virtual AAX_CMidiStream * GetNodeBuffer()=0
Returns a MIDI stream data structure.
Interface to information about the host's transport state.
Definition: AAX_ITransport.h:45
virtual AAX_Result IsTransportPlaying(bool *isPlaying) const =0
CALL: Indicates whether or not the transport is playing back.

Also data from the MIDI nodes that were described with AAX_IComponentDescriptor::AddMIDINode() can be accessed via AAX_CEffectParameters::UpdateMIDINodes() method. This method provides an AAX_CMidiPacket. Because the MIDI packet structure does not identify the associated MIDI stream's type (input, output, global, or transport) this method also provides an index into the plug-in's algorithm context structure which can be used to identify the semantics of the MIDI packet.

Accessing MIDI in the plug-in data model

A plug-in may access MIDI data in its data model via the AAX_CEffectParameters::UpdateMIDINodes() or AAX_CEffectParameters::UpdateControlMIDINodes() methods. Both of these methods provide an AAX_CMidiPacket. Because the MIDI packet structure does not identify the associated MIDI stream's type (input, output, global, or transport) UpdateMIDINodes method also provides an index into the plug-in's algorithm context structure which can be used to identify the semantics of the MIDI packet, while UpdateControlMIDINodes provides MIDI node ID for the same reason.

AAX_Result DemoMIDI_Parameters::UpdateMIDINodes ( AAX_CFieldIndex inFieldIndex, AAX_CMidiPacket& inPacket )
{
if (eAlgPortID_MIDINodeIn == inFieldIndex)
{
if ( (inPacket.mData[0] & 0xF0) == 0x90 )
{
if ( inPacket.mData[2] == 0x00 )
{
// Note Off
}
else
{
// Note On
}
}
}
return AAX_SUCCESS;
}
AAX_CIndex AAX_CFieldIndex
Not used by AAX plug-ins (except in AAX_FIELD_INDEX macro)
Definition: AAX.h:349
@ AAX_SUCCESS
Definition: AAX_Errors.h:39
unsigned char mData[4]
The MIDI message itself. Each array element is one byte of the message, with the 0th element being th...
Definition: AAX.h:640
Note
Only one of the UpdateMIDINodes and UpdateControlMIDINodes can be used in the single plug-in's effect at a time. If plug-in uses MIDI nodes described with AddMIDINode function, then only UpdateMIDINodes method can be used to receive MIDI messages. Otherwise UpdateControlMIDINodes should be used.
Collaboration diagram for MIDI: