as i thought about this more, my 2nd example (dumping/loading state) really needs to be merged upstream and not added as a super-complex add-on which would have to consider every particular script’s state management. so that leaves only one example i have…

yeah i think this cost is not to be underestimated. i cannot come up with more than those two examples, of which one i want to retract. i was interested in seeing whether there were many other such situations. it sounds like @DoS has another situation that could benefit from a startup script, though it sounds like a fit for .matronrc.

it seems like this idea needs many more use cases which is totally fine by me :slight_smile:

2 Likes

Absolutely agreed - the Norns dev team obviously have a huge amount to do already.

2 Likes

I’m just about to do some ropey hacking around where an app uses the MusicUtil.generate_scale_of_length() method. I really like all the scale options but often I just want to select my own notes. For this app it’s a fairly easy gaffa-tape job but it occurred to me that this is just the sort of thing that I would want in other apps and then it occurred to me that this is probably a fairly common use case for others and that there might already be a more elegant solution? If not perhaps I ought to think about how I do it so that it could live as an abstraction and just be dropped into the lib of other apps?
My strategy was to add a use_user_scale option to params and use that to switch the behaviour between normal proper scales or just reading from an array whose elements can be dialled in from params. Either initialised to a common scale or maybe to all at zero offset? I guess that the param stuff could live in the abstracted init. That way you just add an init line to the bottom of the server app init code and add the if-switch where it’s needed anywhere the MusicUtil code is called. Also the scale would be saved with your preset as the notes would all be params.
Marginally less hacky than just pasting all the code into other apps but still fairly hacky and not the most user-friendly for others to pinch and re-use. I guess the proper way to do this would be to redefine the MusicUtil methods? The cleanest option I would guess would be to add a user_scale option to the available scales? Perhaps have a sub page for the notes in params to keep it tidy?

1 Like

A vocal synth with a “speech recognition” interface. talk to your Norns and drive a synthesizer. Keep a continuous buffer/log of words to resynthesize scrambled language. Rap at it, read it a book, tell it a secret, feed it a fax

5 Likes

Some easy way to set Norns version requirement within a script would be nice. A notification would be displayed, urging the user to update their Norns.

I have seen several discussions in the script threads where people encounter bugs that are related to them not having updated the Norns. (I made the same mistake a few days back, hence this idea.) This would lessen the support workload of script developers.

6 Likes

I would like to use norns as a sound source that takes triggers from a contact mic- is this possible already? This is one way I use my modular to interact with drums- I stick a contact mic on a drum and the sound it sends is used like a trigger to strike an envelope/vca (have to boost the signal as well for this to work). I usually set up a sequence or randomized quantizer so each trigger will cycle through the sequence by a step each time its hit. Is there a way to already do this with norns/ would this be possible?

1 Like

i think this is possible with a 12 lines of code that you can add to any script you want to add this functionality:

-- listen to audio
contact_mic_threshold = 0.1 -- pretty loud
p_amp_in=poll.set("amp_in_l")
p_amp_in.time=0.05 -- 50 millisecond resolution
p_amp_in.callback=function(val)
  if val>contact_mic_threshold then 
    -- send osc to any trigger...
    osc.send({"localhost",10111},"/param/sometoggleablething",{2})
    -- send midi? send crow? or other stuff?
  end
end
p_amp_in:start()

put that at the end of a function init() and it will constantly listen for a contact mic hit and then do whatever you want (osc to trigger paramter, midi, crow, etc.)

edit: one addendum. you can actually to the above twice: once for the left channel (amp_in_l) and once for the right channel (amp_in_r). if you have two hard panned contact mics you should be able to monitor two instead of one…

13 Likes

also just crow by itself ! (assuming enough amplification)

input[n].mode( ‘peak’, threshold, hysteresis ) – set input n to:
– ‘stream’: creates an event when an audio transient is detected at the input
– threshold: sets the RMS level required to trigger an event
– hysteresis: sets how far the RMS level needs to decrease before retriggering

1 Like

Beautiful, thank you for the tips @infinitedigits and @andrew. Might have to look for a crow in the future…

I just wanted to suggest looking into the possibility of updating scripts directly from Norns, the same way as you can update the software. Obviously it will probably require a lot of software redesigning (I’m assuming that 3.0 is already quite a major redesign), but yesterday whlist rehearsing for live performance I wanted to quickly update the Cheat Codes, with no direct access to the computer and I thought it would be handy, especially for hotfixes etc.
Just to clarify, not talking about a browser of the scripts directly on norns. Just a quick fetch of updates for already downloaded scripts in the menus.

