Get Arduino LCD to receive and display scene names from Ableton Live
Hi there,
I have recently built an Arduino Uno powered midi controller for Ableton. I would like to add an LCD screen which displays the scene name which is currently active in Live's session view.
I'm looking to use M4L as a bridge to get the scene name, and send it via serial to the Arduino's LCD.
Any help would be much appreciated!
Many Thanks,
Josh
Ok, so I have figured out how to print the current selected_scene name to a field in M4L. (little wins!) so am on my way.. : )
I'm just looking for that little gem of code that will allow me to send data via the connected midi cable (or USB if midi is not possible) down to the Arduino where the LCD screen is.
And then print this variable field of text in M4L on the LCD screen.
Any thoughts? Thanks so much in advance!!
Josh
Use serial object in Max, send the text to Arduino, print received text to LCD.
Or make own text to midi table, receive Midi in arduino , translate it to Text and print it to LCD.
Just please don't ask how to do that, there are so many examples in max as well in arduino that deal with that,
so just use a little bit of time.
Hi there,
thanks for your help source audio! I have since been busy learning about serial communications from Max to Arduino. I can get the LCD on the board to flash which is a nice start.
And I can get the text to display on my LCD if i program it from the Arduino sketch. my problem is i can't find any tutes or videos on how to actually send text from max to arduino.
sorry if my question is obvious, im new to this, and perhaps i'm not googling the correct search terms.
any help from anyone would be much appriciated! thanks heaps : )
Josh
Hi Josh,
the important thing is ASCII conversion before data gets sent to Arduino.
You can't just send plain text over serial object.
Inserting atoi between text and serial object will do the trick.
On arduino side, you just declare serial input as data for LCD print.
It could look like this :
void loop() {
char MaxData;
if(Serial.available() )
{
MaxData = Serial.read();
lcd.setCursor(0,0);
lcd.print (MaxData); // echo the incoming character to the LCD
}
}
Is there a (relatively painless) way to do this sans serial? Like using sysex or something (isn't the push LCD stuff something like that?).
Not specifically related to this topic, but I've been thinking of making a physical (USB-MIDI arduino-based) version of a controller I have setup on an old phone with TouchOSC. Just such a pain to have to worry about charging it, and setting up the network, etc... I'd just rather doing it as MIDI I/O, but I would need to have some text feedback.
Depends a bit on amount of text needed to be displayed .
I would go with Teensy 3.2
It is working fine as USB midi device, and besides sending controller
or whatsoever midi data out, would definitely be possible to translate incoming midi
sysex or assigned controllers to chars which can be printed to LCD.
Ah right, so you would handle the actual LCD writing/formatting on the Arduino, and just push text (as sysex?) out from Max.
Right, if You want Arduino to be USB compliant Midi device, than it has to receive
Midi, does not matter if via sysex or any other way of midi data.
Then You organise translation of incoming midi into chars and write them to lcd.
There are for sure more or less elegant/efficient ways of doing it,
it all depends what Your need is.
If You just for example need specific messages, and not free text transfer,
one could just organise If statements in arduino, like
if incoming Midi is CC# 11 on channel 2, then Arduino could write
"Rodrigo is moving Slider 2" or anything like that.
That way midi data would be less than sending all that via sysex.
Just an idea...
Most of the display would be stuff like that, just reporting the values of certain parameters or settings, but the main need for an LCD would be having some kind of patch/preset name, which would be indicative of the samples that are loaded.
Speaking to a friend here he suggested doing something simple like dedicating a MIDI channel to LCD stuff, then using note number to address a specific LCD position, and velocity as an ASCII lookup table.
Might get complicated if I'm changing LCD "pages" but at this is a conceptual place to start. I just had no idea how this kind of thing worked at all.
That should be all possible.
There are also bigger LCDs which coudl mean less "LCD Pages" to change.
4x16 LCD with I2C buss would be handy, needing only 2 wires for communication.
i built a 2 lines LCD display accepting sysex over MIDI with an arduino years ago (diecimila period). Althought it worked well during years (and still does) I replaced that with an iPod and Lemur (controlled with the same sysex :-) : it's smaller, much more readable, a bit faster (but maybe it was the LCD that was slow) and can be used wirelessly if it doesn't have to be reliable. And if I count the hours I spent on that project, it's also cheaper. OK, I admit it was fun to do.
Anyway if you're interested, i can send the arduino sketch and Max patch.
Yeah that would be great. I have pretty much the same thing done, built around an ancient iPhone and TouchOSC, but I guess I find hardware simpler.
I wish it was possible to just do something that like over a wired connection without having to deal with setting up and connecting a network.
With touchOSC I don't think it's possible to easily send strings over a MIDI connection (it is with OSC), that's why I used Lemur.
Here is the pde file and an old dirty patch. I don't have a sketch for the arduino shield but it was just a MIDI In with an opto-isolator
As you'll see, besides 2 LCD lines there were also 2 LEDs on my display.
Oh, pde is not allowed for security reasons :-)
So:
/*
Patrick Delges - crfmw 2008-2009
Receive MIDI SysEx
(manufacturer ID depends on pin 12 (100 or 101))
Display on LCD using the LCD4Bit library
2 LEDs can be turned on/off too.
Arduino LCD
2 Register Select (RS)
3 Enable
4 (DB4)
5 (DB5)
6 (DB6)
7 (DB7)
10 LED output1
11 LED output2
12 local switch2 input (for machine ID in sysex)
*/
#include
// !! modified version, using adjacent pins!
// http://216.38.50.214/playground/Code/LCD4BitLibrary
// by http://216.38.50.214/playground/Profiles/Neillzero
// states
#define WAITING_FOR_SYSEX 0
#define WAITING_FOR_MANFCT 1
#define WAITING_FOR_OP 2
#define RECEIVING_MSG 3
#define WAITING_FOR_ENDOFSYSEX 4
#define RECEIVING_POSITION 5
#define RECEIVING_ARG1 6
#define RECEIVING_ARG2 7
// operators
#define OP_WRITE 0
#define OP_CLEAR 1
#define OP_MOVE 2
#define OP_LED 3
#define DISPLAY_WIDTH 16 // LCD width
#define DISPLAY_LINES 2 // LCD number of lines
#define FIRST_LED_PIN_ID 9 // in fact, it's pin ID minus 1
// so lEDS are plugged on 10 & 11
byte incomingByte;
int statusLed = 13; // the status LED
int statusLedState = LOW;
int state = WAITING_FOR_SYSEX;
char message[DISPLAY_WIDTH]; // message to be displayed
byte messageLength = 0; // its length
byte line = 0; // line to write on
byte op = 0; // operation to be performed
byte arg1 = 0 ; // a first argument
byte arg2 = 0 ; // a second argument
byte position[DISPLAY_LINES];
byte machineID = 100 ; // sysex manufacturer ID
LCD4Bit lcd = LCD4Bit(DISPLAY_LINES);
void setup()
{
// 6 pins for the LCD
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
// 2 pins for LEDs
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
digitalWrite (10, LOW);
digitalWrite (11, LOW);
pinMode(12,INPUT); // switch
digitalWrite (12, HIGH);
pinMode(statusLed,OUTPUT);
clearMessage(); // empty message string (useless)
lcd.init(); // init LCD
Serial.begin(31250);
//Serial.begin(38400);
lcd.printIn("Display v0.2");
blink();
lcd.cursorTo(2, 0);
delay (1000);
lcd.printIn("crfmw 2009");
lcd.cursorTo (2, 12);
// set machine ID for sysex
if (digitalRead(12) == HIGH)
{
machineID = 100;
lcd.printIn("#100");
}
else
{
machineID = 101;
lcd.printIn("#101");
}
blink();
delay (20);
blink();
delay (20);
blink();
}
void loop () {
int i = 0;
safeBlink(); // no delay blink - uses statusLedState - has to be in the loop()!
/**********/
if (Serial.available() > 0)
{
incomingByte = Serial.read();
if ((state == WAITING_FOR_SYSEX) && (incomingByte == 0xf0)) // sysex begin 240
{
state = WAITING_FOR_MANFCT;
// Serial.println(state, DEC);
return;
}
if (state == WAITING_FOR_MANFCT)
{
if (incomingByte == machineID) // manufacturer 100 or 101
{
state = WAITING_FOR_OP;
// Serial.println(state, DEC);
return;
}
else
{
state = WAITING_FOR_SYSEX; // the sysex is not for us, let's wait for the next one
return;
}
}
/**********/
if (state == WAITING_FOR_OP) // first byte is the op
{
// Serial.print(incomingByte, BIN);
// Serial.print("_");
op = incomingByte & 0x1f; // mask to get bits 0 - 4
line = (incomingByte & 0x60) >> 5; // bits 5 and 6
// Serial.print(op, BIN);
// Serial.print("_");
// Serial.println(line, DEC);
switch (op)
{
case OP_WRITE:
state = RECEIVING_MSG;
clearMessage();
// Serial.println(state, DEC);
return;
case OP_CLEAR:
state = WAITING_FOR_ENDOFSYSEX;
return;
case OP_LED:
state = RECEIVING_ARG1;
return;
case OP_MOVE:
state = RECEIVING_POSITION;
return;
}
}
/**********/
if (incomingByte == 0xf7) // sysex end 247
{
switch (op) // perform the op
{
case OP_WRITE:
if (messageLength && (line >= 0) && (line < DISPLAY_LINES))
{
lcd.cursorTo(line+1, position[line]); // jump to the right position
displayMessage();
}
break;
case OP_CLEAR:
clearLine();
position[line] = 0;
break;
case OP_MOVE:
if ((position[line] < 0 ) || (position[line] >= DISPLAY_WIDTH)) // error
{
position[line] = 0;
}
break;
case OP_LED:
if ((arg1 != 1) && (arg1 != 2))
{
break;
}
if (arg2 == 0)
{
digitalWrite(arg1 + FIRST_LED_PIN_ID, LOW);
}
else
{
digitalWrite(arg1 + FIRST_LED_PIN_ID, HIGH);
}
break;
}
statusLedState = HIGH; // turn on the LED
state = WAITING_FOR_SYSEX; // current op finished
// Serial.println(state, DEC);
return;
}
/**********/
if (state == RECEIVING_MSG) // writing the message in the string
{
// Serial.print(incomingByte, DEC);
if (messageLength < DISPLAY_WIDTH)
message[messageLength++] = incomingByte;
return;
}
/**********/
if (state == RECEIVING_POSITION) // writing the message in the string
{
position[line] = incomingByte;
return;
}
/**********/
if (state == RECEIVING_ARG1) // writing the message in the string
{
arg1 = incomingByte;
state = RECEIVING_ARG2;
return;
}
/**********/
if (state == RECEIVING_ARG2) // writing the message in the string
{
arg2 = incomingByte;
return;
}
/**********/
}
}
void displayMessage()
{
lcd.printIn(message);
}
void blink(){
digitalWrite(statusLed, HIGH);
delay(20);
digitalWrite(statusLed, LOW);
}
void safeBlink()
{
static unsigned long previousTime = 0;
if (statusLedState == HIGH)
{
digitalWrite(statusLed, HIGH);
statusLedState = LOW;
}
else if (abs(millis() - previousTime) > 40)
{
digitalWrite(statusLed, LOW);
previousTime = millis();
}
}
void clearLine ()
{
lcd.cursorTo(line + 1, 0);
clearMessage();
displayMessage();
}
void clearMessage()
{
byte i;
for (i=0; i
{
message[i]=' ';
}
messageLength = 0;
}
To jump in, no wonder LCD display is a bit slow using 4bit LCD lib
That is really outdated.
LiquidCrystal library is what one uses nowadays, and if anything heavy cpu wise
is going on in Arduino, LiquidCrystalFast variant can put display in high priority,
so that it allways updates very fast.
Hi , josh I m From argentine and i want to know if you make this projet. thanks.