Storing a pattern data for later use

I’m trying to work out the best way to store some line data from a pattern track and then write it back at a later stage…

For example if I run the following code:

  
line = renoise.song().patterns[1].tracks[1]:line(1)  
print (line)  
  

I get this output:

  
C-400...... | ---........ | ---........ | ---........ | ---........ | ---........ | ---........ | ---........ | ---........ | ---........ | ---........ | ---........ | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000  
  

Which is all the data from that particular track that I want, however the ‘line’ variable is only pointing to that particular line so if I clear the track then I lose the data in ‘line’. I can get around this by doing

  
line = tostring( renoise.song().patterns[1].tracks[1]:line(1) )  
  

Which works, so I then have the data stored in a string, but now I cannot find a quick way to write this data back to the track at a later stage. The only way I can think of is to iterate over each note and effect column and write the data back from the string variable I have stored it in, this seems a slow way do it.

Another way I can think of is to copy the track into a temporary pattern and then use

renoise.song().patterns[].tracks[]:copy_from(other_pattern_track object)  

when I need to retrieve line data, maybe this is quicker?

However both these methods seem a bit clunky to me. Does anyone know a better way to achieve this?

Thanks

Use table.copy or table.rcopy to copy the contents of the table to a new one, rather than point at the existing table.

From LUA.Standard.API.lua:

