In a script I’m working on I’d like to be able to copy the whole content of a table and insert it into another.
The idea behind it is to have note pattern tables as presets and be able to copy the data of a preset to another. I realised that simply referencing tables creates a big mess and is not the way to go. After some reading I came up with this and wanted to ask if I’m on the right path.
What it should do is clear the table of the preset destination and insert all values of the source table.
function clear_and_paste(table_source, table_destination)
local count = #table_destination
for i = 0, count do
table_destination[i] = nil -- sets all values to nil -> empty table
end
for i, v in ipairs(table_source) do
table.insert(table_destination, i, v) -- for each index insert value
end
end
(my norns needs to be repaired so this is just a proof-of-concept without testing)
1 Like
it might be easier just to clone the table?
function clear_and_paste(table_source, table_destination)
table_destination={table.unpack(table_source)}
end
I like Lua: demo for testing ideas away from norns! you can just make a small prototype script and run it to see if it works. I often do this when I can’t remember how lua does things…
3 Likes
Ha, amazing, thank you. that simplifies things a lot!
This is great, just tested some code it and it does exactly what I need.
1 Like
I’m learning Norns scripting and tried to make a simple SW midi-thru script:
midi_in_device = midi.connect(1)
midi_out_device = midi.connect(2)
midi_in_device.event = function(data)
midi_out_device.send(data)
end
device 1 is connected to my keyboard and device 2 to my synth. The connections are verified to work with other scripts.
What did I do wrong?
zebra
1051
ah, this is confusing. the event handler takes raw MIDI bytes, and the send method expects a structured table.
so you probably want
midi_in_device.event = function(data)
local msg = midi.to_msg(data)
midi_out_device.send(msg)
end
(NB: untested as yet!)
It looks like the send() function can take either one: norns/lua/core/midi.lua at main · monome/norns · GitHub
@barksten have you tried using a colon instead of a period?
midi_in_device.event = function(data)
midi_out_device:send(data)
end
3 Likes
Thanks!
This works. I think I actually tried this earlier but at that point I had some other problems (before I reduced the code to the minimal example above)
Isn’t colon used for “class member functions” and dot for “properties” () in Lua?
anyway. I found this declaration in your link:
send = function(self, …) if self.device then self.device:send(…) end end,
I still have a lot to learn about the Lua language, but as I understand “Midi” is a simple struct with properties (which can hold functions) and Midi.device is a Class?
zebra
1055
its confusing. (you and i are confused. kenji is fine.)
lua doesnt really have classes. it has tables, and it has a feature by which one table can act as a prototype for another. thus, OOP-like constructs are possible.
the colon is just a small bit of syntax sugar, it declares a function where the first argument is the table itself.
if you have
foo = {bar=1}
then these lines are exactly equivalent and describe the same function:
function foo:printbar() print(self.bar) end
function foo.printbar(self) print(self.bar) end
and in fact the function can then be invoked with either form regardless of how it was declared:
foo.printbar(foo)
foo:printbar()
the other point of confusion is that there is a sort of abstraction layer between the “device” interface you’re seeing and the data strucutres corresponding to physical hardware MIDI-USB endpoints . the former are what we call vports in the system, its a little wrapper object. the line you link describes the initialization of a vport that knows how to wrap MIDI messages.
anyways, i think kenji is right and you want the colon. it will still run without it but it will be getting the wrong argument. (attempting to use the data or msg as a vport table.) i’m surprised that what i typed works (in the sense of causing appropriate MIDI bytes to be sent.)
2 Likes
jatwo
1056
novice working my way through the scripting studies. hit a road block in study 5, streams. trying to run the example code:
p = poll.set("amp_in_l")
p.callback = function(val) print("in > "..string.format("%.2f",val)) end
p.time = 0.25
p:start()
but keep getting “error: load fail” for “attempt to index a nil value (global ‘p’)”
Summary
SCRIPT ERROR: load fail
/home/we/dust/code/my_studies/study_5_streams.lua:2: attempt to index a nil value (global ‘p’)
stack traceback:
/home/we/norns/lua/core/norns.lua:146: in metamethod ‘__newindex’
/home/we/dust/code/my_studies/study_5_streams.lua:2: in main chunk
[C]: in function ‘dofile’
/home/we/norns/lua/core/script.lua:192: in function </home/we/norns/lua/core/script.lua:192>
[C]: in function ‘xpcall’
/home/we/norns/lua/core/norns.lua:147: in field ‘try’
/home/we/norns/lua/core/script.lua:192: in function ‘core/script.load’
(…tail calls…)
script clear
lua: /home/we/norns/lua/core/clock.lua:59: bad argument #1 to 'resume' (thread expected)
stack traceback:
[C]: in function 'coroutine.resume'
/home/we/norns/lua/core/clock.lua:59: in function 'core/clock.resume'
my norns shield is up to date. have refreshed browser (firefox) cache and power cycled norns numerous times.
any advice where i might be messing up?
the poll setup needs to be within the init function of your script. however, you can start/stop it form anywhere.
edit: more info here: Rangl - #13 by sonoCircuit
2 Likes
jatwo
1058
genius, that seemed to work! thanks for the prompt help @sonoCircuit 
function init()
p = poll.set("amp_in_l")
p.callback = function(val) print("in > "..string.format("%.2f",val)) end
p.time = 0.25
p:start()
end
3 Likes
Quru
1059
I’ve been working on playable multi-scale/tuning quantizer for Norns, Crow and Grid which I am currently quite happy with. I’m not quite ready to post it on Library yet, but if anyone wants to try it’d be super helpful to get some feedback and exposing potential bugs. Norns and Crow is required, Grid is optional but very much recommended for playability. Github: GitHub - TommiQQ/qqquaint: Multi-tuning playable quantizer for Monome Norns, Crow and Grid
There’s a readme, but in a nutshell: voltage goes into crow input [1], clock/trigger goes into crow input [2], quantized notes come from crow outputs [1] (root], [2] (1st interval) and [3] (3rd interval). Triggers come from crow output [4], steps can be turned on and off. The script continuously saves 10 last note values, which can be looped. Both trigger section and saves voltages are 10 steps long because I’m a big fan of 5-step sequencer on Buchla Easel but wanted a bit more.
Grid:
I’m no programmer and the code is far from pretty, and I don’t have the knowledge or equipment to test accuracy of tuning or responses to voltages etc. but to me it sounds good and is fun to play with. I have worked on it by myself, and don’t personally know anyone with Norns, Crow and Grid to ask anyone to test it out before making it public so this is kind of a middle-step before making proper post, maybe some video etc. to Library. So if there’s anything that makes something go funny, ideas for functionality or so, I’d be glad to hear. If you have a favourite tuning/scale it’d be cool to have too. Tunings are an array within an array, I’ve put on GitHub readme how the tunings array is formatted. One thing I want to note: when looping, the note selection doesn’t work because the looped values are stored after the quantization is done, which is where note selection is checked. That’s something I might change.
Another thing, with fast stream setting there might be issues with bandwidth or something and Norns and/or Crow might get a bit choppy, and with slow stream settings at least on my setup the quantization didn’t always get on time with the clock. There’s something wrong with crow.input[n].query() call, read here ^^ crow help: norns - #185 by barksten?
Also, there’s voltage hysteresis parameter on the settings of the script, because I noted that at least my 0-CTRL doesn’t output straight zero volts even on the lowest settings, so that’s a way to put a threshold under which voltages are treated as 0V.
Big thanks if anyone has time and interest to check this out. It’s quite fun quantizer to play with, if I say so myself.
2 Likes
I definitely check it out later!
Some thoughts:
Have you considered swapping the inputs?
It’s more common to use first input for clock and second for cv.
I leave my crow pre-patched this way and it works with all the scrips I run.
1 Like
Quru
1061
If that’s kind of “standard” I will switch them up, good to know!
1 Like
I just ran into the programmatic tape issue as well. I’m working on a tape op for orca to enable playing over existing tracks with tempo lock, and some other workflows using tape bouncing. Added a note on to the github issue too.
Quick question: how does one set a param to not be mappable? I see it’s possible to query whether it’s mappable or not in the Paramset docs, but can’t see how to set that property.
Also, is it possible to make a text-type param non-editable (for use as a feedback message or instruction/extra info etc.)?
zebra
1064
The tape module is super simple and was only designed to support the uses it’s put to in the menu operations. It sounds like you have some pretty substantial and specific requirements in mind. Maybe it would be helpful to describe the functions you are wanting to implement. If it’s just playback from disk with specific timings, that’s what we have supercollider for.
(I don’t have a lot of motivation to make the Tape module fancier and no one else has stepped up to work on it.)
i’ll try and fix that bug. but buyer beware: the “fix” will involve adding a FIFO queue of commands for Tape to execute. it won’t open a new file until its done with the stop envelope. (its not polyphonic.) it won’t begin playback until its done buffering the requested file. (its not multithreaded.) so timing of new playback will not be tight. with a supercollider component you could have more explicit control over things like allocating and priming a disk streaming buffer.
create the parameter with allow_pmap=false in the args list
1 Like
Thanks @zebra. The main workflow I’m trying to implement is playing an engine live over an underlying track or loop. For example laying down an evolving beat and then improvising over it in Orca or any other sequencing app. I was thinking that an added bonus of such a workflow is that I could bounce one tape file to another every X bars and then leave softcut open for more intricate buffer manipulation duties, but I can see that might be a bridge too far.
zebra
1066
i’ll try and at least get a fix in to make the state machine not be broken - that’s no good. but yeah - i think this is always going to have some timing issues which could get pretty annoying in a heavily sequence-based environment like ORCA.
(TAPE is really two workers, a reader and a writer, which are both streaming to/from disk. it isn’t even engineered so that loop timing is consistent - there’s only one reader thread, and it has to stop playback, then seek to file start, then resume playback. seeking takes unbounded time. tighter timing can really only be acheived by using substantially more RAM and probably switching between two readers.)
1 Like