Lua Math - How To Define Space

Let’s say completely imaginary:

numberspace is 2-16, you can’t go below 2 or over 16. You’ve got one shortcut which sends -1 and one shortcut which sends +1 .

How do you read the current_status of numberspace , add -1 to it or add +1 to it, and make that be the current_status_of_numberspace?

:o

I’m not entirely sure what you’re trying to do, but maybe this will help…

  
local min = 2  
local max = 16  
local current = 2  
  
-- plus one  
current = math.max(min, math.min(max, current + 1))  
  
-- minus one  
current = math.max(min, math.min(max, current - 1))  
  

I’m trying to do a similar thing to

  
renoise.tool():add_keybinding {  
 name = "Global:Impulse:Protman Jump Lines Up",  
 invoke = function() Jump(-1) end  
}  
renoise.tool():add_keybinding {  
 name = "Global:Impulse:Protman Jump Lines Down",  
 invoke = function() Jump(1) end  
}  
  
  • except for a different keybinding and obviously a different function. First test will be to get Metronome LPB to increase or decrease according to keybinding press, second to get Metronome BPB to do the same.
    Then it’s time to hope against hope that LoopBlock can do the same thing :) Eventually this’d allow one to map a shortcut for changing current_sample’s loop_mode, and so on.

So something like this or…?

  
function keybindx(minus)  
local min = 2  
local max = 16  
minus = math.max(min, math.min(max, minus -1))  
renoise.()song.transport_function (as a faulty example)  
  
function keybindx(plus)  
local min = 2  
local max = 16  
plus = math.max(min, math.min(max, plus +1))  
(followed by keybind)  
  

esaruoho,

I’m not 100% sure I fully understand what you are asking.

Do you mean you want a function that receives a relative value (i.e. +1 or -1), performs some math with it (i.e. adds it to another value from Renoise), restricts the range of the value and then uses that somewhere (i.e. sends it back)?

If so the following pseudocode snippet may be helpful as an idea:

function do_something(delta_value)  
 -- set values  
 local current_value = renoise.song().somevalue  
 local max = 16  
 local min = 1  
  
 -- modify  
 new_value = current_value + delta_value  
  
 -- restrict range  
 if new_value > max then  
 new_value = max  
 elseif new_value < min then  
 new_value = min  
 end  
  
 -- send back to renoise  
 renoise.song().somevalue = new_value  
end  

I have written similar code in the past for a variety of tools. One that is fairly well documented can be retrieved from this thread.

Thanks for your help mxb!
At first my re-work of what you wrote didn’t work, but then I added

  
new_value = nil  
  

and hey presto:

  
---- +1 / -1 on MetroLPB and MetroBPB  
function metlpb(metrlpb)  
 -- set values  
 local current_value = renoise.song().transport.metronome_lines_per_beat  
 local max = 16  
 local min = 1  
 local new_value = nil  
  
 -- modify  
 new_value = current_value + metrlpb  
  
 -- restrict range  
 if new_value > max then  
 new_value = max  
 elseif new_value < min then  
 new_value = min  
 end  
 -- send back to renoise  
 renoise.song().transport.metronome_lines_per_beat = new_value  
 renoise.app():show_status("[Metronome LPB is]: " .. new_value  
 .. " [Beats per Bar is]: " .. renoise.song().transport.metronome_beats_per_bar)  
end  
  
function metbpb(metrbpb)  
 -- set values  
 local current_value = renoise.song().transport.metronome_beats_per_bar  
 local max = 16  
 local min = 1  
 local new_valuebpb = nil  
  
 -- modify  
 new_valuebpb = current_value + metrbpb  
  
 -- restrict range  
 if new_valuebpb > max then  
 new_valuebpb = max  
 elseif new_valuebpb < min then  
 new_valuebpb = min  
 end  
 -- send back to renoise  
 renoise.song().transport.metronome_beats_per_bar = new_valuebpb  
 renoise.app():show_status("[Metronome LPB is]: " .. renoise.song().transport.metronome_lines_per_beat  
 .. " [Beats per Bar is]: " .. new_valuebpb)  
end  
  
  
  
renoise.tool():add_keybinding {  
name = "Global:Impulse:MetrLPB -1",  
 invoke = function() metlpb(-1)  
end  
}  
  
