Work-in-progress repo for ambisonics extensions for OM-SoX
Marlon Schumacher
5 days ago 3c36efb7ea5dd8cccd9bcc47f4f6e71ee4cfcbb2
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
; ********************************************************************
; OM-SoX, (c) 2011-2014 Marlon Schumacher (CIRMMT/McGill University) *
;           http://sourceforge.net/projects/omsox/                   *
;                                                                    *
;  Multichannel Audio Manipulation and Functional Batch Processing.  *
;       DSP based on SoX - (c) C.Bagwell and Contributors            *
;               http://sox.sourceforge.net/                          *
; ********************************************************************
;
;This program is free software; you can redistribute it and/or
;modify it under the terms of the GNU General Public License
;as published by the Free Software Foundation; either version 2
;of the License, or (at your option) any later version.
;
;See file LICENSE for further informations on licensing terms.
;
;This program is distributed in the hope that it will be useful,
;but WITHOUT ANY WARRANTY; without even the implied warranty of
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;GNU General Public License for more details.
;
;You should have received a copy of the GNU General Public License
;along with this program; if not, write to the Free Software
;Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,10 USA.
;
;Authors: M. Schumacher
 
(in-package :om)
 
 
;;; variables =======================
 
(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"
 
(defvar *gnuplot-terminal-menu* '(
                                  ("png" "png")
                                  ("aqua" "aqua")
                             ;("ascii" "dumb")
                                  ("jpeg" "jpeg")
                                  ("gif" "gif")
                                  ("pdf" "pdf")
                                  ("eps" "eps")
                                  ("eps-landscape" "eps-landscape")
                                  ))
 
(defparameter *gnuplot-terminal-commands* '(
                                            ("aqua" "set term aqua")
                                            ("pdf" "set term pdf")
                                            ("eps" "set term postscript eps color enhanced rounded font \"Times\" 12")
                                            ("png" "set term pngcairo")
                                            ("jpeg" "set term jpeg")
                                            ("gif" "set term gif")
                                            ))
                              
 
