Midi playback speed inconsistency


#1

My synth app has the capability of importing a midi file and playing it back. I’m creating the midi sequences in Logic, exporting them to files on disk, and then loading and playing them in my synth app (it’s a standalone app). What’s strange is, the sequences are playing back at a faster rate than they were in Logic. I don’t know if I’m using JUCE wrong or I’m making a mistake in my calculations, or perhaps I’m misunderstanding how different apps (Logic vs mine) handle time. Here’s my relevant code:


// Hitting play initializes:
// curEvent = 0;
// startSample = 0;
// midiSeqIsPlaying = true;

void SynthAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
{	
	bufferToFill.clearActiveBufferRegion();
	MidiBuffer incomingMidi;
	
	if (midiSeqIsPlaying) 
	{
		int bufferSize = bufferToFill.numSamples;
		
		do
		{
			curSample = (midiSeq.getEventTime(curEvent) * sampleRate);
			MidiMessage event = midiSeq.getEventPointer(curEvent)->message;
			
			if (curSample - startSample < bufferSize) 
			{
				incomingMidi.addEvent(event, (curSample - startSample));
				curEvent++;
			} 
			else 
			{
				startSample += bufferSize;
			}
		} 
		
		while (curSample - startSample < bufferSize && midiSeqIsPlaying);
	}
	
	synth.renderNextBlock(*bufferToFill.buffer, incomingMidi, 0, bufferToFill.numSamples);
}

I checked the timestamps of each midi event and they match up with the timestamps in Logic. My samplerate is set to 44100. Any ideas?


#2

Asked it, then answered it. Something to do with the “do” that was throwing it off, as well as the placement of “sampleStart += bufferSize”. Here’s the fixed code:

// Hitting play initializes:
// curEvent = 0;
// startSample = 0;
// midiSeqIsPlaying = true;

void SynthAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
{	
	bufferToFill.clearActiveBufferRegion();
	MidiBuffer incomingMidi;
	
	if (midiSeqIsPlaying) 
	{
		int bufferSize = bufferToFill.numSamples;
		
		// Midi Loop
		while (curSample - startSample < bufferSize && midiSeqIsPlaying) 
		{
			curSample = (midiSeq.getEventTime(curEvent) * sampleRate) + loopOffset;
			MidiMessage event = midiSeq.getEventPointer(curEvent)->message;
			
			if (curSample - startSample < bufferSize) 
			{
				incomingMidi.addEvent(event, curSample - startSample);
				curEvent++;
				
				if (curEvent >= numEvents) 
				{
					if (loopState) 
					{
						loopOffset = (curSample - startSample) + (totalSamples - curSample) + loopOffset;
						startSample = 0;
						curEvent = 0;
						curSample = 0;
					} 
					else 
					{
						stopMidiSeq(false);
						const MessageManagerLock mmLock;
						playButton->setButtonText(L"Play");
						break;
					}
				}
			}
		}
		
		startSample += bufferSize;
	}
	
	synth.renderNextBlock(*bufferToFill.buffer, incomingMidi, 0, bufferToFill.numSamples);
}