In DirectMusic parlance, a tool is an object that intercepts messages and handles them in some way. The tool might alter the message and then pass it on to the next tool, or free the message, or send a new message based on information in the old one.
DirectMusic has an output tool that is normally the last in line to receive messages. It is this tool that converts performance messages to standard MIDI messages and streams them to the synthesizer. Other tools are implemented by the application or obtained from libraries.
To implement a tool you must first create an object that supports the IDirectMusicTool interface. The object's implementation of the IDirectMusicTool methods will determine what messages get processed by the tool and what work is performed on these messages.
All tools other than the output tool are normally collected in graphs, and even if your application is using only one other tool, you should create a DirectMusicGraph to contain it. You then add this graph to a segment or the performance. Graphs provide a convenient mechanism for directing messages from one tool to another.
When the performance engine is playing a segment, it gives each tool in the segment graph and then each tool in the performance graph a chance to process each message. After a tool processes a message, it should call the IDirectMusicGraph::StampPMsg method (obtaining the IDirectMusicGraph pointer from the pGraph member of the DMUS_PMSG structure) to stamp the message with a pointer to the next tool, if any, that is to receive it. Then the tool puts the message back in the pipeline.
Tools process messages in a high-priority thread. Do not call time-consuming functions, such as those involving graphics or file input/output, from within a tool's IDirectMusicTool::ProcessPMsg method. If a tool needs to trigger an action, it should do so by signaling a different thread, perhaps the application's main thread.
When implementing the methods of IDirectMusicTool, you must take care not to create circular references to parent objects. Circular references come about when one object creates another and the child keeps an additional reference to the parent. For example, suppose a tool creates a new reference to the graph passed into its IDirectMusicTool::Init method. If the tool fails to release this reference, there is a problem when the segment attempts to release the graph. Because the tool still has a reference to the graph, the graph is not fully released; and because the graph has a reference to the tool, the tool cannot be released either.
For a more detailed look at how to set up a tool, see Tutorial 2: Using Tools.