Nested groups?

Nested groups?

Postby arakula » 15 Mar 2012, 22:10

Hi,

I'm trying to find out the best way to "marry" VSTHost with CopperLan. My current problem is that I have the following structure (just an excerpt to show where I'm getting at):
Code: Select all
VSTHost
  |
  +--- Engine ----+--- BPM
  |               +--- Transport State
  |               +--- ... other Engine-specific things
  |
  +--- Track 1 ---+--- Performance ---+--- PlugIn 1 ---+--- Parameter 1
  |               |                   |                +--- Parameter 2
  |               |                   |                +--- ...
  |               |                   |                +--- Parameter n
  |               |                   +--- PlugIn 2 ---+--- Parameter 1
  |               |                   |                +--- Parameter 2
  |               |                   |                +--- ...
  |               |                   |                +--- Parameter n
  |               |                   +--- ...
  |               |                   +--- PlugIn n ---+--- Parameter 1
  |               |                   |                +--- Parameter 2
  |               |                   |                +--- ...
  |               |                   |                +--- Parameter n
  |               |                   +--- other Performance-specific things
  |               +--- ... other Track-specific things
  |
  +--- Track 2 ---+--- Performance ---+--- PlugIn 1 ---+--- Parameter 1
  |               |                   |                +--- Parameter 2
  |               |                   |                +--- ...
  |               |                   |                +--- Parameter n
  |               |                   +--- ...
  |               |                   +--- PlugIn n ---+--- Parameter 1
  |               |                   |                +--- Parameter 2
  |               |                   |                +--- ...
  |               |                   |                +--- Parameter n
  |               |                   +--- other Performance-specific things
  |               +--- ... other Track-specific things
  |
  +--- ... other groups

"Tracks", in VSTHost's current incarnation, aren't really implemented; there's only one track called "Master", but I might want to expand on that some day. But even if I remove the track concept from my interface -

My problem is that I've got (potentially deeply) nested groups in this setup. Can I get that with CopperLan, or is it fixed to 1 level?
arakula
 
Posts: 29
Joined: 07 Mar 2012, 19:57

Re: Nested groups?

Postby CopperPhil » 15 Mar 2012, 22:48

No there is no limitation.

You can base your tree on multiple layers of sub-devices, each of them being able to host multiple inputs exposing multiple parameters.

Actually I advise to use only one root device per application (even it is technically possible to create multiple), just to keep some consistency, one root device representing one application on the network. A root device is created using ICHAI::Add***LocalDevice().

Then you can add sub-devices using IBaseLocalDevice::AddSub***LocalDevice() from the root device pointer, and so on from each sub-device node. The only important thing is you need to allocate a different ModuleID for each sub-device (value 0 is reserved for the root device). All the devices in a tree have the same [BrandID, ModelID, DuplicateNumber], but they are distinguished by their [ModuleID]. You are free to assign ModuleID values as you wish, just take care to avoid duplicate inside a tree.

Finally, each sub-device can expose multiple inputs with different sets of parameters. It is sometimes useful to group parameters into inputs dedicated to some section/role, such as Oscillator/Filter/Mixer...

In your case, you can create a tree based by default on VSTHost root device and Engine sub-device. Then, depending on project file loaded or user choice from the GUI you can dynamically add Tracks/Performance/Plugins sub-devices branches. Keep in mind that each device is able to expose parameters through a set of inputs. If you are making changes to the device tree while connected, you have to call ICHAI::RedeclareAllDevices each time changed are done to commit your device tree on the network.

In conclusion, you are free to create the device tree you need. The only (theoretically) limitation is 65533 (3 reserved values) devices in a tree, each of them can expose 65533 inputs, with 65533 * 65533 modifiers (it is possible to give an index to messages, providing multiple instances of the same message within a single input), same for selectors, texts...

You see, the only limitation is the system capabilities in term of RAM, processing, resources...
CopperPhil
 
Posts: 480
Joined: 30 Mar 2011, 15:02
Location: Brussels

Re: Nested groups?

Postby arakula » 19 Mar 2012, 15:07

