hmmm, that looks like a bug to me (reproduced it on my system with the same result). VST parameters should be Double values between 0…1.0, so why can’t Cantabile use a calculated Double value to control a VST parameter? I can’t find a conversion function that would convert Double to “numeric” (whatever this is). This is one for @brad…
Indeed a bug. Will get it fixed today.
Great stuff @brad!
One question regarding conditions: Is it possible to check if a string contains a certain word?
The condition State == “Refrain”
is working perfect, but i often have additional information or numbers after the state name, so i would need something like contains(State, “Refrain”)
Greetings Tom
Hi @Siggin0er,
Funny… I looked at this the other day and was going to add it, but thought nobody’s asked for it yet so I’ll leave it.
I’ll be doing a build later today - I’ll add it.
Brad
Thx! I will use that as a fast implementation of song dependent light control wether its chorus or verse or bridge etc…no time to set everything up till the next gig
Next build will have:
strstr(str, find)
: returns the zero-based index of the first occurrence of find
in str
, or -1 if not found.
strhas(str, find)
: returns true
if the string find
is contained in str
, otherwise false
.
strmatch(str, regex)
: returns true
if the string str
matches the regular expression regex
.
All three functions are case-insensitive and culture invariant.
Fixed in build 4154
Yes, as of build 4154. See strstr
, strhas
and strmatch
in the function guide.
When I try to bind continuous controllers using an expression the function “SelectedPluginName” does not work as a condition when I. try to bind a continuous controller to another continuous controller. Here is an example of it.
which translates to If the selected plugin is “VB3-II 1” then allow the binding to work. it does not. It does however work if the source is an edge button to another edge button. @brad does the comparison not apply to continuous connections and only to switches?
Thanks,
Dave
Hey Dave,
I had a quick look at this… does this work if you use an external MIDI device instead of the onscreen keyboard? I think what might be happening is when you click the onscreen keyboard slider, focus moves from the plugin slot and there’s no longer a selected plugin.
Brad
@dave_dore I think you posted a question asking for an example of using the curve
function:
See screen shot below. The thing to understand about the curve function is it takes a value between 0.0 and 1.0 and maps it along a curve yielding a different value between 0.0 and 1.0. So you can apply it to any 0.0 to 1.0 value to stretch and bend its behaviour.
Hi Brad,
Yep, it works with an external device so your reasoning looks to be correct.
Thanks for your help.
Dave
I deleted the post when I figured it out but thanks for the explanation.
Is it possible to also have functions for the slider control curves that are like the ones available in the range mapping or can you use the velocity function for that?
Brad, you made a lot of people hungry with the Binding Expressions, I think.
The latest functions Brad added for chord recognition are incredible. With a little brow sweat I fabbed up a chord recognition string of functions that loads into a Controller bar button or the show now area that covers the most used chords and could be expanded. @Sergio asked Brad about this possibility and it was done way faster than I expected. It also opens up the possibility of using a certain chord to trigger events. So, yes Paulo, my hunger is not satiated but with this big batch of goodies lately I am filling up.
Tell me more, tell me more…
That sounds really interesting, if you have an example of what you have done.
Hi Derek,
I used statements like this one example to detect certain chord elements for ID purposes and then built a long list of these statements to map out all the note combos for the possible chords.
$(any_notes_held([0,12,24,36,48,60,72,84,96,108,120] ,1) ==1 && any_notes_held([4,16,28,40,52,64,76,88,100,112,124] ,1) ==1 && any_notes_held([7,19,31,43,55,67,79,91,103,115,127] ,1) ==1 && any_notes_held([11,23,35,47,59,71,83,95,107,119] ,1) == 1 ? "CMajor7":"")
The finished product of the large one line statement that is loaded into the button dialog field are shown here. Of the 3 new functions Brad introduced I settled on the “any_notes_held” function because it offered a way to reduce the size of the work of mapping all the possible chord variations across the entire keyboard. By using the function in a chained and expression it did the trick.
One drawback to this choice is that multiple statements can be true at the same time when some chords are pressed. For instance I have a CMajor7 pressed down but at the same time I have all the elements for an Eminor to be true at the same time. To fix this I added extra and equations to some of the statements to check for those cases and produce the desired result.
For a single root note I ended up with a group of statements like this to map and check for exceptions.
For Augmented and Diminished chords there are shared elements so only 3 expressions were needed to cover all the diminished chords and 4 were needed for the augmented chords. I just made the labels do that it showed all the possible names for the note combo.
Here’s what those lines looked like.
Once I built up all the root note sections I removed all the CR and empty space and joined all the lines together. As a finishing touch I removed any space between the end of one expression and the beginning of the next so that the text would position itself properly in the small button window later on.
The “all_notes_held” would be useful as a trigger source in bindings I think. Where you knew the specific note numbers of the chord that was the triggering event, Like say this
So there is some more explanation Derek, Thanks for asking about it.
Cheers,
Dave
Interesting…
Hey Guys,
This is both super cool and kind of terrifying. I love that you’ve built this, but have to cringe a bit at what it took.
My biggest concern with this is performance - it shouldn’t be terrible, but I’d be interested to hear what happens to CPU load in Task Manager when playing a fast piece through this.
I did consider adding a chord_name()
function but after looking at a couple of other implementations it’s not trivial to do properly. eg: one implementation I looked at was over 8,000 lines of code.
Still, I’m glad you’ve got something working. You guys always amaze me with what you come up with.
Brad
What if I was to add some functions to check for a note/notes in any active:
is_note_name_held("C")
all_note_names_held("CEG")
any_note_names_held("CEG")
Thanks Brad,
I as you might suspect have a love of a challenge and that is why I build up this crazy stuff sometimes. Yep, it’s a lot of decisions for an event so I see the concern over the performance of such a large linked expression.
In Windows task manager it goes from 0 to as high as 11% when playing rapid chords after isolating it.
I said to Sergio when he first inquired that if you tried to add an implementation it could bloat the code beyond a reasonable amount. I really appreciated that you came up with a user adjustable table based scheme that was build-able (use as much or as little as you needed for the task at hand) so it hopefully didn’t load down the code and still allowed it to be built upon by folks like me. I thought you’d be surprised that the new functions combined with the existing ones allowed the build of such a thing. I was concerned I’d overload the field space in the button dialog box!
It would decrease the size of the beast by a lot if I understand.
The any_note_names_held(“CEG”) replaces
any_notes_held([0,12,24,36,48,60,72,84,96,108,120] ,1) ==1 && any_notes_held([4,16,28,40,52,64,76,88,100,112,124] ,1) ==1 && any_notes_held([7,19,31,43,55,67,79,91,103,115,127] ,1) ==1)
correct? If so it would be a welcome thing.
A few things I found while doing this.
-
When using any_notes_held there were cases where more than one statement was true leading to creating exceptions to work it out. For example if Cmaj7 is true then Eminor is also true. The functions you posted provide a way to correct that so I would think the “names” functions you speak of would too.
-
Augmented and diminished chords were simplified to shared expressions because in order to separate them I would need to know what the lowest note pressed was to determine an arbitrary root note for the chord. Not sure if a function for that would help or not but would (if we assume the lowest note is the root note) provide that part of the picture as well.
Since most chord quadrads have crossovers it seems better to label my chords that are shared that way so that both names can apply and be seen.
Thanks for the feedback and looking forward to your input.
Dave