Add dynamic zoom and ripple amplitude to woods recipe
Some checks are pending
GPU Worker CI/CD / test (push) Waiting to run
GPU Worker CI/CD / deploy (push) Blocked by required conditions

- Zoom now driven by audio energy via core:map-range
- Ripple amplitude reads from dynamic_params in sexp_to_cuda
- Crossfade transition with zoom in/out effect
- Move git clone before COPY in Dockerfile for better caching

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-04 12:04:00 +00:00
parent d5f30035da
commit 949d716d9a
3 changed files with 26 additions and 11 deletions

View File

@@ -74,12 +74,12 @@ COPY --from=builder /decord-install /usr/local/lib/python3.11/dist-packages/
COPY --from=builder /tmp/decord/build/libdecord.so /usr/local/lib/ COPY --from=builder /tmp/decord/build/libdecord.so /usr/local/lib/
RUN ldconfig RUN ldconfig
# Copy application # Clone effects repo (before COPY so it gets cached)
COPY . .
# Clone effects repo
RUN git clone https://git.rose-ash.com/art-dag/effects.git /app/artdag-effects RUN git clone https://git.rose-ash.com/art-dag/effects.git /app/artdag-effects
# Copy application (this invalidates cache for any code change)
COPY . .
# Create cache directory # Create cache directory
RUN mkdir -p /data/cache RUN mkdir -p /data/cache

View File

@@ -125,8 +125,8 @@
dir (get cfg :dir) dir (get cfg :dir)
rot-max-a (get cfg :rot-a) rot-max-a (get cfg :rot-a)
rot-max-b (get cfg :rot-b) rot-max-b (get cfg :rot-b)
zoom-a (get cfg :zoom-a) zoom-max-a (get cfg :zoom-a)
zoom-b (get cfg :zoom-b) zoom-max-b (get cfg :zoom-b)
pair-angle (get pstate :angle) pair-angle (get pstate :angle)
inv-a-on (> (get pstate :inv-a) 0) inv-a-on (> (get pstate :inv-a) 0)
inv-b-on (> (get pstate :inv-b) 0) inv-b-on (> (get pstate :inv-b) 0)
@@ -140,6 +140,10 @@
angle-a (* dir pair-angle rot-max-a 0.01) angle-a (* dir pair-angle rot-max-a 0.01)
angle-b (* dir pair-angle rot-max-b 0.01) angle-b (* dir pair-angle rot-max-b 0.01)
;; Energy-driven zoom (maps audio energy 0-1 to 1-max)
zoom-a (core:map-range e 0 1 1 zoom-max-a)
zoom-b (core:map-range e 0 1 1 zoom-max-b)
;; Define effect pipelines for each source ;; Define effect pipelines for each source
;; These get compiled to single CUDA kernels! ;; These get compiled to single CUDA kernels!
effects-a [{:op "zoom" :amount zoom-a} effects-a [{:op "zoom" :amount zoom-a}
@@ -177,10 +181,20 @@
;; Process active pair with fused pipeline ;; Process active pair with fused pipeline
active-frame (process-pair-fast active) active-frame (process-pair-fast active)
;; Crossfade during transition ;; Crossfade with zoom during transition
;; Old pair: zooms out (1.0 -> 2.0) and fades out
;; New pair: starts small (0.1), zooms in (-> 1.0) and fades in
result (if fading result (if fading
(let [next-frame (process-pair-fast next-idx)] (let [next-frame (process-pair-fast next-idx)
(blending:blend-images active-frame next-frame fade-amt)) ;; Active zooms out as it fades
active-zoom (+ 1.0 fade-amt)
active-zoomed (streaming_gpu:fused-pipeline active-frame
[{:op "zoom" :amount active-zoom}])
;; Next starts small and zooms in
next-zoom (+ 0.1 (* fade-amt 0.9))
next-zoomed (streaming_gpu:fused-pipeline next-frame
[{:op "zoom" :amount next-zoom}])]
(blending:blend-images active-zoomed next-zoomed fade-amt))
active-frame) active-frame)
;; Final effects pipeline (fused!) ;; Final effects pipeline (fused!)
@@ -198,4 +212,5 @@
;; Apply final fused pipeline ;; Apply final fused pipeline
(streaming_gpu:fused-pipeline result final-effects (streaming_gpu:fused-pipeline result final-effects
:rotate_angle spin-angle :rotate_angle spin-angle
:ripple_phase (* now 5))))) :ripple_phase (* now 5)
:ripple_amplitude rip-amp))))

View File

@@ -300,7 +300,7 @@ def _build_params(effects: List[dict], dynamic_params: dict) -> cp.ndarray:
elif op == 'zoom': elif op == 'zoom':
params.append(float(dynamic_params.get('zoom_amount', effect.get('amount', 1.0)))) params.append(float(dynamic_params.get('zoom_amount', effect.get('amount', 1.0))))
elif op == 'ripple': elif op == 'ripple':
params.append(float(effect.get('amplitude', 10))) params.append(float(dynamic_params.get('ripple_amplitude', effect.get('amplitude', 10))))
params.append(float(effect.get('frequency', 8))) params.append(float(effect.get('frequency', 8)))
params.append(float(effect.get('decay', 2))) params.append(float(effect.get('decay', 2)))
params.append(float(dynamic_params.get('ripple_phase', effect.get('phase', 0)))) params.append(float(dynamic_params.get('ripple_phase', effect.get('phase', 0))))