summaryrefslogtreecommitdiff
path: root/lib/lpc.lsp
blob: 5edecf798e73a914201dd95e2dc9f446d11200b4 (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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
;---------------------------------------------------------------------
; LPANAL. Performs LPC analysis
;
; snd        sound for analysis
; an-dur     duration of analysis (= duration of sound)
; skiptime   step frame to frame
; npoles     number of poles
;
; RESULT:    analysis data in list format.
;            Every element of the list is a list of the form
;
;            (RMS1 RMS2 ERR FILTER-COEFS)
;
;             RMS1  Energy (not rms value) of input signal
;             RMS2  Energy (not rms value) of residual signal
;             ERR   = sqrt(RMS2/RMS1) If it is small then VOICED sound,
;                                     else UNVOICED
;             FILTER-COEFS Array of filter coefs.
;
;
;                The z transform of filter is  H(z) = 1/A(z)
;                 
;                where A(z) is a polynome of the form:
;
;
;                A(z) = 1 + a1 z + a2 z^2 + a3 z^3 + ... + aP z^P
;
;             FILTER-COEFS is the array
;
;                  #(-aP -aP-1 -aP-2 ... a3 a2 a1)
;
;                 (this format is suited for the filter ALLPOLES)
;

(setfn lpc-frame-rms1 car)
(setfn lpc-frame-rms2 cadr)
(setfn lpc-frame-err caddr)
(setfn lpc-frame-filter-coefs cadddr) 

;; LPANAL-CLASS -- does lpc analysis. Frames are returned
;;   from an iterator object

(setf lpanal-class (send class :new '(sound framesize skipsize npoles)))

(send lpanal-class :answer :isnew '(snd framedur skiptime np) '(
  (let ((sr (snd-srate snd)))
    (setf sound snd)
    (setf framesize (round (* sr framedur)))
    (setf skipsize (round (* sr skiptime)))
    (setf npoles np))))

(send lpanal-class :answer :next '() '(
  (let ((samps (snd-fetch-array sound framesize skipsize)))
    (cond ((null samps) nil)
          (t 
           (snd-lpanal samps npoles))))))

(defun make-lpanal-iterator (sound framedur skiptime npoles)
  (send lpanal-class :new (snd-copy sound) framedur skiptime npoles))
  
;; LPC-FILE-CLASS -- iterator returns frames from file
;;
(setf lpc-file-class (send class :new '(file)))

(send lpc-file-class :answer :isnew '(filename) '(
  (setf file (open filename))))

(send lpc-file-class :answer :next '() '(
  (read file)))

(defun make-lpc-file-iterator (filename)
  (send lpc-file-class :new filename))


;; SAVE-LPC-FILE -- create a file from an iterator. This file can
;; be turned back into an iterator using make-lpc-file-iterator.
;;
(defun save-lpc-file (lpc-iterator filename)
  (let ((fp (open filename :direction :output))
        (frame t))
    (while frame
      (setf frame (send lpc-iterator :next))
      (if frame (format fp "~A~%" frame)))
    (close fp)))



;; SHOW-LPC-DATA. Show values of LPC analysis frames from interator.
;;
(defun show-lpc-data (lpc-iterator iniframe endframe &optional (poles? NIL))
  (dotimes (i iniframe) (send lpc-iterator :next))
  (dotimes (i (- endframe iniframe))
    (let ((frame (send lpc-iterator :next)))
      (cond ((null frame) (return))
            (poles?
             (format t "FRM ~A : ~A\n" (+ i iniframe) frame))
            (t
             (format t "FRM ~A : ~A\n" (+ i iniframe) 
                     (reverse (cdr (reverse frame)))))))))
                         

;----------------------------------------------------------------------
; LPC-FREQ. Show frequency response of ALLPOLES filter.
;           NEEDS MATLAB or OCTAVE
;
;
; HELPER FUNS :  GET-FILTER-COEFS from a LPC analysis data
;                       lpc-data:   data generated by LPCANAL
;                       numframe:   index of frame data
;
;                LPC-COEFS-TO-MATLAB : transforms LPC coefs format to Matlab format
;
; LPC-FREQ.
;
;           varname : the name of variable that holds coef array in MATLAB
;           lpc-data : as above
;           numframe : as above
;


; THIS CODE TO GET FREQUENCY ASSUMES AN ARRAY OF LPC FRAMES AND REQUIRES
; MATLAB OR OCTAVE. I HAVE NOT ADAPTED THIS TO USE THE STREAM OF FRAMES
; APPROACH. -RBD
;
;(defun get-filter-coefs (lpc-data numframe)
;  (nth 3 (aref lpc-data numframe)))
;
;
;(defun lpc-coefs-to-matlab (lpc-data numframe)
;  (let* ((lpc-coefs (get-filter-coefs lpc-data numframe))
;         (lencoefs (length lpc-coefs))
;         (result (make-array (1+ lencoefs))))
;    (setf (aref result 0) 1.0)
;    (dotimes (i lencoefs)
;      (setf (aref result (1+ i))
;            (- (aref lpc-coefs (- lencoefs i 1)))))
;    result))
;
;
;(defun lpc-freq (varname lpc-data numframe)
;  (octave (list (list (lpc-coefs-to-matlab lpc-data numframe) varname 'ARR))))

 
;----------------------------------------------------------------------------
; ALLPOLES
;
; THIS VERSION IS FOR ARRAY OF FRAMES
;
;(defun get-allpoles-gain (lpc-data numframe)
;  (nth 2 (aref lpc-data numframe)))      ; se toma ERR para que la amplitud de
;                                         ; la salida se aproxime a 1
;
;(defun allpoles-from-lpc (snd lpc-data numframe)
;   (snd-allpoles snd (get-filter-coefs lpc-data numframe) (get-allpoles-gain lpc-data numframe)))

; ALLPOLES USES A SINGLE FRAME TO CREATE A FILTER
;
; We introduce two functions: 
;   NTH-FRAME runs the interator to get the nth frame;
;   ALLPOLES-FROM-LPC filters a sound given a frame from an iterator

;; NTH-FRAME - get the nth frame from lpc iterator, 
;;    first frame is numbered zero
(defun nth-frame (lpc-iterator numframe)
  (dotimes (i numframe) (send lpc-iterator :next))
  (send lpc-iterator :next))


;; ALLPOLES-FROM-LPC -- filter a sound using an LPC frame
;;
(defun allpoles-from-lpc (snd lpc-frame)
  (snd-allpoles snd (lpc-frame-filter-coefs lpc-frame) 
                    (lpc-frame-err lpc-frame))) ;; use ERR for gain

;-------------------------------------------------------------------------------
; LPRESON

(setfn lpreson snd-lpreson)