Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Norns-Crow distributed computation library #300

Open
trentgill opened this issue Apr 10, 2020 · 4 comments
Open

Norns-Crow distributed computation library #300

trentgill opened this issue Apr 10, 2020 · 4 comments
Projects
Milestone

Comments

@trentgill
Copy link
Collaborator

@trentgill trentgill commented Apr 10, 2020

Motivation

norns scripts almost universally control crow's behaviour with direct commands being called by the active norns script. When a musician wants to have crow operate in a free-standing manner, they typically will write a script in a text editor & upload with the druid application. one goal of this issue is to unify these processes for norns users (ie, edit & upload crow-scripts from norns (via maiden)), and provide a mechanism for distributed computation on crow.

Edit & Upload

This element simply requires a bulk-upload command to be added to the norns.crow library. It just extends the current functionality of uploading short code-blocks with the appropriate upload and run commands, and some timing management to make sure buffers aren't overflowed.

  • Would be useful to decide on an idiom that allows crow scripts to be identified & not attempt to run them on norns. This could be in the crow file text itself, or in the naming of the file.

I have a working prototype of this, but it needs stress testing (hasn't been tested since crow 1.0.1).

Distributed components

This section is about a mutual library that makes distributed computation on crow work seamlessly with the existing norns platform. This is useful / meaningful in two contexts:

  • When crow locally transforms input (CV or ii) into an output response (CV or ii), with the transformation controlled remotely
  • When a crow script is configurable remotely, but should be able to continue running even if the host becomes disconnected.

A lua library is required for both norns & crow. I'm currently calling it sync but this needs to be changed. These libraries will perform a handshake when connected, maintain synchronization of shared parameters, store parameters, and gracefully handle disconnection.

norns lib

  • upload a *.lua file from the file-system to an attached crow
  • mechanism for confirming if the attached crow has already has the appropriate script running
  • parameter synchronization (see below)
  • call remote functions
  • save the current parameters into crow's non-volatile memory

crow lib

  • load saved parameters on boot, with default fallback
  • remote function declarations
  • parameter synchronization (see below)

Parameter synchronization

Consider that the params are 'owned' by crow, so:

  • On norns this is a remote parameter.
  • On crow this is a public parameter.

All actions on these parameters are just like normal lua usage, implemented with metatables, so you can assign to, and read from, a public/remote parameter regardless of which device you're on. When a param is changed it will automatically be updated on the other device (though no callback event is triggered).

Either device may declare a parameter, though the idiom shall be to declare them all in the crow init function. This is to allow crow to handle initialization from saved or default values, in lieu of an active connection to norns.

Either device may put functions into the shared table enabling the other device to call those functions.

Initially, numbers, and strings will be supported as data types. In future I'd like to add bools & flat tables, and perhaps nested tables later on.

Saving a parameter set is implemented by re-uploading the script with the list of remote params appended to the script. When crow initializes, it will check if the sync.shared table already has data, indicating the defaults should not be used.

example

This doesn't do anything interesting, but it shows the way params are handled natively in both cases (just inside the sync namespace). Demonstrates reading & updating params on both devices, calling functions on a remote device, and load/save functionality.

--- shared.lua

local remote = crow.sync.shared -- alias for readability

function init()
    -- connect to crow, check for running script & upload if not running
    -- if crow is not connected, this will be run when the connection initializes
    crow.sync.script 'shared_crow.lua' -- idiomatically the script name + _crow
end

function enc(n,d)
    if n == 2 then
        -- updating a remote variable
        remote.length = util.clamp( remote.length + d, 1, 16 )
        redraw()
    end
end

function key(n,s)
    if n==1 then
        -- save remote variables to crow's flash
        if s==1 then crow.sync.save() end
    else
        if s==1 then
            -- call a remote function
            remote.new_word(n) -- key2/3 changes lower/upper casing
        else
            -- wait for key release so remote.string should be up to date
            redraw()
        end
    end
end

function redraw()
    screen.clear()
    screen.level(15)
    screen.move(0,10)
    screen.text( remote.word )
    screen.move(20,60)
    screen.text( remote.length )
    screen.update()
end

-- FIXME should this be public.redraw?
remote.redraw = redraw -- redraw can be called by remote
--- shared_crow.lua

local public = sync.shared -- alias for readability

function init()
    -- attempt to load a saved configuration
    if not sync.load() then
        -- otherwise use the defaults defined here
        public.length = 1
        public.word   = 'sharing'
    end
end

public.new_word = function(case)
    local s = ''
    case = (case==1) and 56 or 96
    for i=1,public.length do
        s = s .. string.char(case+math.random(26))
    end
    public.word = s
    public.redraw() -- FIXME? remote.redraw?
end
@trentgill
Copy link
Collaborator Author

@trentgill trentgill commented Apr 10, 2020

Why?

I really like writing scripts that run standalone on crow, but there's a couple issues:

  • Compositional elements have to be baked into the script itself (makes sharing difficult)
  • Limited hardware IO means compositional elements are typically set in a text editor & reuploaded.

This proposed library attempts to remove the awkwardness of writing crow & norns scripts that can coexist. I specifically want to write sequencers that run on crow, but use norns as an interface into configuring that sequence (and performing other more norns-y duties).

Similarly, I'd love to build a single screen norns script that allows for configuration of the 4 output channels, triggerable/resettable by the inputs. This concept could be extended to a multi-page script with modular assignment of inputs/metros/ii to outputs/variables/ii. Currently this kind of thing is only possible with Max, or by rolling your own application from scratch.

It would also be nice to have a simple crow-script-loader on norns which can pull in the bowery scripts and select & load on-device.

Questions

  • What other use-cases are you interested in?
  • What should the names be?
  • Am I going about this the right way?
@trentgill trentgill added this to the Major milestone Jun 23, 2020
@trentgill trentgill modified the milestones: Major, 3.0 Jul 15, 2020
@trentgill trentgill added this to Major in 3.0 Jul 15, 2020
@trentgill
Copy link
Collaborator Author

@trentgill trentgill commented Jul 15, 2020

like the norns params! this is useful for the webapp idea.

@tehn has some ideas on how this can be almost identical to the params system and not need to reinvent a whole new interaction metaphor!

@tehn
Copy link
Member

@tehn tehn commented Jul 16, 2020

might actually not need something as heavy as the norns params system, but worth looking at as a reference and for potential continuity.

a super-simple approach may be something like:

param = {
  n = 5,
  triad = {1,3,7}
}

the script itself can be super simple, ie, not using get-set methods, just accessing param.n directly.

the "remote" norns script or web UI can modify a running script by simply setting the value param.n directly.

to "store" a "preset" the crow script gets rewritten with a code block at the end which sets the param table according to the current state ie

--- end of script. preset data follows:
param = {
  n = 2,
  triad = {1,5,9}
}

the remote editor/controller (which is basically reading the crow script and sending it to crow for execution) can scrape a comment to populate the UI elements:

--[
meta = {
  n = {
    type = "number",
    min = 0,
    max = 10
    },
  triad = {
    type = "numtable",
    length = 3
  }
--]

the meta table could even be auto-generated with sensible defaults by detecting just checking the type of each param entry. setting meta attributes is really for the UI component. ie, param.n would be assumed a "number" without a range.

what remains then is to identify the param types and attributes we'd like to support.

if a script doesn't have a param table it just wouldn't have any UI.

@tehn
Copy link
Member

@tehn tehn commented Jul 16, 2020

re: serial via web

https://wicg.github.io/serial/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
3.0
Major
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants