summaryrefslogtreecommitdiff
path: root/runtime/envelopes.lsp
blob: 67979972f4cc53b3b744d5cbc8d2b105bdba33eb (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
;; envelopes.lsp -- support functions for envelope editor in jNyqIDE

#| In Nyquist, editable envelopes are saved as one entry in the workspace
named *envelopes*. The entry is an association list where each element
looks like this:

(name type parameters... )

where name is a symbol, e.g. MY-ENVELOPE-1,
      type is a function name, e.g. PWL, PWLV, PWE, etc., and
      parameters are breakpoint data, e.g. 0.1 1 0.2 0.5 1

Example of two envelopes named FOO and BAR:

((FOO PWL 0.1 1 1) (BAR PWE 0.2 1 1))

To convert envelope data into functions, call (MAKE-ENV-FUNCTIONS).
This function should be on the workspace's list of functions to call.
(See ADD-ACTION-TO-WORKSPACE in Nyquist Manual.)

When the jNyqIDE wants to get the envelope data from the workspace, it
should call (GET-ENV-DATA), which will dump formatted data to Nyquist's
standard output as follows:

get-env-data: begin
name (type parameters...) newline
name (type parameters...) newline
...
get-env-data: end

When the IDE wants to save a definition, it should call
(DEFINE-ENV 'NAME 'EXPRESSION)

To delete a definition, call:
(DELETE-ENV 'NAME)

Envelope data will be loaded when the editor window is opened and saved
whenever the user issues a "save" command. If the user switches envelopes
without saving, there is a prompt to save or ignore.

The user will also be prompted to save when the editor window is closed
or when Nyquist is exited.

Saving the workspace automatically is something that Nyquist should do
(or prompt the user to do) when it exits.

|#

;; WORKSPACE -- the workspace is just a set of variables, typically
;;  with scores as values. These are stored in the file workspace.lsp
;;  so that you can work on some data and then store it for use later.

(cond ((not (boundp '*workspace*))
       (setf *workspace* nil)))
(cond ((not (boundp '*workspace-actions*))
       (setf *workspace-actions* nil)))
;; one of the variables in the workspace is *envelopes*
(cond ((not (boundp '*envelopes*))
       (setf *envelopes* nil)))

;; DESCRIBE -- add a description to a global variable
;;
(defun describe (symbol &optional description)
  (add-to-workspace symbol)
  (cond (description
         (putprop symbol description 'description))
        (t
         (get symbol 'description))))

;; ADD-TO-WORKSPACE -- add a global symbol to workspace
;;
(defun add-to-workspace (symbol)
  (cond ((not (symbolp symbol))
         (format t "add-to-workspace expects a (quoted) symbol~%"))
        ((not (member symbol *workspace*))
         (push symbol *workspace*))))


;; ADD-ACTION-TO-WORKSPACE -- call function when workspace is loaded
;;
(defun add-action-to-workspace (symbol)
  (cond ((not (symbolp symbol))
         (format t "add-action-to-workspace expects a (quoted) symbol~%"))
        ((not (member symbol *workspace-actions*))
         (push symbol *workspace-actions*))))

;; SAVE-WORKSPACE -- write data to file
;;
(defun save-workspace ()
  (let (val (outf (open "workspace.lsp" :direction :output)))
    (dolist (sym *workspace*)
      (format outf "(add-to-workspace '~A)~%" sym)
      (cond ((get sym 'description)
             (format outf "(putprop '~A \"~A\" 'description)~%"
                          sym (get sym 'description))))
      (format outf "(setf ~A '" sym)
      (setf val (symbol-value sym))
      (cond ((listp val)
             (format outf "(~%")
             (dolist (elem val)
               (format outf "  ~A~%" elem))
             (format outf " ))~%~%"))
            (t
             (format outf "~A)~%~%" val))))
    (dolist (sym *workspace-actions*) ;; call hooks after reading data
      (format outf "(add-action-to-workspace '~A)~%" sym)
      (format outf "(if (fboundp '~A) (~A))~%" sym sym))
    (format outf "(princ \"workspace loaded\\n\")~%")
    (close outf)
    (princ "workspace saved\n")
    nil))


;; DEFINE-ENV -- save the env data and make corresponding function
;;
(defun define-env (name expression)
  (delete-env name)
  (push (cons name expression) *envelopes*)
  (make-env-function name expression)
  ; make sure envelopes are redefined when workspace is loaded
  (add-to-workspace '*envelopes*) ; so *envelopes* will be saved
  (describe '*envelopes* "data for envelope editor in jNyqIDE")
  (add-action-to-workspace 'make-env-functions)
  nil)


;; DELETE-ENV -- delete an envelope definition from workspace
;;
;; note that this will not undefine the corresponding envelope function
;;
(defun delete-env (name)
  (setf *envelopes* 
        (remove name *envelopes* 
                :test #'(lambda (key item) (eql key (car item))))))


;; MAKE-ENV-FUNCTION -- convert data to a defined function
;;
(defun make-env-function (name expression)
  (setf (symbol-function name)
        (eval (list 'lambda '() expression))))


;; MAKE-ENV-FUNCTIONS -- convert data to defined functions
;;
(defun make-env-functions ()
  (let (name type parameters)
    (dolist (env *envelopes*)
       (setf name (car env))
       (setf type (cadr env))
       (setf parameters (cddr env))
       (make-env-function name (cons type parameters)))))


;; GET-ENV-DATA -- print env data for IDE
;;
(defun get-env-data ()
    (princ "get-env-data: begin\n")
    (dolist (env *envelopes*)
      (format t "~A ~A~%" (car env) (cdr env)))
    (princ "get-env-data: end\n")
    nil)