Here’s what I came up with… It will decode the track title and artist name, as well as the minute, second, track position (in percent). It also calculates the total track length every 20 seconds. It’s not 100% accurate, but it’s the best we have 
The example video shows it rotating between the artist/track and a two line time display with simple bar graph. The delay between changes is currently 15 seconds.
Note: Just want to draw attention to the fact that the decoding functions are completely independent of the MIDI code and the lcd code. While they are of course designed to decode MIDI, how you get the MIDI messages to the functions is up to you 
#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);
}