Skip to content

Instantly share code, notes, and snippets.

@pckv
Last active May 1, 2025 20:22
Show Gist options
  • Save pckv/5bd4d46f1f5ffa2dc02b74ccc826a08e to your computer and use it in GitHub Desktop.
Save pckv/5bd4d46f1f5ffa2dc02b74ccc826a08e to your computer and use it in GitHub Desktop.
Unrepeat - FL Studio Piano Roll Script
"""
Title: Unrepeat
Author: pckv
Category: Edit
Version: 1.1
Description:
Splits all notes with repeats into regular notes
Changelog:
v1.1 (2025-05-01)
Fixed division by zero error for PPQs lower than 96
v1.0 (2025-05-01)
Initial version
"""
from flpianoroll import score, Note
import math
# By default, split notes retain their repeats value, which allows you to
# extend unrepeated notes to restore the previous repeat-value. They should
# still only play once after repeating anyway, since the new length is equal
# to the individual repeat length.
#
# Set this to True if you'd like the repeats to be set to 0 after splitting.
REMOVE_REPEATS = False
# Lengths of each individual note at 96 PPQ
repeat_note_lengths = {
1: 96,
2: 72,
3: 64,
4: 48,
5: 36,
6: 32,
7: 24,
8: 18,
9: 16,
10: 12,
11: 9,
12: 8,
13: 6,
14: 4,
}
def get_repeat_length(note: Note) -> int:
"""Get the length of a single repeat note for the given note."""
new_length = repeat_note_lengths[note.repeats]
# Scale the length based on the current PPQ
return math.floor(new_length * (score.PPQ / 96))
def split_note(note: Note):
"""Split a note into multiple notes based on its repeat length."""
original_length = note.length
end_time = note.time + original_length
# Get the length of a single repeat note
repeat_length = get_repeat_length(note)
# Update the original note's length to the repeat length
note.length = repeat_length
# Ceil to include the remaining note that might be shorter than the repeat
# length
num_splits = math.ceil(original_length / repeat_length)
for i in range(num_splits):
# Create a new note for each split after the first one
split_note = note if i == 0 else note.clone()
# Place the split note
split_note.time = note.time + repeat_length * i
if REMOVE_REPEATS:
# Disable repeats for all new notes
split_note.repeats = 0
# Cut the final split's length to end at the original note's end
# position
remaining_time = end_time - (split_note.time + split_note.length)
if remaining_time < 0:
split_note.length = repeat_length + remaining_time
# Add all new notes
if i > 0:
score.addNote(split_note)
def unrepeat():
"""Split all selected notes with repeats"""
for i in range(score.noteCount):
note = score.getNote(i)
# Skip notes without repeats
if note.repeats == 0:
continue
split_note(note)
if __name__ == "__main__":
unrepeat()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment