Dissecting The Renoise Tools

in this thread i’ll dissect and explore existing renoise scripts from http://tools.renoise.com

i’ll begin with the “Convert Instrument Number” script by Ledger – a very useful script that i often find myself reaching for
i hope Ledger won’t mind that i publish it for study purposes here in the forums :)

in renoise’s scripting terminal and editor, i find that there are two files in this tool: main.lua and manifest.xml

here’s the content of manifest.xml:

Click to view contents
  
<?xml version="1.0" encoding="UTF-8"?>  
<renoisescriptingtool><br>
  <apiversion>2.0</apiversion><br>
  <id>ledger.scripts.ConvertInstrumentNumber</id><br>
  <version>1.0</version><br>
  <name>Convert Instrument Number</name><br>
  <author>Ledger</author><br>
  <description>This tool will take all the current notes instrument numbers, for the chosen range and convert them to the currently selected instrument. Accessed via the right-click menu of the instrument box and available user shortcuts: <br>
"Convert (Track in Pattern) Instruments to Currently Selected", "Convert (Whole Track) Instruments to Currently Selected" and "Convert (Selection in Pattern) Instruments to Currently Selected"<br>
  </description><br>
  <category>Pattern Editor</category><br>
  <homepage></homepage><br>
<br>
</renoisescriptingtool>  
  

this manifest.xml file is obviously just a textfile filled with xml tags and content between the tags, it somehow reminds me of the header tags of html pages that e.g. search engines use to index webpages

it seems to have little to do with the actual lua script content as such, rather these manifest.xml files seem to be more like required description files in a xrnx tool for distribution purposes

let’s return to this .xml file later, but first let’s take a overview look at the the main.lua file:

Click to view contents
  
-------------------------------------------------------------  
--Menus  
-------------------------------------------------------------  
renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:Track in Pattern",  
 invoke = function() change()  
 end  
}  
  
renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:Track",  
 invoke = function() change_all()  
 end  
}  
  
renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:Selection",  
 invoke = function() change_selection()  
 end  
}  
  
  
-------------------------------------------------------------  
--Key Bindings  
-------------------------------------------------------------  
renoise.tool():add_keybinding {  
 name = "Global:Tools:Convert (Track in Pattern) Instruments to Currently Selected",  
 invoke = function() change() end  
}  
  
renoise.tool():add_keybinding {  
 name = "Global:Tools:Convert (Whole Track) Instruments to Currently Selected",  
 invoke = function() change_all() end  
}  
  
renoise.tool():add_keybinding {  
 name = "Global:Tools:Convert (Selection in Pattern) Instruments to Currently Selected",  
 invoke = function() change_selection() end  
}  
  
-----------------------------------------------------------------  
--main(1) [Pattern Track]  
-----------------------------------------------------------------  
  
function change()  
  
local pattern_iter = renoise.song().pattern_iterator  
local track_index = renoise.song().selected_track_index  
local pattern_index = renoise.song().selected_pattern_index  
local inst_number = renoise.song().selected_instrument_index  
  
-- Zero is returned when send/ master selected  
if renoise.song().tracks[track_index].visible_note_columns == 0 then  
 return  
end  
  
--iterate:  
--over "track in pattern" and change instrument values of all notes   
for pos,line in pattern_iter:note_columns_in_pattern_track(pattern_index,track_index) do  
  
 if line.instrument_value ~= 255 then  
 line.instrument_value = (inst_number - 1)  
 end  
end  
  
renoise.app():show_status("Convert Inst. no. Tool: (Instruments Changed in \"Track in Pattern\")")   
end --main  
  
-----------------------------------------------------------------------  
--main(2) [Whole track]  
-----------------------------------------------------------------------  
function change_all()  
  
local pattern_iter = renoise.song().pattern_iterator  
local track_index = renoise.song().selected_track_index  
local inst_number = renoise.song().selected_instrument_index  
  
-- Zero is returned when send/ master selected  
if renoise.song().tracks[track_index].visible_note_columns == 0 then  
 return  
end  
  
--iterate:  
--over "track in pattern" and change instrument values of all notes   
for pos,line in pattern_iter:note_columns_in_track(track_index) do  
  
 if line.instrument_value ~= 255 then  
 line.instrument_value = (inst_number - 1)  
 end  
end  
  
renoise.app():show_status("Convert Inst. no. Tool: (Instruments Changed in \"Track\")")   
end --main  
  
  
  
-----------------------------------------------------------------------  
--main(3) [Pattern Selection]  
-----------------------------------------------------------------------  
function change_selection()  
  
local pattern_iter = renoise.song().pattern_iterator  
local track_index = renoise.song().selected_track_index  
local pattern_index = renoise.song().selected_pattern_index  
local inst_number = renoise.song().selected_instrument_index  
  
-- Zero is returned when send/ master selected  
if renoise.song().tracks[track_index].visible_note_columns == 0 then  
 return  
end  
  
--iterate:  
--over "Pattern" and change instrument values of all notes   
for pos,line in pattern_iter:note_columns_in_pattern(pattern_index,track_index) do  
  
 if line.is_selected then --only selection  
 if line.instrument_value ~= 255 then  
 line.instrument_value = (inst_number - 1)  
 end  
 end   
  
end  
  
renoise.app():show_status("Convert Inst. no. Tool: (Instruments Changed in \"Selection\")")   
end --main  
  
  

to be continued…

ok, the first thing i’ll try is to simply see if i can change the text that appear in renoise’s instrument box menus (right click on an instrument slot and check the menu at the bottom “Convert Notes in”)

will it break anything in the script as it’s running inside my renoise window?

i change this in the “Menus” section of the script:

  
renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:Track",  
 invoke = function() change_all()  
 end  
}  
  

to this

  
[renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:Track in Song",  
 invoke = function() change_all()  
 end  
}  
  

(“Track” changed to “Track in Song”) then click on File and Save in the Scripting Terminal & Editor menu

checking in renoise’s instrument box’s menu

ok, it’s changed and the script doesn’t seem to be broken

now, what else can i check out?

what if i add something in this menu section, like:

  
renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:My Test Option",  
 invoke = function() change_selection()  
 end  
}  
  

i save again and check… yes, the new submenu option “My Test Option” appears

ok… obviously i need to investigate here how the “binding” occurs, i.e. how can i connect the submenu option (“My Test option”) to actually do something, for example write some text in the Renoise’s status message corner?

it seems to me that the “invoke = function()” calls different functions to be run, so that in my new “My Test Option” (since i copy-pasted it) it will call the function “change_selection()”

so i will change this to:

  
renoise.tool():add_menu_entry {  
 name = "Instrument Box:Convert Notes in:My Test Option",  
 invoke = function() my_test_function()  
 end  
}  
  

saving… checking… well, clicking on “My Test Option” will (as expected) result in an error message:

  
*** main.lua:24: variable 'my_test_function' is not declared  
*** stack traceback:  
*** [C]: in function '_error'  
*** [string "local mt = getmetatable(_G)..."]:29: in function   
*** main.lua:24: in function <24><br>
<br>```

<br>
<br>
it complains that my_test_functions is not "declared", which i take to mean that there is no my_test_function anywhere for the script to run<br>
<br>
well, let's add it then... i go down to the end of the main.lua file and write:<br>
<br>

```<br><br>
-----------------------------------------------------------------------<br>
--main(4) [My Test Function]<br>
-----------------------------------------------------------------------<br>
function my_test_function()<br>
<br>
print("my_test_function is called")<br>
<br>
end<br>
<br>```

<br>
saving... clicking My Test Option in the instrument box submenu... switching to the Terminal window... ah yes, the text "my_test_function is called" is printed out so the function is now declared and connected to the menu<br>
<br>
i'm also changing the print so that the message will appear in renoise's status bar instead of the terminal window:<br>
<br>

```<br><br>
function my_test_function()<br>
  renoise.app():show_status("my_test_function was called") <br>
end<br>
<br>```

 <br>
<br>
to be continued...</24>

Just seen this,

No problem atall! :)