Getting Midi Sync Message :: Song , HOW TO ????? [SOLVED]

[EDIT] go to my own replay to see the solution, modifying ofxMidi to handle midi system messages

Hi all OF lovers,

I am programming to sync my c++ application with Ableton Live, using the preference panel, and configuring sync in output with Midi Clock type set to “Song”.

I use ofxMidi and i am in Mac OSX leopard.

Doing this, i receive midi messages, with status 0xF0 (240) each Midi clock time (1/24 th of a quarter note) .
Messages are sent to channels 11 (play) , 13 (midi clock 1/24th qN ) , 3 (pause) or 9 (stop and rewind).
[edit: this is due to the incorrect routing of midi system messages on ofxMidi. See my replay for details]

I can see that byteOne from the message is changing while playing and the higher numbers depend on tempo. So my question is this:

which is the format that Live is sending through this midi message?
can i get the tempo or bar/beat/tick number with this message?

or better :::
How can i get via C++ the info in a Song position Pointer Midi message? or Midi Clock messsage???

thank you !!!

www.tangiblex.net
www.gatodante.com

1 Like

Hi,

I am too making some application with Maschine (midi hardware/soft) and saw that OSCulator could find all those info and I am really curious how it could achieve that.

For now I am doing as follow

  
   
void testApp::newMidiMessage(ofxMidiEventArgs& eventArgs) {  
      
    if (eventArgs.status == 240)  
    {  
        if(eventArgs.channel == 9)  
        {  
            //        Compute the BPM from the interval between 2 midiclock tick (24 ticks/quarter)  
            BITPERMIN = 60000.0/(ofGetElapsedTimeMillis()-clockPastTime)/24;  
            clockPastTime = ofGetElapsedTimeMillis(); //int  
              
            clockTick++; //int  
              
            if(clockTick == 24){  
                isBEAT = true;  
                clockTick = 0;  
                if(clockPeriodValue >= clockPeriod-1) //clockPeriod = 4, at least by default.  
                {  
                    clockPeriodValue = 0;  
                    (clockQuarterValue >= clockQuarter-1)?(clockQuarterValue = 0):(clockQuarterValue++);  
                }else  
                {  
                    clockPeriodValue++;     
                }  
            }else isBEAT = false;  
              
        }  
          
        if((eventArgs.channel == 3)||(eventArgs.channel == 12)){  
            clockQuarterValue = 0;  
            clockPeriodValue = 0;  
            clockTick = 0;  
        }        
    }else  
    {  
        // store some data from midi message in variables  
        stat = eventArgs.status;  
        port = eventArgs.port;  
        id = eventArgs.channel;  
        value = eventArgs.byteOne;  
        value2 = eventArgs.byteTwo;  
        timestamp = eventArgs.timestamp;  
    }  
}  
  
  

Great, good code to handle those messages.

I found what could be a good solution:
We have to modify ofxMidi to handle system messages.
In Midi, Midi Clock is comming on byte “zero” number 248 (MIDI_TIME_CLOCK) , sending each tick (1/24th quarter note). There is no byteOne or Two.
When there is a stop, midi sends in byteZero number 252 (MIDI_STOP)
When there is a start, midi sends byteZero number 250 (MIDI_START).
To send a song position pointer, midi sends on byteZero = 242 (MIDI_SONG_POS_POINTER), byteOne and Two will be the position.

But the problem is how ofxMidi handle those messages.
Let ´s look into ofxMidiIn.cpp -> ManageNewMessage method:

  
  
void ofxMidiIn::manageNewMessage(double deltatime, vector< unsigned char > *message){  
	  
	unsigned int nBytes = message->size();  
	if(bVerbose){  
		cout << "num bytes: "<<nBytes;  
		for ( unsigned int i=0; i<nBytes; i++ )  
			cout << " Byte " << i << " = " << (int)message->at(i) << ", ";  
		if ( nBytes > 0 )  
			cout << "stamp = " << deltatime << '\n';  
	}  
	  
	if(nBytes>0){  
		  
		ofxMidiEventArgs eventArgs;  
		  
		eventArgs.channel = ((int)(message->at(0)) % 16)+1;  
		eventArgs.status = ((int)message->at(0)) - (eventArgs.channel-1);  
		eventArgs.timestamp = deltatime;  
		  
		if(nBytes==2){  
			eventArgs.byteOne = (int)message->at(1);  
		}else if(nBytes==3){  
			eventArgs.byteOne = (int)message->at(1);  
			eventArgs.byteTwo = (int)message->at(2);  
		}  
		  
		  
		ofNotifyEvent( newMessageEvent, eventArgs, this );  
		  
	}  
	  
	  
}  
  
  
  

but there is an incorrect handling here:

  
  
eventArgs.channel = ((int)(message->at(0)) % 16)+1;  
		eventArgs.status = ((int)message->at(0)) - (eventArgs.channel-1);  
		eventArgs.timestamp = deltatime;  
  

For messages like Midi Time Clock one (248, void, void) it will be done:
channel = 9
status = 240
And this is incorrect. It should be:
status = 248
channel = whatever (goes to all channels) , say channel 0 …

Same for all the midi messages that are NOT as control, notes, etc.
So I had to change ofxMidiIn.cpp -> manageNewMessages function to this one:

  
  
