File: convolve.lsp

package info (click to toggle)
nyquist 3.12%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 58,036 kB
  • sloc: ansic: 74,355; lisp: 20,485; java: 9,390; cpp: 6,695; sh: 207; xml: 58; makefile: 39
file content (171 lines) | stat: -rw-r--r-- 6,007 bytes parent folder | download | duplicates (5)
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
; Here is some LISP code to test the convolve function:

;; First, implement convolution in XLISP on vectors to generate correct results
;;   that we can compare to the output of snd-convolve:

(defun s2v (s) (snd-samples s 10000)) ;; sound to vector

;; zero a vector
(defun zerov (v)
  (dotimes (i (length v)) (setf (aref v i) 0)))

;; add vectors with offset
(defun addv (av bv boffset)
  (let ((cv (make-array (max (length av) (+ (length bv) boffset)))))
    (zerov cv)
    (dotimes (i (length av))
      (setf (aref cv i) (aref av i)))
    (dotimes (i (length bv))
      (setf (aref cv (+ i boffset))
            (+ (aref cv (+ i boffset)) (aref bv i))))
    cv))

;; convolve two vectors
(defun correct-convolve (av bv)
  (let ((cv (make-array (+ (length av) (length bv)))))
    (zerov cv)
    (dotimes (i (length av))
      (dotimes (j (length bv))
        (setf (aref cv (+ i j))
              (+ (aref cv (+ i j))
                 (* (aref av i) (aref bv j))))))
    cv))

;; check if two vectors match within epsilon
(setf epsilon 1.0e-5)
(defun ~= (a b) (< (abs (- a b)) epsilon))
(defun check-result (a b m)
  (cond ((/= (length a) (length b))
         (setf m (strcat "!!! ERROR in " m " - length mismatch")))
        ((dotimes (i (length a))
           (cond ((not (~= (aref a i) (aref b i)))
                  (setf m (format nil "!!! ERROR in ~A - differ at ~A~%" m i))
                  (return t)))))
        (t (format t "\n*** ~A - PASSED\n\n" m)
           (setf m nil)))
  (cond (m
          (format t "test data: ~A (length ~A)~%" a (length a))
          (format t "good data: ~A (length ~A)~%" b (length b))
          (error m))))


(print "TEST 1 - computing convolution")
(setf inp1 (snd-from-array 0 44100.0 
      (setf inpv1
       (vector 1 2 3 4 5 6 5 4 3 2 1 0 0 0 0 1 2 3 4 5 6 7 6 5 4 3 2 1 0 0 0 0 0))))

(setf imp1 (snd-from-array 0 44100.0 
      (setf impv1
       (vector 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))))

(setf resv1 (s2v (snd-convolve inp1 imp1)))


(check-result resv1 (correct-convolve inpv1 impv1) "test 1")

(print "TEST 2 - more convolution ---------------------------------------")
(setf impv2 (make-array 10))        ; an array with 10 elements
(dotimes (i 10)
       (setf (aref impv2 i) (float i)))   ; fill array with i
(display "convolve test 2"  impv2)
(print "----------------------------------------------------------------")
(setf imp2 (snd-from-array 0.0 100.0 impv2)) ; make a sound x from impv2

(setf inpv2 (make-array 20))           ; an array with 10 elements
(dotimes (i 20)
       (setf (aref inpv2 i) 0.0))   ; fill array with 0.0
(setf (aref inpv2 0) 1.0)           ; set first element to 1
(setf (aref inpv2 15) 1.0)
(display "convolve test" inpv2)
(print "convolve test--------------------------------------------------")
(setf inp2 (snd-from-array 0.0 100.0 inpv2))   ; make a sound imp2 from inp2

(setf res2 (snd-convolve inp2 imp2))        ; perform convolution

; convert output to an array and print:
(display "convolve test" (setf resv2 (s2v res2)))

(check-result resv2 (correct-convolve inpv2 impv2) "convolution test 2")

(print "TEST 3 -------------------------------------------------------")
(print "    Verify proper logical stop time using seq to add samples")
(setf tenv (make-array 10))
(dotimes (i 10)
       (setf (aref tenv i) 10.0))
(setf ten (snd-from-array 0.0 100.0 tenv))
;; add ten at the logical stop time
(setf resv3 (s2v (seq (cue res2) (cue ten))))
;; make the correct version
(setf corv3 (addv resv2 tenv (length inpv2)))

(check-result resv3 corv3 "logical stop time test")

; more tests for logical stop time and termination
; 4) set the logical stop time to be the terminate time
; 5) set the logical stop time to be after the terminate time
; 6) set the logical stop time to be before the terminate time
; 7) set the input length to be a multiple of the fft block size (16)

(print "TEST 4 --------------------------------------------------------")

(setf res4 (snd-convolve (set-logical-stop inp2 0.30) imp2))

(display "test 4 lst = term time"
  (setf resv4 (s2v (seq (cue res4) (cue ten)))))

(check-result resv4 (addv resv2 tenv (length resv2))
              "test 4 lst = term time")

(print "TEST 5 --------------------------------------------------------")

(setf res5 (snd-convolve (set-logical-stop inp2 0.40) imp2))

(display "test 5 lst > term time"
  (setf resv5 (s2v (seq (cue res5) (cue ten)))))

(check-result resv5 (addv resv2 tenv 40) "logical stop time test (5)")

(print "TEST 6 --------------------------------------------------------")

(setf res6 (snd-convolve (set-logical-stop inp2 0.10) imp2))

(display "test 6 lst < term time"
  (setf resv6 (s2v (seq (cue res6) (cue ten)))))

(check-result resv6 (addv resv2 tenv 10) "logical stop time test (6)")

(print "TEST 7 --------------------------------------------------------")
; (4)
(setf inpv7 (make-array 32))           ; an array with 32 elements
(dotimes (i 32)
  (setf (aref inpv7 i) 0.0))   ; fill array with 0.0
(setf (aref inpv7 0) 1.0)           ; set first element to 1
(setf (aref inpv7 15) 1.0)
(display "convolve test" inpv7)
(setf inp7 (snd-from-array 0.0 100.0 inpv7))   ; make a sound h from inp2
(setf imp7 imp2)
(setf impv7 impv2)

(setf res7 (snd-convolve inp7 imp7))

(display "test 7 input is multiple of fft block size"
  (setf resv7 (s2v (seq (cue res7) (cue ten)))))

(setf corv7 (correct-convolve inpv7 impv7))

(check-result resv7 (addv corv7 tenv (length inpv7)) "test 7 input len 32")

(print "BLOCK-TEST -------------------------------------------------------")

(setf impv8 (make-array 8))
(dotimes (i 8) (setf (aref impv8 i) i))
(setf res8 (snd-convolve inp7 (snd-from-array 0.0 100.0 impv8)))
(display "block-test" (setf resv8 (s2v res8)))

(check-result resv8 (correct-convolve inpv7 impv8) "block test")

(defun long-reverb ()
  (snd-convolve (sim (pluck c4 0.1) (at 5 (pluck c5 0.1)))
                (mult (noise 10) (pwev 1 10 0.001))))

(play (long-reverb))