summaryrefslogtreecommitdiff
path: root/guile/nanolight/fixture.scm
blob: 4a530f73182fd13afbc9a6715f38b3ec3eb552f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
(define-module (nanolight fixture)
  #:use-module (oop goops)
  #:use-module (nanolight state)
  #:use-module (ice-9 threads)
  #:export (<fixture> <fixture-attribute>
             make-output
             patch-fixture show-state
             fixture-string get-address-string
             percent->dmxval
             get-start-addr get-universe))

(use-modules (srfi srfi-1))

(define-class <fixture-attribute> (<object>)

  (name
    #:init-value 'unnamed-attribute
    #:init-keyword #:name
    #:getter name)

  (range
    #:init-value '()
    #:init-keyword #:range
    #:getter range)

  (type
    #:init-value 'continuous
    #:init-keyword #:type
    #:getter type)

  (home-value
    #:init-value 0
    #:init-keyword #:home-value
    #:getter home-value)

  (translator
    #:init-value (lambda (universe start-addr value set-dmx) #f)
    #:init-keyword #:translator
    #:getter translator))


(define-class <fixture> (<object>)

  (attributes
    #:init-value '()
    #:init-keyword #:attributes
    #:getter attributes)

  (universe
    #:init-value #f
    #:init-keyword #:uni
    #:getter get-universe
    #:setter set-universe!)

  (start-addr
    #:init-value #f
    #:init-keyword #:sa
    #:getter get-start-addr
    #:setter set-start-addr!)

  (friendly-name
    #:init-value "Fixture"
    #:init-keyword #:friendly-name
    #:getter get-friendly-name
    #:setter set-friendly-name!)

  (address-string
    #:init-value #f
    #:allocation #:virtual
    #:getter get-address-string
    #:slot-ref (lambda (a)
                 (string-append
                   (number->string (slot-ref a 'universe))
                   "."
                   (number->string (slot-ref a 'start-addr))))
    #:slot-set! (lambda (a s) #f)))


(define (fixture-string fixture)
  (string-append
    (get-friendly-name fixture)
    " at "
    (get-address-string fixture)))


(define (patch-fixture output attributes universe start-addr friendly-name)
  (let ((new-fixture (make <fixture>
                       #:attributes attributes
                       #:uni universe
                       #:sa start-addr
                       #:friendly-name friendly-name)))
    (output 'add-fixture new-fixture)
    new-fixture))


; FIXME: Clamp to range
(define (percent->dmxval val)
  (/ (* 256 val) 100))


(define (show-state output state)
  (output 'show-state state))

(define (find-attribute fix attr)
  (find (lambda (a)
          (eq? (name a) attr))
    (attributes fix)))


(define (round-dmx a)
  (min 255 (max 0 (round a))))

(define (make-output)

  (let ((fixtures '())
        (current-state '()))

    (define (run-scanout)

      (let ((universes '()))

        (define (set-dmx universe addr nbytes value)
          ; FIXME: 16 bit values
          (unless (assq universe universes)
            (set! universes (acons
                              universe
                              (make-u8vector 512 0)
                              universes)))
          (u8vector-set!
            (assq-ref universes universe)
            addr (round-dmx value)))

        (define (execute-state-assignment state-assignment)
          (let ((attr (find-attribute
                        (fixture state-assignment)
                        (attribute state-assignment))))
            (when attr
              (let ((trans (translator attr)))
                (trans
                  (get-universe (fixture state-assignment))
                  (get-start-addr (fixture state-assignment))
                  ((value-func state-assignment))
                  set-dmx)))))


        (for-each execute-state-assignment current-state)

        (display universes)
        (display "\r"))

      (yield)
      (run-scanout))

    ; Start sending output
    (make-thread run-scanout)

    ; Method functions
    (define (show-state state)
      (set! current-state state))

    (define (add-fixture fixture)
      (set! fixtures (cons fixture fixtures)))

    (lambda args
      (apply
        (case (car args)
          ((show-state) show-state)
          ((add-fixture) add-fixture)
          (else => (error "Invalid method")))
        (cdr args)))))