aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-03-15 15:42:15 +0000
committers-ol <s+removethis@s-ol.nu>2025-03-18 11:05:10 +0000
commit62b70c808c9abebb4734232c30a65239d6ec0be3 (patch)
treeead393ef58af3b5417cbf3edbcfb227711e168bd
parentlib: support receiving OSC (diff)
downloadalive-62b70c808c9abebb4734232c30a65239d6ec0be3.tar.gz
alive-62b70c808c9abebb4734232c30a65239d6ec0be3.zip
lib: add glsl-view
-rw-r--r--alv-lib/_osc.moon9
-rw-r--r--alv-lib/glsl-view.moon128
-rw-r--r--alv-lib/link-time.moon34
-rw-r--r--docs/gen/shim.moon5
4 files changed, 173 insertions, 3 deletions
diff --git a/alv-lib/_osc.moon b/alv-lib/_osc.moon
index 265be9e..ba78629 100644
--- a/alv-lib/_osc.moon
+++ b/alv-lib/_osc.moon
@@ -1,6 +1,9 @@
-import new_message from require 'losc'
+import new_message, new_bundle from require 'losc'
import opairs from require 'alv.util'
import T, Array, Struct from require 'alv.base'
+Message = require 'losc.message'
+Bundle = require 'losc.bundle'
+Timetag = require 'losc.timetag'
add_item = (message, type, val, use_arrays=false) ->
switch type.__class
@@ -27,5 +30,9 @@ add_item = (message, type, val, use_arrays=false) ->
{
:new_message
+ :new_bundle
:add_item
+ :Message
+ :Bundle
+ :Timetag
}
diff --git a/alv-lib/glsl-view.moon b/alv-lib/glsl-view.moon
new file mode 100644
index 0000000..5438cc3
--- /dev/null
+++ b/alv-lib/glsl-view.moon
@@ -0,0 +1,128 @@
+import Constant, Op, TemplateString, Input, T, Array, sig, const from require 'alv.base'
+import Message, Bundle, Timetag, add_item from require 'alv-lib._osc'
+import dns, udp from require 'socket'
+
+ALV_TYPES = {}
+GLSL_TYPES =
+ num: 'float'
+ bool: 'bool'
+
+for i=2,4
+ GLSL_TYPES["num[#{i}]"] = "vec#{i}"
+ GLSL_TYPES["bool[#{i}]"] = "bvec#{i}"
+
+ for j=2,4
+ GLSL_TYPES["num[#{j}][#{i}]"] = "mat#{i}x#{j}"
+
+for p in *{'', 'i', 'g'}
+ ALV_TYPES["glsl/#{p}sampler2D"] = T.str
+ GLSL_TYPES["glsl/#{p}sampler2D"] = "#{p}sampler2D"
+ ALV_TYPES["glsl/#{p}sampler2DArray"] = T.str
+ GLSL_TYPES["glsl/#{p}sampler2DArray"] = "#{p}sampler2DArray"
+ ALV_TYPES["glsl/#{p}sampler3D"] = T.str
+ GLSL_TYPES["glsl/#{p}sampler3D"] = "#{p}sampler3D"
+
+uniform = Constant.meta
+ meta:
+ name: 'uniform'
+ summary: "override uniform binding type."
+ examples: { '(uniform glsl-type value)' }
+ description: "Set a specific GLSL type for this value.
+
+For example to send a string to glsl-view and load an image into a sampler:
+
+ vec4 color = texture(#(uniform 'sampler2D' 'image.png'), uv);"
+
+ value: class extends Op
+ pattern = const.str + sig!
+ setup: (inputs, scope) =>
+ { type, value } = pattern\match inputs
+
+ super Input.hot value
+
+ @setup_out '~', T["glsl/#{type.result!}"]
+
+ tick: => @out\set @inputs!
+
+shader = Constant.meta
+ meta:
+ name: 'shader'
+ summary: "control a GLSL shader via OSC."
+ examples: { '(shader [socket] code-tpl-str)' }
+ description: "Syncs code and parameters with glsl-view via OSC.
+
+- `socket` must be an `osc/out~` or read from `*oscout*`
+- `code-tpl-str` is a `str=` that can contain `~-stream` template substitutions
+ that are mapped as follows:
+ - `str`: substituted directly as GLSL
+ - `num`, `bool`: reference to `uniform float/bool`
+ - `num[I]`, `bool[I]`: reference to `uniform vecI/bvecI`
+ - `num[I][J]`: reference to `uniform matIxJ`
+ - `glsl-view/uniform`: reference to uniform of declared type
+
+`params` are substituted in `code` as uniforms using TemplateString logic"
+
+ value: class extends Op
+ pattern = -sig['osc/out'] + const.str + sig!^0
+
+ get_code: =>
+ uniforms = { '#version 330 core' }
+
+ @state = names: {}, types: {}
+ code = TemplateString.subst @inputs.code!, (i) ->
+ param = @inputs.params[i]
+ typename = tostring param\type!
+ if typename == 'str'
+ return param!
+
+ id = tostring math.random!
+ name = "alv_param_#{id\sub 3}"
+
+ typestr = assert GLSL_TYPES[typename], "unsupported type #{typename}"
+ table.insert uniforms, "uniform #{typestr} #{name};"
+ @state.types[i] = ALV_TYPES[typename] or param\type!
+ @state.names[i] = name
+
+ name
+
+ table.insert uniforms, code
+ table.concat uniforms, '\n'
+
+ setup: (inputs, scope) =>
+ { socket, code, params } = pattern\match inputs
+
+ super
+ socket: Input.hot socket or scope\get '*oscout*'
+ code: Input.hot code
+ params: [Input.hot param for param in *params]
+
+ tick: (setup) =>
+ bundle = Bundle.new Timetag.new!
+
+ compile = if setup or @inputs.code\dirty! then @get_code!
+ all = compile or @inputs.socket\dirty!
+
+ for i, input in ipairs @inputs.params
+ if all or input\dirty!
+ if name = @state.names[i]
+ msg = Message.new "/#{name}"
+ add_item msg, @state.types[i], input!
+ bundle\add msg
+ else
+ compile or= @get_code!
+
+ if compile
+ msg = { address: '/-/shader', types: 's', compile }
+ table.insert bundle.content, 1, msg
+
+ with sock = @inputs.socket!
+ \send Bundle.pack bundle.content
+
+Constant.meta
+ meta:
+ name: 'glsl-view'
+ summary: "glsl-view integration via OSC."
+
+ value:
+ :shader
+ :uniform
diff --git a/alv-lib/link-time.moon b/alv-lib/link-time.moon
index 1568b49..34e2220 100644
--- a/alv-lib/link-time.moon
+++ b/alv-lib/link-time.moon
@@ -210,6 +210,39 @@ tick = Constant.meta
vis: => type: 'event'
+phase = Constant.meta
+ meta:
+ name: 'phase'
+ summary: "Get phase."
+ examples: { '(tick [clock] period)' }
+ description: "Counts upwards by one every `period` beats.
+
+- `clock` should be a `link/clock~` stream. This argument can be omitted
+ and the stream be passed as a dynamic definition in `*clock*` instead.
+- `period` should be a num~ stream and defaults to 1.
+- returns a `num~` stream that ticks from 0 to `period`."
+ value: class extends Op
+ pattern = -sig['link/clock'] + -sig.num + -sig.num
+ setup: (inputs, scope) =>
+ { clock, period, phase } = pattern\match inputs
+ super
+ clock: Input.hot clock or scope\get '*clock*'
+ period: Input.cold period or Constant.num 0
+ phase: Input.cold phase or Constant.num 0
+
+ @setup_out '~', T.num
+
+ tick: =>
+ { :clock, :period, :phase, :evt } = @unwrap_all!
+ return if period == 0
+
+ t = clock.state\phase_at_time clock.time, period
+ t = (t + period - phase) % period
+
+ @out\set t
+
+ vis: => type: 'event'
+
Constant.meta
meta:
@@ -222,3 +255,4 @@ Constant.meta
:lfo
:ramp
:tick
+ :phase
diff --git a/docs/gen/shim.moon b/docs/gen/shim.moon
index e8a4f08..6d8fbe9 100644
--- a/docs/gen/shim.moon
+++ b/docs/gen/shim.moon
@@ -4,9 +4,10 @@ export require
require = do
old_require = require
- blacklist = {k, true for k in *{'losc', 'socket', 'system', 'luartmidi', 'abletonlink'}}
+ blacklist = {'^losc', '^socket$', '^system$', '^luartmidi$', '^abletonlink$'}
(mod, ...) ->
- return {} if blacklist[mod]
+ for pat in *blacklist
+ return {} if mod\match pat
old_require mod, ...
get_module = (name) ->