Custom renoise.values example

Here is a simple principle that can be used for storing custom values inside renoise objects, if your tool needs it. Using the Document API, the values will also be observable, just like most other data accessible in the Song API.

Click to view contents
-- Some preparation. Could be set to anything for now,
-- but showing object type just for clarity
--
renoise.Track.creation_time_observable = renoise.Document.ObservableNumber
-- 'Wrapping' the above into a class property like anything else,
-- making it visible via oprint() and easily accessible.
--
renoise.Track.creation_time = property(
  function(obj)
    return obj.creation_time_observable.value
  end,
  function(obj, val)
    assert(tonumber(val), "Expected a number")
    obj.creation_time_observable.value = val
  end
)
-- Our custom track list. Without this, the custom property values would not be
-- remembered, since normal renoise.song():track() access always creates new 'objects'.
-- Moral: Use this table instead of normal tracks if you want to store and
-- access your custom values!
--
current_tracks = table.create()
-- Initialize value(s) whenever a track is inserted
--
function init_track(index)
  current_tracks[index].creation_time_observable = renoise.Document.ObservableNumber(os.clock())
end
-- Initialize the internal tracklist
--
function init_internal_tracklist()
  for track_idx, track in ipairs(renoise.song().tracks) do
    current_tracks:insert(track_idx, track)
    init_track(track_idx)
  end
end
-- Notifier function to keep the internal tracklist in sync with song.tracks
--
function event_tracks_changed(event)
  if event.type == "swap" then
    current_tracks[event.index1], current_tracks[event.index2] =
    current_tracks[event.index2], current_tracks[event.index1]
  elseif event.type == "remove" then
    current_tracks:remove(event.index)
  elseif event.type == "insert" then
    local track = renoise.song():track(event.index)
    current_tracks:insert(event.index, track)
    init_track(event.index)
  end
  
  -- JUST TESTING (look at the console). Remove this later...
  for track_idx, track in ipairs(current_tracks) do
    print(string.format(
      "Track %.2d was created %.2f seconds ago", track_idx, os.clock()-track.creation_time
    ))
  end
  
end
-- Start it all
--
function main()
  init_internal_tracklist()
  renoise.song().tracks_observable:add_notifier(event_tracks_changed)
end
main()

NB1. Doing this per note_column would be more complex, but for something like patterns, tracks or instruments it works really well. These lists are more easy to ‘mirror’.
NB2. Do note that it’s probably not something you want to do per note_column anyway, as custom properties creates some slight extra overhaul (probably due to native __index metatable stuff)
NB3. It’s per session only. Any persistent storage would require something like xml dumping or song comment abuse.

Thanks!

NP. Here is an alternative approach (simplified example) if you don’t want to affect the global class, but only the particular object(s).

local track = renoise.song():track(1)
track.__STRICT = function() return false end
track.my_prop = 10
print(track.my_prop)

NP. Here is an alternative approach (simplified example) if you don’t want to affect the global class, but only the particular object(s).

local track = renoise.song():track(1)
track.__STRICT = function() return false end
track.my_prop = 10
print(track.my_prop)

So here you are replacing __STRICT in the new object instance?

From just seeing [4Teys post](https://forum.renoise.com/t/how-to-test-if-variable-is-already-declared/48640) here, its there to catch undeclared variables. Did you find any consequences/ or things to watch out for with this, since that thread?

Did you find any consequences/ or things to watch out for with this, since that thread?

Not that I know of. AFAIK, it’s only a matter of the __newindex metatable checking if __STRICT is true or not.

I’m sure it’s sacrilege to suggest, but has anyone thought of making videos that walk the new guys through the basics of the Renoise APIs in congruence with Lua?

I’m sure it’s sacrilege to suggest, but has anyone thought of making videos that walk the new guys through the basics of the Renoise APIs in congruence with Lua?

I came to think about it, but it’s a lot of work. There are not many people interested either. If there were 30 people requesting it, maybe there would be videos…

I mean … Out of all the people on this forum (assuming that number to be well above 300), there’s gotta be at least 30 people who wouldn’t mind learning this if they knew the tutorials existed

maybe? :unsure: :unsure: :unsure: :unsure: :unsure: :unsure:

I mean … Out of all the people on this forum (assuming that number to be well above 300), there’s gotta be at least 30 people who wouldn’t mind learning this if they knew the tutorials existed

maybe? :unsure: :unsure: :unsure: :unsure: :unsure: :unsure:

I think you’re being very optimistic :lol:.

I came to think about it, but it’s a lot of work. There are not many people interested either. If there were 30 people requesting it, maybe there would be videos…

I’d be interested, but I’m more interested in concrete written examples. As in these posts.

Given something one can cut-n-paste into the developer console, people can see for themselves how it works, and then tweak things to see if they understand what’s going on.

For example, I was curious about the track.__STRICT thing. My guess was that it was needed in order to allow the addition of custom properties.

So I tried an experiement in the console.

First:

local _song = renoise.song()
_song.versioned = false
print("Is has this song been versions? " , _song.versioned )

This raises an exception about “versioned”

Then

local _song = renoise.song()
_song.__STRICT = function() return false end
_song.versioned = false
print("Is has this song been versions? " , _song.versioned )

This works, thanks to the override of __STRICT

And so I learned.

Question: Is __STRICT built-in to Lua, or is this something coded into Renoise classes to prevent accidentally creating/assigning new properties?

Afaik it’s just a function that’s checked in the __newindex metamethod of the objects. If the metamethod is put there by luabind/some_library or by taktik I don’t know, but I think luabind.