Hi Nils,
Well I'm glad to read you with so much questions
nphuma wrote:My guess would be that I need to query for remote devices, find the one I'm interested in, then query that for in- and outputs and connect myself. So I played around with those async "Find" routines and while I am in fact finding the remote device I have no real idea how to proceed from there onwards.
You are on the right way. The "Find*" async routines are used to enumerate the devices matching your requirements on the network. Usually, enumeration is done using FDO_None flag, meaning that it is done on root devices. FDO_NoHierarchy flag can be used to perform a flat search, but it is rarely used. The result of enumeration is a set of "Remote Devices" which are proxy objects allowing to remote control/get information about a distant device.
nphuma wrote:First of all: How about the IRemoteDevice* validity in the OnCHAI_RemoteDevice_Find_Return callback? It seems to go out of scope when that message returns and I can't seem to access it afterwards. If that is the case, am I expected to trigger In- and Output queries on that device from within the callback?
Just take care about one thing: IRemoteDevice inherit from IHookedObject. The object is dereferenced at the end of the async return handler, and so destroyed if no more hooked. So if you expect to keep a list of IRemoteDevice objects, you have to "Acquire" it at the moment you store it in your list to prevent destruction on async return handler exit. And of course, you have to "Release" it once you don't need it anymore.
So, you can trigger in/out exploration from within the callback, or later... but in any case, it is a good practice to keep alive the IRemoteDevice in an application list during the process, simply because you might need it again later.
I know I have to enhance the documentation, it's a looooong job. But your mail give me motivation to do it
Here you can find this sentence:
A hooked object is always Acquired before being passed as argument to an asynchronous return handler, and then Released on return of this handler. This is to ensure that the object will not be destroyed during the notification call. An application storing a pointer to a hooked object must acquire it and release it once useless.nphuma wrote:Second, when I do that (call FindFirstInputInformation_Async from the callback and FindNextInputInformation_Async from the OnRemoteDevice_XXXInputInfo_Return callback) I do get both a MID2CPInterface and a CP2MIDIInterface pointer. However I would somehow expect one of them to be an output and rather appear in OnRemoteDevice_XXXOutputInfo_Return, but I never get anything in the FindFirst / Next Output / XXXOutput sequence, both are retrieved in the input related sequence. Given that's still perfectly OK, how do I proceed from there in order to connect them to my local device?
Calling Find*InputInformation_Async is used to enumerate inputs from a remote device. You can get input list from a CP2MIDI device, or a HybridMIDI device... not from a MIDI2CP device.
You can find some clue from
here.
A MIDI2CP device is used to translate MIDI to CopperLan, so it has a set of 18 outputs (1 per MIDI channel, 1 for clock messaging, 1 for SysEx and not channel related messages).
A CP2MIDI device is doing the reverse job, it has 17 inputs (1 for each MIDI channel, and 1 for everything not channel related).
A HybridMIDI is a combination of both.
Knowing that, if you want to bind a virtual MIDI cable between both, and since the in/out structure is well-known, you can do it without having to enumerate them. The virtual MIDI cable patching is:
MIDI2CP:Out(0)->CP2MIDI:In(0) Clock
MIDI2CP:Out(1)->CP2MIDI:In(0) Sysex and no channel, sharing the same input than Clock on the target.
MIDI2CP:Out(2->17)->CP2MIDI:In(1->16) Channel to channel patching.
So to perform this, two cases:
- you are expecting to add destination to a remote device's output (related to a MIDI2CP or HybridMIDI device): you just have to call AddDestination on this remote device pointer, giving the output ID (from 0 to 17) and the target endpoint (made from the target device ID and the related input ID).
- you want to add a destination to a local device (you MIDI2CP application is self-connecting to the target device), just call AddDestination from the right output pointer (you can get it using GetOutputFromID on the local device)
Is it clear enough? feel free to call me again if I missed something in your request...
nphuma wrote:Finally I'm afraid I found another problem in CopperLan (you'll start to hate me soon..).....
No problem, you are just the first to report these issues
It's a good point for us! We have tested CopperLan against a lot of systems and configurations, but it's impossible to cover any use case unfortunately.
I'll check if we can make a Pro-Tools debugging session. But in the meantime, I'm thinking about a potential issue with other program creating/handling MIDI ports. By default, CopperLan is configured to handle automatically MIDI ports. It means that these ports are hooked by CopperLan, and so becomes invalid for other applications. Windows does not allow multiple application to open the same MIDI port unfortunately... so if CopperLan is already handling a MIDI port, other application becomes unable to open it.
The CopperLan MIDI auto-handling behavior can be disabled through the Editor, entering in the "MIDI device" related to your computer, "MIDI Settings", "MIDI port auto-handling" parameter. Can you please try again ensuring that this parameter is off, then check that MIDI ports are off in the "MIDI to CP Interface" and "CP to MIDI interface". A reboot might be necessary depending on the MIDI port status and the Pro-Tools ability to handle it again or not.
Thanks again for your feedback and questions,
/Phil