Phrase Iterator - Object ?


(RachmanEnough) #1

Hi,

I’ve just begun digging into the scripting. And I found a pattern iterator object but no phrase iterator. :smashed:

Moreover I’d like to know, how I can print out all members (methods and properties) of an object.

I wrote :

  
  
local newphrase = renoise.song().instruments[6]:insert_phrase_at(1)  
  
--rprint(newphrase)  
  
for key,value in pairs(getmetatable(newphrase)) do  
 print("member:" .. key);  
end  
  
  
  

And what I got was (snippet, cause I cannot copy/paste from the renoise terminal) :

  
  
member: 1  
member: __eq  
member: __call  
member: __concat  
...  
  

I think some properties are missing ? So my question would be, how can I display all (Renoise API)-properties of an object ?

Thanks for the input. :badteeth:


API fun finding 'hidden' code (pattern iterator)
API fun finding 'hidden' code (pattern iterator)
(vV) #2

You can quickly use oprint and rprint in the terminal viewer.

Click to view contents
  
>>> oprint(renoise.song())  
class: Song  
 properties:  
 artist  
 artist_observable  
 comments  
 comments_assignment_observable  
 comments_observable  
 file_name  
 instruments  
 instruments_observable  
 name  
 name_observable  
 pattern_iterator  
 patterns  
 patterns_observable  
 rendering  
 rendering_progress  
 selected_device  
 selected_device_index  
 selected_device_observable  
 selected_effect_column  
 selected_effect_column_index  
 selected_instrument  
 selected_instrument_index  
 selected_instrument_index_observable  
 selected_instrument_observable  
 selected_line  
 selected_line_index  
 selected_note_column  
 selected_note_column_index  
 selected_parameter  
 selected_parameter_index  
 selected_parameter_observable  
 selected_pattern  
 selected_pattern_index  
 selected_pattern_index_observable  
 selected_pattern_observable  
 selected_pattern_track  
 selected_pattern_track_observable  
 selected_phrase  
 selected_phrase_index  
 selected_phrase_observable  
 selected_sample  
 selected_sample_device  
 selected_sample_device_chain  
 selected_sample_device_chain_index  
 selected_sample_device_chain_observable  
 selected_sample_device_index  
 selected_sample_device_observable  
 selected_sample_index  
 selected_sample_modulation_set  
 selected_sample_modulation_set_index  
 selected_sample_modulation_set_observable  
 selected_sample_observable  
 selected_sequence_index  
 selected_sequence_index_observable  
 selected_sub_column_type  
 selected_track  
 selected_track_device  
 selected_track_device_index  
 selected_track_device_observable  
 selected_track_index  
 selected_track_index_observable  
 selected_track_observable  
 selected_track_parameter  
 selected_track_parameter_index  
 selected_track_parameter_observable  
 selection_in_pattern  
 send_track_count  
 sequencer  
 sequencer_track_count  
 tracks  
 tracks_observable  
 transport  
 methods:  
 __STRICT  
 add_track_to_group  
 can_redo  
 can_undo  
 cancel_rendering  
 capture_instrument_from_pattern  
 capture_nearest_instrument_from_pattern  
 clear_midi_mappings  
 delete_group_at  
 delete_instrument_at  
 delete_track_at  
 describe_undo  
 insert_group_at  
 insert_instrument_at  
 insert_track_at  
 instrument  
 load_midi_mappings  
 pattern  
 redo  
 remove_track_from_group  
 render  
 save_midi_mappings  
 select_next_track  
 select_previous_track  
 swap_instruments_at  
 swap_tracks_at  
 track  
 undo  
  

(RachmanEnough) #3

You rock ! :yeah:


(Conner_Bw) #4

Me too.

I need the functional equivalent of

  
iter = renoise.song().pattern_iterator:lines_in_pattern(  
 renoise.song().selected_pattern_index)  
  

