JSUI increase the slope of the filters.

Hugo Villanova's icon

hi I'm making a jsui for an eq. similar to abletons eq. the question is...how can I increase the slope of the lowpass and the highpass filter? I'm using this formula but I can't figure it out...

function calc_filter_coefficients(a_coeff, b_coeff) {
var alpha;
var a0, a1, a2, b0, b1, b2;
var i;

for (i = 0; i < num_filters; i++) {
if (filter_active[i]) {
var w0 = 2.0 * Math.PI * freq_vals[i] / sample_rate;
var cosw = Math.cos(w0);
var sinw = Math.sin(w0);
var A = Math.pow(10.0, gain_vals[i] / 40.0);
var qs = qors_vals[i];

switch (filter_types[i]) {
case 0: // LOWPASS COOKBOOK
alpha = sinw / (2.0 * qs);
a0 = 1.0 + alpha;
a1 = -2.0 * cosw;
a2 = 1.0 - alpha;
b0 = (1.0 - cosw) / 2.0;
b1 = 1.0 - cosw;
b2 = (1.0 - cosw) / 2.0;

break;

case 1: // HIPASS COOKBOOK
alpha = sinw / (2.0 * qs);
a0 = 1.0 + alpha;
a1 = -2.0 * cosw;
a2 = 1.0 - alpha;
b0 = (1.0 + cosw) / 2.0;
b1 = -(1.0 + cosw);
b2 = (1.0 + cosw) / 2.0;
break;

case 2: // PEAKING COOKBOOK
alpha = sinw / (2.0 * qs);
a0 = 1.0 + alpha / A;
a1 = -2.0 * cosw;
a2 = 1.0 - alpha / A;
b0 = 1.0 + alpha * A;
b1 = -2.0 * cosw;
b2 = 1.0 - alpha * A;
break;

case 3: // LO SHELF
alpha = sinw / (2.0 * qs);
a0 = (A + 1.0) - (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha;
a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cosw);
a2 = (A + 1.0) - (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha;
b0 = A * ((A + 1.0) + (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha);
b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cosw);
b2 = A * ((A + 1.0) + (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha);
break;

case 4: // HI SHELF
alpha = sinw / (2.0 * qs);
a0 = (A + 1.0) + (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha;
a1 = -2.0 * ((A - 1.0) + (A + 1.0) * cosw);
a2 = (A + 1.0) + (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha;
b0 = A * ((A + 1.0) - (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha);
b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * cosw);
b2 = A * ((A + 1.0) - (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha);
break;

}

a_coeff.push(a0);
a_coeff.push(a1);
a_coeff.push(a2);
b_coeff.push(b0);
b_coeff.push(b1);
b_coeff.push(b2);
}
}
}

Peter McCulloch's icon

To increase the slope for a highpass or lowpass filter, you need to add more stages to the filter. (I.e. more biquads)

Each biquad section you add will increase the slope by 12 dB/octave. Be aware that if you use the same filter coefficients for N subsequent stages, any gain added via resonance (Q) will be added at each stage.

A low/high pass filter with a Q of 1/sqrt(2) will not add gain so you could use that Q value for the subsequent stages instead to avoid that gain boost. You could experiment with also using a slightly higher/lower corner frequency on the added sections to tailor the response.

Hugo Villanova's icon

Hello peter…thank you for your reply. But is inside of this calculation? Or need to be outside of this? I’m not sure how can I do that…can you show me an example? Thank you so much

Peter McCulloch's icon

What you have generates one set of coefficients for each band. (Each band is one filter)

What you need in the case of variable slope filters is to generate multiple sets of coefficients for that band. (e.g., a 48 dB/Oct lowpass will have require 4 sets of lowpass coefficients)

You could modify your code by adding an array named something like filter_order, similar to the existing filter_active array. Initialize its values to 1. For high and lowpass, set the values for filter_order to the desired multiple of 12 dB/oct. (e.g., 2 will give you 24 dB/octave slope)

Right after your for i=0… statement, add an inner loop:

for (j=0; j<filter_order[i]; j++)

This will make the extra filters for those bands..

Hugo Villanova's icon

can you see what I'm doing wrong? I just want to increase the slope of the lowpass and the highpass filters from 6db to 96db. here's the full code :

// Num of Outlets

outlets = 1;

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// Object Variables ////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

// Colors

var background_rgb = [0.106, 0.106, 0.106, 0.000];
var handle_text_rgb = [0., 0., 0., 1];
var marker_rgb = [0.5, 0.5, 0.5, 0.3];
var label_rgb = [0.8, 0.8, 0.8, 0.];

var curve_rgb = [0.333, 0.871, 0.965, 1.000];

var handle_rgbs = [1.000, 0.710, 0.196, 1.000];

var handle_inactive_rgb = [0.8, 0.8, 0.8, 1.];

// Grid and Labels

var freq_grid = [ 20, 30, 40, 50,60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000];
var freq_labels = [20,"20", 100, "100", 1000, "1K", 10000, "10K"];
var freq_label_point = -10.5;

var gain_grid = [ -6, -3, 0, 3, 6, ];
var gain_labels = [-12, -9, -6, -3, 0, 3, 6, 9, 12];
var gain_label_point = 0;

// Drawing Dimensions

var curve_thickness = 1.8;
var handle_diameter = 11;
var handle_thickness = 2;

// Display and Value Ranges

var freq_lo = 10;
var freq_hi = 22000;
var freq_clip_lo = 15;
var freq_clip_hi = 20000;

var gain_range = 20; // This value should be positive for standard usage
var gain_clip = 18; // This MUST be positive

var qors_vals_clip_lo = 0.7;
var qors_vals_clip_hi = 20;

// Filter Data

var num_filters = 7;
var filter_types = [1, 4, 2, 2, 2, 3, 0];
var freq_defaults = [20, 100, 200, 1000, 2000, 5000, 20000];
var freq_vals = [20, 100, 200, 1000, 2000, 5000, 20000];
var gain_vals = [0., 0, 0, 0, 0, 0, 0,];
var qors_vals = [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7];

// Interaction Variables

var obj_active = 1;
var qors_scale = 10;

// Mousing State Variables

var select = 0;
var handle = 0;
var qors_mode = 0;
var last_x;
var last_y;

// Useful Constants

var sample_rate = 44100;
var handle_dist = handle_diameter * handle_diameter / 2.;
var mod_lo = Math.log(0.5);
var mod_scale = Math.log(2.) - mod_lo;
var log_freq_lo = Math.log(freq_lo);
var log_freq_hi = Math.log(freq_hi);
var log_10 = Math.log(10);
var freq_consts;

var margin = 25;

// Object Size

var ui_width = box.rect[2] - box.rect[0];
var ui_height = box.rect[3] - box.rect[1];

// New variable to store the active state of each filter
var filter_active = [true, true, true, true, true, true, true, true];

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Intilisation //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

// MGraphics Intilisation

mgraphics.init();
mgraphics.relative_coords = 0;
mgraphics.autofill = 0;

// Fill the frequency constants

fill_freq_consts();

// New variable to store the visibility state of each filter handle
var handle_visible = [true, true, true, true, true, true, true, true];

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Set Frequency Constants /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function fill_freq_consts()
{
var freq_val;
var i;

freq_consts = new Array;

for (i = 0; i < ui_width + 50 ; i++)
freq_consts[i] = x2freq(i);
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Parameter Conversion //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function x2freq(x)
{
return Math.exp((x / ui_width) * (log_freq_hi - log_freq_lo) + log_freq_lo);
}

function freq2x(freq)
{
return ui_width * (Math.log(freq) - log_freq_lo) / (log_freq_hi - log_freq_lo);
}

function gain2y(gain)
{
return ((gain / gain_range) - 1) * -(ui_height / 2.);
}

function y2gain(y)
{
return (y / - (ui_height / 2. ) + 1 ) * gain_range ;
}

function ydel2qors(prev_qors, ydel)
{
return prev_qors * Math.exp((mod_scale * (ydel + qors_scale) / (2. * qors_scale)) + mod_lo);
}

// Set all to local

x2freq.local = 1;
freq2x.local = 1;
gain2y.local = 1;
y2gain.local = 1;
ydel2qors.local = 1;

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// Clip Parameters /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function clip_freq(freq)
{
freq = freq < freq_clip_lo ? freq_clip_lo : freq;
freq = freq > freq_clip_hi ? freq_clip_hi : freq;

return freq;
}

function clip_gain(gain)
{
gain = gain < -gain_clip ? -gain_clip : gain;
gain = gain > gain_clip ? gain_clip : gain;

return gain;
}

function clip_qors(qors_vals)
{
qors_vals = qors_vals < qors_vals_clip_lo ? qors_vals_clip_lo : qors_vals;
qors_vals = qors_vals > qors_vals_clip_hi ? qors_vals_clip_hi : qors_vals;

return qors_vals;
}

// Set all to local

clip_freq.local = 1;
clip_gain.local = 1;
clip_qors.local = 1;

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Set Parameter Values //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function setfreq(filter, freq)
{
if (filter > 0 & filter <= num_filters)
{
freq_vals[filter - 1] = clip_freq(freq);
handle = filter - 1;
}

mgraphics.redraw();
}

function setgain(filter, gain)
{
if (filter > 0 & filter <= num_filters)
{
gain_vals[filter - 1] = clip_gain(gain);
handle = filter - 1;
}

mgraphics.redraw();
}

function setq(filter, q)
{
if (filter > 0 & filter <= num_filters)
{
qors_vals[filter - 1] = clip_qors(q);
handle = filter - 1;
}

mgraphics.redraw();
}

function settype(filter, type)
{
type = type < 0 ? 0 : type;
type = type > 6 ? 6 : type;

if (filter > 0 & filter <= num_filters)
{
filter_types[filter - 1] = type;
handle = filter - 1;
}

mgraphics.redraw();
}

function setsr(sr)
{
sample_rate = sr;

mgraphics.redraw();
}

function toggleFilter(filter) {
if (filter > 0 && filter <= num_filters) {
filter_active[filter - 1] = !filter_active[filter - 1];
handle_visible[filter - 1] = filter_active[filter - 1];
}

mgraphics.redraw();
}

function setoff(filter)
{
    toggleFilter(filter);
    mgraphics.redraw();

}

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// Set Active State of Object //////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function active(a)
{
obj_active = a;
mgraphics.redraw();
}

///////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// Filter and Curve Calculations //////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function calc_filter_coefficients(a_coeff, b_coeff) {
var alpha;
var a0, a1, a2, b0, b1, b2;
var i, j;

for (i = 0; i < num_filters; i++) {
if (filter_active[i]) {
var w0 = 2.0 * Math.PI * freq_vals[i] / sample_rate;
var cosw = Math.cos(w0);
var sinw = Math.sin(w0);
var A = Math.pow(10.0, gain_vals[i] / 40.0);
var qs = qors_vals[i];

switch (filter_types[i]) {
case 0: // LOWPASS COOKBOOK
alpha = sinw / (2.0 * qs);
a0 = 1.0 + alpha;
a1 = -2.0 * cosw;
a2 = 1.0 - alpha;
b0 = (1.0 - cosw) / 2.0;
b1 = 1.0 - cosw;
b2 = (1.0 - cosw) / 2.0;

break;

case 1: // HIPASS COOKBOOK
alpha = sinw / (2.0 * qs);
a0 = 1.0 + alpha;
a1 = -2.0 * cosw;
a2 = 1.0 - alpha;
b0 = (1.0 + cosw) / 2.0;
b1 = -(1.0 + cosw);
b2 = (1.0 + cosw) / 2.0;
break;

case 2: // PEAKING COOKBOOK
alpha = sinw / (2.0 * qs);
a0 = 1.0 + alpha / A;
a1 = -2.0 * cosw;
a2 = 1.0 - alpha / A;
b0 = 1.0 + alpha * A;
b1 = -2.0 * cosw;
b2 = 1.0 - alpha * A;
break;

case 3: // LO SHELF
alpha = sinw / (2.0 * qs);
a0 = (A + 1.0) - (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha;
a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cosw);
a2 = (A + 1.0) - (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha;
b0 = A * ((A + 1.0) + (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha);
b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cosw);
b2 = A * ((A + 1.0) + (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha);
break;

case 4: // HI SHELF
alpha = sinw / (2.0 * qs);
a0 = (A + 1.0) + (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha;
a1 = -2.0 * ((A - 1.0) + (A + 1.0) * cosw);
a2 = (A + 1.0) + (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha;
b0 = A * ((A + 1.0) - (A - 1.0) * cosw + 2.0 * Math.sqrt(A) * alpha);
b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * cosw);
b2 = A * ((A + 1.0) - (A - 1.0) * cosw - 2.0 * Math.sqrt(A) * alpha);
break;

}

a_coeff.push(a0);
a_coeff.push(a1);
a_coeff.push(a2);
b_coeff.push(b0);
b_coeff.push(b1);
b_coeff.push(b2);

}
}
}

function calc_db(freq, a_coeff, b_coeff)
{
var freq_val = 2 * Math.PI * freq / sample_rate;
var pow = 1;
var i;

var A = 0.;
var B = 0.;
var C = 0.;
var D = 0.;

var cos1 = Math.cos(freq_val);
var sin1 = Math.sin(freq_val);
var cos2 = Math.cos(freq_val * 2);
var sin2 = Math.sin(freq_val * 2);

// Accumulate the power response of the filters at a given input frequency

for (i = 0; i < num_filters; i++)
{
     if (filter_active[i]) {

A = b_coeff[i * 3] + b_coeff[i * 3 + 1] * cos1 + b_coeff[i * 3 + 2] * cos2;
B = b_coeff[i * 3 + 1] * sin1 + b_coeff[i * 3 + 2] * sin2;
C = a_coeff[i * 3] + a_coeff[i * 3 + 1] * cos1 + a_coeff[i * 3 + 2] * cos2;
D = a_coeff[i * 3 + 1] * sin1 + a_coeff[i * 3 + 2] * sin2;

var denominator = 1. / (C*C + D*D);
var real = (A*C + B*D) * denominator;
var imag = (B*C - A*D) * denominator;

pow *= (real * real + imag * imag);
}
}
// Return the response in db

return 10. * Math.log(pow) / log_10;
}

///////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Paint Routine //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
function logarithm(base, x) {
return Math.log(x) / Math.log(base);
}

function paint() {
var a_coeff = new Array();
var b_coeff = new Array();
var i;

// Clear background
mgraphics.set_source_rgba(0, 0, 0, 1);
mgraphics.rectangle(0, 0, mgraphics.size[0], mgraphics.size[1]);
mgraphics.fill();

// Draw frequency grid
mgraphics.set_line_width(1);
mgraphics.set_source_rgba(0.2, 0.2, 0.2, 1); // Grey color

var minFreq = 10;
var maxFreq = 24000;
var minPosX = 0;
var maxPosX = mgraphics.size[0];

var frequencies = [20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000];

for (var i = 0; i < frequencies.length; i++) {
var freq = frequencies[i];
var posX = minPosX + (maxPosX - minPosX) * (logarithm(10, freq) - logarithm(10, minFreq)) / (logarithm(10, maxFreq) - logarithm(10, minFreq));
mgraphics.move_to(posX, 0);
mgraphics.line_to(posX, mgraphics.size[1]);
mgraphics.stroke();
}

// Draw frequency labels
mgraphics.select_font_face("Arial", "normal", "normal");
mgraphics.set_font_size(10);
mgraphics.set_source_rgba(0.5, 0.5, 0.5, 0.7); // White color

// Labels for the frequencies
var labels = ["20Hz", "100", "1K", "10K", "20K"];
var labelPositions = [20, 100, 1000, 10000, 20000];

var bottomMargin = -9; // Margin from the bottom
var minPosY = bottomMargin;

for (var i = 0; i < labels.length; i++) {
var label = labels[i];
var freq = labelPositions[i];
var posX = minPosX + (maxPosX - minPosX) * (logarithm(10, freq) - logarithm(10, minFreq)) / (logarithm(10, maxFreq) - logarithm(10, minFreq));
var textWidth = mgraphics.text_measure(label)[0];
var posY = mgraphics.size[1] - 15;

// Calculate the vertical position with bottom margin
posY -= minPosY;

mgraphics.move_to(posX - textWidth / 2, posY);
mgraphics.show_text(label);

}

var minGain = -18;
var maxGain = 18;
var topMargin = 25; // Margin from the top
var bottomMargin = 25; // Margin from the bottom

var minPosY = mgraphics.size[1] - topMargin;
var maxPosY = bottomMargin;

var numLines = 7;
var lineSpacing = (maxPosY - minPosY) / (numLines - 1);
var gainStep = (maxGain - minGain) / (numLines - 1);

// Draw horizontal lines and labels
mgraphics.set_line_width(1);
mgraphics.select_font_face("Arial", "normal", "normal");
mgraphics.set_font_size(8);

for (var i = 0; i < numLines; i++) {
var posY = minPosY + i * lineSpacing;

// Draw horizontal line
mgraphics.move_to(0, posY);
mgraphics.set_source_rgba(0.2, 0.2, 0.2, 1);
mgraphics.line_to(mgraphics.size[0], posY);
mgraphics.stroke();

// Draw gain label
var gain = minGain + i * gainStep;
var gainLabel = gain.toFixed(0) + "";
var textWidth = mgraphics.text_measure(gainLabel)[0];
mgraphics.move_to(margin - textWidth - 5, posY + 2);
mgraphics.set_source_rgba(0.5, 0.5, 0.5, 1);
mgraphics.show_text(gainLabel);
}

with (mgraphics) {
internalresize(mgraphics.size[0], mgraphics.size[1]);

// Set curve width and color for the response curve
set_line_width(curve_thickness);

// Draw frequency response
for (i = 0; i < ui_width + 1; i++) {
var db_plot = 0; // Initialize the response curve value

// Calculate the response curve for active filters
for (var j = 0; j < num_filters; j++) {
if (filter_active[j]) {
// Calculate filter coefficients
calc_filter_coefficients(a_coeff, b_coeff, j);

// Calculate response curve value at the given frequency
db_plot = calc_db(freq_consts[i], a_coeff, b_coeff);
}
}

var plot_y = gain2y(db_plot);

if (i == 0)
move_to(0, plot_y);
else
line_to(i, plot_y);
}

// Draw the curve
if (obj_active)
set_source_rgba(curve_rgb);
else
set_source_rgba(curve_inactive_rgb);
stroke();

// Set font and line width for handles
select_font_face("Arial");
set_font_size(8);
set_line_width(handle_thickness);

// Draw filter handles
for (i = 0; i < num_filters; i++) {
if (filter_active[i]) {
if (handle_visible[i]) {
// Calculate handle position
var x = freq2x(freq_vals[i]);
var y = gain2y(gain_vals[i]);
var measure = text_measure((i + 1).toString());

// Set handle color
if (obj_active)
set_source_rgba(handle_rgbs);
else
set_source_rgba(handle_inactive_rgb);

if (i == handle) {
// Draw selected handle
var handle_adjust = handle_diameter + handle_thickness;
ellipse(x - handle_adjust / 2, y - handle_adjust / 2, handle_adjust, handle_adjust);
fill();

// Render handle text
set_source_rgba(handle_text_rgb);
move_to(x - measure[0] / 2, y + (measure[1] / 2) * 0.65);
show_text((i + 1).toString());
} else {
// Draw non-selected handle
ellipse(x - handle_diameter / 2, y - handle_diameter / 2, handle_diameter, handle_diameter);
stroke();

// Render handle text
move_to(x - measure[0] / 2, y + (measure[1] / 2) * 0.65);
show_text((i + 1).toString());
}
}
}
}
mgraphics.redraw();
}
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Mousing Interaction ///////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function onclick(x, y, but, cmd, shift, capslock, option, ctrl)
{
var min_dist = 100000000;
var i;

// Assume no selection - check for qors_vals edit mode

select = 0;
qors_mode = option;

// Cache mouse position for tracking delta movements

last_x = x;
last_y = y;

// Loop over handles looking for the closet valid match to select

for (i = 0; i < num_filters; i++)
{
var compare_x = freq2x(freq_vals[i]);
var compare_y = gain2y(gain_vals[i]);

compare_x -= x;
compare_y -= y;

var compare_dist = compare_x * compare_x + compare_y * compare_y;

if ((compare_dist < handle_dist) && (compare_dist < min_dist))
{
select = 1;
handle = i;
}
}

// If a handle is selected, output the display message and hide the cursor

if (select)
{
outlet(0, "display", handle + 1);
max.message("hidecursor");
}
}

function ondrag(x, y, but, cmd, shift, capslock, option, ctrl)
{
// If a handle is selected and we hace moved, update the values according to mousing

if (select)
{
if (qors_mode)
{
var ydel = y - last_y;
qors_vals[handle] = clip_qors(ydel2qors(qors_vals[handle], ydel));
outlet(0, "q", handle + 1, qors_vals[handle]);
}
else
{
freq_vals[handle] = clip_freq(x2freq(x - last_x + freq2x(freq_vals[handle])));
outlet(0, "freq", handle + 1, freq_vals[handle]);
gain_vals[handle] = clip_gain(y2gain(y - last_y + gain2y(gain_vals[handle])))
outlet(0, "gain", handle + 1, gain_vals[handle]);

}
}

// Deselect if the button has gone up

if (!but)
{
select = 0;
max.message("showcursor");
}

// Store current position and redraw

last_x = x;
last_y = y;
mgraphics.redraw();
}

function ondblclick(x, y, but, cmd, shift, capslock, option, ctrl)
{
// Set last position to current and call click routine to select nearest point

last_x = x;
last_y = y;

onclick (x, y, but, cmd, shift, capslock, option, ctrl);

// If a handle was selected reset the y value

if (select)
{

     freq_vals[handle] = freq_defaults[handle];
     outlet(0, "freq", handle + 1, freq_vals[handle]);
     qors_vals[handle] = 0.7;
     outlet(0, "q", handle + 1, qors_vals[handle]);
gain_vals[handle] = 0.;
outlet(0, "gain", handle + 1, gain_vals[handle]);
}

// Deselect the handle

select = 0;
max.message("showcursor");
}

// Set all to local

ondrag.local = 1;
onclick.local = 1;
ondblclick.local = 1;

///////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Object Resize //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

function internalresize(w,h)
{
if (ui_width !== w || ui_height !== w)
    {
        ui_width = w-4;
    ui_height = h;

    fill_freq_consts();
    }
}
internalresize.local = 1;

function onresize(w,h)
{
ui_width = w + 25;
ui_height = h + 25;

internalresize(w, h);

mgraphics.redraw();
}
onresize.local = 1;

function sethandle_rgbs(r, g, b, a){
handle_rgbs = [r, g, b, a];
mgraphics.redraw();
}

function setHandle_inactive_rgb(r, g, b, a){
handle_inactive_rgb = [r, g, b, a];
mgraphics.redraw();
}

function setCurve_rgb(r, g, b, a){
curve_rgb = [r, g, b, a];
mgraphics.redraw();
}

function setInactiveCurve_rgb(r, g, b, a){
curve_inactive_rgb = [r, g, b, a];
mgraphics.redraw();
}

Hugo Villanova's icon

If I could change the slope with the handles as well, it would be fantastic.

Hugo Villanova's icon

Thank you so much for your help.