summaryrefslogtreecommitdiff
path: root/lpc/lpc.lsp
diff options
context:
space:
mode:
Diffstat (limited to 'lpc/lpc.lsp')
-rw-r--r--lpc/lpc.lsp178
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)