Here is a short presentation of my 42 control (30 faders and 12 buttons) arduino based midi interface to use with QLC+ or any soft that integrate midi control.
It is based on Notes and Volts blog tutorial for an “arduino midi controller: multiplexer” page that you will find here:
http://www.notesandvolts.com/2016/07/ar ... exers.html
Thanks to http://www.notesandvolts.com/ to let me publish his work here.
The video on the page is very clear and there is nothing more to add.
The wiring is very well explained also.
You will be able to make it work easily and the arduino code (call it “sketch”) works well if you follow the explanation on the youtube video.
My controller use 3 cd74hc4067 multiplexer module, called MUX board, wired in //.
PIN S0, S1, S2 and S3 of each MUX board are wired together, PIN SIG 1 and 2 from 2 MUX (fader) board goes to A0 and A1 of the arduino, and the SIG 3 from the third MUX board (button) goes to a digital IN of the arduino.
I have tried more MUX board when coding but the arduino run short of memory with 4 analog MUX board with all the 16 pins of each board coded to be active.
So we have to admit there is a limit in the input and 64 analog input is not possible.
With 30 analog an 12 digital input fro my project, global variables of the arduino code use 1080 bytes (52%) of dynamic memory.
There must be solution to have more input but for the moment that is enough for my use.
I grabbed a very old DMX controller just to have a hard case in which I could wire a lot of fader (the boxing have always been the difficult part of all my project…).
I ended up with a 30 fader/30 button case. That is enough for most application IMHO.
I decided to use only the metal case and I hooked inside 30 new fader and 12 new buttons, for a total of 42 control.
The fader uses 30 PIN of 2 DEMUX board, 15 on the first board, 15 on the second board (one PIN left unused on each board) and the flash button use 12 PIN on the third DEMUX board.
The button are just for flash/scene purpose and I don’t need more than 12.
For button you need to dedicate a MUX board only for digital because you can’t mix digital and analog SIG output.
The output is a midi signal. So you will use midi/usb converter. Mine is directly wired in the case but you can leave it outside of the box of course.
If you wire it inside, you can easily take the USB 5V to run the arduino board. That’s what I have done and it work like a charm. You have only one USB cable to make the controller work and it is recognised as a midi interface.
The midi message for each fader are set in the arduino sketch. You can change them as you need of course but it is more convenient to set them up for once.
For my use, I have distributed the midi note value from 50 to 79 (from fader 1 to fader 30 and each button have the same midi note than its corresponding fader).
That give me room for a specific QLC+widget that I use for theater.
It is a 48 dimmer widget that is set with midi message from 1 to 48.
Generally all theater that uses classical lighting set their dimmer from DMX channel 1 up to 48.
I have set midi message for this widget because I also use touchOSC and an ipad..
I use it for light setup and dimmer check up directly on stage and it is very helpful.
Here are some pictures.
Button are not yet wired because I had hard time to find suitable ones (ones that would fit into the existing mounting holes).
They are on the way home .
Find here some pictures.
https://goo.gl/photos/9xHw2osMHoUu5tMh7
30 fader 12 button arduino midi controller
-
- Posts: 53
- Joined: Wed Jan 20, 2016 7:50 pm
- Location: PARIS France
- Real Name:
Enttec DMX USB Pro
Windows 10
Windows 10
-
- Posts: 58
- Joined: Sun Jul 17, 2016 8:22 am
- Location: Denmark
- Real Name: Allan Madsen
Sorry i can see you do
Take a look here https://github.com/ddiakopoulos/hiduino ... output.ino
Then you can make your own midi controller on a Arduino Uno (org)
Take a look here https://github.com/ddiakopoulos/hiduino ... output.ino
Then you can make your own midi controller on a Arduino Uno (org)
-
- Posts: 53
- Joined: Wed Jan 20, 2016 7:50 pm
- Location: PARIS France
- Real Name:
Good to hear you also have fun as much as I had.
The ardruino project will be soon (I hope and I am waiting for) adapted for a teensy.
I will keep you informed.
Cheers.
The ardruino project will be soon (I hope and I am waiting for) adapted for a teensy.
I will keep you informed.
Cheers.
Enttec DMX USB Pro
Windows 10
Windows 10
-
- Posts: 58
- Joined: Sun Jul 17, 2016 8:22 am
- Location: Denmark
- Real Name: Allan Madsen
I am using a Arduino pro mikro with a atmega32u4 it works.
https://www.google.dk/search?q=arduino+ ... QFmDz6ZHM:
Here is the code for now. (Work in progress)
https://www.google.dk/search?q=arduino+ ... QFmDz6ZHM:
Here is the code for now. (Work in progress)
Code: Select all
/*
* MIDIUSB_v1.ino
*
* Created: 3/29/2017
* Author: Allan Madsen
*/
#include "MIDIUSB.h"
// Total num of MIDI controls.
#define NUM_CONTROLS 1
//Num of channels to read directly through analog pins
#define ANALOG_NUM_CHANNELS 0
// Num of channels read through 4051 muxchip
#define MUX_NUM_CHANNELS 1
// Mux output to Arduino analog pin
#define MUX_COM A10
// Mux address select digital pins
#define MUX_ADDRESS_SEL_0 2
#define MUX_ADDRESS_SEL_1 3
#define MUX_ADDRESS_SEL_2 4
//MIDI channel to use
#define MIDI_CHANNEL 0
//CC slots 14-31 are recognizedas assignable controls by MIDI standard
#define MIDI_CC_START 14
//maps to map log taper slider pots to linear readings
int sliderFromMap[]= {0,62, 187, 550, 1023};
int sliderToMap[] = {0, 255};
byte sliderFromMapSize;
byte sliderToMapSize;
//maps to map log taper rotary pots to linear readings
int knobFromMap[] = {0, 55, 130, 516, 1023};
int knobToMap[] = {0, 127};
byte knobFromMapSize;
byte knobToMapSize;
//Holds currentMIDIcontrol values
int ccValue[NUM_CONTROLS];
//Stores pin numbers of analog channels
byte analogChannelPin[ANALOG_NUM_CHANNELS];
// First parameter is the event type (0x09 = note on, 0x08 = note off).
// Second parameter is note-on/note-off, combined with the channel.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Third parameter is the note number (48 = middle C).
// Fourth parameter is the velocity (64 = normal, 127 = fastest).
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOff);
}
void setup() {
Serial.begin(115200);
pinMode(MUX_ADDRESS_SEL_0, OUTPUT);
pinMode(MUX_ADDRESS_SEL_1, OUTPUT);
pinMode(MUX_ADDRESS_SEL_2, OUTPUT);
sliderFromMapSize = sizeof(sliderFromMap) / sizeof(int);
sliderToMapSize = sizeof(sliderToMap) / sizeof(int);
knobFromMapSize = sizeof(knobFromMap) / sizeof(int);
knobToMapSize = sizeof(knobToMap) / sizeof(int);
}
// First parameter is the event type (0x0B = control change).
// Second parameter is the event type, combined with the channel.
// Third parameter is the control number number (0-119).
// Fourth parameter is the control value (0-127).
void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
MidiUSB.sendMIDI(event);
}
void loop()
{
//Loop through all mux channels
for (byte muxChannel = 0; muxChannel < MUX_NUM_CHANNELS; ++muxChannel)
{
int midiValue = multiMap(readMuxChannel(muxChannel), sliderFromMap, sliderFromMapSize, sliderToMap, sliderToMapSize);
if (ccValue[muxChannel] != midiValue)
{
ccValue[muxChannel] = midiValue;
midiControlChange(MIDI_CHANNEL, MIDI_CC_START + muxChannel, midiValue);
}
}
//Loop through all analog channels
for (byte analogChannel = 0; analogChannel < ANALOG_NUM_CHANNELS; ++analogChannel)
{
int analogValue = analogRead(analogChannelPin[analogChannel]);
int midiValue = 0;
if (analogChannel == 0)
{
//read single remaining slider
midiValue = multiMap(analogValue, sliderFromMap, sliderFromMapSize, sliderToMap, sliderToMapSize);
}
else
{
//the rest are rotary pots
midiValue = multiMap(analogValue, knobFromMap, knobFromMapSize, knobToMap, knobToMapSize);
}
if (ccValue[MUX_NUM_CHANNELS + analogChannel] != midiValue)
{
ccValue[MUX_NUM_CHANNELS + analogChannel] = midiValue;
midiControlChange(MIDI_CHANNEL, MIDI_CC_START + MUX_NUM_CHANNELS + analogChannel, midiValue);
}
}
}
//Reads analog value of mux chip at selected channel
int readMuxChannel(byte channel)
{
//Select mux channel
digitalWrite(MUX_ADDRESS_SEL_0, channel & 1);
digitalWrite(MUX_ADDRESS_SEL_1, (channel >> 1) & 1);
digitalWrite(MUX_ADDRESS_SEL_2, (channel >> 2) & 1);
//Read mux output
return analogRead(MUX_COM);
}
//Linear interpolates a value in fromMap to toMap
int multiMap(int value, int fromMap[], int fromMapSize, int toMap[], int toMapSize)
{
//Boundary cases
if (value <= fromMap[0]) return toMap[0];
if (value >= fromMap[fromMapSize - 1]) return toMap[toMapSize - 1];
//Find the fromMap interval that value lies in
byte fromInterval = 0;
while (value > fromMap[fromInterval + 1])
fromInterval++;
//Find the percentage of the interval that value lies in
float fromIntervalPercentage = (float)(value - fromMap[fromInterval]) / (fromMap[fromInterval + 1] - fromMap[fromInterval]);
//Map it to the toMap interval and percentage of that interval
float toIntervalPercentage = ((fromInterval + fromIntervalPercentage) / (fromMapSize - 1)) * (toMapSize - 1);
byte toInterval = (byte)toIntervalPercentage;
toIntervalPercentage = toIntervalPercentage - toInterval;
//Linear interpolate
return toMap[toInterval] + toIntervalPercentage * (toMap[toInterval + 1] - toMap[toInterval]);
}
//Sends MIDI CC signal
void midiControlChange(byte channel, byte ccNum, byte value)
{
//Send a MIDI control change event through USB
controlChange(channel, ccNum, value);
MidiUSB.flush();
}
/*void loop() {
controlChange(1, 0, 0); // Channel 0, control, value
MidiUSB.flush();
// delay(500);
controlChange(0, 0, 100); // Channel 0, control, value
MidiUSB.flush();
// delay(500);
controlChange(0, 1, 200); // Channel 0, control, value
MidiUSB.flush();
// delay(500);
controlChange(1, 0, 255); // Channel 0, control, value
MidiUSB.flush();
delay(500);
// controlChange(0, 10, 65); // Set the value of controller 10 on channel 0 to 65
}*/
-
- Posts: 5
- Joined: Wed May 01, 2019 6:03 pm
- Real Name: Robin
We are building a similar desk, using an old Strand Level 12 Two Scene analogue desk.
I massively simplified the ADC when I found the AS6408 and Duino Core.
Presently we just have the 24 faders, using Hairless to do the input to QLC. But we have a number of push buttons that will just be connected to spare analogue inputs.
Rob
I massively simplified the ADC when I found the AS6408 and Duino Core.
Presently we just have the 24 faders, using Hairless to do the input to QLC. But we have a number of push buttons that will just be connected to spare analogue inputs.
Rob