| AAX SDK 2.6.1 Avid Audio Extensions Development Kit

- Welcome
- Manual
- Classes
- Files
- Lists
- Support

Loading...
Searching...
No Matches
MIDI
AAX SDK Manual » Additional AAX features

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:

- AAX_eMIDINodeType_LocalInput
- AAX_eMIDINodeType_LocalOutput
- AAX_eMIDINodeType_Global
- AAX_eMIDINodeType_Transport

# 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)
[...]
};
AAX_FIELD_INDEX
#define AAX_FIELD_INDEX(aContextType, aMember)
Compute the index used to address a context field.
Definition: AAX.h:320
AAX_IMIDINode
Interface for accessing information in a MIDI node.
Definition: AAX_IMIDINode.h:37
// ***************************************************************************
// ROUTINE: DescribeAlgorithmComponent
// Algorithm component description
// ***************************************************************************
static void DescribeAlgorithmComponent( AAX_IComponentDescriptor * outDesc )
{
AAX_Result err;
[...]
// 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
@ AAX_eMIDINodeType_Transport
Transport node.
Definition: AAX_Enums.h:1041
AAX_eMIDINodeType_LocalOutput
@ AAX_eMIDINodeType_LocalOutput
Local MIDI output.
Definition: AAX_Enums.h:1011
AAX_eMIDINodeType_LocalInput
@ AAX_eMIDINodeType_LocalInput
Local MIDI input.
Definition: AAX_Enums.h:991
AAX_Result
int32_t AAX_Result
Definition: AAX.h:334
AAX_ASSERT
#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_IComponentDescriptor
Description interface for an AAX plug-in component.
Definition: AAX_IComponentDescriptor.h:44
AAX_IComponentDescriptor::AddMIDINode
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 )
{
AAX_Result err;
[...]
// 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;
}
AAX_IEffectDescriptor
Description interface for an effect's (plug-in type's) components.
Definition: AAX_IEffectDescriptor.h:47

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
AAX_CALLBACK
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--;
}
}
[...]
}
AAX_CALLBACK
#define AAX_CALLBACK
Definition: AAX.h:282
AAX_CMidiPacket
Packet structure for MIDI data.
Definition: AAX.h:636
AAX_CMidiPacket::mTimestamp
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:637
AAX_CMidiStream
MIDI stream data structure used by AAX_IMIDINode.
Definition: AAX.h:661
AAX_CMidiStream::mBuffer
AAX_CMidiPacket * mBuffer
Pointer to the first element of the node's buffer.
Definition: AAX.h:663
AAX_CMidiStream::mBufferSize
uint32_t mBufferSize
The number of AAX_CMidiPacket objects contained in the node's buffer.
Definition: AAX.h:662
AAX_IMIDINode::GetTransport
virtual AAX_ITransport * GetTransport()=0
Returns a transport object.
AAX_IMIDINode::GetNodeBuffer
virtual AAX_CMidiStream * GetNodeBuffer()=0
Returns a MIDI stream data structure.
AAX_IMIDINode::PostMIDIPacket
virtual AAX_Result PostMIDIPacket(AAX_CMidiPacket *packet)=0
Posts an AAX_CMidiPacket to an output MIDI node.
AAX_ITransport
Interface to information about the host's transport state.
Definition: AAX_ITransport.h:53
AAX_ITransport::IsTransportPlaying
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
@ AAX_SUCCESS
Definition: AAX_Errors.h:36
AAX_CFieldIndex
AAX_CIndex AAX_CFieldIndex
Not used by AAX plug-ins (except in AAX_FIELD_INDEX macro)
Definition: AAX.h:346
AAX_CMidiPacket::mData
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:639

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: