Cabbage Logo
Back to Cabbage Site

New ideas for preprocessor (modularising GUI development)

I remember once before mentioning an idea about the cabbage preprocessor being able to do #include files for cabbage, but can’t recall where this got brought up. In my particular use case, you (Rory) can probably see in those examples I sent that many “header” lines are shared between instruments. It would both look cleaner having it moved to an include, and it would allow for a sort of “quick skinning” of sorts by swapping the color/style definitions for a new look.

I also think handling “nested” defines would be a cool addition, in other words cabbage being able to use a previously defined statement in the declaration of a new define, like this:

#define GREEN 0,255,0,255
#define GREY 60,60,60,255
#define PLANT colour($GREY), fontcolour($GREEN)

edit: missed a typo!

Including files should be relatively simple. Nesting macros might be a bit trickier. I’ll have to have a think about it. The macro system in Cabbage 2 is an improvement of the one in Cabbage 1, but it’s still not bullet proof. I know the best approach is to write a proper parser, but I’d have to read plenty first. Which takes time :frowning:

I remember us talking about the preprocessor being a bit “simple”, and I get why it’s a big undertaking.
But… if I only had one wish for it’s improvements, include files would be it :wink:

It might also be a nice way to modularise GUI development too. I’ll take a look.

Hrm, that gives me a thought out loud… can a cabbage define span multiple lines? For instance, could I drop something like one of those “filter groupboxes” that are reused all the same into an include file with everything other than the bounds() for the main groupbox?

edit: Answered my own question, no… since they all have unique channel name/modifiers. (in this particular case, can’t be re-entrant/reiterative)

I sometimes use the code snippet feature for this kind of thing. I’ll save a plant like this to the code repo:

groupbox bounds(x, y, 400, 100), text("ADSR")
{
rslider bounds(10, 10, 70, 70), text("Att."), channel("att")
rslider bounds(100, 10, 70, 70), text("Dec."), channel("dec")
rslider bounds(200, 10, 70, 70), text("Sus."), channel("sus")
rslider bounds(300, 10, 70, 70), text("Rel."), channel("rel")
}

Then when I insert it I merely have to replace x and y with real coordinates. The issue of course is with duplicate channel names. But a little forethought when saving the code snippets can help here too.

Yeah, I do something similar in sublime on occasion.

Just daydreaming here… but maybe it’d be possible with both include files AND nested defines… for example:

#define CHAN_PREFIX "adsr1-"
#include "adsr.inc"
#define CHAN_PREFIX "adsr2-"
#include "adsr.inc"

Where adsr.inc includes something like:

groupbox bounds(x, y, 400, 100), text(“ADSR”)
{
rslider bounds(10, 10, 70, 70), text(“Att.”), channel("$CHAN_PREFIXatt")
rslider bounds(100, 10, 70, 70), text(“Dec.”), channel("$CHAN_PREFIXdec")
rslider bounds(200, 10, 70, 70), text(“Sus.”), channel("$CHAN_PREFIXsus")
rslider bounds(300, 10, 70, 70), text(“Rel.”), channel("$CHAN_PREFIXrel")
}

Tho perhaps the preprocessor would have to use braces to avoid ambiguity:

groupbox bounds(x, y, 400, 100), text(“ADSR”)
{
rslider bounds(10, 10, 70, 70), text(“Att.”), channel("${CHAN_PREFIX}att")
rslider bounds(100, 10, 70, 70), text(“Dec.”), channel("${CHAN_PREFIX}dec")
rslider bounds(200, 10, 70, 70), text(“Sus.”), channel("${CHAN_PREFIX}sus")
rslider bounds(300, 10, 70, 70), text(“Rel.”), channel("${CHAN_PREFIX}rel")
}

Hrm…

I see where this is going :rolling_eyes: :joy: If I could avoid the use of macros it would be quite easy to implement. What about a simple text replacement mechanism, something like this:

#include "adsr.inc" chan_prexifx="adsr" colourCode="blue"

where adsr.inc would look like this:

groupbox bounds(x, y, 400, 100), text(“ADSR”)
{
rslider bounds(10, 10, 70, 70), text(“Att.”), channel(“chan_prexifx_att”), colour(colourCode)
rslider bounds(100, 10, 70, 70), text(“Dec.”), channel(“chan_prexifx_dec”) colour(colourCode)
rslider bounds(200, 10, 70, 70), text(“Sus.”), channel(“chan_prexifx_us”) colour(colourCode)
rslider bounds(300, 10, 70, 70), text(“Rel.”), channel(“chan_prexifx_rel”) colour(colourCode)
}

Or? Maybe would could use something else rather than the include keyword? ‘using’ or ‘import’ maybe? Considering we are passing values to the code? I like the idea. We just need it to be as intuitive as possible. It might work fine with macros. I’d have to look into it.

I like the idea too, one way or another. It works well with the modular sort of code I’ve been writing lately. I agree it probably needs more thought and discussion tho before settling on anything.

I also had one more suggestion that randomly popped in my head today, somewhat related to this. These channel names get a little long winded “shape2-val3”… “adsr3-dec”… who knows. Could we get an option for something like: popupprefix("") or popuplabel("") or whatever it’s named, that essentially replaces the channel name text in the popup window with this new label, but still updates the values as normal through cabbage? This way we could specify it’s label is “Decay” or “Width” etc etc, regardless of all of the potential prefixes and odd naming.

Can’t you just use popuptext()? That’s what it’s there for.

I’d like to get some input from @iain on what we’re discussing here. Considering he has now written more Cabbage instrument to most of us combined, he probably has a few ideas on this matter. I’ll leave the discussion open to all users who want to chime in.

p.s. I’m going to change the title slightly so it better reflects the current direction of conversation…

Hi guys,
Just one question : the cabbage part as such is not doing much because the management of the GUI is done elsewhere in the code. How would you integrate the GUI management with include?

The idea would be to include/import GUI code into the Cabbage section of a file. These imports would be Cabbage only and have nothing to do with Csound.

@Rory: I can (and am currently using) popuptext in places where it’s most important! But that requires special handling of formatting out the new message with sptrinfk or strcpyk and sending in to the control channel. Neither are big operations, but add up over time when you’re doing it with lots of channels. As it is I try to wrap them behind a metro() call to limit UI update rates. Plus that means you need to be careful that you’re only sending messages to the same channel once per control cycle, so that’s required some lucky bug-hunting and creative workarounds too.

I mostly reserve popuptext for the times when the value I want to display on the dial might be different (for example a 0->1 dial that I’m scaling to something else depending on the current mode) This would be a lighter weight version for when I’m fine using and displaying the value as given, just want simplified text. I dunno… hopefully that made some sense?

And agreed, Iain’s feedback should definitely be considered… he’s got quite a collection :slight_smile:

@Karamel: Correct, this is just dealing with managing the cabbage part, it doesn’t do any processing of audio… but I’ve also been working on writing modular code that would work with it… so the idea is you include a few files, add a few lines of preprocessed cabbage code, add a few lines of custom opcode calls, and it all just works together. I’m mostly writing it for me, but once it reaches a decent and “stable” point, I expect to release it and the instruments I have written using it.

I see your point. I can add add an auto-prefix/post-fix label.

Awesome, tho to be clear in many cases I don’t just want a prefix or suffix, I want to entirely overwrite the label… once it gets too large and unwieldy. When I called it a prefix what I meant was the text that would appear before the number generated by cabbage…

Tho I guess maybe suffix could be used to create a popup where the number precedes the text, such as “4 beats per minute” or something like that? I’m actually really starting to like this idea :innocent:

Good, so long as we’re thinking the same way! But to be sure, this solution would always display the current value, either before or after the custom label right? I think we’ve moved more than slightly off topic here :joy:

Totally nonsensical pseudocode, these would be sprintf strings for generating popuptext
prefix: sprintf("%s %d", string_from_user, val_from_cabbage) which could be used for “Voices: 4”
suffix: sprintf("%d %s", val_from_cabbage, string_from_user) which could be used for “3.5 Hz”

And yes, that’s the idea… these are for when using the normal cabbage value is preferred. If you need a different value, that’s what formatting the entire popuptext() is perfect for! Slightly off topic, but all slightly related… sorry, I said earlier I was just thinking out loud and daydreaming a bit, spitballed with the random ideas. :smiling_imp:

I’ve created a Lite version of Cabbage for you to try out. It is built to work with other editors and doesn’t feature any GUI designer. I didn’t have time to test the command line params, maybe you can give it a whirl, you can access here. If you wish to export, you’ll need to copy the plugin bundles from the main Cabbage.app into the Cabbage Lite app bundle. I’ll fix the packaging of this in the future. This is a very early beta release!

Awesome, thanks! I’ve downloaded it, but I’m literally moments from calling it a night, so I probably won’t test this at all until tomorrow evening. Keep in mind I’m still testing with cs6.07, otherwise I still run into those gui issues. I wasn’t able to get a fresh build done local, seems like issues specific to homebrew… but I’m not sure.

How close are you to calling 2.0 a wrap? I know I’m late to the party, so I don’t want to be that guy holding everything up for some bizarre requests… I had another thought today tho, and was literally just about to type a forum post when this msg hit… Would it be possible to have an option (defaults to off for compatibility) that lets you hit a radio button a second time to turn it back off? For example, I made an instrument that generates different noises based on the button, but once started can’t be stopped unless there’s a specific off button and off handling in the cs code.

Still looking forward to the convos and outcome about the include files and modularizing cabbage sections etc… I think that has a lot of potential! I’ll give this version a shot asap.

I’m not addicted to the cabbage… I swear, I can stop any time I want!

So I gave it a shot… seems to work just fine! The first few times had issues “unmuting audio” to avoid a feedback loop, it’d crash… but I think that was because I was trying to change that setting from having launched a file directly from sublime (OMG, YAY!). when I launched c2L directly and changed the setting, it didn’t crash and now I have audio.

I’ll play with it more tomorrow, but so far it’s doing great. seems to be a bit faster overall, and looks like it’s getting more direct console feedback from csound in sublime’s build window.