Work-in-progress repo for ambisonics extensions for OM-SoX
Alexander Nguyen
22.01.25 92c40d00f8ffe4fc6491c0abb70210b31202bd70
commit | author | age
92c40d 1 ; ********************************************************************
AN 2 ; OM-SoX, (c) 2011-2014 Marlon Schumacher (CIRMMT/McGill University) *
3 ;           http://sourceforge.net/projects/omsox/                   *
4 ;                                                                    *
5 ;  Multichannel Audio Manipulation and Functional Batch Processing.  *
6 ;       DSP based on SoX - (c) C.Bagwell and Contributors            *
7 ;               http://sox.sourceforge.net/                          *
8 ; ********************************************************************
9 ;
10 ;This program is free software; you can redistribute it and/or
11 ;modify it under the terms of the GNU General Public License
12 ;as published by the Free Software Foundation; either version 2
13 ;of the License, or (at your option) any later version.
14 ;
15 ;See file LICENSE for further informations on licensing terms.
16 ;
17 ;This program is distributed in the hope that it will be useful,
18 ;but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;GNU General Public License for more details.
21 ;
22 ;You should have received a copy of the GNU General Public License
23 ;along with this program; if not, write to the Free Software
24 ;Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,10 USA.
25 ;
26 ;Authors: M. Schumacher
27
28 (in-package :om)
29
30
31 ;;; variables =======================
32
33 (defparameter *gnuplot-path* "/usr/local/bin/gnuplot") ; should probably be in the preferences file. For now no specific option for this "/usr/local/bin/gnuplot"
34
35 (defvar *gnuplot-terminal-menu* '(
36                                   ("png" "png")
37                                   ("aqua" "aqua")
38                              ;("ascii" "dumb")
39                                   ("jpeg" "jpeg")
40                                   ("gif" "gif")
41                                   ("pdf" "pdf")
42                                   ("eps" "eps")
43                                   ("eps-landscape" "eps-landscape")
44                                   ))
45
46 (defparameter *gnuplot-terminal-commands* '(
47                                             ("aqua" "set term aqua")
48                                             ("pdf" "set term pdf")
49                                             ("eps" "set term postscript eps color enhanced rounded font \"Times\" 12")
50                                             ("png" "set term pngcairo")
51                                             ("jpeg" "set term jpeg")
52                                             ("gif" "set term gif")
53                                             ))
54                               
55
56 (defun gnuplot-not-found ()
57   ;(om-message-abort (format nil "SoX exectuable not found. Path set in preferences?")
58   (om-beep-msg (format nil "gnuplot not found. Is it in /usr/local/bin ?"))
59   )
60
61 #|
62 (if (probe-file *gnuplot-path*)
63     ()
64   (gnuplot-not-found))
65
66 (environment-variable "PATH")
67 (setf (environment-variable "PATH")
68       (concatenate 'string (environment-variable "PATH")
69                    ":/usr/local/bin"))
70 |#
71
72 ;;; sox-plot ===============================
73
74 ; Perhaps I should be able to connect other things to my sox-plot function.
75 ; For example, to draw a waveform or to draw the dftlist
76 ; So that when it receives a list of values it can plot them (in 2D or 3D)
77 ; this function needs to be able to distinguish list of numbers from biquad effects, from fir effects
78 ; so 3 methods?
79
80 ;perhaps introduce a 3rd dimension (z)
81 (defmethod! sox-plot ((commands string) &key output (terminal "png") (samplerate "48k") (numsamples 250) title x-label y-label x-range y-range (x-scale "logarithmic") (y-scale "deciBel"))
82             :icon 07
83             :initvals '(nil nil "aqua" nil nil nil "" "" "" nil nil nil nil) ;(nil "" "aqua" nil nil nil "" "" "" nil nil nil nil)
84             :menuins (list 
85                       (list 2 *gnuplot-terminal-menu*)
86                       (list 3 *sox-samplerates*)
87                       (list 10 '(("linear" "linear") ("logarithmic" "logarithmic")))
88                       (list 11 '(("linear" "linear") ("deciBel" "deciBel"))))
89
90             (if (probe-file *sox-path*)
91                 (if (probe-file *gnuplot-path*)
92
93                       (let ((outfile (create-path () output "plt")))
94                         (sox-print "terminal:" terminal)
95                         (sox-print "outfile:" outfile)
96                         (setf str 
97                               (format nil "~s -r~a --plot gnuplot -n -n " 
98                                       (namestring *sox-path*)     
99                                       samplerate                              
100                                       ))
101                         
102                         (setf str (string+ str commands " >"))
103                         (setf str (sox-concat outfile str))
104                         (om-cmd-line str *sys-console*)
105                         (let ((mypltfile (probe-file outfile)))
106
107                           ;modif of textfile
108                             (let* ((loaded-textfile (objfromobjs outfile (make-instance 'textfile :eval-mode "text")))
109                                    (xscale (if (equal x-scale "logarithmic") "set logscale x" "#set logscale x"))
110                                    (samples (format nil "set samples ~D" numsamples))
111                                    (plot-title (format nil "set title '~a'" title))
112                                    (x-range (or x-range (list 10 "Fs/2")))
113                                    (y-range (or y-range (if (equal y-scale "deciBel") (list -40 12) (list 0 2))))
114                                    (xlabel (if x-label ; maybe this  if-statement is not needed, as X is always Frequency and Y always Amplitude
115                                                (if (equal x-label "") "#set xlabel <not set>" (format nil "set xlabel '~a'" x-label))
116                                              (if (equal x-scale "logarithmic") "set xlabel 'Frequency (Hz) (log.)'" "set xlabel 'Frequency (Hz)'")))
117                                    (ylabel (if y-label
118                                                (if (equal y-label "") "#set ylabel <not set>" (format nil "set ylabel '~a'" y-label))
119                                              (if (equal y-scale "deciBel") "set ylabel 'Amplitude (dBFS)'" "set ylabel 'Amplitude (linear)'")))
120                                    (plot-text (if (equal y-scale "deciBel") 
121                                                   (format nil "plot [f=~D:~a] [~D:~D] 20*log10(H(f))" (first x-range) (second x-range) (first y-range) (second y-range))
122                                                 (format nil "plot [f=~D:~a] [~D:~D] (H(f))" (first x-range) (second x-range) (first y-range) (second y-range))))
123                                    (plot-fir-text (if numsamples (format nil "plot '-' with lines") (format nil "plot '-'")))
124                                    (manipulated-text (if (find (read-from-string commands) '(fir hilbert sinc))
125                                                          (if title
126                                                              (insert-in-list (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) 
127                                                                                         '(0 1 2 5) (list plot-title xlabel ylabel plot-fir-text)) xscale 3)
128                                                            (insert-in-list (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) 
129                                                                                       '(1 2 5) (list xlabel ylabel plot-fir-text)) xscale 3))
130                                                        (if title 
131                                                            (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) '(0 1 2 7 8 11) (list plot-title xlabel ylabel xscale samples plot-text))
132                                                          (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) '(1 2 7 8 11) (list xlabel ylabel xscale samples plot-text)))))
133
134                                    (mypicfile (create-path () output terminal))
135                                    (new-text (x-append *sox-gnuplot-header* 
136                                                        (second (assoc terminal *gnuplot-terminal-commands* :test #'equalp))
137                                                        (format nil "set output ~s" (namestring mypicfile))
138                                                        manipulated-text))
139                                    (new-textfile (make-instance 'textfile :eval-mode "text" )))
140                               (setf (exp-list new-textfile) new-text)
141                               (save-data new-textfile mypltfile)
142                               (probe-file mypltfile)                           
143                               (om-cmd-line (format nil "~s ~s " *gnuplot-path* (namestring mypltfile)) *sys-console*)                            
144                               (let ((myoutfile (probe-file mypicfile))
145                                     (mypict (make-instance 'picture)))
146                                 (setf (background mypict) myoutfile)
147                                 
148                               ;optional removal of temporary files
149                                 (add-tmp-file mypltfile)
150                                 (add-tmp-file myoutfile) 
151                                 (when *delete-inter-file* (clean-tmp-files))
152                                 mypict)
153                               );)
154                           )
155                         )
156                   (gnuplot-not-found))
157               (sox-not-found)
158               )
159             )
160
161
162 (defmethod! sox-plot ((data list) &key output (terminal "png") (samplerate "48k") (numsamples 250) title x-label y-label x-range y-range x-scale y-scale)
163             
164             (if (probe-file *sox-path*)
165                 (if (probe-file *gnuplot-path*)
166
167                             (let* ((mypltfile (print (create-path () output "plt")))
168                                    (default-text *default-gnuplot-text*)
169                                    (dimensions (length (car data)))
170                                    (datalist (if (eq dimensions 3)
171                                                  (loop for item in data collect
172                                                        (format nil "~d ~d ~d" (first item) (if (equal y-scale "deciBel") (lin->dB (abs (second item))) (second item)) (third item) #\newline)
173                                                        )
174                                                (loop for item in data collect
175                                                      (format nil "~d ~d" (first item) (if (equal y-scale "deciBel") (lin->dB (abs (second item))) (second item)) #\newline)
176                                                      )))
177                                    ;isn't that (datalist) like this? (reduce #'(lambda (s1 s2) (format nil "~d ~d " s1 s2)) coefficients) -> and like 'concat-strings'?
178                                    (xscale (if (equal x-scale "logarithmic") "set logscale x" "#set logscale x"))
179                                    (samples (format nil "set samples ~D" numsamples))
180                                    (plot-title (format nil "set title '~a'" title))
181
182                                    ;ranges have no effect at the moment. Don't know how to set it for gnuplot. Would need a band-filter on the data list.
183  
184                                    (xlabel (if x-label (format nil "set xlabel '~a'" x-label) "#set xlabel <not set>"))
185                                    (ylabel (if y-label (format nil "set ylabel '~a'" y-label) "#set ylabel <not set>"))
186                                    (plot-list-text (if (eq dimensions 3)
187                                                        (if numsamples (format nil "splot '-' with lines") (format nil "splot '-'"))
188                                                      (if numsamples (format nil "plot '-' with lines") (format nil "plot '-'"))))
189                                    (manipulated-text (if title (subs-posn default-text '(0 1 2 3 6) (list plot-title xlabel ylabel xscale plot-list-text))
190                                                        (subs-posn default-text '(1 2 3 6) (list xlabel ylabel xscale plot-list-text))))      
191                                    (mypicfile (create-path () output terminal))
192                                    (new-text (x-append *sox-gnuplot-header* 
193                                                        (second (assoc terminal *gnuplot-terminal-commands* :test #'equalp))
194                                                        (format nil "set output ~s" (namestring mypicfile))
195                                                        manipulated-text
196                                                        datalist))
197                                    (new-textfile (make-instance 'textfile :eval-mode "text" )))
198                               (setf (exp-list new-textfile) new-text)
199                               (save-data new-textfile mypltfile)
200                               (probe-file mypltfile)                           
201                               (om-cmd-line (format nil "~s ~s " *gnuplot-path* (namestring mypltfile)) *sys-console*)                            
202                               (let ((myoutfile (probe-file mypicfile))
203                                     (mypict (make-instance 'picture)))
204                                 (setf (background mypict) myoutfile)
205                                 
206                               ;optional removal of temporary files
207                                 (add-tmp-file mypltfile)
208                                 (add-tmp-file myoutfile) 
209                                 (when *delete-inter-file* (clean-tmp-files))
210                                 mypict)                              
211                               )
212                   (gnuplot-not-found))
213               (sox-not-found)
214               )
215             )
216
217 #|
218 (defmethod sox-coeffs-to-string ((coeffs list))
219        (if (eq (length (car coeffs)) 2)
220            (reduce #'(lambda (s1 s2) (format nil "~d ~d " s1 s2 #\newline)) coeffs)
221          (reduce #'(lambda (s1 s2 s3) (format nil "~d ~d ~d " s1 s2 s3 #\newline)) coeffs)
222          )) ;doesn't seem to work -- WHY?
223
224 (setf test-list '(("Aqua" "Bingo") ("Delta" "nothing")))
225 (assoc "Aqua" test-list :test #'equalp)
226 (second (find "Aqua" test-list :test (lambda (item arg)
227                                  (string-equal item (car arg)))))
228 |#
229
230 (defmethod! sox-plot ((data bpf) &key output (terminal "png") (samplerate "48k") (numsamples 250) biquad-cascade title x-label y-label x-range y-range x-scale y-scale)
231             (sox-plot (mat-trans (list (x-points data) (y-points data))) :output output :terminal terminal :samplerate samplerate :numsamples numsamples :biquad-cascade biquad-cascade
232                       :title title :x-label x-label :y-label y-label :x-range x-range :y-range y-range :x-scale x-scale :y-scale y-scale))
233
234 (defmethod! sox-plot ((data 3dc) &key output (terminal "png") (samplerate "48k") (numsamples 250) biquad-cascade title x-label y-label x-range y-range x-scale y-scale)
235             (sox-plot (mat-trans (list (x-points data) (y-points data) (z-points data))) :output output :terminal terminal :samplerate samplerate :numsamples numsamples :biquad-cascade biquad-cascade
236                       :title title :x-label x-label :y-label y-label :x-range x-range :y-range y-range :x-scale x-scale :y-scale y-scale))
237
238 (defparameter *exp-list* '("# gnuplot file" "set title 'SoX effect: bass gain=12 frequency=100 Q=10 (rate=48000)'" "set xlabel 'Frequency (Hz)'" "set ylabel 'Amplitude Response (dB)'" "Fs=48000" "b0=1.000524909583901e+00; b1=-1.998859954575080e+00; b2=9.986767718845346e-01; a1=-1.998987899064422e+00; a2=9.990737369790924e-01" "o=2*pi/Fs" "H(f)=sqrt((b0*b0+b1*b1+b2*b2+2.*(b0*b1+b1*b2)*cos(f*o)+2.*(b0*b2)*cos(2.*f*o))/(1.+a1*a1+a2*a2+2.*(a1+a1*a2)*cos(f*o)+2.*a2*cos(2.*f*o)))" "#set logscale x" "set samples 250" "#set grid xtics ytics" "#set key off" "plot [f=10:Fs/2] [-35:55] H(f) #20*log10(H(f))" "pause -1 'Hit return to continue'" ""))
239
240
241 ;-> perhaps add this to the sox-plot function: Meaning, that you can make a list of the individual fx, then supply them to "biquad" cascade!!
242
243 #|
244 (defmethod! sox-multiplot (&rest biquad-fx &key output (terminal "png") (samplerate "48k") (numsamples 250) biquad-cascade title x-label y-label x-range y-range x-scale y-scale)
245             ; this function is like sox-plot but allows to connect multiple effects which are then combined in the visualization (new inlet per new biquad effect))
246             :icon 07
247            ; :initvals (list (repeat-n nil (length biquad-effects))  nil "" "aqua" nil nil nil "" "" "" nil nil nil nil) ;hmmm, not sure what to do with the initvals
248            ; :menuins (list 
249            ;           (list 2 *gnuplot-terminal-menu*)
250            ;           (list 3 *sox-samplerates*)
251            ;           (list 10 '(("linear" "linear") ("logarithmic" "logarithmic")))
252            ;           (list 11 '(("linear" "linear") ("deciBel" "deciBel"))))
253            ; :doc '("sox-multiplot allows connecting multiple effects which are then combined and plotted (new inlet per sox-effect)
254
255 ;Plots the combined amplitude response of biquad-based effects. Biquad-based effects are: 
256 ;highpass, lowpass, bandpass, bandreject, allpass, bass, treble, equalizer, band, deemph, riaa, biquad.")
257
258             (if (probe-file *sox-path*)
259                 (if (probe-file *gnuplot-path*)
260                     
261                     (let* ((default-text *def-pearl-txt*)                            
262                            (datalist (sox-reduce-fx biquad-fx))
263                            (xscale (if (equal x-scale "logarithmic") "set logscale x" "#set logscale x"))
264                            (samples (format nil "set samples ~D" numsamples))
265                            (plot-title (or title (format nil "set title 'SoX effects: $desc (rate=$rate)'")))
266                            (xlabel (if x-label ; maybe this  if-statement is not needed, as X is always Frequency and Y always Amplitude
267                                        (if (equal x-label "") "#set xlabel <not set>" (format nil "set xlabel '~a'" x-label))
268                                      (if (equal x-scale "logarithmic") "set xlabel 'Frequency (Hz) (log.)'" "set xlabel 'Frequency (Hz)'")))                   
269                            (ylabel (if y-label
270                                        (if (equal y-label "") "#set ylabel <not set>" (format nil "set ylabel '~a'" y-label))
271                                      (if (equal y-scale "deciBel") "set ylabel 'Amplitude (dBFS)'" "set ylabel 'Amplitude (linear)'")))
272                            (sox-gnuplot-call "$_ = `~a --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`" *sox-path*)
273                            (plot-text (if (equal y-scale "deciBel") 
274                                           (format nil "plot [f=~D:~a] [~D:~D] 20*log10(H(f))" (first x-range) (second x-range) (first y-range) (second y-range))
275                                         (format nil "plot [f=~D:~a] [~D:~D] (H(f))" (first x-range) (second x-range) (first y-range) (second y-range))))
276                                    
277                                    (manipulated-text (if title (subs-posn default-text '(0 1 2 3 6) (list plot-title xlabel ylabel xscale plot-list-text))
278                                                        (subs-posn default-text '(1 2 3 6) (list xlabel ylabel xscale plot-list-text))))                                                                                 
279                                    (mypicfile (create-path () output terminal))
280                                    (new-text (x-append *sox-gnuplot-header* 
281                                                        (second (assoc terminal *gnuplot-terminal-commands* :test #'equalp))
282                                                        (format nil "set output ~s" (namestring mypicfile))
283                                                        manipulated-text
284                                                        datalist)) 
285                                    (new-textfile (make-instance 'textfile :eval-mode "text" )))
286                       (setf (exp-list new-textfile) new-text)
287                       (save-data new-textfile mypearlfile)
288                       (probe-file mypearlfile)                           
289                       (om-cmd-line (format nil "~s ~s " mypearlfile (namestring mypltfile)) *sys-console*)
290                               datalist
291                               (let ((myoutfile (probe-file mypicfile))
292                                     (mypict (make-instance 'picture)))
293                                 (setf (background mypict) myoutfile)
294                                 
295                               ;optional removal of temporary files
296                                 (add-tmp-file mypltfile)
297                                 (add-tmp-file myoutfile) 
298                                 (when *delete-inter-file* (clean-tmp-files))
299                                 mypict)                              
300                               )
301                   (gnuplot-not-found))
302               (sox-not-found)
303               )
304 |#
305
306
307 (defparameter *sox-gnuplot-header* '("#This file was produced for gnuplot by OM-SoX v1.0."))
308 (defparameter *default-gnuplot-text* (list 
309                                       "#set title <no title>"
310                                       "set xlabel <not set>"
311                                       "set ylabel <not set>"
312                                       "set scale <not set>"
313                                       "set grid xtics ytics"
314                                       "set key off"
315                                       "plot '-' with lines"))
316
317 (defparameter *def-pearl-txt* '((*sox-gnuplot-header*
318                                  "# Perl Script by Ulrich Klauer"
319                                  ""
320                                  "my $rate = 48000;"
321                                  "$rate = shift   if $ARGV[0] =~ /^\d+$/ && $ARGV[0] != 0;"
322                                  "#usage() if $#ARGV == -1;"
323                                  "my $desc = join(" ", @ARGV);"
324                                  "print <<END;"
325                                  "# gnuplot file"
326                                  "set title 'SoX effects: $desc (rate=$rate)'"
327                                  "set terminal 'png'"
328                                  "set output <not set>"
329                                  "#set xlabel <not set>"
330                                  "#set ylabel <not set>"
331                                  "Fs=$rate"
332                                  "o=2*pi/Fs"
333                                  "#set logscale x"
334                                  "set grid xtics ytics"
335                                  "set key off"
336                                  "END"
337                                  "my $l = 0;"
338                                  "foreach (@ARGV) {"
339                                  "    $l++;"
340                                  "      $_ = `sox --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`;"
341                                  "    s/([ab][012])/$1_$l/g;"
342                                  "    print;"
343                                  "    print \"H_$l(f)=sqrt((b0_$l*b0_$l+b1_$l*b1_$l+b2_$l*b2_$l+2.*(b0_$l*b1_$l+b1_$l*b2_$l)*cos(f*o)+2.*(b0_$l*b2_$l)*cos(2.*f*o))/(1.+a1_$l*a1_$l+a2_$l*a2_$l+2.*(a1_$l+a1_$l*a2_$l)*cos(f*o)+2.*a2_$l*cos(2.*f*o)))\n\";"
344                                  "}"
345                                  "my $prod = join(\"*\", map { \"H_$_(f)\" } (1..$l));"
346                                  "print \"H(f)=$prod\n\";"                      
347                                  "print <<END;"
348                                  "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))" ;this gets replaced by my function
349                                  "END")
350                                 ))
351
352
353 ;(defun string+ (&rest strings) (eval `(concatenate 'string ,.strings)))
354
355 (defun sox-reduce-effects (effects)
356   (reduce #'(lambda (old new) (format nil " ~a \"~a\" " old new)) 
357           effects :initial-value "")
358   )
359
360 (defun sox-reduce-fx (&rest effects)
361   (reduce #'(lambda (old new) (format nil " ~a \"~a\" " old new)) 
362           effects :initial-value "")
363   )
364
365
366 ; the perl script:
367 ; gotta use this together with arguments <file> args ... (which are the commands!)
368
369 #|
370 "#!/usr/bin/perl -w
371
372 sub usage() {
373     print STDERR "Usage: $0 [sampling_rate] \"effect1 effargs1\" " .
374         "\"effect2 effargs2\" ...\n";
375     print STDERR "Plots the combined amplitude response of biquad-based " .
376         "effects.\n";
377     print STDERR "Biquad-based effects are: highpass, lowpass, " .
378         "bandpass, bandreject, allpass,\n" . "bass, treble, " .
379         "equalizer, band, deemph, riaa, biquad.\n";
380     exit(1);
381 }
382
383 usage() if $#ARGV == -1;
384
385
386 ;--------this above is not needed-------
387
388 ;maybe don't change this title (or title (format nil "set title 'SoX effects: $desc (rate=$rate)'"))"
389
390
391 "set title 'SoX effects: $desc (rate=$rate)' 
392 "#set xlabel <not set>"
393 "#set ylabel <not set>"
394 "Fs=$rate"
395 "o=2*pi/Fs"
396 "#set logscale x"
397 "set grid xtics ytics"
398 "set key off"
399 "END"
400 "my $l = 0;"
401 "foreach (@ARGV) {"
402 "    $l++;"
403 "$_ = `sox --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`;"
404 "    s/([ab][012])/$1_$l/g;"
405 "    print;"
406 "    print \"H_$l(f)=sqrt((b0_$l*b0_$l+b1_$l*b1_$l+b2_$l*b2_$l+2.*(b0_$l*b1_$l+b1_$l*b2_$l)*cos(f*o)+2.*(b0_$l*b2_$l)*cos(2.*f*o))/(1.+a1_$l*a1_$l+a2_$l*a2_$l+2.*(a1_$l+a1_$l*a2_$l)*cos(f*o)+2.*a2_$l*cos(2.*f*o)))\n\";"
407 "}"
408 "my $prod = join(\"*\", map { \"H_$_(f)\" } (1..$l));"
409 "print \"H(f)=$prod\n\";"
410
411 "print <<END;"
412 "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))" ;this gets replaced by my function
413 "END")
414
415 (format nil "$_ = `~a --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`" *sox-path*)
416
417 |#
418
419 ; plotting directly in OM would be the most flexible!
420 (defun biquad-equation (f b0 b1 b2 a1 a2 samplerate)
421   (let* ((o (/ (* 2 pi) samplerate)))
422     ; this creates a complex number for some reason... where? probably a negative number
423     ; what does this mean (from the scripts): o=2*pi/Fs
424     (sqrt (/ (+ (* b0 b0)
425                 (* b1 b1)
426                 (* b2 b2)
427                 (* 2 (+ (* b0 b1) (* b1 b2)) (cos (* f o)))
428                 (* 2 (* b0 b2) (cos (* 2 f o))))
429              (+ 1 (* a1 a1) (* a2 a2) 
430                 (* 2 (+ a1 (* a1 a2))
431                    (cos (* f o)))
432                 (* 2 (* a2 (cos (* 2 f o)))))))
433     ))
434