ModScripter LFO script in progress

Hello everybody, I come here for a little bit of help but I post it here because the resolution could add something cool to the topic.

One of the big miss in the modulators is the ability to modulate the intensity of something like the LFO (or shaper and step modulator) when is assigned. I don’t know why you cannot assign a macro to that, and I hope that will be implemented in a next update because searching for it I saw many people asked for that feature.

So I started to ask to AI to give me some code (I don’t know how to code) and after an entire afternoon with different AI I still didn’t have any final result, the closest thing I had is an interface who look promising but don’t activate nothing.
So if a sweet soul knowing some coding could look inside the script to see what is missing and post it here, that will be, I belive a cool and useful help for the Cubase community :slight_smile:
I wish to everybody a nice day, and of course thank you for the help.

PS: Is a slightly enhanced LFO than the original, but if that to complicaded, the same original LFO with only an assignable intensity knob that already be cool for sure

-I will give now the prompt I asked, then the final sript :

For the Cubase 14 Modscripter, can you create a script that works in the following way:

An LFO knob that controls an LFO, which can switch between a mode synchronized to the Cubase sequencer (from 4 bars to 1/64, including triplets and dotted notes) and, with a button, switch to a free mode (ranging from 0 to 3000Hz). Include another knob that allows smooth transitions (morphing) between waveforms: sine, triangle, sawtooth, square, and finally, noise. Add an additional knob to this last knob that will create a randomness intensity on each waveform, ranging from 0% to 100% random. Then add an intensity knob that increases the intensity of the LFO’s action, ranging from 0% to 100%. And give a name to all the knobs and buttons so we can recognize them.

-And here is the script :

//-----------------------------------------------------------
getDescription = function () {
  return "LFO Modulated";
}

//-----------------------------------------------------------
// Function to create a parameter
makeParameter = function (name) {
  var value = 0;
  var listeners = [];
  return {
    name: name,
    units: "",
    stepCount: 0,
    toString: function (val) { return val; },
    fromString: function (str) { return parseFloat(str); },
    addListener: function (obj) { listeners.push(obj); },
    getValue: function () { return value; },
    getPlain: function () { return value; },
    setValue: function (val) {
      value = val;
      for (var i = 0; i < listeners.length; ++i) {
        listeners[i](this);
      }
    }
  };
}

//-----------------------------------------------------------
// Function to create a boolean parameter (On/Off)
makeBoolParameter = function (name) {
  var param = makeParameter(name);
  param.stepCount = 1;
  param.toString = function (value) { return value >= 0.5 ? "On" : "Off"; };
  param.fromString = function (str) { if (str == "On") return 1.; if (str == "Off") return 0.; };
  return param;
};

//-----------------------------------------------------------
// Function to create a parameter with a range of values
makeRangeParameter = function (name, min, max, units, precision) {
  if (precision == undefined) {
    precision = 2;
  }
  var precision = Math.pow(10, precision);
  var param = makeParameter(name);
  param.units = units;
  param.toString = function (value) {
    value = normalizedToPlain(min, max, value);
    value = Math.round(value * precision) / precision;
    return value + (this.units ? " " + this.units : "");
  };
  param.fromString = function (str) {
    var v = parseFloat(str);
    if (!isNaN(v)) {
      return plainToNormalized(min, max, v);
    }
  };
  param.getPlain = function () { return normalizedToPlain(min, max, this.getValue()); };
  return param;
};


//-----------------------------------------------------------
// Parameter definitions
const RateIndex = 1;
const SyncIndex = 2;
const WaveIndex = 3;
const RandomIndex = 4;
const AmountIndex = 5;

var parameter = [];
parameter[RateIndex] = makeRangeParameter("Rate", 0, 3000, "Hz", 0);
parameter[SyncIndex] = makeBoolParameter("Sync");
parameter[WaveIndex] = makeRangeParameter("Wave", 0, 4, "", 1);
parameter[RandomIndex] = makeRangeParameter("Random", 0, 100, "%", 0);
parameter[AmountIndex] = makeRangeParameter("Amount", 0, 100, "%", 0);


//-----------------------------------------------------------
// Function to interpolate between waveforms
function interpolateWaveform(phase, randomness) {
  var waveTypes = [
    Math.sin(phase * 2 * Math.PI), // Sine
    Math.abs(phase * 4 - 2) - 1, // Triangle
    phase < 0.5 ? phase * 2 : (1 - phase) * 2 - 1, // Sawtooth
    phase < 0.5 ? -1 : 1, // Square
    Math.random() * 2 - 1 // Noise
  ];

  var waveIndex = Math.floor(parameter[WaveIndex].getValue());
  var nextWaveIndex = (waveIndex + 1) % waveTypes.length;
  var interpolation = parameter[WaveIndex].getValue() - waveIndex;

  // Add randomness
  var randomOffset = randomness * (Math.random() * 2 - 1);

  return (1 - interpolation) * (waveTypes[waveIndex] + randomOffset) + interpolation * (waveTypes[nextWaveIndex] + randomOffset);
}

//-----------------------------------------------------------
// Variable to track elapsed time
var currentTime = 0;

//-----------------------------------------------------------
// Main modulation function
processModulation = function (inputValue, numSamples) {
  // Calculate LFO frequency
  var frequency = parameter[RateIndex].getPlain();
  if (parameter[SyncIndex].getValue() >= 0.5) {
    // Synchronized mode
    var divisions = [
      4, 2, 1, 1 / 2, 1 / 4, 1 / 8, 1 / 16, 1 / 32, 1 / 64,
      4 * 3 / 2, 2 * 3 / 2, 1 * 3 / 2, (1 / 2) * 3 / 2, (1 / 4) * 3 / 2, (1 / 8) * 3 / 2, (1 / 16) * 3 / 2, (1 / 32) * 3 / 2, (1 / 64) * 3 / 2,
      4 * 4 / 3, 2 * 4 / 3, 1 * 4 / 3, (1 / 2) * 4 / 3, (1 / 4) * 4 / 3, (1 / 8) * 4 / 3, (1 / 16) * 4 / 3, (1 / 32) * 4 / 3, (1 / 64) * 4 / 3
    ];
    frequency = getTempo() / (getMeasureLength() * divisions[Math.round(parameter[RateIndex].getValue() * (divisions.length - 1))]);
  }

  // Calculate LFO phase (using currentTime)
  var phase = (currentTime * frequency) % 1;

  // Increment elapsed time
  currentTime += numSamples / getSampleRate();

  // Calculate randomness
  var randomness = parameter[RandomIndex].getValue() / 100;

  // Generate interpolated waveform
  var wave = interpolateWaveform(phase, randomness);

  // Apply amount
  var amount = parameter[AmountIndex].getValue() / 100;

  return wave * amount;
}

//-----------------------------------------------------------
// Functions to manage parameters
onParamChange = function (paramIndex, newValue) {
  if (parameter[paramIndex]) {
    parameter[paramIndex].setValue(newValue);
  }
}

paramValueToString = function (paramIndex, paramValue) {
  if (parameter[paramIndex]) {
    return parameter[paramIndex].toString(paramValue);
  }
}

stringToParamValue = function (paramIndex, string) {
  if (parameter[paramIndex]) {
    return parameter[paramIndex].fromString(string);
  }
}

getParamTitle = function (paramIndex) {
  if (parameter[paramIndex]) {
    return parameter[paramIndex].name;
  }
}

getParamStepCount = function (paramIndex) {
  if (parameter[paramIndex]) {
    return parameter[paramIndex].stepCount;
  }
}