Cabbage Logo
Back to Cabbage Site

Bézier Curves for Gentables

If you’d like to build the Cabbage part Rory, this is what I have right now. I think it works. It doesn’t catch all the errors yet (fterror is a leftover from fareygen), but I’ll be a little busy for the next couple of days. From what I’ve seen in Cabbage, it’s not going to be that difficult to adapt. The syntax is this:

x1 and x2 in a segment can’t -obviously- have the same value. cx1 can -but shouldn’t- be equal to x1 or x2. This means handles in Cabbage should not be allowed to cross over the x-point of another handle, either to the left or to the right.

“quadbezier” sets p4 (gen routine) to -1. That was what fareygen does. Shall we change that?

As you already know, you’ll need to add make_plugin(quadbezier quadbezier.c) to Opcodes/CMakeLists.txt. (1.4 KB)


Do you have a few example tables for me to test with?

I had a few examples along with some gnuplot scripts and code in Qt to test these bezier curves. I was working inside Builds/Linux/CabbageBuild and then had the brilliant idea of executing ./buildCabbage. It’s all gone now of course.

But I had this three ones in a file outside the Cabbage directory:
f 1 0 800 “quadbezier” 0 0 0 99 0 100 0 100 100 450 150 700 300
f 2 0 800 “quadbezier” 0 0 0 99 0 100 0 100 100 600 50 700 300
f 3 0 800 “quadbezier” 100 450 150 800 300

Hmm, that’s annoying! I just started looking at this and hit the first issue. I need to find out if the gen routine is named, or numbered. I thought I could simply cast the first MYFLT* as a STRINGDAT* but that doesn’t seem to be working. I’ve asked on the Csound list. I’m pretty busy too lately. My wife and I had our first child, so I’m not getting as much time right now on Cabbage matters, but I will try to get some things done whenever I can.

Hey man, congratulations to you and your wife! Sure, you must be busy. Luckily there’s no deadline for hobbies.

I just replied to your message on the Csound list. As I’ve said, to avoid normalizing I had to reset p4 to -1 inside quadbezier.c. You’re probably getting that. I don’t know what to use instead. Let’s wait and see if someone replies over there.

Ah that explains it! My casting to a STRINGDAT* was failing because there was no string data. That solves that problem :wink:

Maybe we’ll need to use a number for p4 or add a parameter to gentable like mode(“bezier”) or something like that.

How do you cast to STRINGDAT* exactly? I tried not resetting p4 but I’m still not able to recover the string from inside Cabbage. I know I should get a data member and a count, but nothing seems to work.

I think something like this should work:

char  *src;
src = ((STRINGDAT*) myfltPointer)->data;

Tried it with no luck. Anyway, the two new functions make it possible to establish if we’re dealing with quadbezier tables or not. The code below is really awful C++, but it prints “quadbezier” correctly.

int noOfArgs = csoundGetTableArgs(csound->GetCsound(), &argsPtr, tableNum);
char s[11];
s[10] = '\0';
csoundGetNamedGEN(csound->GetCsound(), argsPtr[0], s, 10);

At least we know it works. Did you need to update your code? If so can you send it on to me? I have some time put aside early next week for this. Sorry, but I won’t be up to doing much before then. The list of Cabbage things to do is growing day by day!

Sure. There’s no hurry for this. I’m very grateful that you are willing to actually spend any time on this idea at all!

I had to multiply p4 by -1 as Victor suggested. I also fixed a serious bug. It still doesn’t do error-checking and also I need to comment it. But -unless you find a bug- the syntax and the functionality should stay the same. I’m still not sure if control points should be allowed to overlap the regular points in Cabbage. Later on we should decide about that. (1.5 KB)

I tried using a quadbezier table with gentable and the good news is that drawVerticalLine() seems to work fine.

One potential issue I see is the fact that control points can be outside the the Y-bounds of the envelope. If scaling is turned off then this should be fine. I guess as Csound will normalise the contents of the table for us.

Yes, rescaling is always off. That’s why Victor asked me to multiply p4 by -1. The only way you could get a normalized quadbezier is if you call the routine by the corresponding number assigned to plugins by Csound (gen 65 in my machine). Even then, you’d have to call it as -65 to reverse the multiplication. Weird thing is that negative gen number means rescaling for quadbezier!

I think that in order to get the maximum height you should check for the greatest number in the arguments, i.e. y1,cy1,y2… That should work, shouldn’t it?

Yeah. That should work.

I started implementing this earlier, but had to return to life duties after an hour or so! You’ll see that once I detect a quadbezier table I set the gen routine to 999. I did this so I can continue to query gen numbers rather than strings further down the line. I’ve also put in some place holders in table.cpp for places that need bezier attention. When I had to leave it I was at the point of generating the handles for the table here:

But the handles are not appearing in the correct place. I’m sure it’s something simple. Just remember to use the active(1) identifier with the table to display the handles. I’m just letting you know in case you want to follow developments, or have a go at it yourself :wink: Although every time I go over old code I’m shocked at how I’ve over complicated things!

[edit] I’m not finding te correct range of values in the table…just spotted that now…

I created a new branch to work on this. There are a lot of things to do! But it kind of works (

Some issues and other things to do:

  1. SetWaveform() takes an Array of floats to determine MinMax. This won’t work because a CtrlPoint could have a higher y-value. This is the case of my test file inside Build/Linux. Should we overload that function specially for Quadbezier?
  2. You were not getting the correct values mainly because normalised was > 0. I just removed the conditional. Do we need that? quadbezier tables are not supposed to be rescaled anyway.
  3. We may need a way to set the Colour for Control Handles (I set them to blue in my fork). It would be nice to have dotted lines that connect these handles with the regular ones. Every graphic editor that implements bezier curves seems to do this.
  4. It would be nice to be able to change the colour of the CtrlPoint handle to some other colour when you create a straight line between two regular Handles. This way quadbezier=gen05+gen07.
  5. Adding and deleting handles with the mouse doesn’t work.

There was another thing but I can’t remember what it was. Anyway, it is very rewarding to see this (almost) working. I can’t believe that trick with the quadratic equation works. lol.

Great work. I’ll check it in the morning. I just added you up as a collaborator to Cabbage. If you accept the email link I have a new bezier branch set up. Maybe you can pull that, add your changes and push future ones directly to that rather than a fork. I’m happy to have people help out :wink:

1 Like

I’ve made a commit with the changes and also found a bug. Sometimes the new Csound functions return 0 instead of the gen routine number. I don’t know why yet. We may need to store that number instead of making a call on each mouse drag.

I just had a chance to try it now and it works great. I did hit an assertion but hey, that’s bound to happen until everything is ironed out. Whee about are you getting the problems? In which function? I’m amazed at how efficiently the table redraws using the hfgens() method. While I was implementing this the first time I thought it would be nice to expose all those gen routines as an API. As it stands they are kind of buried pretty deep into the Csound source.

Pushed some new changes. The problem was on updatefTableData(). Apparently you can’t call CsoundGetTableArgs so often (mouse drag). I solved it by creating a new isQuadbezier function that is called only once at InsertGenTable(). It shouldn’t crash anymore and I hope I didn’t screw anything else.

If someone creates a new named gen routine we should think of another strategy.

The next thing to fix should be the setWaveform() issue. MinMax in quadbezier tables can be in one of the control points, but the whole thing is prepared to look for inside the table values.