Adding subdevices with AddSub***LocalDevice() seems clear to me now (well, I've just started to implement it, so problems may still arise). But how do I remove them (if, for example, a VST PlugIn is dropped)?

The simple solution of deleting the IBaseLocalDevice* returned by AddSubLocalDevice() sounds too simple... or is that all it needs?
arakula
 
Posts: 29
Joined: 07 Mar 2012, 19:57

Re: Nested groups?

Postby CopperPhil » 19 Mar 2012, 23:29

It's very simple: just use ICHAI::RemoveLocalDevice() :P

You can't delete IBaseLocalDevice*, it is inheriting from IObject, and IObject's destructor is protected to prevent deleting pointer. You must use CHAI's method to remove such object.

As usual, removing local device changes the local device tree structure, so you have to call ICHAI::RedeclareAllDevices() to commit changes if you remove device while connected.

Best regards,

/Phil
CopperPhil
 
Posts: 480
Joined: 30 Mar 2011, 15:02
Location: Brussels

Re: Nested groups?

Postby arakula » 20 Mar 2012, 10:10

Thank you!
Just one more question:

Do subdevices need to register their own notification handlers, or is this something that should only be done by the root device?
arakula
 
Posts: 29
Joined: 07 Mar 2012, 19:57

Re: Nested groups?

Postby CopperPhil » 20 Mar 2012, 11:24

A notification handler is related to the object to which it belongs. If you register a notifcation handler to a localdevice, it will notify about events related to this device. There is no cascading. So you can create a distinct notification object for each input if you need it.

However, you can register a notification handler object with multiple CHAI objects. I mean, you can create a single "MyInputNotificationHandler" inheriting from IInputNotificationHandler, and register it with all the inputs of your application (it's an extreme example of course). When a notification is dropped to the application side, the notification handler gives a pointer to the owner object. In case of my example, the notification handler pass a pointer to the notified IInput by argument. So, you can identify the notified object on your side by comparing this pointer to an application variable storing the pointer returned by IBaseLocalDevice::AddInput()... You have another choice, when you create your inputs, you can associate a user data (void pointer or UInt32) to the object pointer (IInput inherit from IObject, check out IObject::SetUserDataPtr and SetUserDataUInt32). So finally it is very easy to find out the application object related to a notification handler used for multiple objects :D

Let me know if my explanation is not clear enough... :oops:
CopperPhil
 
Posts: 480
Joined: 30 Mar 2011, 15:02
Location: Brussels

Re: Nested groups?

Postby arakula » 29 Mar 2012, 12:00

Since we worked out the installation issue, I can continue on this one...

I got a preliminary version running. More or less. Sometimes.

The problems are a bit hard to describe...

Let's start with the basics: I've created a set of base classes, modeled after the CBase* classes in CopperVex, just with increased capabilities (dynamic setup of inputs, creation / destruction of subdevices, liberally sprinkled with debug output, etc.).

Based on these, I've created a set of classes:
  • an "engine" class that talks to VSTHost's User Exit interface on one side, and is a derived "CopperLan engine" on the other side. This engine creates:
  • a "root device", which has an input set for the "Engine"-specific VSTHost parameters (only BPM at the moment). This root device creates:
  • a "Track" subdevice for each of the tracks defined in the host application (currently only one, as already written). This subdevice has an input set for the track-specific VSTHost parameters (Bank / Performance loaded), and creates:
  • "PlugIn" (sub-)subdevices for each of the PlugIns that are loaded into the track. Each PlugIn subdevice has two input sets: one for the PlugIn's global parameters (currently, only the program loaded into the PlugIn), and one for the PlugIn's parameters (varying number for each PlugIn).
So far, so good... sometimes, this setup even works. Mostly it doesn't.

  • First of all, it only works if the local CopperLan Manager (i.e., the one on the same machine) is running before VSTHost with this setup is started. If the CopperLan Manager is started after VSTHost, or if it is running on another machine in the network, VSTHost freezes (somewhere in CHAI, as far as I could determine) - see below for details.
  • If it works, it works nicely... on Windows 7 x64. On Windows XP, it tends to work once, and after I close and restart it, it freezes regularly, most of the time even kills XP (something hangs - windows refuse to close or accept input, and I can't even shut down and restart the machine any more - blessed be the Reset button!).
  • If it freezes, the symptoms are like that: in the CopperLan Manager, a "VSTHost" device appears (as it should). If I click on it on the "Editor" tab, only the subdevice for the Master Track is shown (no Engine Inputs); at this moment, VSTHost seems to enter an endless loop somewhere in CHAI - I trace each and every "Onxxx" method invocation; nothing reaches this level, but VSTHost suddenly consumes the complete CPU time of one core. VSTHost as a whole still works, as long as nothing is done that would cause an interaction with CHAI. Clicking on the "Master" subdevice in the CopperLan manager sometimes shows the two preloaded {In} and {Out} subdevices - but that's all. No Inputs.
  • If I try to close VSTHost in this state, the first call into any of the CHAI functions causes the VSTHost UI thread to lock up, and I have to close it from the Task Manager. In XP, this also means "Bye, bye, Windows."
As said, it's modeled on the CopperVex helper classes (version from Jan 2012, IIRC) - which works, but is much simpler (only 1 device with 4 input sets - so quite some functionality is missing).

Do you have any idea what this could be? And what (kind of) additional input would you need for a diagnosis?
arakula
 
Posts: 29
Joined: 07 Mar 2012, 19:57

Re: Nested groups?

Postby CopperPhil » 30 Mar 2012, 10:29

Hi

Well, your implementation seems very good to me!

But about the problem itself, I don't see how the CHAI could loop infinitely without calling the application...

An usual issue in CopperLan application development is the deadlock. It can occur if the CHAI is calling a notification handler during a CHAI call initiated by an application thread currently protected by a mutex/criticalsection the notification handler should lock. It is an important note in the SDK (http://www.copperlan.org/doxygen/_s_d_k_o__c_b__thread.html), if you need to protect application data against CHAI modification at some time, use ICHAI::CHAILock and ICHAI::CHAIUnlock to prevent notification handler to be called. Anyway, if you based your code on the helper classes provided with CopperVex, you are using these methods. But some additional explanation about this point is never useless ;)

Actually, the strange thing in your issue description is that you said "I trace each and every "Onxxx" method invocation; nothing reaches this level". It makes me thinking about a ICHAI::CHAILock called from the application side but not followed by a ICHAI::CHAIUnlock. Can you check that?
CopperPhil
 
Posts: 480
Joined: 30 Mar 2011, 15:02
Location: Brussels

Re: Nested groups?

Postby arakula » 30 Mar 2012, 11:40

Well I've noticed quite early that it's easy to kill CHAI if...

  • in a notification, I defer the call to the UI thread in VSTHost, waiting for the result in the CHAI thread
  • do a callback into CHAI from the UI thread
  • Kaboom (deadlock in CHAI) ... which is not really uncommon in networking applications - I've regularly run into this in the last 10 years <sigh>
... and therefore took great care to avoid this kind of deadlock situation.

There's no locking/unlocking in my code, none at all. It's not necessary (yet). Everything's decoupled. If a CHAI notification mandates a change in VSTHost, the change is posted to VSTHost's UI thread, and then the notification is ended. Reporting the changes done in VSTHost's main thread back to CHAI is done after the action, from the main thread.

I can send you a beta version, if you want to try it.
arakula
 
Posts: 29
Joined: 07 Mar 2012, 19:57

Re: Nested groups?

Postby CopperPhil » 30 Mar 2012, 12:16

Ok great. So it seems that it freezes when the CHAI invokes the exploration notification handlers to query information from the application side.

Just to be sure, can you verify that each OnBaseLocalDevice_Request*** returns TRUE if the request is supported and FALSE if not; it must also call one of the IBaseLocalDevice::Reply_Request*** with the wRequestID passed to the handler.

This issue is strange, from my experience the only way to freeze the CHAI is to avoid returning from a notification handler.

Just another track, when you modify the object structure (adding/removing devices, inputs and so on), do you encapsulate this operation between a CHAILock/CHAIUnlock? If you don't, do it to prevent the CHAI to process incoming request from the network while the operation is not complete.

Anyway, it would be interesting for me to have a look to a beta version indeed. Can you compile it using the debug version of freeware CHAI dll from here (http://dl.dropbox.com/u/21532405/Win32Debug.zip)? so I would be able to run it from a debugger allowing me to see where the CHAI freeze.
CopperPhil
 
Posts: 480
Joined: 30 Mar 2011, 15:02
Location: Brussels

Next

Return to Generalities