Add generic streaming interpreter with configurable sources/audio
- Add stream_sexp_generic.py: fully generic sexp interpreter - Add streaming primitives for video sources and audio analysis - Add config system for external sources and audio files - Add templates for reusable scans and macros - Fix video/audio stream mapping in file output - Add dynamic source cycling based on sources array length - Remove old Python effect files (migrated to sexp) - Update sexp effects to use namespaced primitives Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
25
templates/crossfade-zoom.sexp
Normal file
25
templates/crossfade-zoom.sexp
Normal file
@@ -0,0 +1,25 @@
|
||||
;; Crossfade with Zoom Transition
|
||||
;;
|
||||
;; Macro for transitioning between two frames with a zoom effect.
|
||||
;; Active frame zooms out while next frame zooms in.
|
||||
;;
|
||||
;; Required context:
|
||||
;; - zoom effect must be loaded
|
||||
;; - blend effect must be loaded
|
||||
;;
|
||||
;; Parameters:
|
||||
;; active-frame: current frame
|
||||
;; next-frame: frame to transition to
|
||||
;; fade-amt: transition progress (0 = all active, 1 = all next)
|
||||
;;
|
||||
;; Usage:
|
||||
;; (include :path "../templates/crossfade-zoom.sexp")
|
||||
;; ...
|
||||
;; (crossfade-zoom active-frame next-frame 0.5)
|
||||
|
||||
(defmacro crossfade-zoom (active-frame next-frame fade-amt)
|
||||
(let [active-zoom (+ 1.0 fade-amt)
|
||||
active-zoomed (zoom active-frame :amount active-zoom)
|
||||
next-zoom (+ 0.1 (* fade-amt 0.9))
|
||||
next-zoomed (zoom next-frame :amount next-zoom)]
|
||||
(blend active-zoomed next-zoomed :opacity fade-amt)))
|
||||
28
templates/scan-oscillating-spin.sexp
Normal file
28
templates/scan-oscillating-spin.sexp
Normal file
@@ -0,0 +1,28 @@
|
||||
;; Oscillating Spin Scan
|
||||
;;
|
||||
;; Accumulates rotation angle on each beat, reversing direction
|
||||
;; periodically for an oscillating effect.
|
||||
;;
|
||||
;; Required context:
|
||||
;; - music: audio analyzer from (streaming:make-audio-analyzer ...)
|
||||
;;
|
||||
;; Provides scan: spin
|
||||
;; Bind with: (bind spin :angle) ;; cumulative rotation angle
|
||||
;;
|
||||
;; Behavior:
|
||||
;; - Rotates 14.4 degrees per beat (completes 360 in 25 beats)
|
||||
;; - After 20-30 beats, reverses direction
|
||||
;; - Creates a swinging/oscillating rotation effect
|
||||
;;
|
||||
;; Usage:
|
||||
;; (include :path "../templates/scan-oscillating-spin.sexp")
|
||||
;;
|
||||
;; In frame:
|
||||
;; (rotate frame :angle (bind spin :angle))
|
||||
|
||||
(scan spin (streaming:audio-beat music t)
|
||||
:init {:angle 0 :dir 1 :left 25}
|
||||
:step (if (> left 0)
|
||||
(dict :angle (+ angle (* dir 14.4)) :dir dir :left (- left 1))
|
||||
(dict :angle angle :dir (* dir -1)
|
||||
:left (+ 20 (mod (streaming:audio-beat-count music t) 11)))))
|
||||
41
templates/scan-ripple-drops.sexp
Normal file
41
templates/scan-ripple-drops.sexp
Normal file
@@ -0,0 +1,41 @@
|
||||
;; Beat-Triggered Ripple Drops Scan
|
||||
;;
|
||||
;; Creates random ripple drops triggered by audio beats.
|
||||
;; Each drop has a random center position and duration.
|
||||
;;
|
||||
;; Required context:
|
||||
;; - music: audio analyzer from (streaming:make-audio-analyzer ...)
|
||||
;; - core primitives loaded
|
||||
;;
|
||||
;; Provides scan: ripple-state
|
||||
;; Bind with: (bind ripple-state :gate) ;; 0 or 1
|
||||
;; (bind ripple-state :cx) ;; center x (0-1)
|
||||
;; (bind ripple-state :cy) ;; center y (0-1)
|
||||
;;
|
||||
;; Parameters:
|
||||
;; trigger-chance: probability per beat (default 0.15)
|
||||
;; min-duration: minimum beats (default 1)
|
||||
;; max-duration: maximum beats (default 15)
|
||||
;;
|
||||
;; Usage:
|
||||
;; (include :path "../templates/scan-ripple-drops.sexp")
|
||||
;; ;; Uses default: 15% chance, 1-15 beat duration
|
||||
;;
|
||||
;; In frame:
|
||||
;; (let [rip-gate (bind ripple-state :gate)
|
||||
;; rip-amp (* rip-gate (core:map-range e 0 1 5 50))]
|
||||
;; (ripple frame
|
||||
;; :amplitude rip-amp
|
||||
;; :center_x (bind ripple-state :cx)
|
||||
;; :center_y (bind ripple-state :cy)))
|
||||
|
||||
(scan ripple-state (streaming:audio-beat music t)
|
||||
:init {:gate 0 :cx 0.5 :cy 0.5 :left 0}
|
||||
:step (if (> left 0)
|
||||
(dict :gate 1 :cx cx :cy cy :left (- left 1))
|
||||
(if (< (core:rand) 0.15)
|
||||
(dict :gate 1
|
||||
:cx (+ 0.2 (* (core:rand) 0.6))
|
||||
:cy (+ 0.2 (* (core:rand) 0.6))
|
||||
:left (+ 1 (mod (streaming:audio-beat-count music t) 15)))
|
||||
(dict :gate 0 :cx 0.5 :cy 0.5 :left 0))))
|
||||
22
templates/standard-effects.sexp
Normal file
22
templates/standard-effects.sexp
Normal file
@@ -0,0 +1,22 @@
|
||||
;; Standard Effects Bundle
|
||||
;;
|
||||
;; Loads commonly-used video effects.
|
||||
;; Include after primitives are loaded.
|
||||
;;
|
||||
;; Effects provided:
|
||||
;; - rotate: rotation by angle
|
||||
;; - zoom: scale in/out
|
||||
;; - blend: alpha blend two frames
|
||||
;; - ripple: water ripple distortion
|
||||
;; - invert: color inversion
|
||||
;; - hue_shift: hue rotation
|
||||
;;
|
||||
;; Usage:
|
||||
;; (include :path "../templates/standard-effects.sexp")
|
||||
|
||||
(effect rotate :path "../sexp_effects/effects/rotate.sexp")
|
||||
(effect zoom :path "../sexp_effects/effects/zoom.sexp")
|
||||
(effect blend :path "../sexp_effects/effects/blend.sexp")
|
||||
(effect ripple :path "../sexp_effects/effects/ripple.sexp")
|
||||
(effect invert :path "../sexp_effects/effects/invert.sexp")
|
||||
(effect hue_shift :path "../sexp_effects/effects/hue_shift.sexp")
|
||||
14
templates/standard-primitives.sexp
Normal file
14
templates/standard-primitives.sexp
Normal file
@@ -0,0 +1,14 @@
|
||||
;; Standard Primitives Bundle
|
||||
;;
|
||||
;; Loads all commonly-used primitive libraries.
|
||||
;; Include this at the top of streaming recipes.
|
||||
;;
|
||||
;; Usage:
|
||||
;; (include :path "../templates/standard-primitives.sexp")
|
||||
|
||||
(require-primitives "geometry")
|
||||
(require-primitives "core")
|
||||
(require-primitives "image")
|
||||
(require-primitives "blending")
|
||||
(require-primitives "color_ops")
|
||||
(require-primitives "streaming")
|
||||
72
templates/stream-process-pair.sexp
Normal file
72
templates/stream-process-pair.sexp
Normal file
@@ -0,0 +1,72 @@
|
||||
;; stream-process-pair template (streaming-compatible)
|
||||
;;
|
||||
;; Macro for processing a video source pair with full effects.
|
||||
;; Reads source, applies A/B effects (rotate, zoom, invert, hue), blends,
|
||||
;; and applies pair-level rotation.
|
||||
;;
|
||||
;; Required context (must be defined in calling scope):
|
||||
;; - sources: array of video sources
|
||||
;; - pair-configs: array of {:dir :rot-a :rot-b :zoom-a :zoom-b} configs
|
||||
;; - pair-states: array from (bind pairs :states)
|
||||
;; - now: current time (t)
|
||||
;; - e: audio energy (0-1)
|
||||
;;
|
||||
;; Required effects (must be loaded):
|
||||
;; - rotate, zoom, invert, hue_shift, blend
|
||||
;;
|
||||
;; Usage:
|
||||
;; (include :path "../templates/stream-process-pair.sexp")
|
||||
;; ...in frame pipeline...
|
||||
;; (let [pair-states (bind pairs :states)
|
||||
;; now t
|
||||
;; e (streaming:audio-energy music now)]
|
||||
;; (process-pair 0)) ;; process source at index 0
|
||||
|
||||
(require-primitives "core")
|
||||
|
||||
(defmacro process-pair (src-idx)
|
||||
(let [src (nth sources src-idx)
|
||||
frame (streaming:source-read src now)
|
||||
cfg (nth pair-configs src-idx)
|
||||
state (nth pair-states src-idx)
|
||||
|
||||
;; Get state values (invert uses countdown > 0)
|
||||
inv-a-active (if (> (get state :inv-a) 0) 1 0)
|
||||
inv-b-active (if (> (get state :inv-b) 0) 1 0)
|
||||
;; Hue is active only when countdown > 0
|
||||
hue-a-val (if (> (get state :hue-a) 0) (get state :hue-a-val) 0)
|
||||
hue-b-val (if (> (get state :hue-b) 0) (get state :hue-b-val) 0)
|
||||
mix-opacity (get state :mix)
|
||||
pair-rot-angle (* (get state :angle) (get cfg :dir))
|
||||
|
||||
;; Get config values for energy-mapped ranges
|
||||
rot-a-max (get cfg :rot-a)
|
||||
rot-b-max (get cfg :rot-b)
|
||||
zoom-a-max (get cfg :zoom-a)
|
||||
zoom-b-max (get cfg :zoom-b)
|
||||
|
||||
;; Energy-driven rotation and zoom
|
||||
rot-a (core:map-range e 0 1 0 rot-a-max)
|
||||
rot-b (core:map-range e 0 1 0 rot-b-max)
|
||||
zoom-a (core:map-range e 0 1 1 zoom-a-max)
|
||||
zoom-b (core:map-range e 0 1 1 zoom-b-max)
|
||||
|
||||
;; Apply effects to clip A
|
||||
clip-a (-> frame
|
||||
(rotate :angle rot-a)
|
||||
(zoom :amount zoom-a)
|
||||
(invert :amount inv-a-active)
|
||||
(hue_shift :degrees hue-a-val))
|
||||
|
||||
;; Apply effects to clip B
|
||||
clip-b (-> frame
|
||||
(rotate :angle rot-b)
|
||||
(zoom :amount zoom-b)
|
||||
(invert :amount inv-b-active)
|
||||
(hue_shift :degrees hue-b-val))
|
||||
|
||||
;; Blend A+B
|
||||
blended (blend clip-a clip-b :opacity mix-opacity)]
|
||||
|
||||
;; Apply pair-level rotation
|
||||
(rotate blended :angle pair-rot-angle)))
|
||||
Reference in New Issue
Block a user