Modifier curves - mathematics?

Scrutinizer

Experienced
I'm adding modifier support to the Axe for Live template for Lemur/iPad, and was wondering if anyone can help me with the math needed to duplicate the graph shown on the AxeFX modifier screen. I want to use a Lemur signalscope object to display the curve on the iPad screen.

The shape of the AxeFX modifier curve is defined by just four parameters: Start, Mid, End, and Slope. Scale and offset are essentially zoom and pan operations on this curve, so can be ignored for purpose of this discussion.

So I have three points and a mysterious Slope parameter. The curve looks like a polynomial interpolation, but I am not sure how to include Slope into the equation.

Any math wizards in the house that can help?
 
Just a wild guess: a 2D bezier curve. 4 points:

Code:
^
|                 p2
|          p2'    
|    
|
|
|      p1'
|p1
 ----------------->

Start and end points (p1, p2) can vary along the Y axis (vertically).
Slope and mid parameters define the remaining 2 points (p1', p2'). Slope at 50% and mid at 50% -> the 2 points are centered in the graph.
Slope above 50% -> p1' moves toward Y- and p2' moves toward Y+
Mid above 50% -> p1' and p2' both move toward Y+
 
That reads as if SYSEX_GET_GRAPH were documented somewhere where other people would know what it means. Quick search for SYSEX_GET_GRAPH shows 0 hits. Have an inside source?
 
I can't help with the math, but I can cheer the effort. The possibility of support for modifiers within the Lemur template is tremendously exciting news. Go Scrutinizer!!!
 
No need to calculate the graph yourself - the Axe-FX can send the graph to you as plot offsets using a SYSEX_GET_GRAPH MIDI call.
You are awesome! Can you share additional info, like the function ID? As far as I can tell the GET_GRAPH message is not used by the latest AxeEdit ... was it used in a previous AxeEdit version?
 
I don't have any knowledge about AxeEdit sysex messages , I guess You can use midi monitor program to see how the SysEx exchange is done .

Zbyszek
 
Hi ,
I found midi sysex implementation for You with SYSEX_GET_GRAPH commands.

Zbyszek

http://www2.webster.edu/acadaffairs...quipment manuals/k2500_ref_guide/11 SysEx.pdf
Thanks for the info.

Each manufacturer uses a different format for their sysex messages, so the AxeFX's GET_GRAPH message format is probably not the same as the Kurzweil K2500 GET_GRAPH. It is cool to see the K2500 sysex spec, though. Years ago, a jamming buddy of mine used to leave his K2000 at my apartment. I had lots of fun learning how program that synth.
 
Yes, each manufacturer uses GET_GRAPH differently ,but my guess is that the Status Byte stays the same and how many data bytes follow depends of graphics resolution unit is sending.
Anyway, all the best with Your project - keep us informed.

Zbyszek
 
Yeah, the MIDI_GET_GRAPH call is something I will be using all over the next version of AxePad that I am working on. It is in the official MIDI specs from Fractal. I had assumed that Scrutinizer already had a copy of that document.

At risk of getting a slap on the wrist from FA, here is what I have worked out. Note: The MIDI specs are still a little short on detail about this call, so I had to do some sleuthing work myself to work out how to interpolate the values.

MIDI_GET_GRAPH is function number 0x30. It will return a 127 byte stream relating to the LAST block parameter you queried from the device. So, if you query any of the Amp Speaker controls, then a call to MIDI_GET_GRAPH immediately afterwards will return the speaker graph for the block. Similar if you call any of the PEQ parameters, then this call will return the PEQ graph.

I have never actually tested it with the Modifier graph, but it should so the same after you call any Modifier parameter. I'll be including Modifiers in the next AxePad release anyhow, so I expect I will have to come across this at some stage.

The MIDI call to send looks like: F0 00 01 74 03 30 36 F7

The response will be the standard MIDI header (with 0x30 as the function call) plus 127 values split as 2 byte MIDI packets.

That was about as far as the Fractal specs went. The following is what I deduced after a few hours of playing with this command and studying the returned data:

To convert the 2 byte MIDI packets into a readable value is fairly simple. The data comes back as a series with the LSB first then the MSB. To convert to a single value byte:

(MSB << 7) || LSB

This then gives you a series of 127 bytes with the values 0 to 16384. You basically need to plot these values onto a graph with 127 points along the X axis. The values above are the Y axis values... BUT

You will need to cater for negative values. In the returned data, any value ABOVE 8192 is actually a negative value, so you will need to 'clean up' the Y axis values first to give you a proper range of negative and positive values to plot, as thus:

If Value > 8192 Then Value = Value - 16384

Now it is simply a case of plotting these. Pseudocode for doing so will be similar to:

Code:
ReturnedValueArray[] = ResultsOfMIDICall(0x30)

For X = 1 to 127
    Y = ReturnedValueArray[X]
    // Convert to positive/negative as explained above
    If Y > 8192
        Y = Y - 16384
    End If
    Plot(X, Y)
End For

Hope this helps.
 
Thanks so much! Yeah, I hope you don't get into trouble for sharing this.

FWIW, the response message is too long to be received by Lemur. The arrays in Lemur are limited to 256 items, so I only get the first 256 bytes of the response. That will be enough to get the first 125 points in the graph, and the other two points will be easy to calculate.

I've not seen the midi spec yet. I am looking forward to see what other goodies are hidden in there.
 
I didn't realise about the array limits. Does that limit include the MIDI header and footer as well? Don't forget there will be 6 bytes for the header, then a further 2 for the checksum and footer as well as the graph payload.

