Connecting DSPs vs connecting ChannelGroups

I’m trying to understand the the relationship between channels and DSPs. As far as I understand it:

  1. At the lowest level, we’ve got a graph of DSPs
  2. some linear groups of them (DSP Chains) are wrapped up in Channels or ChannelGroups

What I don’t understand is if the Channel to Channel relationships are anything separate from the DSP to DSP relationships.

For example, I can create 2 channel groups:

        FMOD.ChannelGroup cg1, cg2;
        coreSystem.createChannelGroup("cg1", out cg1);
        coreSystem.createChannelGroup("cg2", out cg2);

which creates this graph

If I connect cg2 to cg1, like this:

        FMOD.ChannelGroup cg1, cg2;
        coreSystem.createChannelGroup("cg1", out cg1);
        coreSystem.createChannelGroup("cg2", out cg2);
        cg2.addGroup(cg1);

I get this graph:

So cg1 was disconnected from the master group and connected to cg2. I can do seemingly the same thing by manipulating the DSPs:

        FMOD.ChannelGroup cg1, cg2;
        coreSystem.createChannelGroup("cg1", out cg1);
        coreSystem.createChannelGroup("cg2", out cg2);
        FMOD.DSP cg1_fader, cg2_fader;
        cg1.getDSP(0, out cg1_fader);
        cg2.getDSP(0, out cg2_fader);
        cg1_fader.disconnectAll(true, true);
        cg2_fader.addInput(cg1_fader);

Is this the same thing? One thing that’s confusing is that a ChannelGroup is only supposed to have 1 parent, but if you’re routing the DSPs there’s nothing stopping you from routing a ChannelGroup’s output fader to multiple places.

Maybe a more concise wording for my question is "Is the tree of Channels and ChannelGroups separate from the graph of DSPs?

Yes and no. There isn’t a 1-to-1 relationship between a DSP and a Channel/ChanneGroup. A DSP is a single DSP unit in the chain. A ChannelGroup is a higher level grouping of DSPs, that at minimum includes the Fader DSP you’re observing, but can also include DSPs for playing sounds or plugins, effect DSPs, and other Channels or ChannelGroups. Additionally, while the DSP graph can be manipulated such that a DSP interacts with the signal from multiple Channels, a DSP can only “belong” to a single Channel/ChannelGroup.

I hope that answers your question - feel free to ask if you’re still unclear on anything.

That doesn’t quite get to the root of my confusion.

The interpretation of the DSP graph seems pretty straightforward - each DSP sums its inputs, does its processing, and then sends its output to all the DSP’s that it’s connected to.

(here I’ll use ChannelGroup but generally this also includes Channels at the leaves of the tree)

The tree of ChannelGroups is less clear to me. A lot of the documentation seems to assume a sort of “typical” arrangement where:

  1. each ChannelGroup has a linearly-connected DSP Chain, where audio comes into the tail, passes through the chain, and comes out the head
  2. each ChannelGroup has exactly one parent
  3. If ChannelGroup A is the parent of B, then the output of B’s DSP chain head is connected to the input of A’s DSP chain tail

As far as I can tell, #2 is always true, but #1 and #3 are not, because you can manipulate the DSP connections separately, so for instance you could re-connect the DSP chain inside a ChannelGroup so that they are connected out of order, or have a branching structure. Additionally, you could disconnect a ChannelGroup head from the parent’s tail, and/or connect it to some other ChannelGroup.

As a concrete example, say we have ChannelGroups A, B, and C.

  • The parent of A and B is the master ChannelGroup
  • A is the parent of C
  • the output of C’s head DSP is connected to the input of the tail DSPs of both A and B

Questions:

  1. does the fact that A is the parent of C have any impact here? Is that relationship different from the relationship between C and B?
  2. It seems like most of the behavior is determined by the DSP connections, what do ChannelGroups actually do?
  3. Does the ChannelGroup structure put any constraints on the DSP graph structure?
  4. What order do the DSPs execute in?

Part of the confusion is that a lot of the ChannelGroup actions have an impact on the DSP graph (e.g. ChannelControl::addDSP will connect the new DSP to the adjacent members of the DSP chain), but it’s not clear to me whether those are just for convenience, or are somehow fundamental.

While everything is built on and runs on DSPs, ChannelGroup was initially conceived of as a higher level macro control for child Channels or ChannelGroups, and it has evolved from there into a broader grouping as well. Interacting with a ChannelGroup interacts with its child Channels or ChannelGroups - while functionally it does interact with the underlying DSP chain, it is fundamentally different from just interacting with the DSP chain, which won’t actually add new DSPs or connections to the Channel or ChannelGroup.

The answers to your questions are as follows:

  1. Yes. ChannelGroup API functions execute on child Channels and ChannelGroups. For the purposes of interacting via the ChannelGroup/ChannelControl interface, C is considered a child of A, but not a child of B; thus using the ChannelGroup/ChannelControl interface on B to interact with C will not work.
  2. See my initial explanation in this reply.
  3. It doesn’t necessarily impose a constraint on the structure specifically, but the DSP graph will always be structured a certain way when interacting with it via the ChannelControl interface, and as previously mentioned the interface will not interact with arbitrary DSP connections.
  4. To quote our White Paper on DSP Architecture: “The order of execution for a DSP graph is from right to left, but also top to bottom. Units at the top will get executed before units at the bottom.”

Thanks, that’s super helpful.

  1. To quote our White Paper on DSP Architecture: “The order of execution for a DSP graph is from right to left, but also top to bottom. Units at the top will get executed before units at the bottom.”

I’m assuming that has to do with the arrangement that you see when you open the FMOD Profiler tool, but it’s not clear how that’s affected by the code. Does it have to do with the order the DSPs were created, or the order they were hooked up, or the graph connections themselves (presumably you want each node’s to execute only after all its inputs).

Generally speaking, the arrangement of the DSP graph is determined based on the order in which DSPs are connected. However, the arrangement of DSPs is also affected by higher level groupings of DSP like ChannelGroup - logically, if you were to add a freshly created DSP effect to the first Channel created in the DSP graph, then that DSP effect will execute as a part of that Channel. That said, besides some niche cases, such as the reverb example listed in the DSP Architecture White Paper, the order of execution isn’t worth trying to control.

Great, thanks. That’s very helpful.

1 Like