Sequence from MIDI file skips beats when looping

macOS 15 SDK 2.7.2

I’m working with a MIDI file containing a 2-bar pattern that I’m aiming to play as a loop, and so after initializing a sequence with said MIDI file, I called :setLoops(0) on it so it repeats endlessly.

The looping itself works fine but I found that the loop skips a beat when going back to the start, the same file loops fine when played in software like Logic.

I'm sharing a small sample project that showcases the issue.
Midi-Track-Loop.zip (15.8 KB)

In order to get the result I expect, I had to use a callback passed to :play() that uses a timer and delays the restart. You can toggle the WORKAROUND variable to compare the results with the SDK vs my custom callback.

local WORKAROUND = false

if WORKAROUND then

	-- Looping with a recursive callback that adds a 80ms delay before restarting the sequence
	local playLooped
	playLooped = function(midiLoop)
		
		midiLoop:play(function(seq) pd.timer.new(80, function(seq) playLooped(seq) end, seq) end)
		
	end
	
	playLooped(midiLoop)
	
else

	-- Default looping behavior provided by SDK
	midiLoop:setLoops(0)
	midiLoop:play()
	
end

What to listen for: there's a repeated kick playing once per 2-bar cycle. When letting the SDK call do the looping, the doubled kicks play too close to each other and out of rhythm.

I'm fairly new to using MIDI and the audio world so do let me know if I'm doing something silly with the setup that would be responsible for this issue.

Meanwhile, I thought I'd share in case this is indeed unexpected behavior.


PS: I'm otherwise having lots of fun playing with the audio part of the SDK, it is quite the marvel!

-- Update --

After more experimentation, I discovered that MIDI files that have a note on the last beat of the last bar do loop fine, whereas for files/sequences where the last few beats don't have any notes, the looping seems to skip the final empty beats.

I've updated the sample project with two files:
A. pattern with no note on the final beat -> skips a beat when looping;
B. pattern with a note on the final beat -> loops fine.

I've also noticed that although both files were created with 2 bars in length, Sequence:getLength() returns different step counts for file A and file B.

Meanwhile, if I set file A to loop using the longer step count of file B as its end step value, then file A loops correctly.

Midi-Track-Loop-2.zip (14.5 KB)


In essence, this suggests to me that the Sequence object doesn't have or use the original bar information? So its length is presumably calculated based on the position and length of the last note?

At the moment, it seems that calling the simpler Sequence:setLoops(loopCount) won’t behave as expected for many musical patterns, since most musical loops would want to cycle based on bars and not all music will have a note on the last beat of the last bar?

But anyhow, I'm happy I worked out that the current way to get a MIDI loop that always sounds correct is to pre-calculate an end step that matches the number of bars the loop should be, and use that value with Sequence:setLoops(startStep, endStep, loopCount).

Getting Sequence:setLoops(loopCount) to work for any MIDI file would just be nice to have. :slight_smile:

1 Like