(defun gnuplot-not-found ()
  ;(om-message-abort (format nil "SoX exectuable not found. Path set in preferences?")
  (om-beep-msg (format nil "gnuplot not found. Is it in /usr/local/bin ?"))
  )
 
#|
(if (probe-file *gnuplot-path*)
    ()
  (gnuplot-not-found))
 
(environment-variable "PATH")
(setf (environment-variable "PATH")
      (concatenate 'string (environment-variable "PATH")
                   ":/usr/local/bin"))
|#
 
;;; sox-plot ===============================
 
; Perhaps I should be able to connect other things to my sox-plot function.
; For example, to draw a waveform or to draw the dftlist
; So that when it receives a list of values it can plot them (in 2D or 3D)
; this function needs to be able to distinguish list of numbers from biquad effects, from fir effects
; so 3 methods?
 
;perhaps introduce a 3rd dimension (z)
(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"))
            :icon 07
            :initvals '(nil nil "aqua" nil nil nil "" "" "" nil nil nil nil) ;(nil "" "aqua" nil nil nil "" "" "" nil nil nil nil)
            :menuins (list 
                      (list 2 *gnuplot-terminal-menu*)
                      (list 3 *sox-samplerates*)
                      (list 10 '(("linear" "linear") ("logarithmic" "logarithmic")))
                      (list 11 '(("linear" "linear") ("deciBel" "deciBel"))))
 
            (if (probe-file *sox-path*)
                (if (probe-file *gnuplot-path*)
 
                      (let ((outfile (create-path () output "plt")))
                        (sox-print "terminal:" terminal)
                        (sox-print "outfile:" outfile)
                        (setf str 
                              (format nil "~s -r~a --plot gnuplot -n -n " 
                                      (namestring *sox-path*)     
                                      samplerate                              
                                      ))
                        
                        (setf str (string+ str commands " >"))
                        (setf str (sox-concat outfile str))
                        (om-cmd-line str *sys-console*)
                        (let ((mypltfile (probe-file outfile)))
 
                          ;modif of textfile
                            (let* ((loaded-textfile (objfromobjs outfile (make-instance 'textfile :eval-mode "text")))
                                   (xscale (if (equal x-scale "logarithmic") "set logscale x" "#set logscale x"))
                                   (samples (format nil "set samples ~D" numsamples))
                                   (plot-title (format nil "set title '~a'" title))
                                   (x-range (or x-range (list 10 "Fs/2")))
                                   (y-range (or y-range (if (equal y-scale "deciBel") (list -40 12) (list 0 2))))
                                   (xlabel (if x-label ; maybe this  if-statement is not needed, as X is always Frequency and Y always Amplitude
                                               (if (equal x-label "") "#set xlabel <not set>" (format nil "set xlabel '~a'" x-label))
                                             (if (equal x-scale "logarithmic") "set xlabel 'Frequency (Hz) (log.)'" "set xlabel 'Frequency (Hz)'")))
                                   (ylabel (if y-label
                                               (if (equal y-label "") "#set ylabel <not set>" (format nil "set ylabel '~a'" y-label))
                                             (if (equal y-scale "deciBel") "set ylabel 'Amplitude (dBFS)'" "set ylabel 'Amplitude (linear)'")))
                                   (plot-text (if (equal y-scale "deciBel") 
                                                  (format nil "plot [f=~D:~a] [~D:~D] 20*log10(H(f))" (first x-range) (second x-range) (first y-range) (second y-range))
                                                (format nil "plot [f=~D:~a] [~D:~D] (H(f))" (first x-range) (second x-range) (first y-range) (second y-range))))
                                   (plot-fir-text (if numsamples (format nil "plot '-' with lines") (format nil "plot '-'")))
                                   (manipulated-text (if (find (read-from-string commands) '(fir hilbert sinc))
                                                         (if title
                                                             (insert-in-list (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) 
                                                                                        '(0 1 2 5) (list plot-title xlabel ylabel plot-fir-text)) xscale 3)
                                                           (insert-in-list (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) 
                                                                                      '(1 2 5) (list xlabel ylabel plot-fir-text)) xscale 3))
                                                       (if title 
                                                           (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) '(0 1 2 7 8 11) (list plot-title xlabel ylabel xscale samples plot-text))
                                                         (subs-posn (butlast (butlast (cdr (exp-list loaded-textfile)))) '(1 2 7 8 11) (list xlabel ylabel xscale samples plot-text)))))
 
                                   (mypicfile (create-path () output terminal))
                                   (new-text (x-append *sox-gnuplot-header* 
                                                       (second (assoc terminal *gnuplot-terminal-commands* :test #'equalp))
                                                       (format nil "set output ~s" (namestring mypicfile))
                                                       manipulated-text))
                                   (new-textfile (make-instance 'textfile :eval-mode "text" )))
                              (setf (exp-list new-textfile) new-text)
                              (save-data new-textfile mypltfile)
                              (probe-file mypltfile)                           
                              (om-cmd-line (format nil "~s ~s " *gnuplot-path* (namestring mypltfile)) *sys-console*)                            
                              (let ((myoutfile (probe-file mypicfile))
                                    (mypict (make-instance 'picture)))
                                (setf (background mypict) myoutfile)
                                
                              ;optional removal of temporary files
                                (add-tmp-file mypltfile)
                                (add-tmp-file myoutfile) 
                                (when *delete-inter-file* (clean-tmp-files))
                                mypict)
                              );)
                          )
                        )
                  (gnuplot-not-found))
              (sox-not-found)
              )
            )
 
 
(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)
            
            (if (probe-file *sox-path*)
                (if (probe-file *gnuplot-path*)
 
                            (let* ((mypltfile (print (create-path () output "plt")))
                                   (default-text *default-gnuplot-text*)
                                   (dimensions (length (car data)))
                                   (datalist (if (eq dimensions 3)
                                                 (loop for item in data collect
                                                       (format nil "~d ~d ~d" (first item) (if (equal y-scale "deciBel") (lin->dB (abs (second item))) (second item)) (third item) #\newline)
                                                       )
                                               (loop for item in data collect
                                                     (format nil "~d ~d" (first item) (if (equal y-scale "deciBel") (lin->dB (abs (second item))) (second item)) #\newline)
                                                     )))
                                   ;isn't that (datalist) like this? (reduce #'(lambda (s1 s2) (format nil "~d ~d " s1 s2)) coefficients) -> and like 'concat-strings'?
                                   (xscale (if (equal x-scale "logarithmic") "set logscale x" "#set logscale x"))
                                   (samples (format nil "set samples ~D" numsamples))
                                   (plot-title (format nil "set title '~a'" title))
 
                                   ;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.
 
                                   (xlabel (if x-label (format nil "set xlabel '~a'" x-label) "#set xlabel <not set>"))
                                   (ylabel (if y-label (format nil "set ylabel '~a'" y-label) "#set ylabel <not set>"))
                                   (plot-list-text (if (eq dimensions 3)
                                                       (if numsamples (format nil "splot '-' with lines") (format nil "splot '-'"))
                                                     (if numsamples (format nil "plot '-' with lines") (format nil "plot '-'"))))
                                   (manipulated-text (if title (subs-posn default-text '(0 1 2 3 6) (list plot-title xlabel ylabel xscale plot-list-text))
                                                       (subs-posn default-text '(1 2 3 6) (list xlabel ylabel xscale plot-list-text))))      
                                   (mypicfile (create-path () output terminal))
                                   (new-text (x-append *sox-gnuplot-header* 
                                                       (second (assoc terminal *gnuplot-terminal-commands* :test #'equalp))
                                                       (format nil "set output ~s" (namestring mypicfile))
                                                       manipulated-text
                                                       datalist))
                                   (new-textfile (make-instance 'textfile :eval-mode "text" )))
                              (setf (exp-list new-textfile) new-text)
                              (save-data new-textfile mypltfile)
                              (probe-file mypltfile)                           
                              (om-cmd-line (format nil "~s ~s " *gnuplot-path* (namestring mypltfile)) *sys-console*)                            
                              (let ((myoutfile (probe-file mypicfile))
                                    (mypict (make-instance 'picture)))
                                (setf (background mypict) myoutfile)
                                
                              ;optional removal of temporary files
                                (add-tmp-file mypltfile)
                                (add-tmp-file myoutfile) 
                                (when *delete-inter-file* (clean-tmp-files))
                                mypict)                              
                              )
                  (gnuplot-not-found))
              (sox-not-found)
              )
            )
 
#|
(defmethod sox-coeffs-to-string ((coeffs list))
       (if (eq (length (car coeffs)) 2)
           (reduce #'(lambda (s1 s2) (format nil "~d ~d " s1 s2 #\newline)) coeffs)
         (reduce #'(lambda (s1 s2 s3) (format nil "~d ~d ~d " s1 s2 s3 #\newline)) coeffs)
         )) ;doesn't seem to work -- WHY?
 
(setf test-list '(("Aqua" "Bingo") ("Delta" "nothing")))
(assoc "Aqua" test-list :test #'equalp)
(second (find "Aqua" test-list :test (lambda (item arg)
                                 (string-equal item (car arg)))))
|#
 
(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)
            (sox-plot (mat-trans (list (x-points data) (y-points data))) :output output :terminal terminal :samplerate samplerate :numsamples numsamples :biquad-cascade biquad-cascade
                      :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))
 
(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)
            (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
                      :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))
 
(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'" ""))
 
 
;-> 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!!
 
#|
(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)
            ; 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))
            :icon 07
           ; :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
           ; :menuins (list 
           ;           (list 2 *gnuplot-terminal-menu*)
           ;           (list 3 *sox-samplerates*)
           ;           (list 10 '(("linear" "linear") ("logarithmic" "logarithmic")))
           ;           (list 11 '(("linear" "linear") ("deciBel" "deciBel"))))
           ; :doc '("sox-multiplot allows connecting multiple effects which are then combined and plotted (new inlet per sox-effect)
 
;Plots the combined amplitude response of biquad-based effects. Biquad-based effects are: 
;highpass, lowpass, bandpass, bandreject, allpass, bass, treble, equalizer, band, deemph, riaa, biquad.")
 
            (if (probe-file *sox-path*)
                (if (probe-file *gnuplot-path*)
                    
                    (let* ((default-text *def-pearl-txt*)                            
                           (datalist (sox-reduce-fx biquad-fx))
                           (xscale (if (equal x-scale "logarithmic") "set logscale x" "#set logscale x"))
                           (samples (format nil "set samples ~D" numsamples))
                           (plot-title (or title (format nil "set title 'SoX effects: $desc (rate=$rate)'")))
                           (xlabel (if x-label ; maybe this  if-statement is not needed, as X is always Frequency and Y always Amplitude
                                       (if (equal x-label "") "#set xlabel <not set>" (format nil "set xlabel '~a'" x-label))
                                     (if (equal x-scale "logarithmic") "set xlabel 'Frequency (Hz) (log.)'" "set xlabel 'Frequency (Hz)'")))                   
                           (ylabel (if y-label
                                       (if (equal y-label "") "#set ylabel <not set>" (format nil "set ylabel '~a'" y-label))
                                     (if (equal y-scale "deciBel") "set ylabel 'Amplitude (dBFS)'" "set ylabel 'Amplitude (linear)'")))
                           (sox-gnuplot-call "$_ = `~a --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`" *sox-path*)
                           (plot-text (if (equal y-scale "deciBel") 
                                          (format nil "plot [f=~D:~a] [~D:~D] 20*log10(H(f))" (first x-range) (second x-range) (first y-range) (second y-range))
                                        (format nil "plot [f=~D:~a] [~D:~D] (H(f))" (first x-range) (second x-range) (first y-range) (second y-range))))
                                   
                                   (manipulated-text (if title (subs-posn default-text '(0 1 2 3 6) (list plot-title xlabel ylabel xscale plot-list-text))
                                                       (subs-posn default-text '(1 2 3 6) (list xlabel ylabel xscale plot-list-text))))                                                                                 
                                   (mypicfile (create-path () output terminal))
                                   (new-text (x-append *sox-gnuplot-header* 
                                                       (second (assoc terminal *gnuplot-terminal-commands* :test #'equalp))
                                                       (format nil "set output ~s" (namestring mypicfile))
                                                       manipulated-text
                                                       datalist)) 
                                   (new-textfile (make-instance 'textfile :eval-mode "text" )))
                      (setf (exp-list new-textfile) new-text)
                      (save-data new-textfile mypearlfile)
                      (probe-file mypearlfile)                           
                      (om-cmd-line (format nil "~s ~s " mypearlfile (namestring mypltfile)) *sys-console*)
                              datalist
                              (let ((myoutfile (probe-file mypicfile))
                                    (mypict (make-instance 'picture)))
                                (setf (background mypict) myoutfile)
                                
                              ;optional removal of temporary files
                                (add-tmp-file mypltfile)
                                (add-tmp-file myoutfile) 
                                (when *delete-inter-file* (clean-tmp-files))
                                mypict)                              
                              )
                  (gnuplot-not-found))
              (sox-not-found)
              )
|#
 
 
(defparameter *sox-gnuplot-header* '("#This file was produced for gnuplot by OM-SoX v1.0."))
(defparameter *default-gnuplot-text* (list 
                                      "#set title <no title>"
                                      "set xlabel <not set>"
                                      "set ylabel <not set>"
                                      "set scale <not set>"
                                      "set grid xtics ytics"
                                      "set key off"
                                      "plot '-' with lines"))
 
(defparameter *def-pearl-txt* '((*sox-gnuplot-header*
                                 "# Perl Script by Ulrich Klauer"
                                 ""
                                 "my $rate = 48000;"
                                 "$rate = shift   if $ARGV[0] =~ /^\d+$/ && $ARGV[0] != 0;"
                                 "#usage() if $#ARGV == -1;"
                                 "my $desc = join(" ", @ARGV);"
                                 "print <<END;"
                                 "# gnuplot file"
                                 "set title 'SoX effects: $desc (rate=$rate)'"
                                 "set terminal 'png'"
                                 "set output <not set>"
                                 "#set xlabel <not set>"
                                 "#set ylabel <not set>"
                                 "Fs=$rate"
                                 "o=2*pi/Fs"
                                 "#set logscale x"
                                 "set grid xtics ytics"
                                 "set key off"
                                 "END"
                                 "my $l = 0;"
                                 "foreach (@ARGV) {"
                                 "    $l++;"
                                 "      $_ = `sox --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`;"
                                 "    s/([ab][012])/$1_$l/g;"
                                 "    print;"
                                 "    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\";"
                                 "}"
                                 "my $prod = join(\"*\", map { \"H_$_(f)\" } (1..$l));"
                                 "print \"H(f)=$prod\n\";"                      
                                 "print <<END;"
                                 "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))" ;this gets replaced by my function
                                 "END")
                                ))
 
 
;(defun string+ (&rest strings) (eval `(concatenate 'string ,.strings)))
 
(defun sox-reduce-effects (effects)
  (reduce #'(lambda (old new) (format nil " ~a \"~a\" " old new)) 
          effects :initial-value "")
  )
 
(defun sox-reduce-fx (&rest effects)
  (reduce #'(lambda (old new) (format nil " ~a \"~a\" " old new)) 
          effects :initial-value "")
  )
 
 
; the perl script:
; gotta use this together with arguments <file> args ... (which are the commands!)
 
#|
"#!/usr/bin/perl -w
 
sub usage() {
    print STDERR "Usage: $0 [sampling_rate] \"effect1 effargs1\" " .
        "\"effect2 effargs2\" ...\n";
    print STDERR "Plots the combined amplitude response of biquad-based " .
        "effects.\n";
    print STDERR "Biquad-based effects are: highpass, lowpass, " .
        "bandpass, bandreject, allpass,\n" . "bass, treble, " .
        "equalizer, band, deemph, riaa, biquad.\n";
    exit(1);
}
 
usage() if $#ARGV == -1;
 
 
;--------this above is not needed-------
 
;maybe don't change this title (or title (format nil "set title 'SoX effects: $desc (rate=$rate)'"))"
 
 
"set title 'SoX effects: $desc (rate=$rate)' 
"#set xlabel <not set>"
"#set ylabel <not set>"
"Fs=$rate"
"o=2*pi/Fs"
"#set logscale x"
"set grid xtics ytics"
"set key off"
"END"
"my $l = 0;"
"foreach (@ARGV) {"
"    $l++;"
"$_ = `sox --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`;"
"    s/([ab][012])/$1_$l/g;"
"    print;"
"    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\";"
"}"
"my $prod = join(\"*\", map { \"H_$_(f)\" } (1..$l));"
"print \"H(f)=$prod\n\";"
 
"print <<END;"
"plot [f=10:Fs/2] [-35:25] 20*log10(H(f))" ;this gets replaced by my function
"END")
 
(format nil "$_ = `~a --plot gnuplot --rate $rate -n -n $_ | sed -n -e '6 p'`" *sox-path*)
 
|#
 
; plotting directly in OM would be the most flexible!
(defun biquad-equation (f b0 b1 b2 a1 a2 samplerate)
  (let* ((o (/ (* 2 pi) samplerate)))
    ; this creates a complex number for some reason... where? probably a negative number
    ; what does this mean (from the scripts): o=2*pi/Fs
    (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)))))))
    ))