Code:
#include <WProgram.h>
#include <LiquidCrystal.h>
#include <Midi.h>
struct DENON_SEGMENT {
boolean valid;
byte seg;
byte col;
byte val;
};
struct DENON_TIME {
boolean valid;
byte minute;
byte sec;
byte pos;
byte totMin;
byte totSec;
};
LiquidCrystal lcd(8, 11, 9, 4, 5, 6, 7); // initialize the library with the numbers of the interface pins
class MyMidi : public Midi {
public:
MyMidi(HardwareSerial &s) : Midi(s) {}
void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value) {
if (channel == 1 || channel == 2) {
DENON_SEGMENT segData = checkForSegmentData(controller, value);
DENON_TIME timeData = checkForTimeData(controller, value);
static unsigned long curTime, prevTime = 0;
static boolean flip = false;
curTime = millis();
if (curTime - prevTime > 15000) {
prevTime = curTime;
flip = !flip;
lcd.clear();
}
if (segData.valid == true && flip == false) track_name(segData.seg, segData.col+2, segData.val); // col+2 to center it on my 2x16 screen (the denon only has a 2x12)
if (timeData.valid == true && flip == true) updateTime(timeData.minute, timeData.sec, timeData.pos, timeData.totMin, timeData.totSec);
}
}
};
MyMidi midi(Serial);
void setup() {
lcd.begin(2, 16);
digitalWrite(14, HIGH);
midi.begin(0);
}
void loop() {
midi.poll();
}
struct DENON_TIME checkForTimeData(byte controller, byte value) {
static byte minute, second, pos, totMin, totSec, lastSecond;
static float tot = 0;
if (controller >= 0x40 && controller <= 0x49) {
if (controller == 0x42) {
minute = value;
} else if (controller == 0x43) {
second = value;
} else if (controller == 0x48) {
pos = value;
if (second != lastSecond) {
if (second % 20 == 0) {
tot = ((minute*60)+second) / ((float)pos / 100);
totMin = tot/60;
totSec = (int)tot%60;
}
lastSecond = second;
return (DENON_TIME){true, minute, second, pos, totMin, totSec};
}
}
}
return (DENON_TIME){false,0,0,0};
}
struct DENON_SEGMENT checkForSegmentData(byte controller, byte value) {
static byte seg1MSB, seg2MSB = 0;
if ((controller >= 0x01 && controller <= 0x05) || (controller >= 0x07 && controller <= 0x0D)) { // segment 1 MSB
seg1MSB = value;
} else if (controller >= 0x0E && controller <= 0x19) { // segment 2 MSB
seg2MSB = value;
} else if ((controller >= 0x21 && controller <= 0x25) || (controller >= 0x27 && controller <= 0x2D)) { // segment 1 LSB
return (DENON_SEGMENT){true, 0, getColumn(controller, 1), ((seg1MSB<<4) + value)}; // return completed packet
} else if (controller >= 0x2E && controller <= 0x39) { // segment 2 LSB
return (DENON_SEGMENT){true, 1, getColumn(controller, 2), ((seg2MSB<<4) + value)}; // return completed packet
}
return (DENON_SEGMENT){false,0,0,0}; // incomplete packet
}
// parameters: cc- controller number, seg- segment number
// returns: column number (zero indexed) or 255 if invalid segment
byte getColumn(byte cc, byte seg) {
byte col=255;
if (seg == 1) {
col = cc - 33; // convert into segment number (column)
if (col >= 6) col--; // work around the fact that Denon skipped 0x06 for segment 1-6 (they got segment 2 correct)
} else if (seg == 2) {
col = cc - 46; // convert into segment number (column)
}
return col;
}
void track_name(byte lcd_row, byte lcd_col, byte lcd_data){
lcd.setCursor(lcd_col, lcd_row);
lcd.print(lcd_data);
}
void updateTime(byte minute, byte sec, byte pos, byte totMin, byte totSec) {
char one[17], two[17] = {};
strcat(two, "|");
for (byte i=1;i<=14;i++) {
if (i <= map(pos, 0, 100, 0, 14)) strcat(two,"#");
else strcat(two, " ");
}
strcat(two, "|");
sprintf(one, "R:%02i:%02i T:%02i:%02i", minute, sec, totMin, totSec);
lcd.setCursor(0, 0);
lcd.print(one);
lcd.setCursor(0, 1);
lcd.print(two);
}
Bookmarks