renoise.tool():add_keybinding {  
name = "Global:Impulse:MetrLPB +1",  
 invoke = function() metlpb(1)  
end  
}  
renoise.tool():add_keybinding {  
name = "Global:Impulse:MetrBPB -1",  
 invoke = function() metbpb(-1)  
end  
}  
  
renoise.tool():add_keybinding {  
name = "Global:Impulse:MetrBPB +1",  
 invoke = function() metbpb(1)  
end  
}  
  

[quote=“esaruoho, post:6, topic:32725”]
Thanks for your help mxb!
At first my re-work of what you wrote didn’t work, but then I added

  
new_value = nil  
  

and hey presto:

  
<snip><br>
<br>
  local new_value = nil<br>
<br>
  -- modify<br>
  new_value = current_value + metrlpb<br>
<br>
  <snip><br>
<br>```

<br>[/quote]<br>
<br>
Sorry, I missed out a 'local'.<br>
<br>
These two lines can be combined into one statement as so if you wish:<br>
<br>

```lua<br><br>
  local new_value = current_value + metrlpb<br>
<br>```

</snip></snip>

Here’s a quick tip from me regarding the code that restricts the value ranges.

math.min(a, b) will return whichever value is the lowest. For example: math.min(16, 17) will return 16.

math.max(a, b) will return whichever value is the highest. For example: math.max(2, 1) will return 2.

So instead of this bit of code: (which is perfectly functional but not very elegant)

  
if value > max then  
 value = max  
elseif value < min then  
 value = min  
end  
  

You can do this instead, which is much more sexy:

  
value = math.max(min, math.min(max, value))  
  

:slight_smile:

Finally, here’s something a bit more compact, just for fun:

  
-- +1 / -1 on Metronome LPB and Metronome BPB  
function adjust_metronome(lpb_delta, bpb_delta)  
  
 -- Local reference to transport  
 local t = renoise.song().transport  
  
 -- Adjust LPB  
 t.metronome_lines_per_beat = math.max(1, math.min(16, t.metronome_lines_per_beat + lpb_delta))  
  
 -- Adjust BPB  
 t.metronome_beats_per_bar = math.max(1, math.min(16, t.metronome_beats_per_bar + bpb_delta))  
  
 -- Show status  
 renoise.app():show_status(  
 "Metronome : " .. t.metronome_lines_per_beat .. " LPB : " .. t.metronome_beats_per_bar .. " BPB"  
 )  
  
end  
  
renoise.tool():add_keybinding {  
 name = "Global:Impulse:Metronome LPB -1",  
 invoke = function() adjust_metronome(-1, 0) end  
}  
  
renoise.tool():add_keybinding {  
 name = "Global:Impulse:Metronome LPB +1",  
 invoke = function() adjust_metronome(1, 0) end  
}  
renoise.tool():add_keybinding {  
 name = "Global:Impulse:Metronome BPB -1",  
 invoke = function() adjust_metronome(0, -1) end  
}  
  
renoise.tool():add_keybinding {  
 name = "Global:Impulse:Metronome BPB +1",  
 invoke = function() adjust_metronome(0, 1) end  
}  
  

Thanks, dBlue! I’ll start using those local “aliases” for functions, seems like it’ll look prettier.

Can there be local aliases that stretch across the whole script, or are these local definitions always limited to the function they are in?

Not just visually nicer, but also more efficient from a performance point of view. Every time you call something like renoise.song().transport, each piece of that command has to be resolved one by one. First renoise must be resolved, then song(), then transport, etc.

If you have a function that performs multiple tasks with some properties of the transport object, then you can save some processing overhead by making a local reference to it first, and then doing your processing on the reference object.

You can of course put these references pretty much anywhere you want in your code. For example, you could do something like this:

  
local t = renoise.song().transport  
  
function foo()  
 -- do something here with t.something  
end  
  
function bar()  
 -- do something here with t.something  
end  
  

But you should be very careful when doing this. If you try to access renoise.song() from the main body of your main.lua function, then it’s very easy to get an error. For example, when your tool is first loaded into memory by Renoise, no song() actually exists at that point in time, so you will get an error for trying to access a non-existent object. It’s also possible that the user loads/creates a new song while your tool is running, so now your reference to renoise.song() will be invalid if you don’t update it yourself.

There are of course notifiers to check when the song changes and things like that, so it is possible to do this stuff if you want, but generally speaking it’s much safer to just keep your local references within the functions themselves. This way you can safely assume that when the function is called there is actually a valid, up-to-date song() object for it to work with.