aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-01-31 18:28:10 +0000
committers-ol <s-ol@users.noreply.github.com>2020-01-31 18:28:10 +0000
commit16962e1836251526fa08895b1a76dd72b7fd5ef9 (patch)
treeef60d08e792825407d41fb77c14c26ecb135e2fc
parentnested parens in comments (diff)
downloadalive-16962e1836251526fa08895b1a76dd72b7fd5ef9.tar.gz
alive-16962e1836251526fa08895b1a76dd72b7fd5ef9.zip
modularize
-rw-r--r--ast.moon10
-rw-r--r--base.moon8
-rw-r--r--boot.lua22
-rw-r--r--conf.lua3
-rw-r--r--copilot.moon12
-rw-r--r--gui.moon85
-rw-r--r--init.moon34
-rw-r--r--lib/debug.moon12
-rw-r--r--lib/gui.moon45
-rw-r--r--lib/math.moon68
-rw-r--r--lib/time.moon33
-rw-r--r--lib/util.moon13
-rw-r--r--main.lua5
-rw-r--r--main.moon19
-rw-r--r--old_base.moon70
-rw-r--r--registry.moon26
-rw-r--r--test.alv31
17 files changed, 265 insertions, 231 deletions
diff --git a/ast.moon b/ast.moon
index cfa51df..b6be5f5 100644
--- a/ast.moon
+++ b/ast.moon
@@ -1,4 +1,4 @@
-import Constant from require 'base'
+import Const from require 'base'
unpack or= table.unpack
unescape = (str) ->
@@ -9,7 +9,7 @@ unescape = (str) ->
class Atom
new: (@raw, @style='', value) =>
- @value = Constant value
+ @value = Const value
_walk_sexpr: =>
@@ -81,7 +81,11 @@ class Xpr
make_nexpr: (parts) -> Xpr parts, 'naked'
- __tostring: => @stringify!
+ __tostring: =>
+ if @tag
+ "<Xpr[#{@tag}] #{@value}>"
+ else
+ "<Xpr #{@value}>"
{
:Atom
diff --git a/base.moon b/base.moon
index 4fc2c98..acade78 100644
--- a/base.moon
+++ b/base.moon
@@ -1,11 +1,11 @@
-class Constant
+class Const
new: (@value) =>
get: => @value
getc: => @value
__tostring: => "<const: #{@value}>"
-class OP
+class Op
new: (@node) =>
@setup @node\tail!
@@ -27,6 +27,6 @@ class OP
cls.__base.__tostring = @__tostring
{
- :Constant
- :OP
+ :Const
+ :Op
}
diff --git a/boot.lua b/boot.lua
deleted file mode 100644
index 4226cba..0000000
--- a/boot.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'moonscript'
-
-MODS = MODS or {}
--- table.insert(MODS, 'base')
--- table.insert(MODS, 'debug')
--- table.insert(MODS, 'math')
--- table.insert(MODS, 'time')
-
-for _,mod in ipairs(MODS) do
- package.loaded[mod] = nil
-end
-for _,mod in ipairs(MODS) do
- require(mod)
-end
-for k,v in pairs(require 'base') do
- _G[k] = v
-end
-
-function reload()
- package.loaded.boot = nil
- require 'boot'
-end
diff --git a/conf.lua b/conf.lua
new file mode 100644
index 0000000..8f46767
--- /dev/null
+++ b/conf.lua
@@ -0,0 +1,3 @@
+function love.conf(t)
+ t.window.resizable = true
+end
diff --git a/copilot.moon b/copilot.moon
index 88aa8fa..d0dec92 100644
--- a/copilot.moon
+++ b/copilot.moon
@@ -20,17 +20,21 @@ class Copilot
error "not a file: #{@file}"
patch: =>
+ root = assert (program\match slurp @file), "parse error"
+ @registry\patch_root root
+ spit @file, root\stringify!
+
+ poll: =>
{ :mode, :modification } = (lfs.attributes @file) or {}
if mode != 'file'
return
if @last_modification < modification
print "---"
+ ok, err = pcall @patch, @
+ if not ok
+ print "ERROR: #{err}"
- root = assert (program\match slurp @file), "error parsing"
- @registry\patch_root root
-
- spit @file, root\stringify!
@last_modification = os.time!
:Copilot
diff --git a/gui.moon b/gui.moon
deleted file mode 100644
index 804e212..0000000
--- a/gui.moon
+++ /dev/null
@@ -1,85 +0,0 @@
-{ graphics: lg } = love
-import Registry from require 'registry'
-import Copilot from require 'copilot'
-import Constant, OP from require 'base'
-
-env = Registry!
-copilot = Copilot arg[#arg], env
-
-env.globals.lfo = class LFO extends OP
- tau = math.pi * 2
- new: (...) =>
- super ...
- @phase = 0
-
- setup: (@speed, @wave=Constant 'sin') =>
-
- update: (dt) =>
- @phase += dt * @speed\get!
- @value = switch @wave\get!
- when 'sin' then .5 + .5 * math.cos @phase * tau
- when 'saw' then @phase % 1
- when 'tri' then math.abs (2*@phase % 2) - 1
- else error "unknown wave type"
-
-env.globals.tick = class Tick extends OP
- new: (...) =>
- super ...
- @phase = 0
-
- setup: (@speed, @wave=Constant 'sin') =>
-
- update: (dt) =>
- @phase += dt / @speed\get!
- @value = math.floor @phase
-
-env.globals.pick = class Pick extends OP
- setup: (@i, ...) =>
- @choices = { ... }
-
- update: =>
- i = 1 + (math.floor @i\get!) % #@choices
- @value = @choices[i]\get!
-
-env.globals.mix = class Mix extends OP
- setup: (@a, @b, @i) =>
-
- update: (dt) =>
- i = @i\get!
- @value = i*@b\get! + (1-i)*@a\get!
-
-env.globals['gui/out'] = class Out extends OP
- setup: (name, @chld) =>
- @@instances[@name] = nil if @name
- @name = name\getc!
- @@instances[@name] = @
-
- update: =>
- @value = @chld\get!
-
- destroy: =>
- @@instances[@name] = nil
-
- MARGIN = 16
- WIDTH = 24
- HEIGHT = 120
- @instances: {}
- @draw_all: ->
- outs = [name for name in pairs @@instances]
- table.sort outs
-
- x = MARGIN
- lg.setColor 1, 1, 1
- for name in *outs
- value = @@instances[name].value * HEIGHT
- lg.rectangle 'line', x, MARGIN, WIDTH, HEIGHT
- lg.rectangle 'fill', x, MARGIN + HEIGHT - value, WIDTH, value
- lg.print name, x, MARGIN + HEIGHT + MARGIN
- x += WIDTH + MARGIN
-
-love.update = (dt) ->
- copilot\patch!
- env\update dt
-
-love.draw = ->
- Out.draw_all!
diff --git a/init.moon b/init.moon
new file mode 100644
index 0000000..c028e50
--- /dev/null
+++ b/init.moon
@@ -0,0 +1,34 @@
+import Registry from require 'registry'
+
+env = Registry!
+env\add_module 'math'
+env\add_module 'time'
+env\add_module 'util'
+env\add_module 'debug'
+
+if ... == 'init'
+ return env
+
+-- run from CLI
+import clock_gettime, nanosleep, CLOCK_MONOTONIC from require 'posix.time'
+import Copilot from require 'copilot'
+
+delta = do
+ gettime = ->
+ spec = clock_gettime CLOCK_MONOTONIC
+ spec.tv_sec + spec.tv_nsec * 1e-9
+
+ local last, time
+ ->
+ time = gettime!
+ with time - (last or time)
+ last = time
+
+copilot = Copilot arg[1], env
+while true
+ copilot\poll!
+
+ dt = delta!
+ env\update dt
+
+ assert nanosleep tv_sec: 0, tv_nsec: math.floor 1e9 / 60
diff --git a/lib/debug.moon b/lib/debug.moon
new file mode 100644
index 0000000..c2d0d52
--- /dev/null
+++ b/lib/debug.moon
@@ -0,0 +1,12 @@
+import Op from require 'base'
+
+class out extends Op
+ setup: (name, @chld) =>
+ @name = name\getc!
+
+ update: =>
+ print "#{@name} << ", @chld\get!
+
+{
+ :out
+}
diff --git a/lib/gui.moon b/lib/gui.moon
new file mode 100644
index 0000000..979854f
--- /dev/null
+++ b/lib/gui.moon
@@ -0,0 +1,45 @@
+{ graphics: lg } = love
+import Op from require 'base'
+import Copilot from require 'copilot'
+
+class out extends Op
+ setup: (name, @chld) =>
+ @@instances[@name] = nil if @name
+ @name = name\getc!
+ @@instances[@name] = @
+
+ update: =>
+ @value = @chld\get!
+
+ destroy: =>
+ @@instances[@name] = nil
+
+ MARGIN = 16
+ WIDTH = 24
+ HEIGHT = 120
+ @instances: {}
+ @draw_all: ->
+ outs = [name for name in pairs @@instances]
+ table.sort outs
+
+ x = MARGIN
+ lg.setColor 1, 1, 1
+ for name in *outs
+ value = @@instances[name].value * HEIGHT
+ lg.rectangle 'line', x, MARGIN, WIDTH, HEIGHT
+ lg.rectangle 'fill', x, MARGIN + HEIGHT - value, WIDTH, value
+ lg.print name, x, MARGIN + HEIGHT + MARGIN
+ x += WIDTH + MARGIN
+
+copilot = Copilot arg[#arg], env
+
+love.update = (dt) ->
+ copilot\poll!
+ env\update dt
+
+love.draw = ->
+ out.draw_all!
+
+{
+ :out
+}
diff --git a/lib/math.moon b/lib/math.moon
new file mode 100644
index 0000000..8ada38a
--- /dev/null
+++ b/lib/math.moon
@@ -0,0 +1,68 @@
+import Op from require 'base'
+unpack or= table.unpack
+
+class BinOp extends Op
+ setup: (...) =>
+ @children = { ... }
+ assert #@children >= 2, "#{@} needs at least two parameters"
+
+class add extends BinOp
+ update: =>
+ @value = 0
+ for child in *@children
+ @value += child\get!
+
+class sub extends BinOp
+ update: =>
+ @value = @children[1]\get!
+ for child in *@children[2,]
+ @value -= child\get!
+
+class mul extends BinOp
+ update: =>
+ @value = 1
+ for child in *@children
+ @value *= child\get!
+
+class div extends BinOp
+ update: =>
+ @value = @children[1]\get!
+ for child in *@children[2,]
+ @value /= child\get!
+
+func_op = (name, arity, func) ->
+ k = class extends Op
+ setup: (...) =>
+ @params = { ... }
+ if arity != '*'
+ assert #@params == arity, "#{@} needs exactly #{arity} parameters"
+
+ update: =>
+ @value = func unpack [param\get! for param in *@params]
+
+ k.__name = name
+ k
+
+module = {
+ :add, '+': add
+ :sub, '-': sub
+ :mul, '*': mul
+ :div, '/': div
+
+ mix: func_op 'mix', 3, (a, b, i) -> i*b + (1-i)*a
+}
+
+for name, arity in pairs {
+ exp: 1, log: 2, log10: 1, sqrt: 1
+
+ cos: 1, sin: 1, tan: 1
+ asin: 1, acos: 1, atan: 1, atan2: 2
+ sinh: 1, cosh: 1, tanh: 1
+
+ min: '*', max: '*'
+
+ floor: 1, ceil: 1, abs: 1
+}
+ module[name] = func_op name, arity, math[name]
+
+module
diff --git a/lib/time.moon b/lib/time.moon
new file mode 100644
index 0000000..f2ad70c
--- /dev/null
+++ b/lib/time.moon
@@ -0,0 +1,33 @@
+import Op, Const from require 'base'
+
+class lfo extends Op
+ tau = math.pi * 2
+ new: (...) =>
+ super ...
+ @phase = 0
+
+ setup: (@freq, @wave=Const 'sin') =>
+
+ update: (dt) =>
+ @phase += dt * @freq\get!
+ @value = switch @wave\get!
+ when 'sin' then .5 + .5 * math.cos @phase * tau
+ when 'saw' then @phase % 1
+ when 'tri' then math.abs (2*@phase % 2) - 1
+ else error "unknown wave type"
+
+class tick extends Op
+ new: (...) =>
+ super ...
+ @phase = 0
+
+ setup: (@freq) =>
+
+ update: (dt) =>
+ @phase += dt / @freq\get!
+ @value = math.floor @phase
+
+{
+ :lfo
+ :tick
+}
diff --git a/lib/util.moon b/lib/util.moon
new file mode 100644
index 0000000..7306fbc
--- /dev/null
+++ b/lib/util.moon
@@ -0,0 +1,13 @@
+import Op from require 'base'
+
+class pick extends Op
+ setup: (@i, ...) =>
+ @choices = { ... }
+
+ update: =>
+ i = 1 + (math.floor @i\get!) % #@choices
+ @value = @choices[i]\get!
+
+{
+ :pick
+}
diff --git a/main.lua b/main.lua
index 2bb6e04..b5a9d4a 100644
--- a/main.lua
+++ b/main.lua
@@ -1,2 +1,3 @@
-MODS = {'gui'}
-require 'boot'
+require 'moonscript'
+env = require 'init'
+env:add_module 'gui'
diff --git a/main.moon b/main.moon
deleted file mode 100644
index 9d15f34..0000000
--- a/main.moon
+++ /dev/null
@@ -1,19 +0,0 @@
-sleep = require 'sleep'
-import Copilot from require 'copilot'
-
-class Environment
- spawn: (sexpr) =>
- print "spawning [#{sexpr.tag}]"
-
- patch: (new, old) =>
- -- print "patching [#{new.tag}]"
-
- destroy: (sexpr) =>
- print "destroying [#{sexpr.tag}]"
-
-env = Environment!
-copilot = Copilot arg[1], env
-
-while True
- sleep 0.01
- copilot\patch!
diff --git a/old_base.moon b/old_base.moon
deleted file mode 100644
index 950ea16..0000000
--- a/old_base.moon
+++ /dev/null
@@ -1,70 +0,0 @@
-DISP, OP, OUT = {}, {}, {}
-
-class Value
- new: (@value) =>
-
- __tostring: => "<value: #{@value}>"
-
-class Dispatcher
- new: =>
- @operators = {}
-
- dispatch: (...) =>
- for op in pairs @operators
- op\dispatch ...
- op\update!
-
- register: (op, params=true) =>
- @operators[op] = params
-
- unregister: (op) =>
- @operators[op] = nil
-
-class Op
- new: (opts={}, defaults) =>
- assert defaults, "OP-def needs default arguments"
- for k,v in pairs defaults
- @[k] = opts[k] or v
-
- @parents = 0
- @setup!
-
- setup: =>
- destroy: =>
- update: => -- return current value (pure)
-
- mount: (lastval) =>
- @parents += 1
-
- if lastval and @parents == 1
- @setup lastval
-
- unmount: =>
- @parents -= 1
- if @parents == 0
- @destroy!
-
-class Out
- new: (@handle) =>
- @values = {}
- @mapping = {}
-
- __call: (key, op) =>
- if @mapping[key]
- @mapping[key]\unmount!
-
- @mapping[key] = op
- @mapping[key]\mount @values[key]
-
- update: =>
- for key, op in pairs @mapping
- @values[key] = op\update!
-
- @handle! if @handle
-
-{
- :Value,
- :DISP, :Dispatcher
- :OP, :Op
- :OUT, :Out
-}
diff --git a/registry.moon b/registry.moon
index 65c26a5..a7b4c9d 100644
--- a/registry.moon
+++ b/registry.moon
@@ -3,6 +3,12 @@ class Registry
@globals = {}
@map = {}
+ add_module: (name, tbl=require "lib.#{name}") =>
+ for k,v in pairs tbl
+ @globals["#{name}/#{k}"] = v
+
+ --
+
gentag: => #@map + 1
patch: (sexpr) =>
@@ -38,13 +44,6 @@ class Registry
@destroy_expr expr
@map[tag] = nil
- --
-
- update: (dt) =>
- -- for tag, sexpr in pairs @map
- for sexpr in @root\walk_sexpr!
- sexpr.value\update dt
-
spawn_expr: (sexpr) =>
ref = sexpr\head!\getc!
if sexpr.tag
@@ -52,7 +51,7 @@ class Registry
else
print "spawning '#{ref}'"
- def = rawget @globals, ref
+ def = assert @globals[ref], "no such function: '#{ref}'"
sexpr.value = def sexpr
patch_expr: (new, old) =>
@@ -69,4 +68,15 @@ class Registry
sexpr.value\destroy!
print "destroying [#{sexpr.tag}]"
+ --
+
+ update: (dt) =>
+ -- for tag, sexpr in pairs @map
+ for sexpr in @root\walk_sexpr!
+ continue unless sexpr.value
+
+ ok, err = pcall sexpr.value.update, sexpr.value, dt
+ if not ok
+ print "@#{sexpr}: #{err}"
+
:Registry
diff --git a/test.alv b/test.alv
index 2514822..81b1b65 100644
--- a/test.alv
+++ b/test.alv
@@ -1,17 +1,20 @@
-(osc "/radius" (lfo (cc 14)))
+#(this is a comment)
+([2]debug/out 'a' ([6]math/mix 0.5 1 ([5]time/lfo 1)))
-(set kick (note 38))
-(set pitch (const 440))
-(osc rot
- (step
- kick
- (random-rot)
- (random-rot)
- (random-rot)
- (random-rot)
- )
-)
+([16]util/pick 2 3)
+
+([14]math/mix 0 2 0.5)
+
+([13]debug/out 'b' ([12]math/mix 0 ([11]util/pick ([10]time/tick 4)
+ 0.25
+ 0.5
+ 0.75
+ 1) ([3]time/lfo 1 tri)))
+
+([9]debug/out 'name' ([8]util/pick ([7]time/tick 1)
+ 0.1
+ 0.6
+ 0.3
+ 0.9))
-(amp (env kick 02 10 05)
- (sineosc pitch))