Jump to content


Photo

Lua: Renoise.song().tracks[].members[].track_Index


  • Please log in to reply
7 replies to this topic

#1 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1815 posts
  • Gender:Not Telling

Posted 12 December 2011 - 16:55

There seems to be no way to get what track indexes are part of a group, the same way track index in .group_parent is not available.

These issues could perhaps both be resolved by adding:

[lua]renoise.song().tracks[]....track_index[/lua]

(Unless I'm missing some fundamental lua trick)

EDIT: Perhaps another option would be to add a renoise.song().groups[] structure. That approach may be beneficial coding wise in many cases.

Edited by joule, 12 December 2011 - 17:08.


#2 eeter

eeter

    Guruh Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPip
  • 807 posts
  • Gender:Male
  • Location:Estonia, Jõgeva
  • Interests:Renoise, music, party, psychedelics, beer(<3!!!), travelling.

Posted 12 December 2011 - 17:24

yes, and also the track[].group_parent should return nil when the track has ran away from it's parents.

#3 Cas

Cas

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1719 posts
  • Gender:Male

Posted 02 June 2012 - 10:51

There seems to be no way to get what track indexes are part of a group, the same way track index in .group_parent is not available.

These issues could perhaps both be resolved by adding:

[lua]renoise.song().tracks[]....track_index[/lua]

(Unless I'm missing some fundamental lua trick)

EDIT: Perhaps another option would be to add a renoise.song().groups[] structure. That approach may be beneficial coding wise in many cases.


I'm running into the same thing updating my Push Back tool. When the function is called from a group track I will have to
  • iterate over every track to the left of current track (type group)
  • go through it's group_parent, possibly that one's group_parent, etc. routing
to get the track indexes of subtracks (to be able to modify their delay_column data in this case).
With the current state I'm just gonna not complete the v1.0 of the tool, I might code it, but I'm not confident it's gonna run properly on every sys with the turn of a dial you know? :) and it's just double double inefficient code..
I would really like to know if there's a better way.

music: SoundCloud drumkits: WizzKit no. 01 (thread), 02 (thread), 03 (thread), 04
tutorials: Beat Creators, Drum Synthesis examples
tools: download@box, info@blog, fork@git, discuss@forum
___________

BCF2000, LP S, MPK, nPad2, nKtrl2, NI KA6, Vortex, SP-404SX

Renoise, NI Reaktor


#4 taktik

taktik

    Renoise Developer

  • Admins
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 15040 posts
  • Gender:Male
  • Location:Berlin, Germany
  • Interests:füße waschen

Posted 02 June 2012 - 14:07

You can create a small helper function to get the track index, by using "rawequal" to compare a track object with renoise.song().tracks. "rawequal" bypasses the object's comparison operator (which in most cases is not defined anway), and tests object identity instead:

function get_track_index(_track)
  assert(_track, "expected a valid track object")
  for index, track in ipairs(renoise.song().tracks) do
    if (rawequal(track, _track)) then 
      return index
    end
  end
end

-- test
assert(get_track_index(renoise.song().tracks[2]) == 2)
assert(get_track_index(renoise.song().selected_track) == renoise.song().selected_track_index)

---

A sneaky way (just for fun): Classes in the renoise API are not read-only. So one can define new member functions for existing renoise.* classes, or replace existing ones.

One can also wrap a getter/setter function pair to define new properties this way. This is done with the global function "property()":
property(getter, setter) takes a getter and setter (optional) function as parameter. Every time a property gets read, the getter function is called and it's return value will be put on the stack. Every time you assign the property, the setter function is called with the given argument. The first argument of the passed functions will always be "self".

In the example below, this is used to create a new "track_index" property to renoise.Track and GroupTrack. Because only a getter is present, assignment is disallowed too and will fire an error, which is exactly what we want.

-- Inject a new property "track_index" into the renoise.[Group]Track class.
-- Define this as early as possible in your script to make the property
-- as early as possible available. Once it's defined, the property will be 
-- available for every existing and new object of type "renoise.[Group]Track",
-- so you don't have to define this for every new track that gets created 
-- within Renoise.
local track_index_property = property(function(self)
  for index, track in ipairs(renoise.song().tracks) do
    if (rawequal(self, track)) then 
      return index
    end
  end
end)
-- and apply it to all track classes in the API
renoise.Track.track_index = track_index_property 
renoise.GroupTrack.track_index = track_index_property 

-- test
assert(renoise.song().tracks[6].track_index, 6)
assert(renoise.song().selected_track.track_index, renoise.song().selected_track_index)

-- assignment is not allowed (track_index is read-only)
assert(pcall(function() renoise.song().tracks[2].track_index = 23 end) == false) 

---

Same thing could be done to create a "member_index" for tracks in groups of whatever else you need.


---

Oh and all this of course is not a lame excuse. track_index should be available by default in the API.
  • Djeroek, Frank Baumgartner and Cas like this

#5 Cas

Cas

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1719 posts
  • Gender:Male

Posted 02 June 2012 - 22:03

On the contrary, this is a crazy cool workaround and learning something too :D thx
  • Frank Baumgartner likes this

music: SoundCloud drumkits: WizzKit no. 01 (thread), 02 (thread), 03 (thread), 04
tutorials: Beat Creators, Drum Synthesis examples
tools: download@box, info@blog, fork@git, discuss@forum
___________

BCF2000, LP S, MPK, nPad2, nKtrl2, NI KA6, Vortex, SP-404SX

Renoise, NI Reaktor


#6 Frank Baumgartner

Frank Baumgartner

    Member

  • Normal Members
  • PipPip
  • 37 posts
  • Gender:Male
  • Location:Innsbruck, Austria
  • Interests:MUSIC ;-)

Posted 17 March 2014 - 17:36

Awesome !!

#7 re.dread

re.dread

    Advanced Member

  • Normal Members
  • PipPipPip
  • 97 posts

Posted 19 March 2014 - 14:02

I can't help myself but wonder, is there a way to actually attach a new property with both read and write support?
Simply doing:

renoise.NoteColumn.quantize_value = 0
.. works, but the value is read-only.

local quantize_value_property = 
      property(function(self) return self.quantize_value end,
               function(self, set) self.quantize_value = set end)
   
renoise.NoteColumn.quantize_value = quantize_value_property
.. doesn't work. it gives a
*** TestPad.lua:12: C stack overflow
error ..

what does work is:
local value = 0
local quantize_value_property = 
      property(function(self) return value end,
               function(self, set) value = set end)
   
renoise.NoteColumn.quantize_value = quantize_value_property
.. but it doesn't really make any sense, because the property is not unique for each NoteColumn then.

also tried:
local values = {}
local quantize_value_property = 
      property(function(self) return values[self] end,
               function(self, set) values[self] = set end)
   
renoise.NoteColumn.quantize_value = quantize_value_property
but that gives me:
*** TestPad.lua:18: unknown property or function 'quantize_value'. can not assign new properties to an object of type 'NoteColumn'

I know it's quite a hack, but would be nice to get it working :)/>

#8 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1815 posts
  • Gender:Not Telling

Posted 04 June 2018 - 13:16

I know it's quite a hack, but would be nice to get it working smile.gif/>

 

Late reply, but I wanted to mention that this should be possible if you 'cache' your objects, which might seem slightly impractical but totally doable. If you don't cache them, calls like :line() or .lines[] are technically returning new objects everytime (afaik).

An example that seems to work:
 

renoise.NoteColumn.MY_DEFAULT_VALUE = 10
renoise.NoteColumn._my_value = renoise.NoteColumn.MY_DEFAULT_VALUE

local my_property = property(
  function(self) return self._my_value end,
  function(self, val) self._my_value = val end
)

renoise.NoteColumn.my_property = my_property

-- Testing

local ncol_1 = renoise.song():pattern(1):track(1):line(1):note_column(1)
local ncol_2 = renoise.song():pattern(1):track(1):line(1):note_column(2)

print(ncol_1.my_property)
print(ncol_2.my_property) -- should print 10

ncol_1.my_property = 50
ncol_2.my_property = 30

print(ncol_1.my_property)
print(ncol_2.my_property)

This is kind of a pandoras box ;) You could, for example, make custom getters/setters and observables that will bang due to very specific changes to song data (when edited from a tool).


Edited by joule, 04 June 2018 - 13:35.