aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2022-07-16 09:16:23 +0200
committerThomas White <taw@physics.org>2022-07-17 16:37:14 +0200
commitb102d2403623d515b02eac957690df6a9cbb1e0f (patch)
tree61afbebeefae3efa12670dd3540d840c379142c0
parent8e8a922591f704c5860b0b9a6a728920e960935f (diff)
Update docs
-rw-r--r--README.md11
-rw-r--r--docs/basic-control.rst136
-rw-r--r--docs/cue-list.rst205
-rw-r--r--docs/new-fixture.rst2
-rw-r--r--docs/patching.rst83
-rw-r--r--docs/physical-control.rst4
6 files changed, 389 insertions, 52 deletions
diff --git a/README.md b/README.md
index 20c8e00..8761b35 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ Lighting fixtures are referred to by names, rather than numbers:
;; Turn on both moving lights and set colour
(at moverL moverR 60)
-(at moverL moverR 'colour (make-colour-rgb 45 10 0))
+(at moverL moverR 'colour (rgb 45 10 0))
```
The fixture names are normal Scheme variables. You can do usual things such
@@ -98,7 +98,7 @@ of cues:
;; Act 1, Scene 1
(lighting-state
(at front-wash 80)
- (at moverL 'colour (make-colour-cmy 2700/127 0 0)))
+ (at moverL 'colour (cmy 25 0 0)))
(at moverL 25)
(crossfade 3))
@@ -130,12 +130,11 @@ Documentation index
-------------------
* [Patching fixtures](docs/patching.rst)
+* [Basic attribute control and building states](docs/basic-control.rst)
+* [Cue lists and playbacks](docs/cue-list.rst)
* [The fixture display tool](docs/fixture-display.rst)
+* [Physical controls](docs/physical-control.rst)
* [Defining a new type of fixture](docs/new-fixture.rst)
-* More to come:
- - Basic control of attributes, building states
- - Cue lists
- - Using physical controls via MIDI
(Non-)warranty
diff --git a/docs/basic-control.rst b/docs/basic-control.rst
new file mode 100644
index 0000000..f326a5d
--- /dev/null
+++ b/docs/basic-control.rst
@@ -0,0 +1,136 @@
+===========================================
+Basic attribute control and building states
+===========================================
+
+Once your fixtures are patched (see `<patching.rst>`_), you can set attributes
+sing ``at``. For example, to set the intensity of ``my-dimmer`` to 100%::
+
+ (at my-dimmer 'intensity 100)
+
+If you leave out the attribute name, then ``intensity`` will be assumed::
+
+ (at my-dimmer 100)
+
+The available parameters are determined by the fixture definition (see
+`<new-fixture.rst>`_), and are referred to by their symbolic name (i.e. quote
+them with ``'``). For example::
+
+ (at my-moving-light 'pan 32)
+ (at my-moving-light 'tilt 70)
+ (at my-moving-light 'zoom 60)
+
+Not all fixtures accept a single number. For example, ``'colour`` (note: UK
+spelling) takes a colour object, which can be constructed using ``rgb`` or
+``cmy``. Starlet (or rather, the fixture definition code) is responsible for
+converting the colour to the native representation used by the fixture::
+
+ (at my-moving-light 'colour (rgb 80 23 25))
+
+You can set attributes for multiple fixtures at once::
+
+ (at spotCS spotSR spotSL 90)
+
+Or you can set attributes for a list of fixtures::
+
+ (define all-spots (list spotSL spotCS spotSR))
+ (at all-spots 90)
+
+You can mix individual fixtures and lists of fixtures. However, you can only
+set one attribute (to one value) at a time.
+
+
+The selection
+=============
+
+When setting many attributes for one fixture, you can avoid typing the
+fixture name each time by using the selection. To select a fixture, call
+``sel`` with the fixture(s) to select::
+
+ (sel my-dimmer)
+ (sel all-spots my-moving-light)
+
+If the fixture name is left out from subsequent calls to ``at``, they will
+apply to the currently selected fixture(s). To clear the selection, simply
+call ``(sel #f)`` or simply ``(sel)``::
+
+ (sel my-moving-light)
+ (at 100)
+ (at 'colour (rgb 80 23 25))
+ (at 'tilt 70)
+ (at 'pan 32)
+ (sel #f)
+
+The fixture display window (see `<fixture-display.rst>`_) will highlight the
+selection, and physical control devices (see `<physical-control.rst>`_) will
+affect the selected fixture(s).
+
+To see the contents of the selection, use ``(get-selection)``.
+
+
+State objects
+=============
+
+Attribute values must be stored within a state object. When you set an
+attribute from the Guile REPL, the values will be stored in the programmer
+state. You can examine the contents using ``state-source``, which returns
+the Scheme code corresponding to the state's contents::
+
+ (state-source programmer-state)
+
+You can also use ``print-state``, which just pretty-prints the output of
+``state-source``. To reduce typing, you can use ``ps`` as a synonym for
+``programmer-state``::
+
+ (print-state ps)
+
+You can construct new states by wrapping your ``at`` forms inside
+``lighting-state``. These state objects can be used inside cue lists
+(see `<cue-list.rst>`_), bound to variables etc::
+
+ (define my-state
+ (lighting-state
+ (at spotSR spotSL 50)
+ (at spotCS 100)))
+
+The programmer state has priority over everything else (e.g. cue list
+playbacks). To avoid surprises, you should make sure that it's empty before
+trying to run a show. The ``clear-state!`` procedure empties a state object
+of its contents, without deleting the state itself::
+
+ (clear-state! ps)
+
+There are some utility routines for handling states:
+
+* ``(state-empty? my-state)`` returns ``#t`` if ``my-state`` is empty,
+ otherwise ``#f``.
+* ``(remove-fixture-from-state! my-state spotCS)`` removes all attributes for
+ ``spotCS`` from ``my-state``.
+* ``(remove-fixtures-from-state! my-state (list spotCS spotSL))`` is the same,
+ but removes a list of fixtures from the state.
+* ``(remove-selection-from-programmer!)`` removes from the programmer any
+ attributes referring to fixtures which are currently selected. It is
+ defined as follows::
+
+ (define (remove-selection-from-programmer!)
+ (remove-fixtures-from-state!
+ programmer-state
+ (get-selection)))
+
+
+Effects
+=======
+
+Attribute values aren't restricted to constants. You can also provide a
+function, for example::
+
+ (let ((clock (make-clock)))
+ (at washM
+ (lambda ()
+ (* 50
+ (+ 1 (sin (* 2 (elapsed-time clock))))))))
+
+That's obvious quite complicated, so use the functions in module ``(starlet
+effects)`` instead. For a sine wave once every 2 seconds (0.5 Hz) ranging
+between zero and 100%::
+
+ (at washM (sinewave 0.5 0 100))
diff --git a/docs/cue-list.rst b/docs/cue-list.rst
new file mode 100644
index 0000000..9a83ca0
--- /dev/null
+++ b/docs/cue-list.rst
@@ -0,0 +1,205 @@
+=======================
+Cue lists and playbacks
+=======================
+
+Anatomy of a cue
+================
+
+A cue is formed by associating a lighting state with a *transition effect*.
+As an example, here is cue 4.3 representing a 4 second crossfade to a dim
+lighting wash::
+
+ (cue 4.3 ;; <---- the cue number
+
+ (lighting-state ;;
+ (at washL washR 30) ;; lighting state
+ (at washM 40)) ;;
+
+ (crossfade 4)) ;; <---- transition: 4 second crossfade
+
+The simplest transition effect is ``(snap)``, which produces a hard zero-time
+transition to the cue. The usual one is ``crossfade``, which produces a smooth
+fade in the time you specify (in seconds). It gives you a lot of control, for
+example, to fade intensities up in 4 seconds but down in 2 seconds::
+
+ (crossfade 4 2)
+
+To delay the up fade part by 2 seconds relative to everything else::
+
+ (crossfade 4 #:up-delay 2)
+
+To delay the down fade part, use ``#:down-delay``. To control the fade times
+for non-intensity parameters, use ``#:attr-time`` and ``#:attr-delay``.
+Putting it all together for a complicated crossfade::
+
+ (crossfade 3 4
+ #:up-delay 2
+ #:attr-time 1
+ #:attr-delay 1.5)
+
+You can write your own transition effects, if you want some other kind of
+transition. Documentation pending, but look at snap-transition.scm and
+crossfade.scm for some examples.
+
+
+Cue lists
+==========
+
+A cue list is simply a list of cues. For example::
+
+ (cue-list
+
+ (cue 0.5
+ ;; Tab warmers
+ (lighting-state
+ (at washL washR 30)
+ (at washM 40))
+ (snap))
+
+ (cue 0.8
+ ;; Blackout
+ (lighting-state)
+ (crossfade 6)) ;; 6 second fade
+
+ (cue 1
+ ;; Act 1, Scene 1
+ (lighting-state
+ (at front-wash 80)
+ (at moverL 'colour (cmy 21 0 0)))
+ (at moverL 25)
+ (crossfade 3))
+
+ (cue 2
+ (lighting-state
+ (at washM 100))
+ (crossfade 3 4)) ;; Separate up/down fade times
+
+ (cue 2.5
+ (lighting-state
+ (apply-state home-state)
+ (at moverR 100))
+ (crossfade 2)))
+
+Just so you know, the cue list is represented internally as a Scheme *vector*,
+not a real list.
+
+
+Playback objects
+================
+
+The cue list doesn't do anything on its own. To actually see the contents on
+the stage, it needs to be loaded into a playback. In practice, the best way to
+work is to put the cue list in a file on its own and create the playback with
+a reference to that file::
+
+ (define pb
+ (make-playback
+ #:cue-list-file "shows/my-show.qlist.scm"
+ #:recovery-file "recovery.q"))
+
+The ``#:recovery-file`` is optional but highly recommended, discussed below.
+
+Once the playback has been created like this, if you change the cue list file
+then you can re-load it::
+
+ scheme@(guile-user)> (reload-cue-list! pb)
+ $8 = cue-list-reloaded
+
+If the modifications to the cue list file involved the currently active cue,
+the state shown on the stage will *not* be updated until you say so, with::
+
+ (reassert-current-cue! pb)
+
+The playback object shows useful information when printed::
+
+ scheme@(guile-user)> pb
+ $1 = #<<starlet-playback> state: ready current-cue: 43.0 next-cue: 44.0>
+
+For completeness, know that you can also create a playback like this::
+
+ (define my-cue-list
+ (cue-list
+ (cue ...)))
+
+ (define pb (make-playback #:cue-list my-cue-list))
+
+However, this makes it much harder to make subsequent changes to the cue list.
+
+
+Running cues
+============
+
+To rapidly jump (with a snap transition) to a cue, use ``cut-to-cue-number!``.
+To run a cue using the transition specified in the cue list, use
+``run-cue-number!``::
+
+ (cut-to-cue-number! pb 1)
+ (run-cue-number! pb 4)
+
+Calling ``go!`` will run the next cue in the cue list::
+
+ (go! pb)
+
+Playbacks also implement the other familiar operations:
+
+* ``(stop! pb)`` - immediately pause any running cue. The next call to
+ ``go!`` will continue it.
+* ``(cut! pb)`` - run the next cue, using a snap transition regardless of what
+ the cue specifies.
+* ``(back! pb)`` - go backwards one step in the cue list, using a snap
+ transition.
+
+
+Tracking
+========
+
+By default, non-intensity parameters will "track" from one cue into the next
+cue. That helps to avoid unexpected parameter changes, e.g. a moving light
+changing position while it dims. If you run cues *out of order*, the result
+will be the same as if you'd run the cues *in order* from the start, to get to
+the cue you wanted. If you're lucky enough to have never encountered a system
+that works any other way, just know that it works the way you'd expect it to
+work in a theatrical system.
+
+If you additionally want to track *intensities* into a cue, use
+``#:track-intensities``::
+
+ (cue 1
+ (lighting-state
+ (at front-wash 80))
+ (crossfade 3))
+
+ (cue 2
+ (lighting-state
+ (at spotC 100))
+ (crossfade 3)
+ #:track-intensities #t)
+
+In this example, cue 2 will include ``spotC`` at full intensity, **and**
+``front-wash`` at 80% intensity.
+
+
+Fixture presetting ("auto move while dark")
+===========================================
+
+Starlet tries as hard as it can to get non-intensity parameters into the right
+state before running a cue. In other words, it makes a big effort to avoid the
+audience seeing moving lights actually move. If a fixture's ``intensity``
+parameter is zero after running a cue, Starlet will set all its non-intensity
+parameters to the values in the next cue. Of course, if a non-intensity
+parameter changes while the intensity is non-zero, the audience will see the
+move!
+
+
+The recovery file
+=================
+
+The purpose of the playback recovery file is to make a rapid recovery after a
+crash (not that there will be any, of course!). If the file specified by the
+``#:recovery-file`` keyword argument to ``make-playback`` exists when the
+playback is created, the playback will immediately jump to the cue number in
+the file. Whenever you run (or jump to) a cue, the cue number in the file will
+be updated. If you don't use a recovery file, the playback will revert to cue
+zero on creation and you'll have to use ``cut-to-cue-number!``. That will
+create a blackout of a few seconds while you figure out the right cue number to
+pick up from where things went wrong.
diff --git a/docs/new-fixture.rst b/docs/new-fixture.rst
index 2c0771d..408f2ab 100644
--- a/docs/new-fixture.rst
+++ b/docs/new-fixture.rst
@@ -99,7 +99,7 @@ Worked example
==============
Here is an annotated version of the definition for the
-`Stairville Octagon Theatre CW/WW fixture <https://www.thomannmusic.com/stairville_octagon_theater_cw_ww_36x1w.htm>`_
+`Stairville Octagon Theatre CW/WW <https://www.thomannmusic.com/stairville_octagon_theater_cw_ww_36x1w.htm>`_.
The channels for this fixture are:
1. Cold LED intensity (0-255 min-max)
diff --git a/docs/patching.rst b/docs/patching.rst
index aaf25ff..37c2f2e 100644
--- a/docs/patching.rst
+++ b/docs/patching.rst
@@ -14,8 +14,7 @@ to patch a simple dimmer with DMX address 32 on universe 4::
(patch-fixture! my-dimmer <generic-dimmer> 32 #:universe 4)
Universe numbering starts from zero (consistent with OLA's numbering), and
-channel numbering starts from 1 (consistent with every other system on the
-planet).
+channel numbering starts from 1.
After the above, the symbol ``my-dimmer`` will be bound to an object
representing the dimmer::
@@ -26,6 +25,16 @@ representing the dimmer::
Intelligent fixtures should go to their home positions immediately after being
patched.
+Note that you can give a fixture multiple names. For example, if the spotlight
+you use for a throne (``throne-spot``) is re-used to light a table::
+
+ (define table-spot throne-spot)
+
+This leaves the door open for replacing ``table-spot`` with a separate fixture
+later on, if the re-usage doesn't work out as you expected. In that case,
+after rigging the new fixture, simply replace the above ``define`` call with a
+new call to ``patch-fixture!``.
+
Lists of fixtures
=================
@@ -34,22 +43,22 @@ Starlet fixture objects are just normal `GOOPS
<https://www.gnu.org/software/guile/manual/html_node/GOOPS.html>`_ objects. You
can do normal Scheme-y things with them, such as making lists of them::
- (define red-backlight (list backlight-red-usl
- backlight-red-usr
- backlight-red-dsl
- backlight-red-dsr))
+ (define red-backlight
+ (list backlight-red-usl
+ backlight-red-usr
+ backlight-red-dsl
+ backlight-red-dsr))
Procedures such as ``at`` work with these lists in the same way that they work
on individual fixtures::
(at red-backlight 100)
-See the documentation about setting attributes for more information on this
-topic.
+See `<basic-control.rst>`_ for more information about ``at``.
-Multiple fixtures with similar names
-====================================
+Patching multiple fixtures at once
+==================================
At this point, you might be tempted to create a standard file which defines all
the fixtures in your venue, naming them ``dimmer1``, ``dimmer2``, ``dimmer3``
@@ -65,49 +74,33 @@ use descriptive names for your fixture objects. When using Starlet, you
shouldn't need to constantly look up fixture names (or worse, numbers) in a
lighting plan. Instead, give your fixtures names which represent what they do,
for example: ``balcony-front-warm``, ``followspot`` or ``throne-spot``.
-Note that you can give a fixture multiple names. For example, if the spotlight
-you use for a throne (``throne-spot``) is re-used to light a table::
-
- (define table-spot throne-spot)
-This leaves the door open for replacing ``table-spot`` with a separate fixture
-later on, if the re-usage doesn't work out as you expected. In that case,
-simply replace the above ``define`` call with a new call to ``patch-fixture!``.
-
-
-Patching multiple fixtures at once
-==================================
-
-Despite the above, there will probably be times when you have a large number of
-fixtures that should be treated to a greater extent as one entity. For this
-situation, use ``patch-many!``, which patches a series of fixtures of the same
-type. For example, to create eight dimmers with DMX addresses numbered 2, 4,
-6... ::
-
- (patch-many! foh-warm <generic-dimmer> '(2 4 6 8 10 12 14 16))
-
-Symbol ``foh-warm`` will be bound to a list containing the fixture objects::
+What you *can* do, however, is to create a list of fixtures all at once. The
+individual fixtures in the list won't have their own names, so this is meant
+for situations where you mainly want to control the fixtures as a group. For
+example, to create eight dimmers with DMX addresses numbered 2, 4, 6... ::
+ scheme@(guile-user)> (patch-many! foh-warm <generic-dimmer> '(2 4 6 8 10 12 14 16))
scheme@(guile-user)> foh-warm
- $2 = (#<<generic-dimmer> 7f6da7c3dc00> #<<generic-dimmer> 7f6da7c3db80>
+ $1 = (#<<generic-dimmer> 7f6da7c3dc00> #<<generic-dimmer> 7f6da7c3db80>
#<<generic-dimmer> 7f6da7c3db00> #<<generic-dimmer> 7f6da7c3da80>
#<<generic-dimmer> 7f6da7c3da40> #<<generic-dimmer> 7f6da7c3d9c0>
#<<generic-dimmer> 7f6da7c3d940> #<<generic-dimmer> 7f6da7c3d8c0>)
+ scheme@(guile-user)> (at foh-warm 85)
-Instead of explicitly specifying the list of addresses, you could use ``iota``.
-For example, this time putting the dimmers on universe 3::
+To address a fixture individually from the list, you would need to use
+``list-ref``. This is a little clumsy, but as mentioned above should be a rare
+exception::
- (patch-many! foh-warm <generic-dimmer> (iota 8 2 2)
- #:universe 3)
+ (at (list-ref foh-warm 2) 85)
-Hopefully obviously, the fixtures in one ``patch-many!`` call all need to be on
-the same DMX universe.
+Instead of explicitly specifying the list of addresses in ``patch-many!``, you
+can use ``iota`` to generate the list of addresses. The following call has the
+same effect as the example above, except this time the dimmers are on universe
+3 instead of 0::
-For the rare situation when you need to control a single fixture from the list
-separately to the others, create a new binding to an item from the list::
-
- (define forestage-warm-patch (list-ref foh-warm 2))
+ (patch-many! foh-warm <generic-dimmer> (iota 8 2 2)
+ #:universe 3)
-As before, this leaves an easy way to install a dedicated fixture for the
-purpose, should it later become necessary, without having to re-write your
-entire lighting program.
+Note that the fixtures in one ``patch-many!`` call all need to be on the same
+DMX universe.
diff --git a/docs/physical-control.rst b/docs/physical-control.rst
new file mode 100644
index 0000000..1305673
--- /dev/null
+++ b/docs/physical-control.rst
@@ -0,0 +1,4 @@
+==================================
+Using physical controls (MIDI etc)
+==================================
+