Large diffs are not rendered by default.

@@ -1,7 +1,7 @@
local m = {
pos = 1,
list = {"AUDIO > ", "DEVICES > ", "WIFI >", "RESET", "UPDATE"},
pages = {"AUDIO", "DEVICES", "WIFI", "RESET", "UPDATE"}
list = {"DEVICES > ", "WIFI >", "RESET", "UPDATE"},
pages = {"DEVICES", "WIFI", "RESET", "UPDATE"}
}

m.key = function(n,z)
@@ -399,12 +399,13 @@ _norns.midi.event = function(id, data)
if d.port and Midi.vports[d.port].event then
Midi.vports[d.port].event(data)
end

-- hack = send all midi to menu for param-cc-map
norns.menu_midi_event(data, d.port)
else
error('no entry for midi '..id)
end

-- hack = send all midi to menu for param-cc-map
norns.menu_midi_event(data)
end

return Midi
@@ -0,0 +1,31 @@
-- Group class
-- @module group

local Group = {}
Group.__index = Group

local tGROUP = 7

function Group.new(name, n)
local g = setmetatable({}, Group)
g.name = name or "group"
g.n = n or 1
g.t = tGROUP
g.action = function() end
return g
end

function Group:get()
return self.n
end

function Group:set(v) end
function Group:delta(d) end
function Group:set_default() end
function Group:bang() end

function Group:string()
return self.name
end

return Group
@@ -53,5 +53,10 @@ function Number:string()
end
end

function Number:get_range()
local r = { self.min, self.max }
return r
end


return Number
@@ -55,5 +55,10 @@ function Option:string()
return self.options[self.selected]
end

function Option:get_range()
local r = { 1, self.count }
return r
end


return Option
@@ -6,8 +6,9 @@ Separator.__index = Separator

local tSEPARATOR = 0

function Separator.new()
function Separator.new(name)
local s = setmetatable({}, Separator)
s.name = name or ""
s.t = tSEPARATOR
s.action = function() end
return s
@@ -23,7 +24,7 @@ function Separator:set_default() end
function Separator:bang() end

function Separator:string()
return "---"
return self.name
end

return Separator
@@ -0,0 +1,49 @@
-- Text class
-- @module Text

local Text = {}
Text.__index = Text

local tText = 8

function Text.new(id, name, text)
local o = setmetatable({}, Text)
o.t = tText
o.id = id
o.name = name
o.text = text or ""
o.action = function() end
return o
end

function Text:get()
return self.text
end

function Text:set(v, silent)
local silent = silent or false
if self.text ~= v then
self.text = v
if silent==false then self:bang() end
end
end

function Text:delta(d)
--noop
end

function Text:set_default()
--noop
end

function Text:bang()
self.action(self.text)
end

function Text:string()
-- any formatting here? concat?
return self.text
end


return Text
@@ -8,6 +8,8 @@ local control = require 'core/params/control'
local file = require 'core/params/file'
local taper = require 'core/params/taper'
local trigger = require 'core/params/trigger'
local group = require 'core/params/group'
local text = require 'core/params/text'

