User Tools

This is an old revision of the document!


Chataigne

GrandMa2 fader automation

module.json

	{
	"name":"GrandMa2Msc",
	"type":"MIDI",
	"path":"Hardware",

	"version":"0.0.1",
	"description":"Chataigne script to record and play grandma2 msc events",
	"url":"https://github.com/ssm2017/chataigne_grandma2msc",
	"downloadURL":"Chataigne script to record and play grandma2 msc events",

	"hasInput":true,
	"hasOutput":true, 

	"hideDefaultCommands":true,
	"parameters":
	{
		"Module parameters":
		{
			"type":"Container",
			"collapsed":false,
			"LogSysex":{"type":"Boolean", "description":"Choose if you want to see a translation of the sysex.\nThe script logs must be activated.", "default":false}
		}
	},
	"defaults":
	{
		"autoAdd":false
	},
	"hideDefaultParameters":
	[
		"autoAdd",
		"autoFeedback",
		"infos",
		"tempo",
		"MTC"
	],
	"scripts":
	[
		"grandma2msc.js"
	]
}

module script

/**
 * Vanilla JUCE JS doesn't support the toFixed() function for rounding numbers to decimal places.
 * So we need to make our own to get around the floating point math errors causing glitches
 * @author : DJSTech + ssm2017 (convert to float)
 * @link : https://discord.com/channels/697400442027769998/1058493819877851136/1059853940818198629
 * @param {int} precision 
 * @param {float} value 
 * @returns {float}
 */
function fixedIt(value, precision) {
  var num = "" + (Math.round(value * Math.pow(10, precision)));
  return parseFloat(num.substring(0, num.length - precision) + "." + num.substring(num.length - precision, num.length));
}

/**
 * Convert the hex values sent by the desk to 0 thru 100 level
 * @param {*} coarse (coarse value (byte 8))
 * @param {*} fine (fine value (byte 7))
 * @returns {float} (the fader level)
 */
function hex2FaderLevel(coarse, fine) {
  return fixedIt((((fine / 128) + coarse) / 1.28), 2);
  //return (((fine / 128) + coarse) / 1.28);
}

/**
 * Set the fader level if the param exists or create the param if not exists.
 * @param {int} exec_page (the fader page id (byte 6))
 * @param {int} exec_id (the fader id in the page (byte 5))
 * @param {float} fader_level (the level of the fader (see: hex2FaderLevel function))
 */
function setFaderParamLevel(exec_page, exec_id, fader_level) {
  var param_name = "faderPage"+ exec_page+ "Exec"+ exec_id;
  //var param = script.params.getChild(param_name);
  //var param = local.parameters.getChild(param_name);
  var param = local.values.getChild(param_name);
  if (typeof param === "void") {
    //script.addFloatParameter(param_name,"Value of the fader Exec ", fader_level, 0, 100);
    //local.parameters.addFloatParameter(param_name,"Value of the fader Exec ", fader_level, 0, 100);
    local.values.addFloatParameter(param_name,"Value of the fader Exec ", fader_level, 0, 100);
  }
  else {
    param.set(fader_level);
  }
}

/**
 * Display the sysex data with translation in the log
 * @param {array} data (the sysex message as array of bytes)
 */
function logSysex(data) {
	script.log("-------- sysex message start ---------");
	script.log("0 universal_sysex > "+ data[0]);
	script.log("1 device_id > "+ data[1]);
	script.log("2 msc > "+ data[2]);
	script.log("3 command_format > "+ data[3]);
	script.log("4 command > "+ data[4]);
  // if this is a goto message (go)
  if (data[4] == 1) {
    script.log("go");
  }
  // if this is a pause message (stop)
  if (data[4] == 2) {
    script.log("stop");
  }
  // if this is a un-pause message (resume)
  if (data[4] == 3) {
    script.log("resume");
  }
  // if this is a timed go message (timed_go)
  if (data[4] == 4) {
    script.log("timed go");
  }
  // if this is a fader level (set)
  if (data[4] == 6) {
    script.log("5 exec > "+ data[5]);
	  script.log("6 exec page > "+ data[6]);
	  script.log("7 fine value > "+ data[7]);
	  script.log("8 coarse value > "+ data[8]);
  }
  // if this is a macro trigger message (fire)
  if (data[4] == 7) {
    script.log("timed go");
  }
  // if this is a off message (go_off)
  if (data[4] == 10 || data[4] == 11) {
    script.log("go off");
  }
	script.log("-------- sysex message end ---------");
}

/**
 * Parse received data and fill parameters
 * @param {array} data (sysex data received knowing that the first (f0) and the last one (f7) are truncated)
 */
function parseSysex(data) {
  // check if data is a fader move
  if (data[4] == 6) {
    var fader_level = hex2FaderLevel(data[8], data[7]);
    setFaderParamLevel(data[6], data[5], fader_level);
  }
}

/**
 * Get the page and exec id from parameter name
 * @param {string} param_name 
 * @returns {array} 0=page / 1=fader
 */
function getFaderIdFromParamName(param_name) {
  var strings = param_name.replace("faderPage", "").replace("Exec", "-").split("-");
  return [parseInt(strings[0]), parseInt(strings[1])];
}

/**
 * Get coarse and fine values to be sent to sysex
 * @param {float} fader_value 
 * @returns {array} 0=coarse / 1=fine
 */
function parseFaderValueToCoarseFine(fader_value) {
  var temp_coarse = fader_value * 1.28;
  var coarse = parseInt(Math.floor(temp_coarse));
  var coarse_decimals = parseFloat(fixedIt(2,temp_coarse %2));
  var temp_fine = coarse_decimals * 128;
  var fine = parseInt(Math.floor(temp_fine));
  return [coarse, fine];
}

/**
 * Build the sysex output and send it to move the selected fader
 * @param {int} execId 
 * @param {int} pageId 
 * @param {float} fader_value 
 */
function sendFaderSysex(execId, pageId, fader_value) {
  // workaround for an error when loading the module without parameter defined ? no, need to find something
  script.log("===== "+ typeof fader_value);
  if (typeof fader_value === array) return;
  // send sysex
  var sysex = [127,112,2,1,6];
  sysex[5] = execId;
  sysex[6] = pageId;
  var coarse_fine = parseFaderValueToCoarseFine(fader_value);
  sysex[7] = coarse_fine[1];
  sysex[8] = coarse_fine[0];
  local.sendSysex(sysex[0], sysex[1], sysex[2], sysex[3], sysex[4], sysex[5], sysex[6], sysex[7], sysex[8]);
}

/**
 * Chataigne event triggered when receiving sysex data
 * @param {array} data (sysex data received)
 */
function sysExEvent(data) {
  if (local.parameters.moduleParameters.logSysex.get())logSysex(data);
  parseSysex(data);
}

/**
 * Chataigne event triggered when a script parameter value has changed
 * @param {object} param 
 */
function moduleParameterChanged(param) {
  var index = getFaderIdFromParamName(param.name);
  sendFaderSysex(index[1], index[0], param.get());
}

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also, you acknowledge that you have read and understand our Privacy Policy. If you do not agree, please leave the website.

More information