I might start a separate thread. It really might be a useful tool for a lot of Norns users to be able to easily get Norns midi in to VCV Rack with no additional parts or tools.

Thanks for the tip though!

1 Like

Messing around with triggering random samples in Ack. I’m looking for a less convoluted way of playing random samples from a directory. I’m guessing it would be more practical to do this on the supercollider end, but I’m thinking it might require some additions to the norns codebase (ParamSet:add_dir?). Has anyone else spent time doing something similar?

-- trigger random files in the same directory

engine.name = 'Ack'

local ack = require 'ack/lib/ack'

function init()
  ack:add_params()
  
  clk = metro.init()
  clk.time = 0.25
  clk.count = -1
  clk.event = tick
  clk:start()
end

function tick()
  local path = params:get("1_sample")
  local name = params:string("1_sample")
  if name ~= "-" then
    -- get parent directory of a file
    local dir = string.gsub(path, escape(name), "")
    f = GetSiblings(dir)
    engine.trig(0)
    engine.loadSample(0, f[math.random(1,#f)])
    -- print(f[math.random(1,#f)])
  end
end

function GetSiblings(path)
   local files = {}
   local tmpfile = norns.state.data.."files.txt"
   os.execute('ls -1 '..path..' > '..tmpfile)
   local f = io.open(tmpfile)
   if not f then return files end  
   local k = 1
   for line in f:lines() do
      files[k] = path..line
      k = k + 1
   end
   f:close()
   return files
 end
 
function escape (s)
  -- "606-BD.wav" -> "606%-BD%.wav"
  s = string.gsub(s, "[%p%c]", function (c)
    return string.format("%%%s", c) end)
return s end

I guess I don’t see this as particularly convoluted. You could factor some stuff out to reusable utilities to make it cleaner, and you could tidy up the file parsing and string building. I don’t see the advantage of scanning for files in the engine.

I have an issue that’s really puzzling me. Perhaps someone can look at the trimmed down code?

I am on Norns study 4/5, but this relates to study #2.
I have a table (4x4). Encoder 3 allows for value (number) selection of 1-16. Key 2 randomizes the location of the selected table values using the encoder 3 value as a maximum allowable limit. Key 2 randomizes the value and locations. So, you can either select your max value using the encoder3, or, press key 3 and it’ll choose a max value at random AND choose table selections at random. After that you could just press key 2 and it would cycle through different variations of that max value in the table. Clear as mud? Probably easier if you ran the lua example above. I should note that I tried to remove as much garbage from the posted example to highlight the issue (in case you’re wondering what I’m trying to do!).

Here are my questions:

  1. Randomization only seems to be ~ n-3(ish). For example, if the value of the encoder value is set to 8 and I press key 2, I’ll see a lot of 6-8 circles being filled in, rarely a 5, and NEVER anything lower. I can’t understand why this is happening. It can’t be random chance.

  2. When the bottom right circle is selected (location x=4 and y=4), it also lights up the text that follows it. If it’s not selected, that text doesn’t get lit up. I think I understand why this is happening (because it’s within redraw), but I’m not sure how to fix it. The code looks pretty simple in terms of selecting something within the 4x4 table, so why does it keep selecting stuff that’s outside that table? I thought I could call a second redraw but that appears to screw things up.

Apologies if my code is excruciatingly painful to look at; I’m not a coder, but I am trying to learn. I’ve mostly modified Tehn’s code and looked up Lua commands elsewhere to see what would work. Any insight would be appreciated!

I’m looking for more resources on the HID Lua api, is there any demo code out their for a touch pad or stylus? The codes come in really quick so it’s tough for me to decide the stream.

Have you already looked at my hid demo stuff?

When I tried with a Wacom tablet, it streams a pile of data. Did not get to the point of trying to use any of it though.

Yes I did thanks for sharing that. Ah so I thought maybe I was accessing the hid values from my Wacom wrong. I’d like to use my Wacom will the Norns if possible so maybe I’ll continue digging.

norns event codes follow those in libevdev.

i googled and quickly found this libevdev wrapper for wacoms. from this header:
[ https://github.com/sonologico/evtablet/blob/master/evtablet.hpp ]

i get this list of events:

type = EV_ABS:
  ABS_X
  ABS_Y
  ABS_PRESSURE
  ABS_DISTANCE

type = EV_KEY:
  BTN_TOOL_PEN
  BTN_TOOL_RUBBER
  BTN_TOUCH
  BTN_STYLUS
  BTN_STYLUS2

thank you for looking into that and sharing! I’m looking at this project too for the decoding.

Is there any way to change param options dynamically?

For example, I have multiple parameters that use the same options, and I want to prevent setting param1 to the same option as param2. Ideally I could update the options in real time, but don’t think this is currently possible?

everything is possible. could you give a more specific example?

maybe i’m misunderstanding, but it seems like you should be able to do this with variations of something like

function change_param(some_param, value) 
	if params:get(‘related_param’) ~= value then 
		params:set(‘some_param’, value)
	end
end

as far as i know you should be able to stick that kind of thing throughout the script and even in the params:set_action function and it should work?

Well, I’ve decided to take a different approach, but in this case I was trying to use the parameters menu to change the crow input event handlers. So I have something like:

  params:add_option('crow_input1', 'crow input 1', {'reverse', 'hold', 'clock'}, 1)
  params:add_option('crow_input2', 'crow input 2', {'reverse', 'hold', 'clock'}, 2)

and then the crow change events will behave differently depending on which option is selected.

I know I could check if crow_input1 is set to a given option, and then prevent crow_input2 from doing anything if it is set to the same option, but my question is if there is an easy way to literally remove that option from the list in the parameters menu for crow_input2 if it is selected for crow_input1, so it is impossible for the user to select it, and then add it back once it is deselected.

I was imagining calling something like params:update_option('crow_input1', newOptions) (which I know doesn’t exist in the current paramset API)

I’m likely overcomplicating things though, and I suppose I don’t really need to do this if I just do a similar check to what you wrote above.

I also decided I can just have both inputs use different sets of options if I don’t want them to be set to the same things, but I can imagine other use cases where the behavior I’m describing might be desirable, like having multiple modulation sources with configurable destinations where you may always want a 1-to-1 src -> destination relationship

i don’t think that will work without a lot of hacking of the option and maybe paramset internals. (e.g., option params assume that their option set will not change after instantiation.)

the action system is flexible enough to implement ‘radio groups’ pretty directly.

here’s an untested example of a helper class that modifies a list of option parameters such that when any one is updated, any other that shares the new selection will update to select an arbitrary ‘fallback’ value.

RadioParams = {}

-- create a new radio parameters group
-- @param params: list of option parameter specs that you want to 'radioize'
-- @param fallback: "none" or "deselected" index to fall back on
-- @return: list of parameter specs with updated action funcs

RadioParams.add_params = function(opts, params)
   local n = #params
   for local i=1..n do
      local act = params[i].action
      -- create a wrapper function that checks all the other params in the group
      params[i].action = function(x)
	 -- check if any of the other params is equal to `x`
	 for local j=1..n do	   
	    if params[j]:get() == x then
	       -- if so, set that param to the "fallback" value
	       params[j]:set(fallback)
	       act(x)
	    end
	 end
      end	    
   end
   return params
end


return RadioParams
2 Likes

thanks for that! the “fallback” approach is a good solution for this, and I’ll likely end up using it in the future.

Hi :slight_smile:

I’m back with more silly questions, but this time I feel like I once knew the answer but I’ve looked everywhere and can’t find where the answer was, this thread is a monster.

I was wondering,

Is it possible to connect the norns via usb and have it being detected as a midi device?

And listen to the incoming midi events?

Right now I open a serial connection and send UDP events which are basically midi data, but it feels really silly, ideally if I could have the norns show up as a midi device when I connect it to my computer, that would be huge for me.

the only thing norns can be via the mini-usb power connector is a usb-tty interface (because it has an FTDI uart on the hardware).

one solution to do what you want is to use a midi host-host solution… there are a few threads here about this.

edit for link: How to sync two USB MIDI hosts

aaah right, I wasn’t sure if it was possible or not, but yes I remember now that usb-tty is all that’s allowed ever at once.

I don’t want more midi dongle bits right now.
Thanks for the quick answer!

you could hack a couple programs together to connect via tty and convert midi… but it wouldn’t be a class compliant solution

That’s pretty much what I do at the moment, I have a python udp listener that just passes the 3 midi bites over to the repl.

1 Like