aboutsummaryrefslogtreecommitdiff
path: root/examples/luametro.pd_lua
diff options
context:
space:
mode:
Diffstat (limited to 'examples/luametro.pd_lua')
-rw-r--r--examples/luametro.pd_lua161
1 files changed, 161 insertions, 0 deletions
diff --git a/examples/luametro.pd_lua b/examples/luametro.pd_lua
new file mode 100644
index 0000000..8041e6e
--- /dev/null
+++ b/examples/luametro.pd_lua
@@ -0,0 +1,161 @@
+-- reimplementation of [metro] with a twist
+-- fbar 2007
+
+-- we need an urn:
+local urn = {}
+
+function urn.new(size)
+ assert(size > 0, "Error: size of urn must be greater than 0")
+ local t = {size=size, last=size}
+ for i=1,size do
+ t[i] = i
+ end
+ return t
+end
+
+function urn.get(u)
+ if u.last > 0 then
+ local i = math.random(u.last)
+ local res = u[i]
+ u[i] = u[u.last]
+ u.last = u.last - 1
+ return res
+ else
+ return nil
+ end
+end
+
+function urn.reset(u)
+ u.last = u.size
+ for i=1,u.size do
+ u[i] = i
+ end
+end
+
+local modes = {"alea", "series", "sequence", "rota"}
+
+local function contains(t,x)
+ for k,v in pairs(t) do
+ if v == x then return true end
+ end
+ return false
+end
+
+-- pd:
+
+local M = pd.Class:new():register("luametro")
+
+function M:initialize(name, atoms)
+ self.periods = {}
+ self.i = 1
+ self.mode = "sequence"
+ self.direction = 1
+ self.u = urn.new(math.max(1, #atoms))
+ if not self:setperiods(atoms) then return false end
+ self.inlets = 2
+ self.outlets = 2
+ return true
+end
+
+function M:postinitialize()
+ self.clock = pd.Clock:new():register(self, "tick")
+end
+
+function M:finalize()
+ self.clock:destruct()
+end
+
+function M:setperiods(periods)
+ self.periods = {}
+ for i,j in ipairs(periods) do
+ if type(j) == "number" then
+ self.periods[i] = math.max(0.01, j)
+ else
+ self:error("non-number in period list!")
+ return false
+ end
+ end
+ -- start over at front:
+ self.i = 1
+ return true
+end
+
+function M:in_2(sel, atoms)
+ if sel == "list" or sel == "float" then
+ self:setperiods(atoms)
+ end
+end
+
+function M:in_1_float(f)
+ if f ~= 0 then
+ self:tick()
+ else
+ self.clock:unset()
+ end
+end
+
+function M:in_1_bang()
+ self.i = 1
+ self:tick()
+end
+
+function M:in_1_start()
+ self.i = 1
+ self:tick()
+end
+
+function M:in_1_stop()
+ self.clock:unset()
+end
+
+function M:in_1_mode(atoms)
+ if type(atoms[1]) == "number" then
+ self.mode = modes[atoms[1]]
+ if self.mode == "series" then
+ self.u = urn.new(#self.periods)
+ end
+ self.i = 1
+ elseif type(atoms[1]) == "string" then
+ if contains(modes, atoms[1]) then
+ self.mode = atoms[1]
+ else
+ self:error("no such mode: " .. atoms[1])
+ end
+ end
+ pd.post("Mode set to: " .. self.mode)
+end
+
+
+function M:tick()
+ self:outlet(1, "bang", {})
+ -- pd.post("selection: " .. tostring(self.i))
+ if type(self.periods[self.i]) == "number" then
+ self.clock:delay(self.periods[self.i])
+ end
+ if self.mode == "sequence" then
+ self.i = self.i + 1
+ if self.i > #self.periods then
+ self.i = 1
+ self:outlet(2, "bang", {})
+ end
+ elseif self.mode == "alea" then
+ self.i = math.random(#self.periods)
+ elseif self.mode == "series" then
+ local f = urn.get(self.u)
+ if not f then
+ urn.reset(self.u)
+ f = urn.get(self.u)
+ self:outlet(2, "bang", {})
+ end
+ self.i = f
+ elseif self.mode == "rota" then
+ self.i = self.i + self.direction
+ if self.i > #self.periods or self.i < 1 then
+ self.direction = -self.direction
+ self.i = self.i + self.direction
+ self:outlet(2, "bang", {})
+ end
+ else
+ self:error("Unknown mode")
+ end
+end