Skip to content

Instantly share code, notes, and snippets.

@cfdrake
Created August 11, 2021 19:43
Show Gist options
  • Save cfdrake/a0312eaff1d892d745aedb14a846888e to your computer and use it in GitHub Desktop.
Save cfdrake/a0312eaff1d892d745aedb14a846888e to your computer and use it in GitHub Desktop.
wrms + passersby
--
-- wrms/lite
--
-- simple stereo delay & looper
--
-- version 2.0.0 @andrew
-- https://norns.community/
-- authors/andrew/
-- wrms#wrmslite
--
-- E1 changes which page
-- is displayed. pages contain
-- controls, mapped to the
-- lower keys and encoders.
-- the location of the control
-- (left, right, center)
-- shows which wrm will be
-- affected.
--
-- wrm 1 (on the left) is a delay
-- & wrm 2 (on the right) is a
-- live looper. feed the wrms
-- some audio to begin exploring!
-- tap K3 once to begin
-- recording a loop, then again
-- to begin playback.
--
-- for documentation of each
-- control, head to:
-- https://norns.community/
-- authors/andrew/
-- wrms#wrmslite
local MusicUtil = require "musicutil"
local Passersby = include("passersby/lib/passersby_engine")
engine.name = "Passersby"
function r() norns.script.load(norns.script.state) end
--external libs
include 'wrms/lib/nest/core'
include 'wrms/lib/nest/norns'
include 'wrms/lib/nest/txt'
cartographer, Slice = include 'wrms/lib/cartographer/cartographer'
crowify = include 'wrms/lib/crowify/lib/crowify' .new(0.01)
cs = require 'controlspec'
wrms = include 'wrms/lib/globals' --saving, loading, values, etc
sc, reg = include 'wrms/lib/softcut' --softcut utilities
wrms.gfx = include 'wrms/lib/graphics' --graphics & animations
include 'wrms/lib/params' --create params
local x, y = wrms.pos.x, wrms.pos.y
local _rec = function(i)
return _txt.key.toggle {
n = 2, x = x[i][1], y = y.key,
label = 'rec', edge = 'falling',
v = function() return params:get('rec '..i) end,
action = function(s, v, t)
if t < 0.5 then params:set('rec '..i, v)
else params:delta('clear '..i, 1) end
end
}
end
local _trans = function(i, o)
return _txt.key.trigger {
label = { '<<', '>>' },
edge = 'falling',
blinktime = 0.2,
n = { 2, 3 },
y = y.key, x = { { x[i][1] }, { x[i][2] } },
action = function(s, v, t, d, add, rem, l)
s.blinktime = sc.slew(i, t[add]) / 2
if #l == 2 then
params:set('dir '..i, params:get('dir '..i)==1 and 2 or 1)
else
params:delta('oct '..i, add==2 and 1 or -1)
end
end
} :merge(o)
end
--the wrmslite template
wrms_ = nest_ {
gfx = _screen {
redraw = wrms.gfx.draw
},
tab = _txt.enc.option {
n = 1, x = x.tab, y = y.tab, sens = 0.5, align = sh and 'right' or 'left', margin = 2,
flow = 'y', options = { 1, 2, 3 },
lvl = { 4, 15 }
},
pages = nest_ {
[1] = nest_ {
v = _txt.enc.control {
n = 2, x = x[1][1], y = y.enc,
} :param('vol 1'),
l = _txt.enc.number {
min = 0, max = math.huge, inc = 0.01,
n = 3, x = x[1][2], y = y.enc, step = 1/100/100/100,
value = function() return reg.play:get_length(1) end,
sens = function(s)
return sc.punch_in[sc.buf[1]].big and (
s.p_.v <= 0.00019 and 1/100/100 or s.p_.v <= 0.019 and 1/100 or 1
) or 1
end,
action = function(s, v)
reg.play:set_length(1, v)
if v > 0 and not sc.punch_in[sc.buf[1]].recorded then
params:set('rec 1', 1, true)
sc.punch_in:manual(1)
end
sc.punch_in:big(1, v)
sc.fade(1, v)
sc.punch_in:untap(1)
end
},
rec = _rec(2)
},
[2] = nest_ {
old = nest_(2):each(function(i)
return _txt.enc.control {
n = i + 1, x = x[i][1], y = y.enc, label = 'old'
} :param('old '..i)
end),
rec = _rec(2)
},
[3] = nest_ {
bnd = _txt.enc.control {
n = 2, x = x[1][1], y = y.enc, label = 'bnd',
min = -1, max = 1,
action = function(s, v)
sc.ratemx[1].bnd = v + 1
sc.ratemx:update(1)
end
},
wgl = _txt.enc.control {
n = 3, x = x[1.5], y = y.enc
} :param('wgl'),
trans = _trans(2, {})
}
} :each(function(k, v)
v.enabled = function(s) return wrms_.tab.options[wrms_.tab.v//1] == k end
end)
} :connect { screen = screen, enc = enc, key = key }
function init()
params:set('>', 0)
params:set('<', 1)
params:set('input routing', 2)
wrms.setup()
params:read()
wrms.load()
params:bang()
wrms_:init()
pb_init()
end
local function note_on(note_num, vel)
engine.noteOn(note_num, MusicUtil.note_num_to_freq(note_num), vel)
table.insert(active_notes, note_num)
input_indicator_active = true
screen_dirty = true
end
local function note_off(note_num)
engine.noteOff(note_num)
for i = #active_notes, 1, -1 do
if active_notes[i] == note_num then
table.remove(active_notes, i)
end
end
if #active_notes == 0 then
input_indicator_active = false
screen_dirty = true
end
end
local function set_pitch_bend(bend_st)
engine.pitchBendAll(MusicUtil.interval_to_ratio(bend_st))
end
local function set_channel_pressure(pressure)
engine.pressureAll(pressure)
end
local function set_channel_timbre(value)
engine.timbreAll(value)
timbre = value * 0.5
wave_folds.dirty = true
end
local function midi_event(data)
local msg = midi.to_msg(data)
local channel_param = params:get("midi_channel")
if channel_param == 1 or (channel_param > 1 and msg.ch == channel_param - 1) then
-- Note on
if msg.type == "note_on" then
note_on(msg.note, msg.vel / 127)
-- Note off
elseif msg.type == "note_off" then
note_off(msg.note)
-- Pitch bend
elseif msg.type == "pitchbend" then
local bend_st = (util.round(msg.val / 2)) / 8192 * 2 -1 -- Convert to -1 to 1
set_pitch_bend(bend_st * params:get("bend_range"))
-- Pressure
elseif msg.type == "channel_pressure" or msg.type == "key_pressure" then
set_channel_pressure(msg.val / 127)
end
end
end
function pb_init()
midi_in_device = midi.connect(1)
midi_in_device.event = midi_event
params:add_separator("Passersby")
Passersby.add_params()
end
function cleanup()
-- wrms.save()
params:write()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment