Hello, I want to build my own midi class compliant midi controller uding arduino pro micro. I want it to have 3x 74hc4067 mux/demux ic, two for buttons and one for potentiometers. On top of this I want to add stereo VU Meter that reads volume level from master track and then the output is shown through 3 74hc595 ICs (12 leds left, 12 led right). I'm using FL studio 21 and don't want to use extra software. I thought of writing custom script or using one for already made controller and adapting it to mine but I don't know how to code. Is there some way of reaching this?
Hi @mvacoss welcome to the forum.
Please post your code and schematic.
You might want to look at this How to get the best out of this forum before you proceed any further.
Hi @mvacoss ,
sounds as if you do not have any code available up to now, do you?
I do not know if there is an application that is exactly like or comes close to your requirements.
A method to find out is to search the internet for appropriate solutions. For a general midi controller project you may have a look at this one
https://www.instructables.com/DIY-USB-Midi-Controller-With-Arduino-a-Beginners-G/
I found it by using the following key words taken from your post:
midi controller arduino pro micro
Good luck!
ec2021
Okay, thank you. Actually I have code of some sort.
#include <Control_Surface.h>
USBMIDI_Interface midi;
const pin_t dataPin = 2; // Pin connected to DS of 74HC595
const pin_t clockPin = 4; // Pin connected to SH_CP of 74HC595
const pin_t latchPin = 3; // Pin connected to ST_CP of 74HC595
// Instantiate two daisy-chained shift register with the SPI slave select pin as
// latch pin, most significant bit first, and a total of 16 outputs.
ShiftRegisterOut<16> sreg {dataPin, clockPin, latchPin, MSBFIRST};
// Instantiate a VULEDs object with 12 LEDs.
MCU::VULEDs<12> vu {
sreg.pins().slice<0, 11>(), // first 12 pins of the shift registers
1, // track number [1, 8]
50, // how long does it take for the meter to decay
};
// If you don't want to use shift registers, you can just specify a list of pin
// numbers:
//
// MCU::VULEDs<12> vu {
// {{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, // Arduino pin numbers
// 1, // track number [1, 8]
// MCU::VUDecay::Default, // how long does it take for the meter to decay
// };
// You can also use a different number of LEDs, but keep in mind that the MCU
// protocol sends the level on a scale from 0 to 12.
// If you use 24 LEDs, for example, the LEDs will turn on in groups of 2 at a
// time.
// Push button to switch between dot and bar mode.
Button dotBarModeButton = A0;
#define ATMEGA32U4 1 // put here the uC you are using, like in the lines above followed by "1", like "ATMEGA328 1", "DEBUG 1", etc.
/////////////////////////////////////////////
// Are you using buttons?
#define USING_BUTTONS 1 // comment if not using buttons
/////////////////////////////////////////////
// Are you using potentiometers?
#define USING_POTENTIOMETERS 1 // comment if not using potentiometers
/////////////////////////////////////////////
// LIBRARIES
// -- Defines the MIDI library -- //
// if using with ATmega328 - Uno, Mega, Nano...
#ifdef ATMEGA328
#include <MIDI.h> // by Francois Best
//MIDI_CREATE_DEFAULT_INSTANCE();
// if using with ATmega32U4 - Micro, Pro Micro, Leonardo...
#elif ATMEGA32U4
#include "MIDIUSB.h"
#endif
#ifdef USING_POTENTIOMETERS
// incluir a biblioteca ResponsiveAnalogRead
#include <ResponsiveAnalogRead.h> // [https://github.com/dxinteractive/ResponsiveAnalogRead](https://github.com/dxinteractive/ResponsiveAnalogRead)
#endif
// ---- //
/////////////////////////////////////////////
// BUTTONS
#ifdef USING_BUTTONS
const int N_BUTTONS = 2; // total numbers of buttons
const int BUTTON_ARDUINO_PIN[2] = {8, 9}; // pins of each button connected straight to the Arduino
int buttonCState[N_BUTTONS] = {}; // stores the button current value
int buttonPState[N_BUTTONS] = {}; // stores the button previous value
//#define pin13 1 // uncomment if you are using pin 13 (pin with led), or comment the line if not using
byte pin13index = 12; // put the index of the pin 13 of the buttonPin[] array if you are using, if not, comment
// debounce
unsigned long lastDebounceTime[N_BUTTONS] = { 0 }; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
#endif
/////////////////////////////////////////////
// POTENTIOMETERS
#ifdef USING_POTENTIOMETERS
const int N_POTS = 1; // total numbers of pots (slide & rotary)
const int POT_ARDUINO_PIN[1] = {A1}; // pins of each pot connected straight to the Arduino
int potCState[N_POTS] = { 0 }; // Current state of the pot
int potPState[N_POTS] = { 0 }; // Previous state of the pot
int potVar = 0; // Difference between the current and previous state of the pot
int midiCState[N_POTS] = { 0 }; // Current state of the midi value
int midiPState[N_POTS] = { 0 }; // Previous state of the midi value
const int TIMEOUT = 300; // Amount of time the potentiometer will be read after it exceeds the varThreshold
const int varThreshold = 20; // Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[N_POTS] = { 0 }; // Previously stored time
unsigned long timer[N_POTS] = { 0 }; // Stores the time that has elapsed since the timer was reset
int reading = 0;
// Responsive Analog Read
float snapMultiplier = 0.01; // (0.0 - 1.0) - Increase for faster, but less smooth reading
ResponsiveAnalogRead responsivePot[N_POTS] = {}; // creates an array for the responsive pots. It gets filled in the Setup.
int potMin = 10;
int potMax = 1023;
#endif
/////////////////////////////////////////////
// MIDI
byte midiCh = 0; // MIDI channel to be used - start with 1 for MIDI.h lib or 0 for MIDIUSB lib
byte note = 36; // Lowest note to be used
byte cc = 1; // Lowest MIDI CC to be used
/////////////////////////////////////////////
// SETUP
void setup() {
Control_Surface.begin();
dotBarModeButton.begin();
// Baud Rate
// use if using with ATmega328 (uno, mega, nano...)
// 31250 for MIDI class compliant | 115200 for Hairless MIDI
Serial.begin(115200); //
#ifdef DEBUG
Serial.println("Debug mode");
Serial.println();
#endif
#ifdef USING_BUTTONS
// Buttons
// Initialize buttons with pull up resistors
for (int i = 0; i < N_BUTTONS; i++) {
pinMode(BUTTON_ARDUINO_PIN[i], INPUT_PULLUP);
}
#ifdef pin13 // initialize pin 13 as an input
pinMode(BUTTON_ARDUINO_PIN[pin13index], INPUT);
#endif
#endif
#ifdef USING_POTENTIOMETERS
for (int i = 0; i < N_POTS; i++) {
responsivePot[i] = ResponsiveAnalogRead(0, true, snapMultiplier);
responsivePot[i].setAnalogResolution(1023); // sets the resolution
}
#endif
}
/////////////////////////////////////////////
// LOOP
void loop() {
Control_Surface.loop();
if (dotBarModeButton.update() == Button::Falling) // when button is pressed
vu.toggleMode(); // toggle between dot and bar mode
#ifdef USING_BUTTONS
buttons();
#endif
#ifdef USING_POTENTIOMETERS
potentiometers();
#endif
}
/////////////////////////////////////////////
// BUTTONS
#ifdef USING_BUTTONS
void buttons() {
for (int i = 0; i < N_BUTTONS; i++) {
buttonCState[i] = digitalRead(BUTTON_ARDUINO_PIN[i]); // read pins from arduino
#ifdef pin13
if (i == pin13index) {
buttonCState[i] = !buttonCState[i]; // inverts the pin 13 because it has a pull down resistor instead of a pull up
}
#endif
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (buttonPState[i] != buttonCState[i]) {
lastDebounceTime[i] = millis();
if (buttonCState[i] == LOW) {
// Sends the MIDI note ON accordingly to the chosen board
#ifdef ATMEGA328
// use if using with ATmega328 (uno, mega, nano...)
MIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel
#elif ATMEGA32U4
// use if using with ATmega32U4 (micro, pro micro, leonardo...)
noteOn(midiCh, note + i, 127); // channel, note, velocity
MidiUSB.flush();
#elif TEENSY
//do usbMIDI.sendNoteOn if using with Teensy
usbMIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel
#elif DEBUG
Serial.print(i);
Serial.println(": button on");
#endif
} else {
// Sends the MIDI note OFF accordingly to the chosen board
#ifdef ATMEGA328
// use if using with ATmega328 (uno, mega, nano...)
MIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel
#elif ATMEGA32U4
// use if using with ATmega32U4 (micro, pro micro, leonardo...)
noteOn(midiCh, note + i, 0); // channel, note, velocity
MidiUSB.flush();
#elif TEENSY
//do usbMIDI.sendNoteOn if using with Teensy
usbMIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel
#elif DEBUG
Serial.print(i);
Serial.println(": button off");
#endif
}
buttonPState[i] = buttonCState[i];
}
}
}
}
#endif
/////////////////////////////////////////////
// POTENTIOMETERS
#ifdef USING_POTENTIOMETERS
void potentiometers() {
for (int i = 0; i < N_POTS; i++) { // Loops through all the potentiometers
reading = analogRead(POT_ARDUINO_PIN[i]);
responsivePot[i].update(reading);
potCState[i] = responsivePot[i].getValue();
potCState[i] = analogRead(POT_ARDUINO_PIN[i]); // reads the pins from arduino
midiCState[i] = map(potCState[i], potMin, potMax, 0, 127); // Maps the reading of the potCState to a value usable in midi
//midiCState[i] = map(potCState[i], 0, 4096, 0, 127); // Maps the reading of the potCState to a value usable in midi - use for ESP32
if (midiCState[i] < 0) {
midiCState[i] = 0;
}
if (midiCState[i] > 127) {
midiCState[i] = 0;
}
potVar = abs(potCState[i] - potPState[i]); // Calculates the absolute value between the difference between the current and previous state of the pot
//Serial.println(potVar);
if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
PTime[i] = millis(); // Stores the previous time
}
timer[i] = millis() - PTime[i]; // Resets the timer 11000 - 11000 = 0ms
if (timer[i] < TIMEOUT) { // If the timer is less than the maximum allowed time it means that the potentiometer is still moving
potMoving = true;
} else {
potMoving = false;
}
if (potMoving == true) { // If the potentiometer is still moving, send the change control
if (midiPState[i] != midiCState[i]) {
// Sends the MIDI CC accordingly to the chosen board
#ifdef ATMEGA328
// use if using with ATmega328 (uno, mega, nano...)
MIDI.sendControlChange(cc + i, midiCState[i], midiCh); // cc number, cc value, midi channel
#elif ATMEGA32U4
//use if using with ATmega32U4 (micro, pro micro, leonardo...)
controlChange(midiCh, cc + i, midiCState[i]); // (channel, CC number, CC value)
MidiUSB.flush();
#elif TEENSY
//do usbMIDI.sendControlChange if using with Teensy
usbMIDI.sendControlChange(cc + i, midiCState[i], midiCh); // cc number, cc value, midi channel
#elif DEBUG
Serial.print("Pot: ");
Serial.print(i);
Serial.print(" ");
Serial.println(midiCState[i]);
//Serial.print(" ");
#endif
potPState[i] = potCState[i]; // Stores the current reading of the potentiometer to compare with the next
midiPState[i] = midiCState[i];
}
}
}
}
#endif
/////////////////////////////////////////////
// if using with ATmega32U4 (micro, pro micro, leonardo...)
#ifdef ATMEGA32U4
// Arduino (pro)micro midi functions MIDIUSB Library
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 controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
MidiUSB.sendMIDI(event);
}
#endif
This is just example from Control Surface library I modified a bit. It uses mappings of MCU or Mackie Control Universal to display the VU Meter. I personally like the button that switches the dot-bar mode of led indication. But the problem is that there is no VU Meter mapping on MCUs master track because it doesn't have it. My main problem is How do I make VU Meter reading from master track and then adding all the things like muxes or bit shifters. In this example the buttons don't play specific note because the MCU is mapping them as different things. Anyway I was testing muxes and bit shifters separately and it worked fine. But for now I am not able to merge these two codes (VU Meter from Control surface and multiplexer examples) together.
Then post the different sketches ...
I currently don't have them because I overwrited them by the VU meter code. But you can basically take any mux example and it will work.
If you're already using the Control Surface library, why bother with all the manual button and potentiometer logic? Control Surface already supports push buttons, potentiometers, multiplexers etc. out of the box. See e.g. Control Surface: Getting Started and Control Surface: NoteButton.ino.
Yes, I know I can use control surface library for this but there is a problem that I don't know how to make VU meter getting volume level from master track.
As discussed in your GitHub thread, that's an issue that needs to be resolved on the DAW side, it cannot be resolved using Arduino code.
I know and that's why I am here. Because I don't know how to properly write a script for my controller in python. For example I would like to read value from master using function readTrackVolume (or something like this) from official FL wiki but I don't know how to properly use it.
I know this is maybe not the best place to solve these things around my DAW and outputting the right type of midi but I thought someone here maybe knows something that can help me.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.