I don't think that missing a few points at the end will really be a major issue, especially on a small display screen. If you trimmed off the first few as well, and perhaps plotted 120 values on the graph then it should still give a good indication of the slope to the end user.

The Modifier graphs are straight linear I believe, but don't forget that the PEQ graphs etc. are logarithmic, so if you are displaying axis values/indicators in lemur you have to cater for that. Check the graph backgrounds in Axe-Edit for details.
 
I didn't realise about the array limits. Does that limit include the MIDI header and footer as well? Don't forget there will be 6 bytes for the header, then a further 2 for the checksum and footer as well as the graph payload.
The Lemur array limit is incredibly frustrating. There are no 2D arrays, but text arrays are supported. Arrays of bytes can be converted to a text string, but text strings cannot be converted to arrays of bytes, and there is no way to manipulate the string (no way concatenate or split strings, and no sprintf functions to convert numbers into text strings).

The array containing the incoming sysex does not include the F7 byte, but it does include the final F0 byte. Here is what the GET_GRAPH response looks like in my Lemur test template (let me know if you could use the template, I'm more than happy to share this).
IMG_0345.PNG


I don't think that missing a few points at the end will really be a major issue, especially on a small display screen. If you trimmed off the first few as well, and perhaps plotted 120 values on the graph then it should still give a good indication of the slope to the end user.
Agreed. And I think the final point in the graph will be easy to determine from the End, Scale, and Offset numbers.

The Modifier graphs are straight linear I believe, but don't forget that the PEQ graphs etc. are logarithmic, so if you are displaying axis values/indicators in lemur you have to cater for that. Check the graph backgrounds in Axe-Edit for details.
Wow, EQ graphs can be queried. Awesome!
 
Anyone know where this is? I couldn't find it on the website.

It's not released officially yet, as it is still a 'works in progress'. I am hoping I do not get into strife for sharing what I already did, but actually, the extra things that I have worked out, I intend to pass back to the document author so that they can incorporate it into the official specs.
 
(let me know if you could use the template, I'm more than happy to share this).

Thanks! I may take you up on this. I haven't actually got the Lemur editor on my iPad yet, but am thinking I might have to bite the bullet and get it. Would make testing/playing with MIDI a lot easier! :)

Wow, EQ graphs can be queried. Awesome!

Yes - any graph that the Axe-FX can display can be queried, even the Tone Match one. The trick is to do a little housekeeping because you cannot ask it for WHICH graph. It will send you the graph pertaining to the last parameter your queried. So if you asked for an Amp Speaker parameter value, the next call to SYSEX_GET_GRAPH would return the Speaker EQ graph. If you queried a Tone Match parameter, then the TM graph would be returned. You just have to be aware what the last parameter call was so you can put the graph into context.
 
I was having trouble getting the AxeII into the state where it returns the modifier graph. The Axe returns the graph pertaining to the last parameter that was queried, or whatever graph is last shown on the Axe front panel. So it sometimes is an EQ graph, other times I see one of the ADSR graphs.

So I gave up on that and found a nice solution using Bezier curves (thanks gpz for the hint!).

After lots of thinking and a little experimentation, I found that the modifier curve can be plotted using two quadratic Bezier curves defined by Y coordinates {a,b,c} and {c,d,e}, where
s = SLOPE, range -1 to +1
a = START, range 0 to 1
c = MID, range 0 to 1
e = END, range 0 to 1
b = c - (e - a + s)/4
d = c + (e - a + s)/4

The graph generated by these Bezier curves looks identical to the front panel at all settings I've tried so far.
IMG_0346.PNG
 
Very nice Scrutinizer! Did you try first with cubic bezier (4 points)?
Yes, I tried that, in a thought experiment using this Bezier curve demo:
Bezier Curve Demo

With a 4 point Bezier the MID point in the modifier curve will not always be on the line connecting the two internal control points, so it seemed like that was not the solution. With a composite curve built from two 3 point Bezier curves, the curve must pass thru the MID point.

Feel free to copy and modify this code...
Code:
/****
 * Draw AxeFX modifier curve using DeCasteljau algorithm
 * Inspired by: http://cubic.org/docs/bezier.htm
 * Inputs:
 *    ay is the START setting, range 0 to 1
 *    cy is the MID setting, range 0 to 1
 *    ey is the END setting, range 0 to 1
 *    slope is the SLOPE setting, range -1 to 1
 *    scale is the SCALE setting, range 0 to 1
 *    offset is the OFFSET setting, range 0 to 1
****/
by = cy - (ey - ay + slope) / 4
dy = cy + (ey - ay + slope) / 4
k = (100 ^ scale) / 10

// draws graph of 2*n+1 points
For i=0 To n
    t = i / n

    aby = ay + (by - ay) * t
    bcy = by + (cy - by) * t
    y = aby + (bcy - aby) * t    // left side Bezier curve
    y = (y - 0.5) * k + offset    // scale and offset
    If y < 0 Then y = 0    // constrain values
    If y > 1 Then y = 1
    Plot(i, y * (2 * n + 1))

    cdy = cy + (dy - cy) * t
    dey = dy + (ey - dy) * t
    y = cdy + (dey - cdy) * t    // right side Bezier curve
    y = (y - 0.5) * k + offset    // scale and offset
    If y < 0 Then y = 0    // constrain values
    If y > 1 Then y = 1
    Plot(i + n, y * (2 * n + 1))
End For

Edit: fixed bug so it will now plot start, mid, and end points in the graph accurately
 
Last edited:
Back
Top Bottom