void ofxMidiIn::manageNewMessage(double deltatime, vector< unsigned char > *message){  
	  
	unsigned int nBytes = message->size();  
	if(bVerbose){  
		cout << "num bytes: "<<nBytes;  
		for ( unsigned int i=0; i<nBytes; i++ )  
			cout << " Byte " << i << " = " << (int)message->at(i) << ", ";  
		if ( nBytes > 0 )  
			cout << "stamp = " << deltatime << '\n';  
	}  
	  
	if(nBytes>0){  
		  
		ofxMidiEventArgs eventArgs;  
		  
		  
		eventArgs.timestamp = deltatime;  
		  
		int byteZero =  (int)(message->at(0));   
		  
		/// this is when the midi message is NOT into the category of midi system messages...			    
		if( byteZero < MIDI_TIME_CODE){   
		  
			eventArgs.channel = ((int)(message->at(0)) % 16)+1;  
			eventArgs.status = ((int)message->at(0)) - (eventArgs.channel-1);	  
			  
			if(nBytes==2 ){  
					  
				eventArgs.byteOne = (int)message->at(1);  
				eventArgs.byteTwo = 0;  
  
					  
			}else if(nBytes==3) {  
					  
				eventArgs.byteOne = (int)message->at(1);  
				eventArgs.byteTwo = (int)message->at(2);  
				  
	  
			}  
				  
				  
				ofNotifyEvent( newMessageEvent, eventArgs, this );  
		  
	  
		/// and now for midi messages INTO the category of midi system, etc. 	  
		} else {  
		  
		  
			eventArgs.channel = 0;  
			eventArgs.status = (int)message->at(0);	  
			  
			if(nBytes==1 ){  
				  
                                // we make byeOne and Two = 0 to not to deal with previous values.   
				eventArgs.byteOne = 0;  
				eventArgs.byteTwo = 0;  
			  
			}else if(nBytes==2 ){  
				  
				eventArgs.byteOne = (int)message->at(1);  
				eventArgs.byteTwo = 0;  
				  
				  
			}else if(nBytes==3) {  
				  
				eventArgs.byteOne = (int)message->at(1);  
				eventArgs.byteTwo = (int)message->at(2);  
				  
				  
			}  
			  
			  
			ofNotifyEvent( newMessageEvent, eventArgs, this );  
		  
		  
		  
		}  
							    
	  
	}  
  
  
  

So this would be an example of code that uses this new ofxMidiIn.cpp::

  
  
  
int     port = args.port ;    
	int     channel = args.channel;    
	int     status = args.status;    
	int     byteOne = args.byteOne;    
	int     byteTwo =  args.byteTwo;    
	double  timestamp = args.timestamp;    
	  
	int _ticksPerqNote = (int) 24.0 * 4.0/tempoDenominator;   
	ticksPerBar = tempoNumerator * ticksPerqNote;   
	ticks32thNotePerBar = (int) ticksPerBar/8.0;    
	ticksPer32thNote = (int) ticksPerqNote/8.0;  
  
  
if(status == MIDI_TIME_CLOCK)){  
		  
		  
		  
		tempoTicks += 1;  
		ticksfor32thNote +=1;  
		  
		  
		if(ticksfor32thNote % ticksPer32thNote == 0 ) {  
			  
			  
			// if(num32thNotes % 2 == 0) midiOut.sendNoteOff(1, 62, 0); else  midiOut.sendNoteOn(1, 62, 127);  
			num32thNotes  += 1;   
			  
		}  
		  
		if(tempoTicks % _ticksPerqNote == 0 ) {  
			  
			tempoqNotes += 1;  
			tempoTicks = 0;   
			  
			//// hemos llegado al beat final::::   
			  
			if (tempoqNotes % (tempoNumerator + 1) == 0 ) {   /// eso está bien ???   
				tempoBars += 1;	  
				tempoqNotes = 1;   
				num32thNotes = 0;   
				ticksfor32thNote = 0;  
			}  
			  
		}  
	}  
 	  
	////////////////////  
	if(status == MIDI_START) {  
		  
		//ticks = 0;   
		//qNotes = 0;   
		//bars = 0;   
		tempoTicks = 0;   
		tempoqNotes = 1;   
		tempoBars = 1;   
		isPlaying = false;  
		num32thNotes = 0;   
		ticksfor32thNote = 0;  
		  
		cout << " live Set playing ...." << endl;  
		  
		isPlaying = true;   
	};  
	  
	//////////////////  
	if(status == MIDI_STOP) cout << " live Set paused " << endl;  
	  
	//////////////////  
	if(status == MIDI_SONG_POS_POINTER  && byteOne == 0 && byteTwo == 0)  {  
		  
		cout << " live Set  stopped " << endl;  
		tempoTicks = 0;   
		tempoqNotes = 1;   
		tempoBars = 1;   
		//isPlaying = false;  
		num32thNotes = 0;   
		ticksfor32thNote = 0;  
		  
	}  
  
  
  

wow great!
Thank you so much.

However, I wanted to try your example and had some issues as I don’t know you initial value for a few variables:
tempoDenominator
numerator
ticksPerqNote
tempoNumerator
May be also some other ?
Would you mind sharing those?

I will try to check this out without the example too.
Thank you again!!

Hi Mukei,
good that you liked the replay.

so those would be the intial values:

i had to modify the line :

  
 ticksPerBar = numerator * ticksPerqNote;     

for this one on my code:

  
 ticksPerBar = tempoNumerator * ticksPerqNote;     

(i edited the previous post)
with this you will have:

  
  
tempoNumerator = 4; /// chose the one of your song...., ie. 4/4, 2/4 ..... the number in the numerator of the signature.  
tempoDenominator = 4; /// choose the one you want...  
        tempoTicks = 0;     
        tempoqNotes = 1;     
        tempoBars = 1;     
        isPlaying = false;    
        num32thNotes = 0;     
        ticksfor32thNote = 0;   
  

best,

miguel.