Samson Conspiracy MIDI Controller working with QLC+

This is a place for sharing with the community the results you achieved with QLC+, as a sort of use case collection.
You can share photos, videos, personal hardware/software projects, interesting HOWTO that might help other users to achieve great results.
Post Reply
ssribeiro
Posts: 2
Joined: Tue Dec 24, 2019 9:45 pm
Real Name: Luan Ribeiro

I got it working in my Linux 64 bits, after a long struggle battle.

What I did? I created a MIDI translator using NodeJs (which one I kindly called midi3po { qlc midi controllers relationship droid }).
I will share the code index.js I used and if can edit the "names" to match your system names..
If anyone got interested I can share more details about setup..

I am planning to use the matrix button colors to match the fixture selected (each matrix button is a par 54 leds).
This controller also has a x/y pad to setup moving heads.

(in case you think the 127 range to 254 range is an issue, I got some range selectors to help with this..)

// index.js

Code: Select all

/*
 * Matrix Buttons COLORS
 *
 * 0 - off
 * 1 - RED
 * 2 - GREEN
 * 3 - BLUE
 * 4 - off
 * 5 - off
 * 6 - off
 * 7 - off
 * 8 - RED + GREEN = YELLOW
 * 9 - RED + GREEN = YELLOW
 * 10 - RED + GREEN = YELLOW
 * 11 - RED + GREEN = YELLOW
 * 12 - off
 * 13 - RED + GREEN = YELLOW
 * 14 - off
 * 15 - off
 * 16 - off
 * 17 - off
 * 18 - off
 * 19 - RED + GREEN = YELLOW
 * 20 - off
 * 21 - RED
 * 22 - GREEN
 * 23 - RED + GREEN = YELLOW
 * 24 - BLUE
 * 25 - RED + BLUE = MAGENTA
 * 26 - GREEN + BLUE = CYAN
 * 27 - ALL = WHITE
 * 28 - off
 * 29 - RED
 * 30 - GREEN
 * 31 - YELLOW
 * 32 - BLUE
 * 33 - MAGENTA
 * 34 - CYAN
 * 35 - WHITE
 * 36 - off
 * 37 - RED
 * 38 - GREEN
 * 39 - YELLOW
 * 40 - BLUE
 */

const easymidi = require("easymidi");

const inputs = easymidi.getInputs();
const outputs = easymidi.getOutputs();

console.log("Inputs: ");
console.log(inputs);
console.log("Outputs: ");
console.log(outputs);

const qlcIn = new easymidi.Input("MIDI 3PO QLC INPUT", true);
const qlcOut = new easymidi.Output("MIDI 3PO QLC OUTPUT", true);

const consIn = new easymidi.Input("Conspiracy:Conspiracy MIDI 1 20:0");
const consOut = new easymidi.Output("Conspiracy:Conspiracy MIDI 1 20:0");

console.log("Virtual QLC Input:");
console.log(qlcIn);
console.log("Virtual QLC Output:");
console.log(qlcOut);
console.log("Conspiracy Input:");
console.log(consIn);
console.log("Conspiracy Output:");
console.log(consOut);

/* CONS INPUT RACE */

// FOR CC

consIn.on("cc", msg => {
  console.log("_____________________________________________________");
  console.log("FROM Conspiracy INPUT");
  console.log("cc", msg.controller, msg.value, msg.channel);

  // Filter for F1 to F10 functions makes the SIGNAL
  // on Release instead of on push
  if (
    msg.controller >= 20 &&
    msg.controller <= 29 &&
    (msg.channel === 1 || msg.channel === 2)
  ) {
    msg.value = msg.value === 127 ? 0 : 127;
    console.log("sent to qlc: ");
    console.log("cc", msg);
    qlcOut.send("cc", msg);
    return;
  }

  // basic thru if no filters
  qlcOut.send("cc", msg);
});

// FOR NOTEON // NOTEOFF

consIn.on("noteon", msg => {
  // Matrix is noteon/off 36 ~ 60 channel 1
  // should respond feedback is noteon/off 0 ~ 25 (transposed) channel 0

  console.log("_____________________________________________________");
  console.log("FROM Conspiracy INPUT");
  console.log("noteon", msg.note, msg.velocity, msg.channel);

  // basic thru if no filters
  // qlcOut.send("noteon", msg); // ignore
});

consIn.on("noteoff", msg => {
  console.log("_____________________________________________________");
  console.log("FROM Conspiracy INPUT");
  console.log("noteoff", msg.note, msg.velocity, msg.channel);

  // change the velocity from the minimum to the max
  msg.velocity = 127;

  // basic thru if no filters
  qlcOut.send("noteon", msg); // translates to the onRelease
});

// ____________________________________________________________________

/* QLC FEEDBACK RACE */

