How Add An Effect With A Shortcut Key

The question is how to automatically write an effect to the pattern on the selected note column with a shortcut key.

I’ve already implemented the add_keybindings, so I’ve just to know the code to write desired effected, which should be something like
renoise.song().patterns[].tracks[].lines[].effect_columns (that is in read only).

Here’s a quick example that will write a random 0Sxx sample offset command:

  
local effect_column = renoise.song().selected_effect_column  
if (effect_column ~= nil) then  
 effect_column.number_string = "0S"  
 effect_column.amount_value = math.floor(math.random() * 255)  
end  
  

good! this works for a selected effect column.

Is it possible to apply the same for the first effect column with a selected note column (instead of effect) also ?

Hi Zenon. Let me show you a little something.

currently functions with +1/+10/-10/-1 pitch-up, pitchdown, notecut, retrig, arpeggio (which i forgot to show) and vibrato.

if you want to take a peek:

  
  
function arpxy(effect,x,y)  
local counter=nil   
local currentamount=nil  
local old_x=nil  
local old_y=nil  
local new_x=nil  
local new_y=nil  
  
if renoise.song().selection_in_pattern==nil then return end  
  
  
for i=renoise.song().selection_in_pattern.start_line,renoise.song().selection_in_pattern.end_line   
do   
  
if   
renoise.song().patterns[renoise.song().selected_pattern_index].tracks[renoise.song().selected_track_index].lines[i].effect_columns[1].amount_value == 0 and (x < 0 or y < 0)  
then renoise.song().patterns[renoise.song().selected_pattern_index].tracks[renoise.song().selected_track_index].lines[i].effect_columns[1].number_string=""   
  
else  
renoise.song().patterns[renoise.song().selected_pattern_index].tracks[renoise.song().selected_track_index].lines[i].effect_columns[1].number_string=effect  
old_y=renoise.song().patterns[renoise.song().selected_pattern_index].tracks[renoise.song().selected_track_index].lines[i].effect_columns[1].amount_value % 16  
old_x=math.floor (renoise.song().patterns[renoise.song().selected_pattern_index].tracks[renoise.song().selected_track_index].lines[i].effect_columns[1].amount_value/16)  
  
new_x=old_x+x  
new_y=old_y+y  
print ("new_x: " .. new_x)  
print ("new_y: " .. new_y)  
if new_x > 15 then new_x = 15 end  
if new_y > 15 then new_y = 15 end  
if new_y < 1 then new_y = 0 end  
if new_x < 1 then new_x = 0 end  
  
counter=(16*new_x)+new_y   
  
renoise.song().patterns[renoise.song().selected_pattern_index].tracks[renoise.song().selected_track_index].lines[i].effect_columns[1].amount_value=counter   
end  
end  
end  
  
renoise.tool():add_keybinding {name = "Global:Paketti:Arp Amount Xy -1", invoke = function() arpxy("0A",-1,0) end}  
renoise.tool():add_keybinding {name = "Global:Paketti:Arp Amount Xy +1", invoke = function() arpxy("0A",1,0) end}  
renoise.tool():add_keybinding {name = "Global:Paketti:Arp Amount xY -1", invoke = function() arpxy("0A",0,-1) end}  
renoise.tool():add_keybinding {name = "Global:Paketti:Arp Amount xY +1", invoke = function() arpxy("0A",0,1) end}  
  

now, dblue will obviously have opinions on the ugliness of the code, and he will know how to present it more understandable, but basically this arpxy function means that if you just copy the addkeybinding and switch “0A” to ANY effect you want, you’ll be able to create +1/-1 shortcuts for either effectXy or effectxY.

  
local line = renoise.song().selected_line  
local effect_column = line:effect_column(1)  
effect_column.number_string = "0S"  
effect_column.amount_value = math.floor(math.random() * 255)  
  

I think this is what you’re looking for?

The effect column index should obviously be a valid number from 1 to renoise.song().selected_track.max_effect_columns

You may also want to check for which effect columns are actually visible, although technically you can still write values to hidden columns.

esaruoho, respect for the great effort.

Thank you ! :slight_smile:

Yep. I mean absolutely no offense mate, but your code is often quite “interesting”, to say the least ;)

I love your enthusiasm, but you still have a few bad habits you need to break (not using more local variables, not taking full advantage of useful helper functions, etc), so in this case I do think it’s better to give a simple and clear example of how this stuff works, rather than a big chunk of code ripped straight from Paketti. Of course, you did also show something I did not: working with renoise.song().selection_in_pattern

Nevertheless, you have your own style of doing things, and it’s great to see how much energy you’re putting into your tool(s). Keep it up! :D

1 Like

@esa: Just to show there are no hard feelings, here’s something that I hope will inspire you a bit :)

  
function arpxy(effect, x, y)  
  
 -- local reference to the song  
 local song = renoise.song()  
  
 -- local reference to the selection  
 local selection = song.selection_in_pattern  
  
 -- if we have no selection...  
 if selection == nil then   
  
 -- nothing to do!  
 return  
  
 end   
  
 -- local reference to the selected pattern track  
 local pattern_track = song.selected_pattern_track  
  
 -- loop through all selected lines  
 for i = selection.start_line, selection.end_line do   
  
 -- local reference to the effect column we are working with  
 local effect_column = pattern_track:line(i):effect_column(1)  
  
 -- if the new effect amount would go below zero...  
 if effect_column.amount_value == renoise.PatternTrackLine.EMPTY_EFFECT_AMOUNT and (x < 0 or y < 0) then  
  
 -- erase the effect  
 effect_column.number_value = renoise.PatternTrackLine.EMPTY_EFFECT_NUMBER  
  
 -- else apply our modifications to the effect x/y values  
 else  
  
 -- write the effect string  
 effect_column.number_string = effect  
  
 -- extract the old x/y values  
 local old_x = math.floor(effect_column.amount_value / 16)  
 local old_y = effect_column.amount_value % 16  
  
 -- calculate the new x/y values and limit them to 0 - 15  
 local new_x = math.max(0, math.min(15, old_x + x))  
 local new_y = math.max(0, math.min(15, old_y + y))  
  
 -- combine the new x/y values into a single amount  
 local amount_value = (new_x * 16) + new_y  
  
 -- write the new amount  
 effect_column.amount_value = amount_value  
  
 end  
  
 end  
  
end  
  

i also meant no offence(*). i am barely able to understand any code so it’s like “umm uh oh wow!!” followed by some more “umm uhh ?!?”. when i end up writing selected_track_index selected_pattern_index selected_line_index into those super-long strings, i keep wondering, what am i not seeing. i know you’ve tried to show it to me a few times, and i appreciate the efforts you make to beautify my (absolutely horrific looking and barely understandable) “code”.

i know this is exactly like what my 1994 .mods look like to me, just a bit of “what? was? i? thinking?”. im not sure what helper functions are, but yeah, i could shorten with a lot of locals. I see sometimes you drop in some api functions that have the character “:” in them, and those seem to be the ones used by those who have progressed further away from just poking at something in the terminal and then pasting it into a function. hence why i dont really use locals, because if i go
local sli=renoise.song().selected_line_index
i can’t test the line that uses sli on the terminal because it will shoot an error. once i can map that mess into the helpers that you guys have helpfully created in the api, i guess all my functions will work faster, better and will look prettier. i’m just poking around in the dark with grep as my makeshift flashlight and just generally makin a mess everywhere i go :)

i hope that i’ll eventually get the subtlety and the beauty of code and be able to make something that’s optimized and non-messy. it really feels like there’s just some sort of crucial key information that i have not been able to grok via just grepping keywords from the documentations to see which functions have “pattern” in the name, f.ex.

also im actually afraid of code, maybe that’s the reason for trying to do it in the simplest most lowlevel way possible which then ends up being just… uhh… awkward and ugly.

i hope to one day just re-write all of paketti from scratch and then be able to just get at it so that it is less prone to errors and looks less like code written, copypasted from the forums and just mucked about by someone who doesn’t know how to code.

TL;DR i know im wonky and weird but the ideas are what matter, the subtlety and beauty of code i can learn (this i know for a fact), and maybe it’ll be useful as a case-example - because many have very strong a priori opinions about lua-scripting being completely impossible to learn.
every day im more and more shocked at the possibilities of LUA. i know pretty much every bit of code in paketti can be traced back to vV, conner_bw, dblue or anyone else inside the community, and some friends i’ve had facetoface chats with and who have tried to humor me enough to kinda try and break it down to me so that i can grok it… but… the past year has been totally absolutely worth it. i still don’t understand tables, can barely comprehend what im doing most of the time, but there’s just something there that seems to work (barely) :)
that’s why im so chuffed about the possibility of live broadcasts of lua coding for beginners like mxb was proposing elsewhere, and i can’t wait to visit augsburg again and talk with koppi about stuff, since now he knows how to code.

and yep, i know it’s silly, but i still can’t get over how people who code are able to code something even if they have never used the language before - this coder-logic kind of thing is just a sight to behold.

(*) when i dont know something, what i do know, is that someone else will know how to do it better, just because they swim in those lakes. so i always defer to what you say.

(edit) oh, i forgot to press send on this :D

thank you so very much. i guess i will always wonder why math.max is (0 and math.min is (15 ;)
i’ll modify the XX -type effects to use this same idea, and im sure i can pull off 0-255 with this blueprint.

math.max(a, b) will return whichever value (ie. a or b) has the highest value

Therefore, math.max(0, -1) will return 0

.

math.min(a, b) will return whichever value (ie. a or b) has the lowest value

Therefore, math.min(15, 16) will return 15

.

When you combine these functions in the correct order, you can effectively limit the range of a calculated value. That’s why math.max(0, math.min(15, some_value)) will always return a value between 0 and 15

1 Like