Midi clock display jittery
craig@unifiedsystems.ca
Posts: 8
Hey there, I am working on a project where the master controller is taking in midi (converted to serial) and displaying the Midi beat clock on the MVP touch panel
The display shows " BARS:BEATS:DIVISIONS" , every 6 times that the the panel receives the "$F8" message it advances the divisions by one unit. Everything seems to work fairly well except for when the tempo of my sequencer gets up around the 180 beats per minute tempo (72 x $F8 messages per second). The clock begins to get really jittery and advances in big chunks of time.
I am quite new and and need some guidance as to where the bottleneck is that is causing the jittering.
The "$F2" at the bottom of the code is to set the beginning position of the song position pointer and seems to work flawlessly.
Thanks.
DEFINE_CALL 'SEND MIDI COUNT'
{
SEND_COMMAND dvTP1,"'^TXT-50,0,',FORMAT('%02d',(1+(NMIDI_SPP/16))),':',FORMAT('%02d',(1+((NMIDI_SPP)%16)/4)),':',FORMAT('%02d',(1+(NMIDI_SPP %4)))"
}
DEFINE_EVENT
DATA_EVENT [dvMIDI]
{
STRING:
{
LOCAL_VAR CHAR JUNK[10]
MIDI_BUFFER = DATA.TEXT
WHILE (LENGTH_STRING(MIDI_BUFFER) > 0 ) //re-runs if there is data in the buffer after one round
{
NTEST3++ // for debug
CMIDI_STATUSBYTE = GET_BUFFER_CHAR(MIDI_BUFFER) // strips first byte of midi message
SWITCH(CMIDI_STATUSBYTE) // does things dependant on first byte of message
{
CASE $F8: // timing clock at 24 pulses per quarter note
{
Ntest1++ // for debug
nmidi_clock++
IF (NMIDI_clock >= 6 ) // every 6 ticks of timing clock
{
NMIDI_clock = 0
NMIDI_SPP++ // moves song position pointer up one division
CALL 'SEND MIDI COUNT' // sends data to TP
}
}
CASE $F2: // starting point of song position pointer
{
ntest2++ //debug
CMIDI_LSB = GET_BUFFER_CHAR(MIDI_BUFFER) // LSB of song position pointer
CMIDI_MSB = GET_BUFFER_CHAR(MIDI_BUFFER) // MSB of song position pointer
NMIDI_SPP =((TYPE_CAST(cMIDI_LSB))+(128*(TYPE_CAST(CMIDI_MSB))))
NMIDI_clock = 0
CALL 'SEND MIDI COUNT'
}
}
}
The display shows " BARS:BEATS:DIVISIONS" , every 6 times that the the panel receives the "$F8" message it advances the divisions by one unit. Everything seems to work fairly well except for when the tempo of my sequencer gets up around the 180 beats per minute tempo (72 x $F8 messages per second). The clock begins to get really jittery and advances in big chunks of time.
I am quite new and and need some guidance as to where the bottleneck is that is causing the jittering.
The "$F2" at the bottom of the code is to set the beginning position of the song position pointer and seems to work flawlessly.
Thanks.
DEFINE_CALL 'SEND MIDI COUNT'
{
SEND_COMMAND dvTP1,"'^TXT-50,0,',FORMAT('%02d',(1+(NMIDI_SPP/16))),':',FORMAT('%02d',(1+((NMIDI_SPP)%16)/4)),':',FORMAT('%02d',(1+(NMIDI_SPP %4)))"
}
DEFINE_EVENT
DATA_EVENT [dvMIDI]
{
STRING:
{
LOCAL_VAR CHAR JUNK[10]
MIDI_BUFFER = DATA.TEXT
WHILE (LENGTH_STRING(MIDI_BUFFER) > 0 ) //re-runs if there is data in the buffer after one round
{
NTEST3++ // for debug
CMIDI_STATUSBYTE = GET_BUFFER_CHAR(MIDI_BUFFER) // strips first byte of midi message
SWITCH(CMIDI_STATUSBYTE) // does things dependant on first byte of message
{
CASE $F8: // timing clock at 24 pulses per quarter note
{
Ntest1++ // for debug
nmidi_clock++
IF (NMIDI_clock >= 6 ) // every 6 ticks of timing clock
{
NMIDI_clock = 0
NMIDI_SPP++ // moves song position pointer up one division
CALL 'SEND MIDI COUNT' // sends data to TP
}
}
CASE $F2: // starting point of song position pointer
{
ntest2++ //debug
CMIDI_LSB = GET_BUFFER_CHAR(MIDI_BUFFER) // LSB of song position pointer
CMIDI_MSB = GET_BUFFER_CHAR(MIDI_BUFFER) // MSB of song position pointer
NMIDI_SPP =((TYPE_CAST(cMIDI_LSB))+(128*(TYPE_CAST(CMIDI_MSB))))
NMIDI_clock = 0
CALL 'SEND MIDI COUNT'
}
}
}
0
Comments
Store the current midi clock in a variable and create a timeline that triggers no more than 10 times per second (5 times a second should be fine), on the timeline event send the current midi clock value.
If timelines are too much effort then use a wait in mainline.
I'd also create another variable to keep track of updates in the clock so you don't update the touch panel unnecessarily; and don't send updates when the panel is offline or it will get a surprising bucketload of junk when it comes online.
IF (NMIDI_clock >= 6 ) // every 6 ticks of timing clock
{
NMIDI_clock = 0
NMIDI_SPP++ // moves song position pointer up one division
CALL 'SEND MIDI COUNT' // sends data to TP
}
I have found it's best to create essentially a different frame rate for the touch panel. Sending the MIDi/SMPTE time clock at the roughly 30fps it spews out at is just to much traffic for the poor thing. If you write a routine to convert the time scale coming from themMIDI clock to downscale it to between 5-10 fps, you might find your TP Able to handle it. Just skip sending time data that comes in between TP frames. You could just do the math and divide by 3-6 to get there. Or you could make a timeline that grabs the current MIDI time at the 5-10 fps frame rate. I'd do the latter myself. The human eye won't see that much of a difference and you won't be making the TP drink from a fire hose.
Midi timecode and Midi Beat Clock are two different things. The beat clock is tempo dependant while timecode is more of an absolute time. I can reduce the traffic from the controller to the TP as much as I want via timeline but it doesn't seem to help. Here is a breakdown of what should be happening.
- Every six "$F8" received, NMIDI_SPP++
- Six times per second, display "NMIDI_SPP" // just added this via timeline, didn't seem to help
Change this:
To this:
Maybe there is a flaw in the math or in the data processing? It might be worth trying to rule that out at this point. Just a thought...
Im unsure what you mean by self inducted. I agree that I think I am seeing exactly what I'm sending and that the TP is accurately displaying the value of nMIDI_SPP (however I decide to format). I just can't figure out why that variable seems to change in big increments once the tempo gets fast enough. Again, I'm the rookie but I'm leaning towards one of 3 things
1. code parsing/processing in-efficiencies
2. serial to midi conversion problems (outside the scope of AMX on this one)
3. hardware processing limitations (anyone with any input on this ?)
From what you’ve posted so far I can’t tell what is making the variable (nMIDI_SPP?) change in big increments. Hopefully someone else can.
What others are suggesting is that maybe AMX is displaying exactly what it is being told and that the MIDI strings coming in have errors; so this could be the second possibility on your list, or maybe the problem is occurring before the MIDI to serial conversion.
The only way to know if the problem is in the AMX is to look at the incoming strings in diagnostics.
The next thing i suggest is some error correction, compare values before sending to the touch panel, if the value change is above a threshold then assume it is an error.
Tried a 38.4k and 115k. Im starting to think that the serial/midi converter might be buffering, I've got a couple optocouplers and max232 chips coming and I'm going to make my own converter. I understand that AMX master controllers can do 31.25k so only voltage conversion is required, not baud rate.
MIDI is one of the most chatty protocols I've ever done. It depends on what's going in. I did a high-end teleconferencing system with a broadcast quality video desk (Grass Valkey) and a digital mixing console. (Neve ) the midi was a fire hose.