But for the phrase editor. What are my options? The Api 3 to 4 post mentions:

  
enoise.song().instruments[].phrases[]:lines_in_range(index_from, index_to)  
 -> [array of renoise.PatternLine objects]  
  

But I don’t need and array of renoise.PatternLine objects, insteadI need an [iterator with pos, line (renoise.PatternTrackLine object)], or are these the same thing?


(Conner_Bw) #5

Never mind, I figured it out.

I just have to use ipairs() on the result and the behaviour I want is the same, Ie.

  
iter = renoise.song().selected_phrase:lines_in_range(1, renoise.song().selected_phrase.number_of_lines)   
for pos,line in ipairs(iter) do  
 -- ...  
  

Good times.


(taktik) #6

The pattern iterators are implemented in Lua, based on the existing C++ wrappers. See below for the implementation, which could be tweaked to support phrases too.

Iter’s pos would be a pos = { phrase, line } table then. There’s no “track” in phrases and “pattern” index should be “phrase” index then.

Click to view contents

–[[--------------------------------------------------------------------------
TestPatternIterators.lua
--------------------------------------------------------------------------]]–

–[[

The following iter functions are the ones that are defined in
Renoise - exactly as provided below. They are copy & pasted for more
finetuning & testing, cause the internal Lua scripts are hard to
change and debug. Once you run this file, you’ll override the internal
versions with the ones specified here…

–]]


– make_note_column_iter

local function make_note_column_iter(song, line_iter, visible_columns_only)
assert(type(line_iter) == ‘function’)
visible_columns_only = visible_columns_only or false

local pos, line = line_iter()

if (pos == nil or line == nil) then
return nil
end

local columns = line.note_columns
local column_count = #columns

if visible_columns_only then
column_count = song.tracks[
pos.track].visible_note_columns
end

– we start by increasing the column
pos.column = 0

return function()
pos.column = pos.column + 1

if (pos.column <= column_count) then
return pos, columns[pos.column]
end

– loop until we found a line with visible columns
while true do
pos, line = line_iter()

if (pos == nil or line == nil) then
return nil
end

columns = line.note_columns
column_count = #columns

if visible_columns_only then
column_count = song.tracks[
pos.track].visible_note_columns
end

if (column_count > 0) then
pos.column = 1
return pos, columns[pos.column]
end
end

return nil
end
end

– make_effect_column_iter

local function make_effect_column_iter(song, line_iter, visible_columns_only)
assert(type(line_iter) == ‘function’)
visible_columns_only = visible_columns_only or false

local pos, line = line_iter()

if (pos == nil or line == nil) then
return nil
end

local columns = line.effect_columns
local column_count = #columns

if visible_columns_only then
column_count = song.tracks[
pos.track].visible_effect_columns
end

– we start by increasing the column
pos.column = 0

return function()
pos.column = pos.column + 1

if (pos.column <= column_count) then
return pos, columns[pos.column]
end

– loop until we found a line with visible columns
while true do
pos, line = line_iter()

if (pos == nil or line == nil) then
return nil
end

columns = line.effect_columns
column_count = #columns

if visible_columns_only then
column_count = song.tracks[
pos.track].visible_effect_columns
end

if (column_count > 0) then
pos.column = 1
return pos, columns[pos.column]
end
end

return nil
end
end


– renoise.PatternIterator:lines_in_song

function renoise.PatternIterator:lines_in_song(visible_patterns_only)
visible_patterns_only = visible_patterns_only or true

local pattern_order = {}
if visible_patterns_only then
local pattern_sequence = self.song.sequencer.pattern_sequence
local referenced_patterns = {}

