diff options
Diffstat (limited to 'lpc/lpc.lsp')
-rw-r--r-- | lpc/lpc.lsp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/lpc/lpc.lsp b/lpc/lpc.lsp new file mode 100644 index 0000000..d1008f4 --- /dev/null +++ b/lpc/lpc.lsp @@ -0,0 +1,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 skiptime (round (* sr skiptime))) + (setf npoles np)))) + +(send lpanal-class :answer :next '() '( + (let ((samps (snd-fetch-array 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) |