User Tools

Site Tools


chataigne

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);
  if (typeof param === "void") {
    //script.addFloatParameter(param_name,"Value of the fader Exec ", fader_level, 0, 255);
    local.parameters.addFloatParameter(param_name,"Value of the fader Exec ", fader_level, 0, 255);
  }
  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) {
  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());
}

chataigne.1675473892.txt.gz · Last modified: by ssm2017