[SOLVED] Clone Pattern & Merge With Current Pattern?

Hi, Is it possible to do the “Clone pattern” and “Merge pattern” within the API? I would sometimes like to double up the riffs but still maintain the same “one pattern” playability, and am finding pressing a key to Clone and then clicking on two pattterns and rightclicking and merging a bit tedious.
How would one go about doing this kind of work?

  1. Double the number of lines on the current pattern
  2. Copy the first half of the pattern to the second (empty) one, suggesting this approach:

Use the table with the all lines of the pattern found somewhere in renoise.song(). Make a function that copies line x to x+old_patternlength until x = old_patternlength.

Ok, I think the table with “all lines of the pattern” is renoise.song().selected_pattern_track.lines
Current row amount is accessible at renoise.song().selected_pattern.number_of_lines
renoise.song().selected_pattern.number_of_lines=30 changes a 64 row pattern to 30 rows.
renoise.song().selected_pattern.number_of_lines=8 to 8 rows, which I’ll try to start with.

renoise.song().patterns.tracks.lines:copy_from(other_line object)


[s]Well, I discovered
– Copy all settings from the other instruments, including all samples.
renoise.song().instruments:copy_from(other_instrument object)

so will try and see if I can get a catch on that (other_instrument object) by trying to do my age-old nemesis, the “copy instrument/” “/copy sample to new” with functionalities. This copy_from grep also bleeds to the copying of patterns so I guess I’ll get down to trying to get all three working:)[/s]

Ok, got the doubling to work (this of course ignores over512 doubles ;) )

local old_patternlength = renoise.song().selected_pattern.number_of_lines  
rprint (shouldbe)  

So this does decide that your current pattern is 16 rows and will multiply it by two and set it to 32.

What I really don’t grok is
renoise.song().patterns.tracks.lines:copy_from(other_line object)

Ok, so it’s destructive, I’m fine with that, but “other_line object”, I can’t find any other reference to that in the api


Will destructively copy first pattern contents over the currently selected pattern, check

renoise.song().selected_pattern.number_of_lines = renoise.song().selected_pattern.number_of_lines * 2  

Yes. I didn’t get the copy line to work either. It might have to do with string-formatting. The easiest thing is to check some other tool that you suspect copies lines (split/merge pattern tools for example).

Looked up from the “Pattern split+” tool, example:


This will copy line 2 content to line 1, in current track. Make a loop out of that and you’re done :)

Update for future reference:

 local old_patternlength = renoise.song().selected_pattern.number_of_lines  
 local s=renoise.song()  
 renoise.song().selected_pattern.number_of_lines = old_patternlength*2  
 if old_patternlength >256 then return  
 for track in ipairs(s.selected_pattern.tracks) do  
 if not renoise.song().selected_pattern.tracks[track].is_empty then  
 for line in ipairs(s.selected_pattern.tracks[track].lines) do  
 if line <= old_patternlength then  

What would one do to modify that to also duplicate the automation on all tracks (if there’s automation on all tracks, that is :) )

I believe that is a bit trickier. You would need to iterate thru renoise.song().patterns.tracks.automation.points and use the renoise.song().patterns.tracks.automation:add_point_at in a correct manner. Everything within a track iteration of course.

thanks Joule, i eventually got it working with

function pakettiPatternDoubler()
  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

      -- 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)
        print("No automation found in track", track_index)

    song.selected_line_index = old_patternlength + 1
    print("Pattern doubled successfully.")
    print("New pattern length exceeds 512 lines, operation cancelled.")

function pakettiPatternHalver()
  local s = renoise.song()
  local old_patternlength = s.selected_pattern.number_of_lines
  local resultlength = math.floor(old_patternlength / 2)

  -- Check if the result length is less than 1, which would be invalid
  if resultlength < 1 then
    print("Resulting pattern length is too small, operation cancelled.")

  -- Set the new pattern length
  s.selected_pattern.number_of_lines = resultlength

  -- Adjust automation for each track
  for track_index, track in ipairs(s.selected_pattern.tracks) do
    local track_automations = s.patterns[s.selected_pattern_index].tracks[track_index].automation
    for _, automation in pairs(track_automations) do
      local points = automation.points
      local new_points = {}

      -- Collect new points, scaling down the time values
      for _, point in ipairs(points) do
        local new_time = math.floor((point.time / old_patternlength) * resultlength)
        if new_time >= 1 and new_time <= resultlength then
          table.insert(new_points, {time = new_time, value = point.value})

      -- Clear existing points and add scaled points
      for _, point in ipairs(new_points) do
        automation:add_point_at(point.time, point.value)

-- Add menu entries and keybindings for the tool
renoise.tool():add_menu_entry{name="--Main Menu:Tools:Paketti..:Paketti Pattern Doubler", invoke=pakettiPatternDoubler}
renoise.tool():add_keybinding{name="Pattern Editor:Paketti:Paketti Pattern Doubler", invoke=pakettiPatternDoubler}
renoise.tool():add_keybinding{name="Mixer:Paketti:Paketti Pattern Doubler", invoke=pakettiPatternDoubler}

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