local ParamSet = {
tSEPARATOR = 0,
@@ -17,6 +19,8 @@ local ParamSet = {
tFILE = 4,
tTAPER = 5,
tTRIGGER = 6,
tGROUP = 7,
tTEXT = 8,
sets = {}
}

@@ -31,15 +35,33 @@ function ParamSet.new(id, name)
ps.name = name or ""
ps.params = {}
ps.count = 0
ps.hidden = {}
ps.lookup = {}
ps.group = 0
ParamSet.sets[ps.id] = ps
return ps
end

--- add separator.
function ParamSet:add_separator()
table.insert(self.params, separator.new())
function ParamSet:add_separator(name)
local param = separator.new(name)
table.insert(self.params, param)
self.count = self.count + 1
self.group = self.group - 1
self.hidden[self.count] = false
end

--- add group.
function ParamSet:add_group(name,n)
if self.group < 1 then
local param = group.new(name,n)
table.insert(self.params, param)
self.count = self.count + 1
self.group = n
self.hidden[self.count] = false
else
print("ERROR: paramset cannot nest GROUPs")
end
end

--- add generic parameter.
@@ -73,6 +95,8 @@ function ParamSet:add(args)
param = taper.new(id, name, args.min, args.max, args.default, args.k, args.units)
elseif args.type == "trigger" then
param = trigger.new(id, name)
elseif args.type == "text" then
param = text.new(id, name, args.text)
else
print("paramset.add() error: unknown type")
return nil
@@ -81,7 +105,9 @@ function ParamSet:add(args)

table.insert(self.params, param)
self.count = self.count + 1
self.group = self.group - 1
self.lookup[param.id] = self.count
self.hidden[self.count] = false
if args.action then
param.action = args.action
end
@@ -124,6 +150,11 @@ function ParamSet:add_file(id, name, path)
self:add { param=file.new(id, name, path) }
end

--- add text.
function ParamSet:add_text(id, name, txt)
self:add { param=text.new(id, name, txt) }
end

--- add taper.
-- @tparam string id
-- @tparam string name
@@ -156,7 +187,13 @@ end
--- name.
-- @tparam number index
function ParamSet:get_name(index)
return self.params[index].name
return self.params[index].name or ""
end

--- id.
-- @tparam number index
function ParamSet:get_id(index)
return self.params[index].id
end

--- string.
@@ -217,9 +254,37 @@ end
--- get type.
-- @param index
function ParamSet:t(index)
return self.params[index].t
local param = self:lookup_param(index)
return param.t
end

--- get range
-- @param index
function ParamSet:get_range(index)
local param = self:lookup_param(index)
return param:get_range()
end


--- set visibility to hidden.
-- @param index
function ParamSet:hide(index)
self.hidden[index] = true
end

--- set visiblility to show.
-- @param index
function ParamSet:show(index)
self.hidden[index] = false
end

--- get visibility.
-- @param index
function ParamSet:visible(index)
return self.hidden[index]
end


local function quote(s)
return '"'..s:gsub('"', '\\"')..'"'
end
@@ -240,59 +305,60 @@ end

--- write to disk.
-- @param filename either an absolute path, a number (to write [scriptname]-[number].pset to local data folder) or nil (to write default [scriptname].pset to local data folder)
function ParamSet:write(filename)
filename = filename or 0
function ParamSet:write(filename, name)
filename = filename or 1
if type(filename) == "number" then
local n = filename
filename = norns.state.data .. norns.state.shortname
if n > 0 then
filename = filename .. "-" .. string.format("%02d",n)
end
filename = filename .. ".pset"
filename = filename .. "-" .. string.format("%02d",n) .. ".pset"
end
print("pset >> write: "..filename)
local fd = io.open(filename, "w+")
io.output(fd)
for _,param in pairs(self.params) do
if param.id and param.t ~= self.tTRIGGER then
io.write(string.format("%s: %s\n", quote(param.id), param:get()))
if fd then
io.output(fd)
if name then io.write("-- "..name.."\n") end
for _,param in pairs(self.params) do
if param.id and param.t ~= self.tTRIGGER then
io.write(string.format("%s: %s\n", quote(param.id), param:get()))
end
end
end
io.close(fd)
io.close(fd)
else print("pset: BAD FILENAME") end
end

--- read from disk.
-- @param filename either an absolute path, number (to read [scriptname]-[number].pset from local data folder) or nil (to read default [scriptname].pset from local data folder)
function ParamSet:read(filename)
filename = filename or 0
filename = filename or 1
if type(filename) == "number" then
local n = filename
filename = norns.state.data .. norns.state.shortname
if n > 0 then
filename = filename .. "-" .. string.format("%02d",n)
end
filename = filename .. ".pset"
filename = filename .. "-" .. string.format("%02d",n) .. ".pset"
end
print("pset >> read: " .. filename)
local fd = io.open(filename, "r")
if fd then
io.close(fd)
for line in io.lines(filename) do
local id, value = string.match(line, "(\".-\")%s*:%s*(.*)")

if id and value then
id = unquote(id)
local index = self.lookup[id]

if index and self.params[index] then
if tonumber(value) ~= nil then
self.params[index]:set(tonumber(value))
elseif value == "-inf" then
self.params[index]:set(-math.huge)
elseif value == "inf" then
self.params[index]:set(math.huge)
elseif value then
self.params[index]:set(value)
if util.string_starts(line, "--") then
params.name = string.sub(line, 4, -1)
else
local id, value = string.match(line, "(\".-\")%s*:%s*(.*)")

if id and value then
id = unquote(id)
local index = self.lookup[id]

if index and self.params[index] then
if tonumber(value) ~= nil then
self.params[index]:set(tonumber(value))
elseif value == "-inf" then
self.params[index]:set(-math.huge)
elseif value == "inf" then
self.params[index]:set(math.huge)
elseif value then
self.params[index]:set(value)
end
end
end
end
@@ -0,0 +1,109 @@
-- parameter map

local pmap = {
data = {},
rev = {}
}

pmap.__index = pmap

function pmap.new(id)
local p = setmetatable({}, pmap)
p.cc = 100
p.ch = 1
p.dev = 1
p.in_lo = 0
p.in_hi = 127
p.out_lo = 0
p.out_hi = 1
p.accum = false
p.value = 0
pmap.data[id] = p
end

function pmap.remove(id)
local p = pmap.data[id]
if p then pmap.rev[p.dev][p.ch][p.cc] = nil end
pmap.data[id] = nil
end

function pmap.assign(id, dev, ch, cc)
local prev = pmap.rev[dev][ch][cc]
if prev and prev ~= id then
pmap.remove(prev) end
local p = pmap.data[id]
pmap.rev[p.dev][p.ch][p.cc] = nil
p.dev=dev
p.ch=ch
p.cc=cc
pmap.rev[dev][ch][cc] = id
end

function pmap.refresh()
for k,v in pairs(pmap.data) do
pmap.rev[v.dev][v.ch][v.cc] = k
end
end

function pmap.clear()
pmap.data = {}
pmap.rev = {}
-- build reverse lookup table: dev -> ch -> cc
for i=1,4 do
pmap.rev[i]={}
for n=1,16 do
pmap.rev[i][n]={}
end
end
end

function pmap.write()
local function quote(s)
return '"'..s:gsub('"', '\\"')..'"'
end
local filename = norns.state.data..norns.state.shortname..".pmap"
print(">> saving PMAP "..filename)
local fd = io.open(filename, "w+")
io.output(fd)
local line = ""
for k,v in pairs(pmap.data) do
line = string.format('%s:"{', quote(tostring(k)))
for x,y in pairs(v) do
line = line..x.."="..tostring(y)..", "
end
line = line:sub(1,-3)..'}"\n'
--print(line)
io.write(line)
line=""
end
io.close(fd)
end

function pmap.read()
local function unquote(s)
return s:gsub('^"', ''):gsub('"$', ''):gsub('\\"', '"')
end
local filename = norns.state.data..norns.state.shortname..".pmap"
print(">> reading PMAP "..filename)
local fd = io.open(filename, "r")
if fd then
io.close(fd)
for line in io.lines(filename) do
--local name, value = string.match(line, "(\".-\")%s*:%s*(.*)")
local name, value = string.match(line, "(\".-\")%s*:%s*(.*)")
if name and value and tonumber(value)==nil then
--print(unquote(name) .. " : " .. unquote(value))
local x = load("return "..unquote(value))
pmap.data[unquote(name)] = x()
end
end
pmap.refresh()
else
print("m.read: "..filename.." not read.")
end
end


pmap.clear()

return pmap
@@ -70,6 +70,9 @@ Script.clear = function()

-- clear params
params:clear()
norns.pmap.clear()
-- add audio
audio.add_params()

-- reset PLAY mode screen settings
local status = norns.menu.status()
@@ -178,6 +181,7 @@ Script.run = function()
else
engine.load("None", Script.init)
end
norns.pmap.read() -- load parameter map
end

--- load script metadata.
@@ -25,6 +25,7 @@ controlspec = require 'core/controlspec'
paramset = require 'core/paramset'
params = paramset.new()
mix = require 'core/mix'
norns.pmap = require 'core/pmap'


-- load menu