hi, so, i’ve got this nice little @joule pattern doubler in use for eons now, or maybe just a decade or something. it’s really to die for.
but i just realized that the doubler does not also double automation, which is a shame, as the result is:
what would the process of modifying this function to both double the pattern data and the automation data be?
function joulepatterndoubler()
local s=renoise.song()
local old_patternlength = s.selected_pattern.number_of_lines
local resultlength = nil
resultlength = old_patternlength*2
if not (resultlength > 512) then
s.selected_pattern.number_of_lines = resultlength
for track_index, patterntrack in ipairs(s.selected_pattern.tracks) do
if not patterntrack.is_empty then
for line_index, line in ipairs(patterntrack.lines) do
if line_index <= old_patternlength then
if not line.is_empty then
patterntrack:line(line_index+old_patternlength):copy_from(line)
else
patterntrack:line(line_index+old_patternlength):clear()
end
end
end
end
end
else
return
end
--Modification, cursor is placed to "start of "clone""
--renoise.song().selected_line_index = old_patternlength+1
s.selected_line_index = old_patternlength+s.selected_line_index
-- s.transport.edit_step=0
end
Then you would have to iterate all devices/parameters to copy any automation that is present.
But instead, why not use:
renoise.song().patterns.tracks:copy_from(other renoise.PatternTrack object)
Copy contents from other pattern tracks, including automation when possible.
function joulepatterndoubler()
local s=renoise.song()
local old_patternlength = s.selected_pattern.number_of_lines
local resultlength = nil
resultlength = old_patternlength*2
if not (resultlength > 512) then
s.selected_pattern.number_of_lines = resultlength
for track_index, patterntrack in ipairs(s.selected_pattern.tracks) do
if not patterntrack.is_empty then
for line_index, line in ipairs(patterntrack.lines) do
if line_index <= old_patternlength then
if not line.is_empty then
patterntrack:line(line_index+old_patternlength):copy_from(line)
else
patterntrack:line(line_index+old_patternlength):clear()
end
end
end
end
end
else
return
end
--Modification, cursor is placed to "start of "clone""
--renoise.song().selected_line_index = old_patternlength+1
s.selected_line_index = old_patternlength+s.selected_line_index
-- s.transport.edit_step=0
end
renoise.tool():add_menu_entry{name="--Main Menu:Tools:Paketti..:Joule Pattern Doubler",invoke=function() joulepatterndoubler() end}
renoise.tool():add_keybinding{name="Pattern Editor:Paketti:Joule Pattern Doubler",invoke=function() joulepatterndoubler() end}
renoise.tool():add_keybinding{name="Mixer:Paketti:Joule Pattern Doubler",invoke=function() joulepatterndoubler() end}
and the copy_from other patterntrack object for me feels like i don’t know if i would know how to use it, esp since this doubling of patterns is done within the pattern, i.e. 64 row pattern turns into 128row pattern… so what am i copying it from?
if that api call mentioned “row 1-63” and “copy it to 64-128”, i’d get it, but i’m not clever enough to sort it out.
function joulepatterndoubler()
local song = renoise.song()
local old_patternlength = song.selected_pattern.number_of_lines
local new_patternlength = old_patternlength * 2
if new_patternlength <= 512 then
song.selected_pattern.number_of_lines = new_patternlength
-- Loop through each track in the selected pattern
for track_index, pattern_track in ipairs(song.selected_pattern.tracks) do
if not pattern_track.is_empty then
-- Copy notes in the pattern
for line_index, line in ipairs(pattern_track.lines) do
if line_index <= old_patternlength then
if not line.is_empty then
pattern_track:line(line_index + old_patternlength):copy_from(line)
else
pattern_track:line(line_index + old_patternlength):clear()
end
end
end
-- Handle automation duplication
local automations = song.patterns[song.selected_pattern_index].tracks[track_index].automation
if automations then
for _, automation in pairs(automations) do
local new_automation = song.patterns[song.selected_pattern_index].tracks[track_index]:create_automation(automation.dest_parameter)
new_automation.playmode = automation.playmode
for _, point in ipairs(automation.points) do
-- Copy existing automation points to the new pattern length
new_automation:add_point_at(point.time, point.value)
-- Duplicate the automation to the extended part of the pattern
new_automation:add_point_at(point.time + old_patternlength, point.value)
end
end
end
end
end
-- Update cursor position to the start of the "clone" area
song.selected_line_index = old_patternlength + song.selected_line_index
else
-- If the new pattern length exceeds the maximum, do not alter the pattern
return
end
end
-- Add menu entries and keybindings for the tool
renoise.tool():add_menu_entry{name="--Main Menu:Tools:Paketti..:Joule Pattern Doubler", invoke=joulepatterndoubler}
renoise.tool():add_keybinding{name="Pattern Editor:Paketti:Joule Pattern Doubler", invoke=joulepatterndoubler}
renoise.tool():add_keybinding{name="Mixer:Paketti:Joule Pattern Doubler", invoke=joulepatterndoubler}
function joulepatterndoubler()
local song = renoise.song()
local pattern_index = song.selected_pattern_index
local old_patternlength = song.selected_pattern.number_of_lines
local new_patternlength = old_patternlength * 2
if new_patternlength <= 512 then
song.selected_pattern.number_of_lines = new_patternlength
-- Loop through each track in the selected pattern
for track_index, pattern_track in ipairs(song.selected_pattern.tracks) do
if not pattern_track.is_empty then
-- Copy notes in the pattern
for line_index = 1, old_patternlength do
local line = pattern_track:line(line_index)
local new_line = pattern_track:line(line_index + old_patternlength)
if not line.is_empty then
new_line:copy_from(line)
else
new_line:clear()
end
end
end
-- Handle automation duplication with detailed debug output
local track_automations = song.patterns[pattern_index].tracks[track_index].automation
if next(track_automations) ~= nil then -- Check if there's any automation
for param, automation in pairs(track_automations) do
print("Processing automation for parameter:", param)
local points = automation.points
for i, point in ipairs(points) do
local new_time = point.time + old_patternlength
if new_time <= new_patternlength then
automation:add_point_at(new_time, point.value)
print("Duplicating point:", point.time, point.value, "to", new_time)
end
end
end
else
print("No automation found in track", track_index)
end
end
song.selected_line_index = old_patternlength + 1
print("Pattern doubled successfully.")
else
print("New pattern length exceeds 512 lines, operation cancelled.")
end
end
-- Add menu entries and keybindings for the tool
renoise.tool():add_menu_entry{name="--Main Menu:Tools:Paketti..:Joule Pattern Doubler", invoke=joulepatterndoubler}
renoise.tool():add_keybinding{name="Pattern Editor:Paketti:Joule Pattern Doubler", invoke=joulepatterndoubler}
renoise.tool():add_keybinding{name="Mixer:Paketti:Joule Pattern Doubler", invoke=joulepatterndoubler}