qlcIn.on("cc", msg => {
  console.log("-----------------------------------------------------");
  console.log("FROM QLC FEEDBACK");
  console.log("cc", msg.controller, msg.value, msg.channel);

  // Filter F1 ~ F9 functions buttons
  if (msg.controller >= 20 && msg.controller <= 28 && msg.channel === 1) {
    msg = filterToFunctionValue(msg);
    const transNote = {
      note: msg.controller + 5,
      velocity: msg.value,
      channel: msg.channel - 1
    };

    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }
  // ENDOF Filter F1 ~ F9 functions buttons

  // Filter F10 function button
  if (msg.controller === 29 && msg.channel === 1) {
    msg = filterToFunctionValue(msg);
    const transNote = {
      note: msg.controller + 12,
      velocity: msg.value,
      channel: msg.channel - 1
    };

    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }
  // ENDOF Filter F10 function button

  // Midia BUTTONS

  // Filter Back Button
  if (msg.controller == 20 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 34,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // Filter Next Button
  if (msg.controller == 21 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 36,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // Filter Up Button
  if (msg.controller == 22 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 35,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // Filter Down Button
  if (msg.controller == 23 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 37,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // Filter Play Button
  if (msg.controller == 24 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 38,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // Filter Stop Button
  if (msg.controller == 25 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 39,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // Filter Record Button
  if (msg.controller == 26 && msg.channel === 2) {
    msg = filterToMidiaValue(msg);
    const transNote = {
      note: 40,
      velocity: msg.value,
      channel: 0
    };
    console.log("sent to conspiracy: ");
    console.log("noteon", transNote);
    consOut.send("noteon", transNote);
    console.log(".................................................");
    return;
  }

  // ENDOF Filter Play/Stop.. buttons

  // basic thru if no filters
  consOut.send("cc", msg);
});

const filterToFunctionValue = msg => {
  // basic value fixes:
  if (msg.value === 127) {
    msg.value = 42;
  }

  if (msg.value === 0) {
    msg.value = 43;
  }
  // ENDOF basic value fixes:
  return msg;
};

const filterToMidiaValue = msg => {
  // basic value fixes:
  if (msg.value === 127) {
    msg.value = 1;
  }

  if (msg.value === 0) {
    msg.value = 2;
  }
  // ENDOF basic value fixes:
  return msg;
};

/* QLC FEEDBACK RACE FOR NOTEON / NOTEOFF */

qlcIn.on("noteon", msg => {
  console.log("-----------------------------------------------------");
  console.log("FROM QLC FEEDBACK");
  console.log("noteon", msg.note, msg.velocity, msg.channel);

  // first botton line
  if (msg.channel === 1 && msg.note >= 36 && msg.note <= 40) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 + 20;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // second botton line
  if (msg.channel === 1 && msg.note >= 41 && msg.note <= 45) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 + 10;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // third botton line
  if (msg.channel === 1 && msg.note >= 46 && msg.note <= 50) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // fourth botton line
  if (msg.channel === 1 && msg.note >= 51 && msg.note <= 55) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 - 10;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // fifth botton line
  if (msg.channel === 1 && msg.note >= 56 && msg.note <= 60) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 - 20;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // basic thru if no filters
  consOut.send("noteon", msg);
});

qlcIn.on("noteoff", msg => {
  console.log("-----------------------------------------------------");
  console.log("FROM QLC FEEDBACK");
  console.log("noteoff", msg.note, msg.velocity, msg.channel);

  // first botton line
  if (msg.channel === 1 && msg.note >= 36 && msg.note <= 40) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 + 20;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // second botton line
  if (msg.channel === 1 && msg.note >= 41 && msg.note <= 45) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 + 10;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // first botton line
  if (msg.channel === 1 && msg.note >= 46 && msg.note <= 50) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // first botton line
  if (msg.channel === 1 && msg.note >= 51 && msg.note <= 55) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 - 10;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // first botton line
  if (msg.channel === 1 && msg.note >= 56 && msg.note <= 60) {
    msg = filterToMatrixValue(msg);
    msg.channel = 0;
    msg.note = msg.note - 36 - 20;

    console.log("sent to conspiracy: ");
    console.log("noteon", msg);
    consOut.send("noteon", msg);
  }

  // basic thru if no filters
  consOut.send("noteoff", msg);
});

const filterToMatrixValue = msg => {
  // basic value fixes:
  if (msg.velocity === 127) {
    msg.velocity = 22;
  }

  if (msg.velocity === 0) {
    msg.velocity = 23;
  }
  // ENDOF basic value fixes:
  return msg;
};

// and on package.json

Code: Select all

{
  "name": "midi3po",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js"
  },
  "author": "ssribeiro",
  "license": "ISC",
  "dependencies": {
    "easymidi": "^1.0.3"
  }
}
// .nvmrc

Code: Select all

v10.18.0
npm i && npm start && echo "be happy"
ssribeiro
Posts: 2
Joined: Tue Dec 24, 2019 9:45 pm
Real Name: Luan Ribeiro

Added Sansom Conspiracy Profile and Virtual Controller design.
Attachments
Samson-Conspiracy.qxi
(5.72 KiB) Downloaded 89 times
Screenshot_Samson_Conspiracy.png
Conspiracy.qxw
(39.36 KiB) Downloaded 84 times
Post Reply