AAX SDK 2.8.0
Avid Audio Extensions Development Kit
Loading...
Searching...
No Matches

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

MIDI Overview

AAX plugins create MIDI nodes. MIDI nodes define points where the plugin can send or receive MIDI data. The data at these nodes is represented as a sequence of AAX MIDI packet data structures. The AAX host manages connections between these nodes and other points in the system. The host also performs conversion between raw MIDI data and AAX MIDI packets.

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:333
Interface for accessing information in a MIDI node.
Definition: AAX_IMIDINode.h:50
// ***************************************************************************
// 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);
[...]
}
@ AAX_eMIDINodeType_Transport
Transport node.
Definition: AAX_Enums.h:1087
@ AAX_eMIDINodeType_LocalOutput
Local MIDI output.
Definition: AAX_Enums.h:1057
@ AAX_eMIDINodeType_LocalInput
Local MIDI input.
Definition: AAX_Enums.h:1037
int32_t AAX_Result
Definition: AAX.h:347
#define AAX_ASSERT(condition)
Asserts that a condition is true and logs an error if the condition is false.
Definition: AAX_Assert.h:281
Description interface for an AAX plug-in component.
Definition: AAX_IComponentDescriptor.h:57
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:60
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
// NOTE: See warning at AAX_IMIDINode::GetTransport() regarding use of this interface
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:295
Packet structure for MIDI data.
Definition: AAX.h:649
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:650
MIDI stream data structure used by AAX_IMIDINode.
Definition: AAX.h:674
AAX_CMidiPacket * mBuffer
Pointer to the first element of the node's buffer.
Definition: AAX.h:676
uint32_t mBufferSize
The number of AAX_CMidiPacket objects contained in the node's buffer.
Definition: AAX.h:675
virtual AAX_ITransport * GetTransport()=0
Returns a transport object.
virtual AAX_CMidiStream * GetNodeBuffer()=0
Returns a MIDI stream data structure.
virtual AAX_Result PostMIDIPacket(AAX_CMidiPacket *packet)=0
Posts an AAX_CMidiPacket to an output MIDI node.
Interface to information about the host's transport state.
Definition: AAX_ITransport.h:66
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_SUCCESS
Definition: AAX_Errors.h:49
AAX_CIndex AAX_CFieldIndex
Not used by AAX plug-ins (except in AAX_FIELD_INDEX macro)
Definition: AAX.h:359
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:652
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.

Support functions

Additional definitions and support functions for MIDI in AAX are available in AAX_MIDIUtilities.h

Collaboration diagram for MIDI: