Midi Map Instrument Settings

Hi all!!
Nice to meet you all!
Can anyone suggest me how to add a midimap to the sample transpose of the instrument settings ?
Or is it not possible.

Thank you


not possible.

Yes it is. This is the API forum and this is very much possible through scripting.

I personally haven’t done any MIDI bits with the API but search the Renoise.Song.API for Transpose and you should find some useful bits…

Thank you for your reply:D
but i’ve got no idea how to do so ? is there some hint somewhere?

For currently selected sample you will want to set the value of “renoise.song().selected_sample.transpose” with your MIDI knob for Transpose, or “renoise.song().selected_sample.fine_tune” for finetune.
For instrument plugin (EG VSTi) use “renoise.song().selected_instrument.plugin_properties.transpose”

But I haven’t written anything using MIDI so beyond that you will have to do some research/testing yourself or wait until somebody more experienced than myself answers.

If you use the tool-creator from Bantai, you will have a few default bindings that you can work with. It includes one automatic midi binding as well.
Then there are also the Lua API snippets (somewhere in the scripts-folder (Help -> Show preferences folder, from there go to the scripts folder) that you can load in the terminal editor to analyse and investigate: they contain descriptions of what each function does and show you how to achieve basic functionality with the desired functions.

Well… I’d say the best thing is looking into SevenScientist’s MPE2000 tool. He created a GUI knob which controls the current-instrument’s sample pitches, all of them.

Here’s how:

First, isolate the bit of code (this one is simple)

 vb:rotary {  
 tooltip = "SINGLE sample transpose.\nmidi map-mode = Relative bin offset",  
 id = "smptran",  
 min = -120,   
 max = 120,  
 midi_mapping = "MPE:Sample:Transpose",  
 notifier = function()  

It’s just a gui code showing a rotary knob, which is findable by going to MidiMap -> Typing MPE in and then it shows all MPE-script-created shortcuts. It can be midimapped, and when it fires, it runs a ftransample() function. So let’s look at ftransample():

local function ftransample()  
 renoise.song().selected_instrument.samples[renoise.song().selected_sample_index].transpose = vb.views.smptran.value  

Well, this one is straightforward. The selected sample, within the selected instrument, gets a transpose from the rotary knob, which is controlled by midimapping - and the rotary knob is midimappable so when you move your midiknob around, the script activates, and changes the transposition by min -120 max 120. While the GUI knob code is large, the actual function is very simple.

So, to start from scratch, try like this:

Load a new sample to instrument box #01 ( just one sample )

Start scripting terminal&editor.

Go into Scripting Terminal.

Switch your Lower Frame to Instrument Settings->Sample (tab1 of Instrument Settings). Either by mouse. Or type this in your Scripting Terminal:

``` <- type this verbatim. If you succeed, your lower_frame changes to Instrument Settings. Why should you do this? So you can see when you do your first sample transposition by LUA.  
You have one instrument, with one sample. Fine. So, what is the current transposition value of the sample? type  

oprint (renoise.song().selected_sample.transpose)

Now change it. If oprint can be used to output current value, then setting the value will change it. Type this into your terminal:  


First try what doesn't work:  


result: Error. You can't just say "increase by 1". It needs to know WHAT is being increased by one. so, since you already know how to access "current transpose value" by oprint from the terminal, try this:  


function pitchplus1()  
renoise.song().selected_sample.transpose=renoise.song().selected_sample.transpose+1 end  
function pitchminus1()  
renoise.song().selected_sample.transpose=renoise.song().selected_sample.transpose-1 end  
renoise.tool():add_keybinding {  
 name = "Pattern Editor:Paketti:Selected Sample Pitch +1",  
 invoke = function() pitchplus1() end}  
renoise.tool():add_keybinding {  
 name = "Pattern Editor:Paketti:Selected Sample Pitch -1",  
 invoke = function() pitchminus1() end}  

Now, what is actually informative for your issue, is the format for adding a keybinding. You state the place where the keybind will function (within Pattern Editor). You could decide on an arbitrary name you can look for in the prefs->keys (I use Paketti for everything since it’s my grabbag script). Then you define that Selected Sample Pitch +1 will run the function pitchplus1. As you can see, we’ve moved from using the terminal to control stuff, to actually editing a functional script.
Now, this script has limitations. If you’re already at 120, and you +1, it won’t do anything. (Well, it will shoot errors complaining that 121 is not a possible selected_sample transposition pitch - but you won’t see them unless if your Scripting Terminal & Editor is open). same with -120 and you -1 - nothing happens.

So, how would this bit of code be changed to make it into two midimappable functions (one midibutton for +1, one midibutton for -1). Like this:

renoise.tool():add_midi_mapping{name="Paketti:Selected Sample Pitch +1", invoke = function() pitchplus1() end}   

Notice how the only thing that changed was “add_keybinding” was switched to “add_midi_mapping”. Well, you’re already halfway there. Now I guess someone else could step in and explain how to change a 1-127 outputting midiknob to control the overall pitch of the selected_sample. Someone might make it so that 1-127 will cover -120 to 120, i.e. multiply the message being received by the script which is listening to a specific midimapping. Someone else might just go for “0 to 120” and ignore the minus-pitches. I don’t know where you’ll go, that’s up to you!
Also notice one other thing about the keybinding & midi_mapping – there’s no reference to Pattern Editor. This will function globally - i.e., no matter where you are, you can use a midibutton to +1 or -1 a selected_sample’s transposition value.

K, let’s switch approaches. Instead of +1/-1 with pckeyboard or midibutton, we just want to have a random knob, outputting at least something, to the pitch. First version doesn’t work:

function pitchctrl()  
renoise.tool():add_midi_mapping {  
 name = "Paketti:Selected Sample Pitch Control", invoke = function() pitchctrl() end}  

Well, of course it doesn’t work, the transposition receives absolutely nothing from the midi_mapping. You need to tell the midi_mapping to send something to the script (the function called pitchctrl()). This is where I admit that I’ll just peek at other people’s code, to get it going. Okay, well, the best thing about scripting is that you can do things wrong - then find out how someone else did it right, and improve yours. So let’s just rewrite the whole thing so it works simpler - so that the whole function is inside the midi_mapping. Here’s the end result:

renoise.tool():add_midi_mapping{name = "Paketti:Selected Sample Pitch Control",  
 invoke = function(midi_message)  
 renoise.song().selected_sample.transpose = midi_message.int_value  

Keeping the whole function inside a midi_mapping CAN be a useful way to do things, and sometimes it isn’t a good way to go about things. Someone else will fill in the details as to why it’s a bad thing.
Anyway, see what happened there? the midi_message.int_value is what your midiknob sends to the selected_sample.transpose value. This functions in as messy a way as possible - i.e., when your knob is at 1, the pitch is at 0. when your knob is at 127, selected_sample pitch is 120. (or maybe it’ll be something else, if you have a choppy midicontroller - it might jump from 110 to 118 and your pitch will remain at 118. Again, if you go higher than 120, terminal will start spouting errors. There are ways to make sure the errors don’t happen - how? You take the midi_message.int_value, and set it to the maximum value (120) if it is over the maximum value (over 120). Since I’m not a coder, I’ll do it like this:

renoise.tool():add_midi_mapping{name = "Paketti:Selected Sample Pitch Control",  
 invoke = function(midi_message)  
 local over120=nil  
 if midi_message.int_value > 120 then over120=120   
 else over120 = midi_message.int_value  
 renoise.song().selected_sample.transpose = over120  

What we do is first we define a local, called over120 (for the sake of it “kinda making sense” - you can mostly name the locals as you wish - try and be informative so that others can benefit from it too). This “over120” is set to nil (why? Because if it’s not set to nil, it doesn’t exist!). Next is to say "if incoming midi_message value is over 120, then set the local “over120” to contain the number “120”. If the incoming midimessage value is BELOW 120, then just set “over120” to incomind midimessage value. Then set the selected_sample.transpose value to “over120” - which will now either contain 120 if you are moving your midiknob in 120-127 territory, or will go down to 0 if you move your midiknob down to 0.

But hey, while we now have 0-120 covered, that’s just not good enough. Not by a long shot. We need at least some sort of midicontrol over pitch values -120 and 120 - can’t just be going up without also going down with this one 1-127 midiknob of yours. Well, how about -64 and 64? Sure, that might work. Anyway, here’s where I admit defeat at 03.35am:

renoise.tool():add_midi_mapping{name = "Paketti:Selected Sample Pitch Control",  
 invoke = function(midi_message)  
 local modifiedresult = nil  
 if midi_message.int_value <64 then modifiedresult = 0-midi_message.int_value   
 else modifiedresult = midi_message.int_value  
 renoise.song().selected_sample.transpose = modifiedresult  

Yep, ugliest possible method - and about as buggy as I know how to make it. But you are suddenly accessing at least some buggy faulty method of going below 0. What this does is (and here’s where coders groan)
go "well if the received midiCC is below 64, then start transposing by doing a calculation of 0-(number). So when you go below 64, it jumps to pitch -63, then while you go to 1 to your CC, transpose is 0. when you go up to 63 with your midiCC, you get to a maximum of -63 pitch. Then when you go over 64 with your midiCC, your beautiful -63 pitch jumps to +64 pitch :D and going to 127, you’ll get to 120 as pitch. - - and, since there’s no protection in this bit of code to make sure “over 120 is 120”, it will start shooting errors in the terminal.

[strike]Now, here’s a great place for someone to step in and say “no! do it right! make CC_amount64 0, make CC_amount0 -63, make CC_amount127 +64 – and here’s how!” . Off to you, magic man.[/strike] see edit below

[strike]Anyway, I hope this helps at least somehow.[/strike]

[strike]- Figure out how to modify 1 - 127 incoming midiCC data to fit into -63 / +64 land. It’s probably real easy! (these things always are)[/strike] see Edit below

  • Figure out how the int.value changes if you are using a rotary knob instead of a regular 1-127 knob. It will change, after all.

All it took was a bit more thinking. Here, this gives you selected_sample.transpose control of -64 to 64:

renoise.tool():add_midi_mapping{name = "Paketti:Selected Sample Pitch Control",  
 invoke = function(midi_message)  
 renoise.song().selected_sample.transpose = midi_message.int_value-64 end}  

Simple, easy, and probably enough to carry on with. Why? Because if you know how to do this, and you paid attention to the oprint bit of code, do this!

oprint (renoise.song().selected_sample)  

Result is:

[details=“Click to view contents”] ```

oprint (renoise.song().selected_sample)
class: Sample

Well, aren't you lucky! So many possibilities. You just used oprint to show all the possible functions that renoise.song().selected_sample can have. Since you already know that renoise.song().selected_sample.transpose is pitch control, just go for the ones that don't have _observable in their name and start bashing numbers in. Some of the things you'll encounter can't take numbers in (slice_markers works with tables, for instance, so sending renoise.song().selected_sample.slice_markers=30 will do nothing whatsoever.   
Anyway, I hope this helps at least somehow.