Problem with changing the multi-output buses on the Macro Page

Hi

I’m building a HS instrument with a lot of layers and buses and I want to be able to change the output of some of those buses from the macro page in order to route them to different audio tracks inside the DAW. By default all those buses go to the Program Bus which has some insert effects. But I encountered a very big problem: if I change the output of those buses in the macro page to a different output channel (for example Out 2) but then I want to change it back to the Program Bus it cannot be done. There is no “Program Bus” option in the list of the available outputs. There’s just the “Master” option which for some reason bypasses the Program Bus and goes straight to the master output.

Here’s a very simplified example so you can better understand my issue:

This is the program tree:
img1

And the instrument in the macro page:
img2

Each of those two layers has a bus and each of those buses has the output routed to the Program Bus, like this:
img3

Now when I want to change the output of those two layers so I can send their audio signal to a different track inside my DAW, I can choose from a list of 32 output channels:
img4

But, as I said, if then I want to go back to the default state of the instrument and send those two layers back to the Program Bus I have no option in that list to select the Program Bus output.

Is there a way (maybe using some script) I could add the Program Bus output to that list (or better yet to replace the “Master” output with the Program Bus output in that list)?

How did you set the TargetBusses parameter in Mixer Channel template? When I set it to local it shows all busses. You could also try the default option.

Mixer Channel - HALion Macro Page - Steinberg Developer Help

1 Like

Thank you so much for the help, Misohoza!! :hugs:

I didn’t set the TargetBusses parameter at all, it remained empty. I had no clue what that parameter does and because the Mixer Channel worked just fine without setting it up I thought that the TargetBusses parameter is not important in my case. :neutral_face: My mistake I didn’t search the manual to see what’s that parameter for. :roll_eyes:
But now I’m gonna study that link you sent me.

Thank you! :hugs:

Here’s a follow-up. So, on that Developer Help page it says:

To filter the outputs that are made available by the menu, you can configure the menu control by adding one of the following tags to the value name (separated by spaces):

  • default allows setting no explicit target bus. In this case, the audio is routed to the default bus (usually the next bus higher up in the hierarchy)
  • default=‘name’ as above, but “name” is shown as text instead of “–”
  • local shows all available busses higher up in the hierarchy
  • buslist=‘BusName1; BusName2; …’ allows to specify a list of busses

Additionally, you can set the following tags:

  • aux shows the plug-in aux busses
  • noplug hides the plug-in out busses

Are these all the available tags that can be used to filter the outputs that are shown in that menu? Whould it be possible to further filter the outputs using some script?

What I try to accomplish is to get rid of the “Master” option from that list, because I will use the buslist tag to add the program bus which is named Master Output (or Master Bus or Main Output) to that list of available outputs and I don’t want the user to get confused by having two similar named outputs in that list: Master and Master Output (and they are not the same).

Probably, yes. Depends what busses you need. Something like this should give you plugin outputs and the Program bus. You may need to adjust it to fit your program structure.

ins = this.program.instance
outputBusses = ins:findBusses(false, function(bus) return string.match(bus.name, "Out") and true or false end)

programBus = this.parent:getBus()

table.insert(outputBusses, 1, programBus)

busNames = {}

for i, bus in ipairs(outputBusses) do
	print(bus.name)
	busNames[i] = bus.name
end

busNames[0] = "--" --will be nil - use default routing


defineParameter("Output1", nil, 0, busNames, function() outputChanged(1) end)
defineParameter("Output2", nil, 0, busNames, function() outputChanged(2) end)

function outputChanged(i)
	local bus = this.parent:getLayer(i):getBus()
	bus:setOutputBus(outputBusses[_G["Output"..i]])
end

Output Bus.vstpreset (8.8 KB)

1 Like

Excelent!!! Seems to do exactly what I needed! :partying_face: :partying_face:
Thank you soooooo much, misohoza! :hugs: :hugs:

Well, I tried to implement your script in my instrument but unfortunately it doesn’t work as I thought it would and I have no idea why. I made a modified version of the vstpreset file you sent (to be a little closer to the structure of my instrument) so you can better understand my situation:

The routing is as follow:

  • Layer1-Bus goes into Bus A
  • Layer2-Bus goes into Bus B
  • Bus A goes straight into MainOutBus (bypassing the Bus B) and Bus B goes into MainOutBus

What I was hoping to get using your script (btw, I edited it and added two more outputs) is to have the output menu for each mixer channel showing the following:

  • the default routing (the custom routing I’ve set for each bus) instead of the “–”
  • the MainOutBus (which is the program bus)
  • all the other external outputs (Out 1, Out 2, etc)

Like this:
img4

Instead, what I got so far (for every mixer channel) is this:
img2

Here is the modified vstpreset
Output Bus modified.vstpreset (12.8 KB)

I see. You could try like this:

ins = this.program.instance
outputBusses = ins:findBusses(false, function(bus) return string.match(bus.name, "Out") and true or false end)

busA = this.parent:getBus("Bus A")
busB = this.parent:getBus("Bus B")
mainOutBus = this.parent:getBus("MainOutBus")
layer1Bus = this.parent:getLayer(1):getBus()
layer2Bus = this.parent:getLayer(2):getBus()