for seq_index, pattern_index in pairs(pattern_sequence) do
if not referenced_patterns[pattern_index] then
referenced_patterns[pattern_index] = true
pattern_order[#pattern_order + 1] = pattern_index
end
end
else
for pattern_index = 1,#self.song.patterns do
pattern_order[#pattern_order + 1] = pattern_index
end
end

local pattern_order_index = 1
local start_pos = { pattern = pattern_order[1], track = 1, line = 1 }
local pos = { pattern = pattern_order[1], track = 1, line = 1 }

local patterns = self.song.patterns
local pattern = patterns[pos.pattern]
local pattern_tracks = pattern.tracks
local pattern_track = pattern_tracks[pos.track]

– we start by increasing the line
start_pos.line = start_pos.line - 1
pos.line = pos.line - 1

local function line_iter()
pos.line = pos.line + 1

if pos.line > pattern.number_of_lines then
pos.line = 1; pos.track = pos.track + 1

if pos.track > #pattern_tracks then
pos.track = 1; pattern_order_index = pattern_order_index + 1

if pattern_order_index > #pattern_order then
– completed: reset and stop
pattern_order_index = 1
pos.pattern = start_pos.pattern
pos.track = start_pos.track
pos.line = start_pos.line

pattern = patterns[pos.pattern]
pattern_tracks = pattern.tracks
pattern_track = pattern_tracks[pos.track]
return nil

else
– new pattern
pos.pattern = pattern_order[pattern_order_index]

pattern = patterns[pos.pattern]
pattern_tracks = pattern.tracks
pattern_track = pattern_tracks[pos.track]
end

else
– new track
pattern_track = pattern_tracks[pos.track]
end

else
– new line
end

return pos, pattern_track:line(pos.line)
end

return line_iter, self
end

– note_columns_in_song

function renoise.PatternIterator:note_columns_in_song(visible_only)
return make_note_column_iter(self.song, self:lines_in_song(
visible_only), visible_only)
end

– effect_columns_in_song

function renoise.PatternIterator:effect_columns_in_song(visible_only)
return make_effect_column_iter(self.song, self:lines_in_song(
visible_only), visible_only)
end


– renoise.PatternIterator:lines_in_pattern

function renoise.PatternIterator:lines_in_pattern(pattern_index)
assert(type(pattern_index) == ‘number’, ('pattern_index parameter: ’ …
‘expected an index (a number), got a ‘%s’ object’):format(type(pattern_index)))

local start_pos = { pattern = pattern_index, track = 1, line = 1 }
local pos = { pattern = pattern_index, track = 1, line = 1 }

local pattern = self.song.patterns[pos.pattern]
local pattern_tracks = pattern.tracks
local pattern_track = pattern_tracks[pos.track]

– we start by increasing the line
start_pos.line = start_pos.line - 1
pos.line = pos.line - 1

local function line_iter()
pos.line = pos.line + 1

if pos.line > pattern.number_of_lines then
pos.line = 1; pos.track = pos.track + 1

if pos.track > #pattern_tracks then
– completed: reset and stop
pos.track = start_pos.track
pos.line = start_pos.line

pattern_track = pattern_tracks[pos.track]
return nil

else
– new track
pattern_track = pattern_tracks[pos.track]
end

else
– new line
end

return pos, pattern_track:line(pos.line)
end

return line_iter, self
end

– note_columns_in_pattern

function renoise.PatternIterator:note_columns_in_pattern(pattern_index, visible_only)
return make_note_column_iter(self.song, self:lines_in_pattern(
pattern_index), visible_only)
end

– effect_columns_in_pattern

function renoise.PatternIterator:effect_columns_in_pattern(pattern_index, visible_only)
return make_effect_column_iter(self.song, self:lines_in_pattern(
pattern_index), visible_only)
end


– renoise.PatternIterator:lines_in_track

function renoise.PatternIterator:lines_in_track(track_index, visible_patterns_only)
assert(type(track_index) == ‘number’, ('track_index parameter: ’ …
‘expected an index (a number), got a ‘%s’ object’):format(type(track_index)))

visible_patterns_only = visible_patterns_only or true

local pattern_order = {}
if visible_patterns_only then
local pattern_sequence = self.song.sequencer.pattern_sequence
local referenced_patterns = {}

for seq_index, pattern_index in pairs(pattern_sequence) do
if not referenced_patterns[pattern_index] then
referenced_patterns[pattern_index] = true
pattern_order[#pattern_order + 1] = pattern_index
end
end
else
for pattern_index = 1,#self.song.patterns do
pattern_order[#pattern_order + 1] = pattern_index
end
end

local pattern_order_index = 1
local start_pos = { pattern = pattern_order[1], track = track_index, line = 1 }
local pos = { pattern = pattern_order[1], track = track_index, line = 1 }

local patterns = self.song.patterns
local pattern = patterns[pos.pattern]
local pattern_tracks = pattern.tracks
local pattern_track = pattern_tracks[pos.track]

– we start by increasing the line
start_pos.line = start_pos.line - 1
pos.line = pos.line - 1

local function line_iter()
pos.line = pos.line + 1

if pos.line > pattern.number_of_lines then
pos.line = 1; pattern_order_index = pattern_order_index + 1

if pattern_order_index > #pattern_order then
– completed: reset and stop
pattern_order_index = 1
pos.pattern = start_pos.pattern
pos.line = start_pos.line

pattern = patterns[pos.pattern]
pattern_tracks = pattern.tracks
pattern_track = pattern_tracks[pos.track]
return nil

else
– new pattern
pos.pattern = pattern_order[pattern_order_index]

pattern = patterns[pos.pattern]
pattern_tracks = pattern.tracks
pattern_track = pattern_tracks[pos.track]
end

else
– new line
end

return pos, pattern_track:line(pos.line)
end

return line_iter, self
end

– note_columns_in_track

function renoise.PatternIterator:note_columns_in_track(track_index, visible_only)
return make_note_column_iter(self.song, self:lines_in_track(
track_index, visible_only), visible_only)
end

– effect_columns_in_track

function renoise.PatternIterator:effect_columns_in_track(track_index, visible_only)
return make_effect_column_iter(self.song, self:lines_in_track(
track_index, visible_only), visible_only)
end


– renoise.PatternIterator:lines_in_pattern_track

function renoise.PatternIterator:lines_in_pattern_track(pattern_index, track_index)
assert(type(pattern_index) == ‘number’, ('pattern_index parameter: ’ …
‘expected an index (a number), got a ‘%s’ object’):format(type(pattern_index)))
assert(type(track_index) == ‘number’, ('track_index parameter: ’ …
‘expected an index (a number), got a ‘%s’ object’):format(type(track_index)))

local start_pos = { pattern = pattern_index, track = track_index, line = 1 }
local pos = { pattern = pattern_index, track = track_index, line = 1 }

local pattern = self.song.patterns[pos.pattern]
local pattern_tracks = pattern.tracks
local pattern_track = pattern_tracks[pos.track]

– we start by increasing the line
start_pos.line = start_pos.line - 1
pos.line = pos.line - 1

local function line_iter()
pos.line = pos.line + 1

if pos.line > pattern.number_of_lines then
– completed: reset and stop
pos.line = start_pos.line
return nil

else
– new line
end

return pos, pattern_track:line(pos.line)
end

return line_iter, self
end

– note_columns_in_pattern_track

function renoise.PatternIterator:note_columns_in_pattern_track(
pattern_index, track_index, visible_only)
return make_note_column_iter(self.song, self:lines_in_pattern_track(
pattern_index, track_index), visible_only)
end

– effect_columns_in_pattern_track

function renoise.PatternIterator:effect_columns_in_pattern_track(
pattern_index, track_index, visible_only)
return make_effect_column_iter(self.song, self:lines_in_pattern_track(
pattern_index, track_index), visible_only)
end

–[[--------------------------------------------------------------------------
--------------------------------------------------------------------------]]–

Also no need to use ‘lines_in_range’ here, so this can be simplified to:

  
for index,line in pairs(renoise.song().selected_phrase.lines) do  
 print(index, line)  
end