so in general it is a good idea to keep scope in mind and make things local when they can be. in particular it’s a really good idea to keep vars in functions local.
but actually @ppqq and @tehn made a really nice change a while back which is to swap out the global environment between scripts. this means you can absolutely declare globals with impunity in scripts, and in fact this is now recommended practice for top-level variables. (it is less verbose and makes it so you can access those vars in the REPL.)
you still do need to watch out for overriding fields in system globals. there’s not really a feasible way for us to prevent you from, say, breaking the menu by saying menu.redraw = nil or something.
i believe that in the present version of lua you can always access locals declared in surrounding scopes. (in older versions there were weird edge cases with nested functions.)
oh but @wheelersounds i guess i should say that in response to that example (and i know it’s not real, so this is just a point for discussion/pedantry), IMHO it’s much better practice to make functions that don’t rely on any implicit knowledge of state outside their scope. so in that case, to just pass billy as a function parameter.
in the extreme case, you can make all your functions immutable (they don’t modify anything and just return whatever mutated state you need), then you’re doing Functional programming. (lua helps you with this because you can’t pass parameters by reference, and functions can return multiple values and/or tables.)
--- @returns new billy
function addBillly(arg, oldBilly) return oldBilly + arg end
or if you find yourself wanting to mutate external state a lot, without copying big tables on return, then you can make functions into “methods” that operate on specific data structures. then you’re doing Object Oriented programming. (lua helps with this by providing the “colon” syntax that hides a “self” argument)
Thing = { billy = 10 }
--- (... insert boilerplate: Thing factory, &c)
--- mutates the `billy` of a Thing
function Thing:addBilly(arg) self.billy = self.billy + arg end
those programming patterns arose because things become pretty difficult to manage without them.
no, it should just work. but, what levels? TAPE doesn’t have a dedicated level meter since it just takes the main output bus. you mean you don’t see the output levels you’re hearing? and/or, you get silence in the recording even though output is audible?
anyone who hasn’t yet might like to check out the routing diagrams
https://github.com/monome/norns/blob/master/doc/crone/crone-process-routing.pdf