Cabbage Logo
Back to Cabbage Site

Creating widgets dynamically after init

Hey there,

I was trying to see if Cabbage would be useful for developing my application. I need to be able to instantiate widgets dynamically as I’d like to include controls to add/remove different types of sequencers and then switch between them (showing/hiding as needed).

In the documentation it says that cabbageCreate must be used at time 0. Is this time 0 for csounds itself or is this per instrument? If it is for csounds, is it possible to simply instantiate a group of widgets and then change their channel names as needed? I figure having a pool of all expected controls would be one workaround, altering the channel names they are associated with when switching between sequencers of the same kind.

Thanks in advance for any help!


Hi @lo_94 :slight_smile: Creating widgets has to be done at i-time and should be done as soon as the instrument starts. You cannot change channel names during performance. But you can create a pool of channels and switch between them, but it all depends on your needs. What exactly are you trying to achieve?

1 Like

Ahhh okay, so when you say you cannot change channel names you mean you cannot change the name of the csound channel itself, but you can switch the channel that a widget is associated with correct? Maybe I’m misunderstanding

Basically each “instrument” will be a different type of sequencer that will contain specific controls. I’m looking to be able to add and remove these sequencers dynamically and have an array of buttons that will operate as a tab view essentially, allowing me to view a particular sequencer (up to 6). Only one of these sequencers will be visible at a time.

Basically I’m looking to be able to have a cabbage plant that contains the sequencer control, to be able to add different sequencers and then switch between them. So my thought is to create each plant at i time, and then when switching to the sequencer adjust each widget within a plant to the sequencers designated channel names for that control (cause there will be duplicates so for example 8StepSequencer1Pitch1 or DrumSequencer2Trigger4)

Instead of adding and removing them, I’d just hide and unhide them? I can’t see any obvious issues with this approach. You basically create your 6 sequencers, and only show the current one. I’ve done things like this in the past and was quite happy with the results.

1 Like

So I guess the main question I have is can cabbageSet be used to set the channel attribute of a widget during runtime?

No cabbageSet cannot be used to change the channel attribute in run time. But, can’t you simply set your 6 or so channel name at i-time, and toggle through them as you need within your instrument? When plant 6 is open, use DrumSequencer6Trigger, when 5 is showing DrumSequencer5Trigger. You will know which plant is currently visible, so there you can modify the channel name at run-time to communicate with the correct widget. For is

SChannel = sprintfk("DrumSequencer%dTrigger", kCurrentPlant)

where kCurrentPlant is the index of one shown on screen. Would this not work?

I think this would work in theory, however the main issue I see is that I’m looking to basically design a modular sequencer where I can add/remove sequencers at runtime. So effectively to do this, if I wanted the channel name to be something like DrumSequencer4Trigger after instantiating the drum sequencer in slot 4, wouldn’t I have to create all desired widgets for each potential sequencer at time 0? So if one sequencer had 20 controls, I’d wind up creating 120 controls if the max number of sequencer slots is 6 with each potential widget’s name when csound initializes.

I’m not opposed to this as I could probably do this cleanly in a user opcode, I’m just not sure how performant this would be because then the more sequencer types I add, this will very quickly add a lot of widgets to the program.

One workaround I could think of would be to have a router instrument that contains all the potential widgets a sequencer could use and routes these to the currently active/selected sequencer’s channels.

It’s an interesting design issue and I understand your concerns. Yes, you would in fact have to create 120 widgets at i-time to accommodate all widgets, however, I’m not sure how bad this would be in practice. I added the new cabbage* opcodes to better handle large numbers of widgets, so I think it should be Ok.

One thing you may need to consider is whether or not you wish to expose all of these widgets to the DAW as parameters. If so, users might have a hell of a time finding the correct widget to attach automation too. So automatable(0) might be useful across widgets that don’t need automation.

I think I may have figured out a way to do this. I have a simple pool system that works quite well, so instruments can fetch widgets as needed and the instrument that pools these widgets then redirects any changes to the channels desired for the instruments using them. Maybe it’ll be useful to others for similar use cases. I’ll go ahead and post it here once I test it a bit more and clean it up cause it’s currently very ugly haha

1 Like