Thanks, I tried that but got the following error: 

  ```

*** [string “-- create or convert a table to an object t…”]:93: bad argument #1 to ‘table.copy’ (table expected, got ‘PatternTrackLine’)
*** stack traceback:
*** [C]: in function ‘assert’
*** [string “-- create or convert a table to an object t…”]:93: in function ‘copy’
*** testlib.lua:66: in main chunk

  
</div></div>

OK, seems it is a PatternTrackLine object, not a table as such. Sure with these types of Renoise defined objects using var = object actually copies the object, not just points to it like it does with a table. If you use var = renoise.song().patterns[1].tracks[1]:line(1) and then edit line 1 and after print var does it really print the changed value?

(Sorry can’t be done in the TestPad and not got the time to try and set up a quick test tool right now… Especially with how much my GUI skills suck!!)

Yep it prints the changed value, if I run this code:

  
line = renoise.song().patterns[1].tracks[1]:line(1)  
renoise.song().patterns[1].tracks[1]:clear()  
print (line)  
  

I get an output of a blank pattern line, doing these steps in the terminal gives the same results, the variable always points to what is currently in the line so it seems it only references.

com.renoise.PatternRotate.xrnx does something like this, by hackily copying all properties of a line manually into a standard table:
See https://code.google.com/p/xrnx/source/browse/trunk/Tools/com.renoise.PatternRotate.xrnx/pattern_line_tools.lua

  
--------------------------------------------------------------------------------  
  
-- copy all effect column properties from src to dest column  
  
local effect_column_properties = {  
 "number_value",  
 "amount_value",  
}  
  
function copy_effect_column(src_column, dest_column)  
 for _,property in pairs(effect_column_properties) do  
 dest_column[property] = src_column[property]  
 end  
end  
  
  
--------------------------------------------------------------------------------  
  
-- copy all note column properties from src to dest column  
  
local note_column_properties = {  
 "note_value",  
 "instrument_value",  
 "volume_value",  
 "panning_value",  
 "delay_value",  
}  
  
function copy_note_column(src_column, dest_column)  
 for _,property in pairs(note_column_properties) do  
 dest_column[property] = src_column[property]  
 end  
end  
  
  
--------------------------------------------------------------------------------  
  
-- creates a copy of the given patternline  
  
function copy_line(src_line, dest_line)  
  
 for index,src_column in pairs(src_line.note_columns) do  
 if (not dest_line.note_columns[index]) then  
 dest_line.note_columns[index] = {}  
 end  
  
 local dest_column = dest_line.note_columns[index]  
 copy_note_column(src_column, dest_column)  
 end  
  
 for index,src_column in pairs(src_line.effect_columns) do  
 if (not dest_line.effect_columns[index]) then  
 dest_line.effect_columns[index] = {}  
 end  
  
 local dest_column = dest_line.effect_columns[index]  
 copy_effect_column(src_column, dest_column)  
 end  
end  
  
  
--------------------------------------------------------------------------------  
  
--- test  
  
local src_line = renoise.song().selected_line  
local temp_line = { note_columns = {}, effect_columns = {} }  
  
copy_line(src_line, temp_line) -- create copy  
src_line:clear() -- modify line  
copy_line(temp_line, src_line) -- restore line from copy  
  

Thanks taktik

That’s very useful, although completely different to the approach I have taken!

I have come up with this:

  
  
-- Function to copy track line data  
local function copy_line(pattern, track, line)  
 return tostring ( renoise.song().patterns[pattern].tracks[track]:line(line) )  
end  
  
  
-- Function to write track line data  
local function write_line(source, pattern, track, line)   
 -- Write note values  
 for n = 0, 11 do  
 local s = n*14+1  
 local note = renoise.song().patterns[pattern].tracks[track].lines[line].note_columns[n+1]  
 note.note_string = string.sub(source, s, s+2)  
 note.instrument_string = string.sub(source, s+3, s+4)  
 note.volume_string = string.sub(source, s+5, s+6)  
 note.panning_string = string.sub(source, s+7, s+8)  
 note.delay_string = string.sub(source, s+9, s+10)  
 end  
 -- Write effect values  
 for n = 0, 7 do  
 local s = n*7+169  
 local efx = renoise.song().patterns[pattern].tracks[track].lines[line].effect_columns[n+1]  
 efx.number_string = string.sub(source, s, s+1)  
 efx.amount_string = string.sub(source, s+2, s+3)   
 end   
end  
  
  
-- Call it   
write_line(copy_line(1,1,1), 1, 1, 33)  
  

I want this to happen in realtime so I wonder which approach executes faster?

I took the following approach in the Clip Composing Language, which is similar to taktiks.
I would guess, my method is slightly faster than taktiks, as I don’t use string-indices for
the lua tables. But I can imagine, as you are using fixed string offsets, that your string
method is maybe even faster. But you can’t be sure without benchmarking yourself :slight_smile:

  
class "CclLine"  
  
function CclLine:__init (trackidx)  
 self.track = trackidx  
 self.nc = { } -- note columns  
 self.xc = { } -- fx columns  
 self.atm = { } -- automation data  
end  
  
function CclLine:from_line (line)  
 for i, c in ipairs (line.note_columns) do  
 if (not c.is_empty) then  
 self.nc[i] = {  
 c.note_value, c.instrument_value, c.volume_value,  
 c.panning_value, c.delay_value  
 }  
 end  
 end  
 for i, c in ipairs (line.effect_columns) do  
 if ((not c.is_empty) and c.number_string:sub (1, 1) ~= "Y") then  
 self.xc[i] = { c.number_value, c.amount_value }  
 end  
 end  
end  
  
function CclLine:write (line_idx, pattern, pattern_line)  
 pattern_line:clear ()  
  
 for i, v in pairs (self.nc) do  
 local nc = pattern_line:note_column(i)  
 nc.note_value = v[1]  
 nc.instrument_value = v[2]  
 nc.volume_value = v[3]  
 nc.panning_value = v[4]  
 nc.delay_value = v[5]  
 end  
  
 for i, v in pairs (self.xc) do  
 local xc = pattern_line:effect_column(i)  
 xc.number_value = v[1]  
 xc.amount_value = v[2]  
 end  
  
 -- snip --  
end  
  

(Full code can be found at http://ist.m8geil.de/hg/com.elmex.ClipComposingLanguage.xrnx.hg/file/tip/ccl_line.lua )