Skip to content

Commit 65e44e2

Browse files
committed
Allow to copy the pattern and keep the seek cursor in the same relative position
1 parent e42ba4d commit 65e44e2

File tree

4 files changed

+52
-28
lines changed

4 files changed

+52
-28
lines changed

brute-seq/Modules/GUI.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,13 @@ function drawTrackLabel(ctx, sprite, text)
136136
local dl = reaper.ImGui_GetWindowDrawList(ctx)
137137
reaper.ImGui_DrawList_AddText(dl, cx, cy, 0xFFFFFFFF, text)
138138
end
139+
140+
function drawButton(ctx, text)
141+
local y = reaper.ImGui_GetCursorPosY(ctx)
142+
reaper.ImGui_SetCursorPosY(ctx, y + 1)
143+
reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 4, 2)
144+
local result = reaper.ImGui_Button(ctx, text)
145+
reaper.ImGui_PopStyleVar(ctx)
146+
reaper.ImGui_SameLine(ctx)
147+
return result
148+
end

brute-seq/Modules/MIDI.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ function createItem(track, steps)
4343
return newItem
4444
end
4545

46+
function copyMidiContent(srcItem, dstItem)
47+
local srcTake = reaper.GetActiveTake(srcItem)
48+
local dstTake = reaper.GetActiveTake(dstItem)
49+
-- read whole event stream from the source take
50+
local _, midiData = reaper.MIDI_GetAllEvts(srcTake, "")
51+
52+
-- wipe any existing events in the destination take
53+
reaper.MIDI_SetAllEvts(dstTake, midiData) -- paste
54+
reaper.MIDI_Sort(dstTake) -- keep PPQ order
55+
56+
reaper.UpdateArrange()
57+
end
58+
4659
function removeItem(item)
4760
reaper.DeleteTrackMediaItem(reaper.GetMediaItemTrack(item), item)
4861
reaper.UpdateArrange()

brute-seq/Modules/Transport.lua

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function setTimeSelectionFromItem(item)
55
local length = reaper.GetMediaItemInfo_Value(item, "D_LENGTH")
66
local endPos = startPos + length
77

8-
reaper.GetSet_LoopTimeRange(true, false, startPos, endPos, true)
8+
reaper.GetSet_LoopTimeRange(true, true, startPos, endPos, false)
99
end
1010

1111
function setTimeSelectionFromTrack(track)
@@ -24,7 +24,7 @@ function setTimeSelectionFromTrack(track)
2424
if start + len > lastEnd then lastEnd = start + len end
2525
end
2626

27-
reaper.GetSet_LoopTimeRange(true, false, firstStart, lastEnd, true)
27+
reaper.GetSet_LoopTimeRange(true, true, firstStart, lastEnd, false)
2828
end
2929

3030
function getCursorPos()
@@ -46,8 +46,6 @@ function getCurrentStep(item)
4646
end
4747

4848
function jumpToStep(item, stepIdx)
49-
if not item or stepIdx < 0 then return end
50-
5149
local startPos = reaper.GetMediaItemInfo_Value(item, 'D_POSITION')
5250
local secPerBeat = reaper.TimeMap2_beatsToTime(0, 1)
5351
local stepSize = secPerBeat / time_resolution
@@ -56,6 +54,17 @@ function jumpToStep(item, stepIdx)
5654
reaper.SetEditCurPos(targetPos, true, true)
5755
end
5856

57+
function jumpToItem(currentItem, nextItem)
58+
local playing = reaper.GetPlayState() & 1 == 1
59+
local currentStart = reaper.GetMediaItemInfo_Value(currentItem, 'D_POSITION')
60+
local nextStart = reaper.GetMediaItemInfo_Value(nextItem, 'D_POSITION')
61+
62+
-- it only offsets the item when playing
63+
local offset = playing and (reaper.GetPlayPosition2() - currentStart) or 0
64+
65+
reaper.SetEditCurPos(nextStart + offset, true, true)
66+
end
67+
5968
function getItemIndexAtCursor(track)
6069
local curPos = getCursorPos()
6170
for i = 0, reaper.CountTrackMediaItems(track) - 1 do

brute-seq/brute-seq.lua

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ local function updateCurrentPatternIndex()
102102
end
103103
end
104104

105-
local function updateCursor(item, stepIndex)
105+
local function updateCursor(currentItem, nextItem)
106106
if followCursor then
107-
jumpToStep(item, stepIndex)
107+
jumpToItem(currentItem, nextItem)
108108
end
109109
end
110110

@@ -219,19 +219,9 @@ local function loop()
219219
changedPattern, currentPatternIndex = drawSlider(ctx, '##Pattern', currentPatternIndex, 1, patternCount, 140)
220220
reaper.ImGui_SameLine(ctx)
221221

222-
local y = reaper.ImGui_GetCursorPosY(ctx)
223-
reaper.ImGui_SetCursorPosY(ctx, y + 1)
224-
reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 2)
225-
removedPattern = reaper.ImGui_Button(ctx, "-")
226-
reaper.ImGui_PopStyleVar(ctx)
227-
reaper.ImGui_SameLine(ctx)
228-
229-
local y = reaper.ImGui_GetCursorPosY(ctx)
230-
reaper.ImGui_SetCursorPosY(ctx, y + 1)
231-
reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 4, 2)
232-
addedPattern = reaper.ImGui_Button(ctx, "+")
233-
reaper.ImGui_PopStyleVar(ctx)
234-
reaper.ImGui_SameLine(ctx)
222+
local removePattern = drawButton(ctx, "-")
223+
local addPattern = drawButton(ctx, "+")
224+
local dupPattern = drawButton(ctx, "++")
235225

236226
reaper.ImGui_Text(ctx, 'Steps:')
237227
reaper.ImGui_SameLine(ctx)
@@ -276,19 +266,21 @@ local function loop()
276266
updateTimeSelection()
277267
end
278268
-- Delete pattern
279-
elseif removedPattern then
269+
elseif removePattern then
280270
removeItem(currentPattern.item)
281271
updateCurrentPatternIndex()
282-
currentPattern = getPattern(sequencerTrack, currentPatternIndex - 1)
283-
if currentPattern then
284-
updateCursor(currentPattern.item, 0)
285-
end
286272
updateTimeSelection()
287273
-- Add pattern
288-
elseif addedPattern then
274+
elseif addPattern then
289275
newItem = createItem(sequencerTrack, currentPattern.steps > 0 and currentPattern.steps or 16)
276+
updateCursor(currentPattern.item, newItem)
277+
currentPatternIndex = patternCount + 1
278+
updateTimeSelection()
279+
elseif dupPattern then
280+
newItem = createItem(sequencerTrack, currentPattern.steps)
281+
copyMidiContent(currentPattern.item, newItem)
282+
updateCursor(currentPattern.item, newItem)
290283
currentPatternIndex = patternCount + 1
291-
updateCursor(newItem, 0)
292284
updateTimeSelection()
293285
-- Resize pattern
294286
elseif changedSteps or changedTimes then
@@ -304,8 +296,8 @@ local function loop()
304296
updateTimeSelection()
305297
reaper.Undo_EndBlock('Resize pattern',-1)
306298
elseif changedPattern then
307-
currentPattern = getPattern(sequencerTrack, currentPatternIndex - 1)
308-
updateCursor(currentPattern.item, 0)
299+
nextPattern = getPattern(sequencerTrack, currentPatternIndex - 1)
300+
updateCursor(currentPattern.item, nextPattern.item)
309301
updateTimeSelection()
310302
end
311303
else -- if currentPattern

0 commit comments

Comments
 (0)