Lua Macros

Seems a few users would benefit from a Macro layer in Renoise.

Macro, instead of script, in the sense that you would be allowed to send keystroke combinations directly to Renoise, procedurally and programatically.

So instead of this:

  
function toggle_edit_mode()  
 if renoise.song().transport.edit_mode == true then   
 renoise.song().transport.edit_mode = false  
 else  
 renoise.song().transport.edit_mode = true  
 end  
end  
  

A user could do this:

  
renoise.macro().send({ name = 'esc' })  
  

Or even better, this:

  
local key = renoise.macro().query("Pattern Editor:Play:Toggle EditMode")  
renoise.macro().send(key)  
  

Better syntax, welcome.

hmm… So one could have a macro which runs through multiple keyboard shortcuts, which each start a different script?

this’d be really swell for rather complex workflows… i’d really have to think about what i want renoise to do which renoise isn’t capable of doing right now.

btw, your macro suggestion currently sends keycommands. what if it could also start buttons? I have a few in mind which cannot be accessed via LUA (Automatically Detect Transients and Place Slice Markers) (Sample_Recorder line-input and also channel)…

The only problem with something like having a macro which sends esc is if the user has changed esc to do something else. (for me, esc is follow pattern toggle/on/off, for instance.).

I actually thought (and mentioned it) that a Macro-builder would be part of the Scripting when it was announced.

It shouldn’t matter if your keyboard shortcuts are different to somebody elses. Although building a Marco, and finding the command you want to do, may be easier with entering a keyboard shortcut, the Macro should be saved and made in a readable way using the names as they are displays in the Preferences -> Keys section.

I’ve been wanting this feature but didn’t know how to articulate how it would work.
I have script ideas that would be made possible/so much easier with this.

I’ve made my own hacky renoise macros using external software so that I could do processes like adding 50 instances of a device and then offsetting a parameter on each one. So many possibilities to control a lot of stuff and do tasks that might be cool but would waste too much time otherwise. If there were an implementation of macros in Renoise that supported recording mouse clicks, hotkeys etc, I would be thrilled. So many doors would open up in terms of sound design.

Yes, macros! +1

Beautiful! How about an observable as well? By this we can actually add a behaviour to existing shortcuts.

(Perhaps the observable should even override the native macro, as you can always trig the native function if you want to include it.)

+1 for
renoise.macro().send({ name = ‘Enter’ })

Yes, please. This would rock so hard it hurts. :guitar:

Edited for the format I’d personally prefer see it in ;)

I see these letting you access (for eg) Pattern Editor keyboard shortcuts from the Sample Editor as well as making it easy to set up a Macro (list of functions/shortcuts executed in turn.)

Here goes:
renoise.macro().send name = ‘Enter’

+1
:D

+1, but I don’t fully understand the syntax in any of the (pseudo)scripting parts y’all posted. Conner, could you give an example 1on1 of what you want to get replaced by what?

Hi Cas,

The syntax comes from the existing spec for key_handler_func() in the current docs.

  
"key" is a table with the fields:  
-- > key = {   
-- > name, -- name of the key, like 'esc' or 'a' - always valid   
-- > modifiers, -- modifier states. 'shift + control' - always valid   
-- > character, -- character representation of the key or nil   
-- > note, -- virtual keyboard piano key value (starting from 0) or nil   
-- > repeated, -- true when the key is soft repeated (hold down)   
-- > }  
  

My pseudo example is simply:

  
renoise.macro().send(key)  
  

Or:

  
local key = renoise.macro().query("Pattern Editor:Play:Toggle EditMode")  
renoise.macro().send(key)  
  

Where key is defined like the spec above.

What’s missing from all this, of course, is “middle click” aka “orange border” aka the selected view you would send keystrokes too.

I’m not sure of the best approach for that particularity.

Improved syntax, welcome.

Hacking in mouse support could “probably” be done fairly quickly by abusing the key table:

name = L_CLICK, R_CLICK, M_CLICK  
modifiers = empty  
character = nil  
note = nil  
repeated = false / true for single / double click respectively.  

It’s not elegent, it’s not The Right Thing, but it may be feasible as I’ve seen other APIs report mouse events in this way.

I’m not 100% convinced it’s a good idea though.

Not at all! We are talking about sending direct function shortcuts, not press-of-a-key shortcuts. Sure it does mean you could end up pasting a load of data into the Pattern Editor while you can’t currently see it (for one of a infinite number of examples) but it also means it will work on anybody’s install of Renoise, when whereas if you used key macros it wouldn’t work if your keyboard shortcuts were different from somebody else’s.

And as macros could be nested in functions you could well have if focus is x pane check then do y or z macro depending. I see no issue with this!

The problem is that you can assign the same shortcut combo more than once, depending on the selected view. An out of the box example:

Edit → Preferences → Keys:

  • Sample Editor:Edit:Paste = CTRL + V
  • Automation:Process:Paste = CTRL + V
  • Track DSPs Chain:Edit:Paste Device = CTRL + V

So when I do

  
local key = { name = 'v', modifiers = 'control' }  
renoise.macro().send(key)  
  

Which one of am I doing? If I do:

  
local key = renoise.macro().query("Track DSPs Chain:Edit:Paste Device")  
  

Then key is { name = ‘v’, modifiers = ‘control’ }, nothing more.

There’s no magic “I see what you did there, you mean Pattern Editor?” built into the query system. It’s just going to query the assignment table, and return the key, not the view.

Am I wrong? I haven’t looked at this in a while. Honest question.

But If I’m right we either have to add the view to the key table which is not there now, which could break backward compatibly, and so on. Or do something new which I have no good idea for.

Becasue the Macro does not ever refer to which key is being pressed!!! Then your Macros couldn’t be shared to people who use different keyobard shortcuts to you!! What I suggested is that they are always defined with the Track DSPs Chain:Edit:Paste Device type syntax, not by letter name/modifier combinations! Therefore there is never any mistaking what you are wanting to do!! And you can very easily set up shortcuts to do operations in areas which don’t currently have focus, which currently require a lot more lines of code to reprogram purely in the API!

So you above example:

You have created a macro with the name v with a junk bit of code called modifiers. So it will sit in the root levels of any macros list. But no sensible definition…

My syntax is likely to be out here as not on a computer with a Renoise install… Anyway this is a lot closer to what I would hope to see:

  
function pastefill()  
 renoise.macro():run(Pattern Editor:Edit:Copy Selection)  
 renoise.macro():run(Pattern Editor:Navigation:Goto Top of Pattern)  
 renoise.macro():run(Pattern Editor:Edit:Paste Continuously)  
end  
  
renoise.macro():create{  
 name = "Kaza's Test:Paste Fill"  
 invoke = function() pastefill end  
}  

Possibly all commands within the function could be part of the same macro():run call and separated by semi-colons…