I have gotten audio and midi to co-exist happily creating Audio Units of type "Music Effect", though it did take some time. They way I understand it, as far as the AU class hierarchy goes, these are just AU's configured to respond to both MIDI and I/O Render dispatch calls. I also attempted to support both the old and new versions for OS X, since many AU hosts still needed the v1 info. If you don't want to support both, you don't have to do as much as I did.
The first part of this is setting the COMP_TYPE to kAudioUnitType_MusicEffect for the .r file and in the AudioComponetns type value to aumf in the plist. Again, as the document states the .r file should not be necessary, but I have found some hosts expected it.
The next thing is putting the correct factory type into the AUDIOCOMPONENT_ENTRY macro. If you search through the special AU factory class (the first argument to the macro) you will see it really just returns the callbacks for all that you need: AUBase's Render calls, Midi events, sysex, etc. I use AUMusicDeviceFactory which uses the AUMusicLookup struct. You may want to use a different factory. The caveat is: the methods you implement must match the factory/lookup combo. The Apple supplied derived classes do this for you and arguably hide this detail a bit...
I then derived directly from AUBase and implement the needed/expected methods of the above type. By bypassing the supplied audio unit derived classes, I was able to get the exact behavior I wanted. This involved two sets of overloads to work with v1 and v2 hosts:
For v2 hosts, checkout AUPluginDispatch.cpp. This has the static functions that call into your AU via some casting macros. For example, overriding AUBase::MIDIEvent() got me MIDI events, and your custom Render() method should get called by the DoRender in AUMethodRender(). Side Note: You may notice that the AUBase implementation of the MIDI methods returns an error. This error only gets returned to hosts that think you implemented those methods. They think you implemented it because you are one of the AU types that can receive MIDI via the factory type.
Overriding ComponentEntryDispatch() is required to get MIDI added to AUBase for older hosts, I believe. In it I add a switch on kMusicDeviceMIDIEventSelect, kMusicDeviceSysExSelect, and then for any other case (i.e. default:) I pass on the incoming method arguments to AUBase::ComponentEntryDispatch() and return that result. However, I think I abandoned this a year or two ago, as most hosts seem to have upgraded by now. I recently wrapped that override in the macro CA_USE_AUDIO_PLUGIN_ONLY so that it doesn't end up in the newer model or on iOS.
One last fun note: After spelunking and debugging to figure this all out, I was able to create better unit tests for my AU's; one's that didn't require a real host but my own stubbed out version calling into the correct dispatch calls with different inputs and checking the different outputs.