Midi playback speed inconsistency

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?

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);
}
1 Like