assert(busA, busB, mainOutBus, layer1Bus, layer2Bus)

table.insert(outputBusses, 1, mainOutBus)

layer1Busses = {}
layer2Busses = {}

layer1BusNames = {}
layer2BusNames = {}
outputBusNames ={}

for i, bus in ipairs(outputBusses) do
	layer1Busses[i] = bus
	layer1BusNames[i] = bus.name
	layer2Busses[i] = bus
	layer2BusNames[i] = bus.name
	outputBusNames[i] = bus.name
end

table.insert(layer1Busses, 1, busA)
table.insert(layer1BusNames, 1, busA.name)
table.insert(layer2Busses, 1, busB)
table.insert(layer2BusNames, 1, busB.name)

defineParameter("Layer1Bus", nil, 1, layer1BusNames, function() outputBusChanged(layer1Bus, layer1Busses, _G["Layer1Bus"]) end)
defineParameter("Layer2Bus", nil, 1, layer2BusNames, function() outputBusChanged(layer2Bus, layer2Busses, _G["Layer2Bus"]) end)
defineParameter("BusA", nil, 1, outputBusNames, function() outputBusChanged(busA, outputBusses, _G["BusA"]) end)
defineParameter("BusB", nil, 1, outputBusNames, function() outputBusChanged(busB, outputBusses, _G["BusB"]) end)

function outputBusChanged(bus, outputs, index)
	bus:setOutputBus(outputs[index])
end

This should work in HALion 6. But if you plan to export it as HSSE layer and use it in HALion Sonic (SE) you shouldn’t have 3 busses at the top level. It will cause problems. It will let you export it as layer with a warning. When you save it as HSSE program it will remove 2 out of the 3 busses and break both script and the macro page controls.

Output Bus 1.vstpreset (8.8 KB)
Output Bus 2.vstpreset (8.8 KB)
Output Bus 3.vstpreset (8.8 KB)

1 Like

Yessss, you did it! :star_struck: Thank you thank you thank you! :hugs:
But boy, this is getting quite complicated! My head hurts just by trying to understand what is going on in that script you wrote. And I will have to adapt it to my instrument which has around 20 buses! Wish me luck! :smile:
And all this script pretty much just to get rid of that damn “Master” option from the output menu. I was hoping it would just need a very simple script to accomplish that. :face_exhaling:

There’s one more question that i want to ask you: what part of that script I have to modify if I want to remove the “MainOutBus” option from the output menus of the Layer 1 bus and Layer 2 bus? In order to have something like this:

img3

I guess the Output Bus 2 vstpreset file you sent me will resolve this issue, right? As it only has one bus at the top level, and all the other buses inside the “Main” layer.

Check the lines with table.insert

ins = this.program.instance
-- get plugin output bus objects
outputBusses = ins:findBusses(false, function(bus) return string.match(bus.name, "Out") and true or false end)

-- variables for bus objects 
busA = this.parent:getBus("Bus A")
busB = this.parent:getBus("Bus B")
mainOutBus = this.parent:getBus("MainOutBus")
layer1Bus = this.parent:getLayer(1):getBus()
layer2Bus = this.parent:getLayer(2):getBus()

-- check if the busses are found
assert(busA, busB, mainOutBus, layer1Bus, layer2Bus)

-- create tables for bus objects
layer1Busses = {}
layer2Busses = {}

-- create tables for bus names - will be used for script parameters
layer1BusNames = {}
layer2BusNames = {}
outputBusNames ={}

-- loop through the output bus objects and copy them, create the names
-- so far only plugin output busses are added
for i, bus in ipairs(outputBusses) do
	layer1Busses[i] = bus
	layer1BusNames[i] = bus.name
	layer2Busses[i] = bus
	layer2BusNames[i] = bus.name
	outputBusNames[i] = bus.name
end

-- add the remaining busses and their names
table.insert(layer1Busses, 1, busA)
table.insert(layer1BusNames, 1, busA.name)
table.insert(layer2Busses, 1, busB)
table.insert(layer2BusNames, 1, busB.name)
table.insert(outputBusses, 1, mainOutBus)
table.insert(outputBusNames, 1, mainOutBus.name)

defineParameter("Layer1Bus", nil, 1, layer1BusNames, function() outputBusChanged(layer1Bus, layer1Busses, _G["Layer1Bus"]) end)
defineParameter("Layer2Bus", nil, 1, layer2BusNames, function() outputBusChanged(layer2Bus, layer2Busses, _G["Layer2Bus"]) end)
defineParameter("BusA", nil, 1, outputBusNames, function() outputBusChanged(busA, outputBusses, _G["BusA"]) end)
defineParameter("BusB", nil, 1, outputBusNames, function() outputBusChanged(busB, outputBusses, _G["BusB"]) end)

function outputBusChanged(bus, outputs, index)
	bus:setOutputBus(outputs[index])
end
1 Like

Great! Thank you for explaining all those script parts! Now it’s much easier for me to understand how this script works. Your help is greatly appreciated! :hugs: