I would like to build a horizontal bar with a timeline marker for the song.I think I would be able to build a reasonable GUI. But I need some way to calculate the time in seconds at all duration of the song.Some notions that I have thought to do this.
Basically, the song consists of patterns in sequence, from 1 to 1000. Each pattern is formed by a certain number of lines, from 1 to 512.
The minimum of a song is a pattern with a single line. The maximum would be 512 lines x 1000 patterns
The time of song depends on the BPM (beats per minute) and LPB (lines per beat) settings. EDIT: and the parameters ZT ZL!!!
My doubts are to construct a mathematical code that sums the linesof the whole song in each moment to get the real time of the song.Can anyone think of a code that can do that?I think the sum in seconds would be enough. Subsequently, it can be converted to minutes and seconds. If the user includes or deletes a single line (line or pattern (group of lines)), the mathematical code would recalculate the final figure in seconds.
It would be possible to use a timer to detect any line / pattern changes (not to be confused with the time calculation of the song, which is something else).
Any ideas for the mathematical code?
Some API data:
#renoise.song().sequencer.pattern_sequence
renoise.song().patterns[].number_of_lines
… number_of_lines_in_pattern ???
renoise.song().transport.bpm(beats per minute, a minute = 60 s)
Not considering any speed changes that might occur. To keep track of such changes, you would have to iterate all patternlines. That’s way too heavy, so I suggest that you just assume that the speed is the same thru-out the song. Anything else is too impractical, unfortunately.
Seconds / Line = bpm * lpb / 60. Iterate all previous patterns in the sequence and sum their number_of_lines (and of course, add the line_index in the current pattern to that). Multiply this by seconds / line, and reformat to taste.
To keep track of any updates in the sequence, you need to observe renoise.song().sequencer.pattern_sequence_observable and renoise.song().sequencer.pattern_assignments_observable, if I recall correctly.
PS. Do note that the estimated time is always visible in the native GUI, top right.
Wow, I had not thought about the parameters that modify the time.I did not have this in mind.If I advance with this topic, this point will be ignored.
2)I really do not know how to approach this by iterating, to sum it all up, considering that each pattern can have a particular number of lines.
3)I do not think I’d have a problem with this.
Your PD) I am aware.
Really, I wanted to make this bar as a kind of LUA exercise, to manipulate the GUI and try things out.But sometimes some detail makes me unable to build certain things. Such a simple bar of time may not be useful, beyond learning itself.
Well. I haven’t said anything of the sorts.If someone wants to learn LUA and the Renoise API, that’s up to him/her.
@Raul, 2) Each renoise.Pattern has a property named something like .number_of_lines. And the sequence list (with pattern numbers) is accessible from renoise.song().sequencer.pattern_sequence[]
I think most of the work here would be about getting the UI right. Obtaining the patterns that make up the song, easy. Length of each pattern, easy.
The “hard part” is to represent this on the screen in a way that adapts to whatever size your tool might have.
Actually, I have been dabbling a bit with this. My (slightly delayed )update to the selection-shaper tool has a helper function which can be used for representing the relative size of a list of numbers.
So you give it a horizontal size and hand over all the pattern lengths. Voilá, it will then give you the size your buttons/whatever would need to have.
It’s used for building stuff like the keyzone and slice marker visualization in this screenshot:
@FFX, I have no problem reading the time clock (top right), in knowing which pattern I am in the sequence (left column). I’m just trying to build a tool involving the time of the song, to see if I’m capable. Rubbing windows are useful if they are well made.I’m not interested in other DAWs to learn LUA.We are discussing if there is any way to get song time in seconds at all times (I guess it plays iterate and the sum), depending on what the user does (using timers to update or _observables).
@Joule.I am able to get the number of lines in each pattern separately, but I do not know how to add it in an iteration (do the sum).Yes, I saw your transporter tool in its infancy. It looks like you’ve released other versions.
I’ll take a look.I think this issue of getting the total time of the song is somewhat complicated, precisely by the parameters ZL and ZT of LPB and BPM.Anyway, I want to make clear that I am doing exercises with LUA, I really do not seek to create a useful tool with this, just experiment.
Get the necessary values (numbers), patterns, lines, the time each line lasts, the sum of all times …
Using the previous numbers, build the UI
So I’m getting into these things for fun. Probably find things to help me in the future for other tools. Thanks for all the links! I will look at them in depth.
@Raul, The for loop has its own scope, so you should put the sum in an outer scope. Otherwise the “sum” variable below will get overwritten in every loop.
local sum = 0
for i = 1, 100 do
sum = sum + 10
end
-- here, the sum will be 1000
I do think these functions benefit from minimum overhead (?). I did something similar in my chordtracker tool. I would suspect they are a bit faster, but I’m not sure.
Click to view contents
-- Functions for manipulating a table of values,
-- used for calculating vb:button widths within a fixed total width.
function round_array(numbers_table)
local sum = 0
for k, val in ipairs(numbers_table) do
sum = sum + val
end
local tempArr = { }
local lowerSum = 0
for i = 1, #numbers_table do
tempArr[i] = {
result = math.floor(numbers_table[i]),
difference = numbers_table[i] - math.floor(numbers_table[i]),
index = i }
lowerSum = lowerSum + tempArr[i].result
end
table.sort(tempArr, function(a, b) return a.difference < b.difference end)
local difference = sum - lowerSum
for i = math.floor((#tempArr - difference + 1 )), #tempArr do
tempArr[i].result = tempArr[i].result + 1
end
table.sort(tempArr, function(a, b) return a.index < b.index end)
return tempArr
end
function tbl_scale_to_new_sum(values, new_sum)
local old_sum = 0
for k = 1, #values do
old_sum = old_sum + values[k]
end
local factor = new_sum / old_sum
for k = 1, #values do
values[k] = values[k] * factor
end
return values
end
function tbl_lower_limit_preserve_sum(values, lower_limit)
local sum = 0
for k = 1, #values do
local val = values[k]
sum = sum + val
values[k] = val - lower_limit > 0 and val - lower_limit or 0
end
values = tbl_scale_to_new_sum(values, sum - #values * lower_limit)
for k = 1, #values do
values[k] = values[k] + lower_limit
end
return values
end
function tbl_lower_limit_preserve_sum_and_first_value(values, lower_limit)
local sum = 0
for k = 2, #values do
local val = values[k]
sum = sum + val
values[k] = val - lower_limit > 0 and val - lower_limit or 0
end
values = tbl_scale_to_new_sum(values, values[1] + sum - (#values - 1) * lower_limit)
for k = 2, #values do
values[k] = values[k] + lower_limit
end
return values
end
@joule: hah, that’s cool. And true, raw performance was not my main concern.
One edge case you don’t seem to be concerned about: Once you set something to a sufficiently small value, the actual displayed button/rack/whatever size doesn’t necessarily reflect the size you tried to set -
so some “magic” has to be injected then
In any case, it’s always great to see alternative takes on the same problem !