I’m not an my norns right now, but I often open a remote terminal over to my norns for whatever reasons, and there a possibility to run maiden to update installed scripts.

I meant more of a standalone solution in situation when you don’t have access to the terminal.

I am not near norns right now but updating via iPad works fine for me, not sure if a phone also works, never tried.

Guys, thank you for trying to help, but you are missing the point. It’s not really a post looking for a workaround. I’m just suggesting a feature which I guess would be useful, the same way as updating the software from norns menu.

1 Like

it’d be somewhat trivial to add a function to update a script.

but i also wanted to say: updating a script just prior to a performance seems like a very bad idea— what it a bad update was pushed?

and then we’d want another feature to “go backwards” (un-update), and then before we know it, we’re adding the whole project manager into the menu system.

2 Likes

Although I completely agree that it is too brave to update before performance I also think this is a good idea. I am often away from a laptop and don’t want to take my phone and 99% of the time I am just updating all scripts without reading release notes anyway so this will be much easier to just do it from norns.

I’m not saying to update it right before the performance, but while rehearsing. Sometimes bugfix update can fix some annoyances that you have been struggling with whlist trying out some new functions.

1 Like

understood! i can throw together a proof-of-concept

3 Likes

you could just run maiden from your phone?

1 Like

The infinitedigits solution is super tidy compared to mine but I thought I’d share this as I’ve found it really useful to allow me to have the polling set fast but not get loads of re-triggers. This one is using crow but you could just just pinch the re-trigger stuff or swap in the p_amp_in code wherever the crow stuff is. If you just need one then dump the socket stuff but you could also re-purpose that to be L/R inputs.

I’ve got this as a separate object that I can drop into the lib folder. Then you just add the include at the top of the client script, run the init at the bottom of your app’s init code, pass whatever method you want to call into the init and specify which port.
The threshold, hysteresis and hold time all come up in params so you can tweak while you tap.

I should warn you that the amplitude reading is probably not the peak. I guess it’s a trade off, if you want fast response then there’s alway the chance that you are triggering as the amplitude rises rather than at it’s peak.

Summary

– Crow Audio input driven event triggers
– Pass in callback function and it calls it with the amplitude, I think thresh->1, as the return argument
– Second init argument can be 1 or 2 or specify the input to listen to, defaults to 1.

local tr = {}
local function callback() end

local input_socket = 1

–audio input polling variables
local refresh_rate = 0.005
local amp_in = 0
local triggered = false

local hold_timer
local retrigger_hold = false

local function retriggerholdtimer()
clock.sleep(params:get(“retrigger_hold_time”)/100.0) – params map to 100ths of a second
retrigger_hold = false
end

local function triggerhold()
if retrigger_hold then – cancel the previous hold timer, edge case, prevent double offs.
clock.cancel(triggerholdtimer)
else
retrigger_hold = true
end
clock.run(retriggerholdtimer)
end

local function inputreading(amp)
amp_in = amp
–print(amp_in)
if triggered then --if we were already above theshold then see if we are now low enough to be ready for another transient
if amp_in < (params:get(“trigger_threshold”)/10) - (params:get(“trigger_hysteresis”)/10) then
triggered = false
end
elseif retrigger_hold then – if too close to a recent trigger

elseif not triggered and not retrigger_hold then – if not already above threshold or close to previous trigger
if amp_in > (params:get(“trigger_threshold”)/10) then
triggered = true
triggerhold()
print('trigger ’ … string.format("%.4f", amp_in) )
callback(amp_in)
end
end

end

function tr.init(cb, socket)
if socket == 1 then
input_socket = socket
elseif socket == 2 then
input_socket = socket
end

callback = cb
crow.input[input_socket].mode( ‘volume’, refresh_rate )
crow.input[input_socket].volume = inputreading

params:add_separator()
params:add{type = “number”, id = “trigger_threshold”, name = "trigger threshold "…input_socket, min = 10, max = 50, default = 30}
params:add{type = “number”, id = “trigger_hysteresis”, name = "trigger hysteresis "… input_socket, min = 1, max = 30, default = 10}
params:add{type = “number”, id = “retrigger_hold_time”, name = "retrigger hold time "… input_socket, min = 1, max = 30, default = 8}
end

return tr