1;; envelopes.lsp -- support functions for envelope editor in NyquistIDE
2
3#| In Nyquist, editable envelopes are saved as one entry in the workspace
4named *envelopes*. The entry is an association list where each element
5looks like this:
6
7(name type parameters... )
8
9where name is a symbol, e.g. MY-ENVELOPE-1,
10      type is a function name, e.g. PWL, PWLV, PWE, etc., and
11      parameters are breakpoint data, e.g. 0.1 1 0.2 0.5 1
12
13Example of two envelopes named FOO and BAR:
14
15((FOO PWL 0.1 1 1) (BAR PWE 0.2 1 1))
16
17To convert envelope data into functions, call (MAKE-ENV-FUNCTIONS).
18This function should be on the workspace's list of functions to call.
19(See ADD-ACTION-TO-WORKSPACE in Nyquist Manual.)
20
21When the NyquistIDE wants to get the envelope data from the workspace, it
22should call (GET-ENV-DATA), which will dump formatted data to Nyquist's
23standard output as follows:
24
25get-env-data: begin
26name (type parameters...) newline
27name (type parameters...) newline
28...
29get-env-data: end
30
31When the IDE wants to save a definition, it should call
32(DEFINE-ENV 'NAME 'EXPRESSION)
33
34To delete a definition, call:
35(DELETE-ENV 'NAME)
36
37Envelope data will be loaded when the editor window is opened and saved
38whenever the user issues a "save" command. If the user switches envelopes
39without saving, there is a prompt to save or ignore.
40
41The user will also be prompted to save when the editor window is closed
42or when Nyquist is exited.
43
44Saving the workspace automatically is something that Nyquist should do
45(or prompt the user to do) when it exits.
46
47|#
48
49;; WORKSPACE -- the workspace is just a set of variables, typically
50;;  with scores as values. These are stored in the file workspace.lsp
51;;  so that you can work on some data and then store it for use later.
52
53(cond ((not (boundp '*workspace*))
54       (setf *workspace* nil)))
55(cond ((not (boundp '*workspace-actions*))
56       (setf *workspace-actions* nil)))
57;; one of the variables in the workspace is *envelopes*
58(cond ((not (boundp '*envelopes*))
59       (setf *envelopes* nil)))
60
61;; DESCRIBE -- add a description to a global variable
62;;
63(defun describe (symbol &optional description)
64  (add-to-workspace symbol)
65  (cond (description
66         (putprop symbol description 'description))
67        (t
68         (get symbol 'description))))
69
70;; ADD-TO-WORKSPACE -- add a global symbol to workspace
71;;
72(defun add-to-workspace (symbol)
73  (cond ((not (symbolp symbol))
74         (format t "add-to-workspace expects a (quoted) symbol~%"))
75        ((not (member symbol *workspace*))
76         (push symbol *workspace*))))
77
78
79;; ADD-ACTION-TO-WORKSPACE -- call function when workspace is loaded
80;;
81(defun add-action-to-workspace (symbol)
82  (cond ((not (symbolp symbol))
83         (format t "add-action-to-workspace expects a (quoted) symbol~%"))
84        ((not (member symbol *workspace-actions*))
85         (push symbol *workspace-actions*))))
86
87;; SAVE-WORKSPACE -- write data to file
88;;
89(defun save-workspace ()
90  (let (val (outf (open "workspace.lsp" :direction :output)))
91    (dolist (sym *workspace*)
92      (format outf "(add-to-workspace '~A)~%" sym)
93      (cond ((get sym 'description)
94             (format outf "(putprop '~A \"~A\" 'description)~%"
95                          sym (get sym 'description))))
96      (format outf "(setf ~A '" sym)
97      (setf val (symbol-value sym))
98      (cond ((listp val)
99             (format outf "(~%")
100             (dolist (elem val)
101               (format outf "  ~A~%" elem))
102             (format outf " ))~%~%"))
103            (t
104             (format outf "~A)~%~%" val))))
105    (dolist (sym *workspace-actions*) ;; call hooks after reading data
106      (format outf "(add-action-to-workspace '~A)~%" sym)
107      (format outf "(if (fboundp '~A) (~A))~%" sym sym))
108    (format outf "(princ \"workspace loaded\\n\")~%")
109    (close outf)
110    (princ "workspace saved\n")
111    nil))
112
113
114;; DEFINE-ENV -- save the env data and make corresponding function
115;;
116(defun define-env (name expression)
117  (delete-env name)
118  (push (cons name expression) *envelopes*)
119  (make-env-function name expression)
120  ; make sure envelopes are redefined when workspace is loaded
121  (add-to-workspace '*envelopes*) ; so *envelopes* will be saved
122  (describe '*envelopes* "data for envelope editor in NyquistIDE")
123  (add-action-to-workspace 'make-env-functions)
124  nil)
125
126
127;; DELETE-ENV -- delete an envelope definition from workspace
128;;
129;; note that this will not undefine the corresponding envelope function
130;;
131(defun delete-env (name)
132  (setf *envelopes*
133        (remove name *envelopes*
134                :test #'(lambda (key item) (eql key (car item))))))
135
136
137;; MAKE-ENV-FUNCTION -- convert data to a defined function
138;;
139(defun make-env-function (name expression)
140  (setf (symbol-function name)
141        (eval (list 'lambda '() expression))))
142
143
144;; MAKE-ENV-FUNCTIONS -- convert data to defined functions
145;;
146(defun make-env-functions ()
147  (let (name type parameters)
148    (dolist (env *envelopes*)
149       (setf name (car env))
150       (setf type (cadr env))
151       (setf parameters (cddr env))
152       (make-env-function name (cons type parameters)))))
153
154
155;; GET-ENV-DATA -- print env data for IDE
156;;
157(defun get-env-data ()
158    (princ "get-env-data: begin\n")
159    (dolist (env *envelopes*)
160      (format t "~A ~A~%" (car env) (cdr env)))
161    (princ "get-env-data: end\n")
162    nil)
163
164