collidxr

2026-01-01

A collection of syntax sugar and conveniences extending cl-collider, a Common Lisp interface to the SuperCollider sound synthesis server.

Upstream URL

Author

modula t.

License

MIT
README
collidxr

This is a small collection of extensions for working with cl-collider. It includes:

  • Pseugens (pseudo-ugens) like b2 and fbn.
  • Syntax sugar like ds (wrapping defsynth) and dn (wrapping proxy).
  • Convenience functions like plot.
  • Maybe more in the future?

Refer to the "Features" section below for a more detailed overview of the provided functionality.

NOTE: This library should be considered to be in "beta" stages. You will probably run into a bug or two, so it's advised not to depend on its functionality for a live performance yet.

1Intro

collidxr is not yet part of Quicklisp, but it will be added in the future.

In the meantime, it can be installed manually by cloning the repo into your Quicklisp local-projects directory.

Once you've done that, you can simply run (ql:quickload "collidxr") in your REPL to load it into Lisp.

2Features

2.1plot

Show a graphical plot of the provided data. Data can be:

  • A list of numbers
  • A cl-collider buffer
  • A pattern (when cl-patterns is loaded)
  • A bdef (when bdef is loaded)

2.2b2

Wrap the provided ugen in a pan2.ar or balance2.ar as appropriate. In other words, if IN is mono, wrap it in pan2.ar, or if IN is stereo, wrap it in balance2.ar. PAN and LEVEL are the panning and amplitude arguments, respectively.

2.3fbnode

Feedback node, for creating feedback loops within synthdefs. It's recommended to use fbn to create an fbnode, and then fbn-read and fbn-write to read and write to it.

2.3.1fbn

Create a fbnode for doing feedback within synthdefs. NUM-CHANNELS is the number of channels of the internal delay buffer. MAX-DELAY-TIME is the length in seconds that the delay buffer should be allocated to, defaulting to the minimum delay possible (one block). INTERPOLATION is the type of interpolation to use when reading from the delay, as per buf-rd.ar.

  (defsynth :echoed ((freq 440) (delay 0.5) (feed 0.5) (amp 0.5) (out 0))
    (let* ((fbn (fbn 2 0.5))
           (sig (var-saw.ar (+ (rand.ir -2.0 (list 2.0 2.0)) freq) 0 0.5 (env-gen.kr (perc 0.01 0.25))))
           (sig (rlpf.ar (+ sig (* feed (fbn-read fbn delay)))
                         (* freq 0.9) 0.9)))
      (fbn-write fbn sig)
      (detect-silence.ar (leak-dc.ar sig) 1.0e-4 :time delay :act :free)
      (out.ar out (* sig amp))))

2.3.2fbn-read

Read from FBNODE at a time DELAY seconds from its input. DELAY defaults to the fbnode's max delay time.

2.3.3fbn-write

Write INPUT to FBNODE.

2.4ds

"Define Synth"; syntax sugar wrapping defsynth. It does the following:

  • Provides a more concise syntax for writing proxies; BODY is simply a plist mapping variable names to their values. No let* needed!
  • params are inserted as with-controls.
  • If not specified by the user, auto-inserts parameters for dur, tempo, pan, amp, and out with sensible defaults, marked as ignorable, to avoid warnings if they aren't used.
  • Bindings named - or _ are automatically declared ignorable.
  • When :fx is the first element of PARAMS, allocate a 2-channel bus and bind sig to (in.ar BUS 2).
  • If out is bound in BODY, its value is automatically used as the input for an out.ar.
  • If there is no out in BODY but there is a sig, sig is automatically fed into a b2 inside an out.ar. In other words, the pan, amp, and out arguments will "just work".
  • Can be provided as an :instrument in a pbind to set the parameters of the node.
  • Can be provided as an :out in a pbind to send the output of triggered synths to the node (for use with :fx nodes).

Example; you can write this:

  (ds :foo ((gate 1) (freq 440))
    :env (env-gen.kr (env-adsr 0.01 0.1 0.5 0.1) :gate gate :act :free)
    :sig (pulse.ar freq)
    :sig (rlpf.ar sig (* freq 2) 0.5)
    :sig (* sig env)
    :- (poll.kr (impulse.kr 1) sig))

instead of this:

  (defsynth :foo ((gate 1) (freq 440) (pan 0) (amp 0.5) (out 0))
    (let* ((env (env-gen.kr (adsr 0.01 0.1 0.5 0.1) :gate gate :act :free))
           (sig (pulse.ar freq))
           (sig (rlpf.ar sig (* freq 2) 0.5))
           (sig (* sig env))
           (ign (poll.kr (impulse.kr 1) sig)))
      (declare (ignore ign))
      (out.ar out (pan2.ar sig pan amp))))

In the future, it might also:

  • Allow specifying a ControlSpec, lag time, and rate (:ar, :kr, etc) for each parameter.
  • Allow output with replace-out.ar instead of only out.ar.

2.5synth-variant

Like cl-collider:synth, but can also start a synth variant. To specify a variant, NAME should be in the format NAME.VARIANT.

Synth variants are specified in the synthdef metadata. Set the metadata key :VARIANTS to a plist mapping the name of the variant to the plist of arguments to the synthdef.

Example:

  ;; define the \"noisy\" variant for the :tb303 synth:
  (setf (synthdef-metadata :tb303 :variants) (list :noisy (list :dist 1 :clip 1 :bias 1)))

  ;; play the variant:
  (synth-variant :tb303.noisy :freq 420 :dist 0) ; notice that you can override the arguments set in the variant.

  ;; the above is the same as doing:
  (synth :tb303 :freq 420 :dist 0 :clip 1 :bias 1)

2.6dn

"Define Node"; syntax sugar wrapping proxy. In addition to its standard functionality, it also does the following:

  • Provides a more concise syntax for writing proxies; BODY is simply a plist mapping variable names to their values. No let* needed!
  • params are inserted as with-controls.
  • Without BODY, just returns the node.
  • If not specified by the user, auto-inserts parameters for dur, tempo, pan, amp, and out with sensible defaults, marked as ignorable, to avoid warnings if they aren't used.
  • Bindings named - or _ are automatically declared ignorable.
  • :pos binding can be used to specify the :pos of the node within its group (i.e. :head, :tail, etc).
  • When :fx is the first element of PARAMS, allocate a 2-channel bus and bind sig to (in.ar BUS 2).
  • If out is bound in BODY, its value is automatically used as the input for an out.ar.
  • If there is no out in BODY but there is a sig, sig is automatically fed into a b2 inside an out.ar. In other words, the pan, amp, and out arguments will "just work".
  • Can be provided as an :instrument in a pbind to set the parameters of the node.
  • Can be provided as an :out in a pbind to send the output of triggered synths to the node (for use with :fx nodes).
Example; you can write this:
  (dn :echo (:fx (time 1.0) (decay 0.5) (pos :head))
    :sig (comb-c.ar sig 1 time decay))

instead of this:

  (proxy :echo
         (with-controls ((time 1.0) (decay 0.5) (dur 1) (tempo 1) (pan 0) (amp 0.5))
           (let* ((sig (in.ar 16 2))
                  (sig (comb-c.ar sig 1 time decay)))
             sig))
         :pos :head) ; note that :pos defaults to :head for non-:fx `dn's and :tail for :fx `dn's

Dependencies (6)

  • alexandria
  • cl-collider
  • fiveam
  • mutility
  • trivial-types
  • vgplot

Dependents (0)

    • GitHub
    • Quicklisp