[SOLVED] How to duplicate automation when duplicating pattern content

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

There is:

renoise.song().patterns.tracks.automation:copy_from(other renoise.PatternTrackAutomation object)

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.

1 Like

mainly because this is what i have

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.

so @joule
i was given this but it did nothing

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}

here it is

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}

seems to work

added to Paketti

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.