Transferring notation from pattern to phrase automatically using LUA?

I’m trying to create a keyboard shortcut that would let me take a currently selected set of notes, copy them to clipboard, create a phrase of that selection length, paste the content in, and write the instrument phrase onto the pattern editor. how would i go about copying from the pattern editor to the phrase editor and setting the phrase editor length to be that?

1 Like

You can look at these functions that I write several months ago. I would probably write it differently now, but here we understand how to translate data between patterns and phrases:

-------------------------------------------------------------------------------------------------
--pattern & phrase export
function pht_patterns_track_to_phrases()
  local x = os.clock()
  local ssi = song.selected_sequence_index
  --sequence range selection
  local value_a = song.sequencer.selection_range[1]
  local value_b = song.sequencer.selection_range[2]
  local phra = #song.selected_instrument.phrases
  --print( "value_a:",value_a,"value_b:",value_b )
  local value_c = value_b - value_a
  local str = song.selected_track
  if ( #song.instruments <= 255 ) and ( value_a > 0 ) and ( value_c + phra <= 126 ) and ( str.type == renoise.Track.TRACK_TYPE_SEQUENCER ) then
    --locals for pattern properties
    local pt_vnc = str.visible_note_columns
    local pt_vec = str.visible_effect_columns
    local pt_vcv = str.volume_column_visible
    local pt_pcv = str.panning_column_visible
    local pt_dcv = str.delay_column_visible
    local pt_ecv = str.sample_effects_column_visible
    --select phrase editor
    local phrase_editor = renoise.ApplicationWindow.MIDDLE_FRAME_INSTRUMENT_PHRASE_EDITOR
    if ( rna.window.active_middle_frame ~= phrase_editor  ) then
      rna.window.active_middle_frame = phrase_editor
    end
    --iterate the range (1 until 126 phrases)
    local phri = phra + 1
    local pt_nol
    for i = 0, value_c do
      local idx = i + phri
      song.selected_sequence_index = value_a + i
      if ( PHT_PHRASES_NOL.value == 0 ) then
        pt_nol = song.selected_pattern.number_of_lines
      else
        pt_nol = PHT_PHRASES_NOL.value
      end
      --insert new phrase & clear first each phrase
      song.selected_instrument:insert_phrase_at( idx )
      song.selected_phrase_index = idx
      song.selected_phrase:clear()

      --phrases equal pattern-tracks
      local sph = song.selected_instrument:phrase( idx )
      local pt_tr = song.selected_pattern_track
      sph.number_of_lines = pt_nol
      sph.visible_note_columns = pt_vnc
      sph.visible_effect_columns = pt_vec

      sph.volume_column_visible = pt_vcv
      sph.panning_column_visible = pt_pcv
      sph.delay_column_visible = pt_dcv
      sph.sample_effects_column_visible = pt_ecv
      --lines
      for ln = 1, pt_nol do
        local ph_ln = sph:line( ln )
        local pt_ln = pt_tr:line( ln )
        if not ( pt_ln.is_empty ) then
          --for note columns
          for nc = 1, 12 do
            local pt_nc = pt_ln:note_column( nc )
            local ph_nc = ph_ln:note_column( nc )
            if not ( pt_nc.is_empty ) then
              ph_nc.note_value          = pt_nc.note_value
              ph_nc.volume_value        = pt_nc.volume_value
              ph_nc.panning_value       = pt_nc.panning_value
              ph_nc.delay_value         = pt_nc.delay_value
              ph_nc.effect_number_value = pt_nc.effect_number_value
              ph_nc.effect_amount_value = pt_nc.effect_amount_value
            end
          end
          --for effect columns
          for ec = 1, 8 do
            local pt_ec = pt_ln:effect_column( ec )
            local ph_ec = ph_ln:effect_column( ec )
            if not ( pt_ec.is_empty ) then
              ph_ec.number_value = pt_ec.number_value
              ph_ec.amount_value = pt_ec.amount_value
            end
          end
        end
      end
    end
    song.selected_sequence_index = value_b
    song.selected_phrase_index = 1
    song.selected_instrument.phrase_playback_mode = renoise.Instrument.PHRASES_PLAY_KEYMAP
    show_tool_dialog()
    local val_c = value_c + 1
    pht_change_status( "All the patterns-track "..("(%.3d)"):format( val_c ).." of sequence range are exported into "..("%.2X (%.3d)"):format( val_c, val_c ).." phrases of selected instrument." )
  end
  if ( value_a == 0 ) then
    song.selected_sequence_index = ssi
    pht_pattern_track_to_phrase()
  end
  if ( value_c + phra > 126 ) then
    pht_change_status( "Impossible export. Select first a sequence range (until "..("%s"):format( 126 - #song.selected_instrument.phrases )..") and a track or select another instrument!" )
  end
  if ( str.type ~= renoise.Track.TRACK_TYPE_SEQUENCER ) then
    pht_change_status( "Impossible export. Select first a track!" )
  end
  --print( string.format("elapsed time: %.4f ms", ( os.clock() - x ) * 1000) )
end



---
function pht_pattern_track_to_phrase()
  local pattern = song:pattern( song.selected_pattern_index )
  local pt_nol
  if ( PHT_PHRASES_NOL.value == 0 ) then
    pt_nol = pattern.number_of_lines
  else
    pt_nol = PHT_PHRASES_NOL.value
  end
  local str = song.selected_track
  local pt_vnc = str.visible_note_columns
  local pt_vec = str.visible_effect_columns

  local pt_vcv = str.volume_column_visible
  local pt_pcv = str.panning_column_visible
  local pt_dcv = str.delay_column_visible
  local pt_ecv = str.sample_effects_column_visible
  --if not phrase, create a phrase and select it
  if ( song.selected_phrase == nil ) then
    song.selected_instrument:insert_phrase_at( 1 )
    song.selected_phrase_index = 1
  end
  song.selected_phrase:clear()
  --show phrase editor and duplicate pattern-track to phrase
  if ( str.type == renoise.Track.TRACK_TYPE_SEQUENCER ) then
    local phrase_editor = renoise.ApplicationWindow.MIDDLE_FRAME_INSTRUMENT_PHRASE_EDITOR
    if ( rna.window.active_middle_frame ~= phrase_editor ) then
      rna.window.active_middle_frame = phrase_editor
    end
    local sph = song.selected_phrase
    local spt = song.selected_pattern_track
    sph.number_of_lines = pt_nol
    sph.visible_note_columns = pt_vnc
    sph.visible_effect_columns = pt_vec
    
    sph.volume_column_visible = pt_vcv
    sph.panning_column_visible = pt_pcv
    sph.delay_column_visible = pt_dcv
    sph.sample_effects_column_visible = pt_ecv
    
    for ln = 1, pt_nol do
      local ph_ln = sph:line( ln )
      local pt_ln = spt:line( ln )
      if not ( pt_ln.is_empty ) then
        --for note columns
        for nc = 1, 12 do
          local pt_nc = pt_ln:note_column( nc )
          local ph_nc = ph_ln:note_column( nc )
          if not ( pt_nc.is_empty ) then
            ph_nc.note_value          = pt_nc.note_value
            ph_nc.volume_value        = pt_nc.volume_value
            ph_nc.panning_value       = pt_nc.panning_value
            ph_nc.delay_value         = pt_nc.delay_value
            ph_nc.effect_number_value = pt_nc.effect_number_value
            ph_nc.effect_amount_value = pt_nc.effect_amount_value
          end
        end
      end
      --for effect columns
      for ec = 1, 8 do
        local pt_ec = pt_ln:effect_column( ec )
        local ph_ec = ph_ln:effect_column( ec )
        if not ( pt_ec.is_empty ) then
          ph_ec.number_value = pt_ec.number_value
          ph_ec.amount_value = pt_ec.amount_value
        end
      end
    end
  end
  song.selected_instrument.phrase_playback_mode = renoise.Instrument.PHRASES_PLAY_KEYMAP
  show_tool_dialog()
  local sphi = song.selected_phrase_index
  pht_change_status( "Selected pattern-track exported in the selected phrase "..("%.2X (%.3d)"):format( sphi, sphi ).."." )
end



---
function pht_phrase_to_pattern_track()
  local str = song.selected_track
  local sph = song.selected_phrase
  if sph == nil then
    rna.window.active_middle_frame = renoise.ApplicationWindow.MIDDLE_FRAME_INSTRUMENT_PHRASE_EDITOR
    pht_change_status( "The export operation is not possible. Create a phrase first or select an existing!" )
    return
  else
    local ph_nol = sph.number_of_lines
    local ph_vnc = sph.visible_note_columns
    local ph_vec = sph.visible_effect_columns
  
    local ph_vcv = sph.volume_column_visible
    local ph_pcv = sph.panning_column_visible
    local ph_dcv = sph.delay_column_visible
    local ph_ecv = sph.sample_effects_column_visible  
    if ( str.type == renoise.Track.TRACK_TYPE_SEQUENCER ) then
      rna.window.active_middle_frame = renoise.ApplicationWindow.MIDDLE_FRAME_PATTERN_EDITOR

      song.selected_pattern.number_of_lines = ph_nol
      str.visible_note_columns   = ph_vnc
      str.visible_effect_columns = ph_vec
      
      str.volume_column_visible  = ph_vcv
      str.panning_column_visible = ph_pcv
      str.delay_column_visible   = ph_dcv
      str.sample_effects_column_visible = ph_ecv

      local in_ph = song.selected_phrase
      local pt_tr = song.selected_pattern_track

      for ln = 1, ph_nol do
        local ph_ln = in_ph:line( ln )
        local pt_ln = pt_tr:line( ln )
        --for note columns
        for nc = 1, 12 do
          local pt_nc = pt_ln:note_column( nc )
          local ph_nc = ph_ln:note_column( nc )
          if not ph_nc.is_empty then
            pt_nc.note_value          = ph_nc.note_value
            if ( pt_nc.note_value < 120 ) then
              pt_nc.instrument_value  = song.selected_instrument_index - 1
            end
            pt_nc.volume_value        = ph_nc.volume_value
            pt_nc.panning_value       = ph_nc.panning_value
            pt_nc.delay_value         = ph_nc.delay_value
            pt_nc.effect_number_value = ph_nc.effect_number_value
            pt_nc.effect_amount_value = ph_nc.effect_amount_value
          end
        end
        --for effect columns
        for ec = 1, 8 do
          local pt_ec = pt_ln:effect_column( ec )
          local ph_ec = ph_ln:effect_column( ec )
          if not ph_ec.is_empty then
            pt_ec.number_value = ph_ec.number_value
            pt_ec.amount_value = ph_ec.amount_value
          end
        end
      end
    end
  end
  local sphi = song.selected_phrase_index
  local spi = song.selected_pattern_index -1
  local sti = song.selected_track_index
  pht_change_status( "Selected phrase "..("%.2X (%.3d)"):format( sphi, sphi ).." exported in the selected pattern-track "..("(pattern: %.3d - track: %.3d)"):format( spi, sti ).."." )
end

You can define the range of lines of the selection before: end_line - start_line

-- Read/write access to the selection in the pattern editor.
-- The property is a table with the following members:
--
--  {
--    start_line,     -- Start pattern line index
--    start_track,    -- Start track index
--    start_column,   -- Start column index within start_track   
-- 
--    end_line,       -- End pattern line index
--    end_track,      -- End track index
--    end_column      -- End column index within end_track
--  }
--
-- Line indexes are valid from 1 to renoise.song().patterns[].number_of_lines
--
-- Track indexes are valid from 1 to #renoise.song().tracks
--
-- Column indexes are valid from 1 to 
--   (renoise.song().tracks[].visible_note_columns +
--    renoise.song().tracks[].visible_effect_columns)
--
-- When setting the selection, all members are optional. Combining them in 
-- various different ways will affect how specific the selection is. When 
-- 'selection_in_pattern' returns nil or is set to nil, no selection is present.
--
-- Examples: 
-- renoise.song().selection_in_pattern = {} 
--   --> clear
-- renoise.song().selection_in_pattern = { start_line = 1, end_line = 4 } 
--   --> select line 1 to 4, first to last track
-- renoise.song().selection_in_pattern = 
--   { start_line = 1, start_track = 1, end_line = 4, end_track = 1 } 
--   --> select line 1 to 4, in the first track only 
--
renoise.song().selection_in_pattern
  -> [table of start/end values or nil]

much appreciated, raul :slight_smile: will give it a whirl! have a good rest of the weekend!

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