;********************************************************************* ; OM-SoX, (c) 2011-2013 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) (defmethod! mag->lin ((magnitude number) (windowsize number) (wcoef number)) :icon 141 :indoc '("a value or list of values" "windowsize" "window coefficient") :initvals '(100 4096 1) :doc "Converts magnitude values of a power spectrum to linear gain" (* 2 (/ (sqrt magnitude) windowsize) wcoef)) (defmethod! mag->lin ((magnitude list) (windowsize number) (wcoef number)) (mapcar (lambda (themagnitude) (mag->lin themagnitude windowsize wcoef)) magnitude) ) ; needs sorting function (defmethod! find-n-peaks ((points list) (numpeaks integer) (mode t) &key (test '>) (decimals 10) (deltaparam 1) (mindistance-factor 0.01) (filter-window 5) (filter-recursions 3) (sort '<)) :icon '(233) :indoc '("a bpf or point-list" "Number of Peaks to find" "mode (Peak or Trough)" "sorting function for result" "decimals for calculation" "delta step to determine peak or trough") :initvals '(((0 1) (5 10) (10 1)) 1 peak > 10 1 0.01 5 2) ; no quote needed because it is already quoted :menuins '((2 (("peak" 'peak) ("trough" 'trough))) (3 ((">" >) ("<" <))) (9 ((">" >) ("<" <)))) :doc "finds the n highest/lowest peaks or troughs in a bpf or point-list" :numouts 2 (let* ((transpoints (mat-trans points)) (filteredpoints (list (first transpoints) (sox-median-filter-rec (second transpoints) filter-window filter-recursions))) (thedxpoints (mat-trans (list (first filteredpoints) (x-append 0 (x->dx (second filteredpoints)))))) (thezerocrossings (remove-duplicates (y-transfer thedxpoints 0 decimals))) (thecrossingfrequencies (x-transfer thedxpoints (om- thezerocrossings deltaparam) decimals)) (thepeakfrequencies (remove nil (if (equal mode 'peak) (loop for item in thecrossingfrequencies for x from 0 to (length thecrossingfrequencies) collect (omif (> item 0) nil x) ) #| (loop for item in thecrossingfrequencies for x from 0 to (length thecrossingfrequencies) if (> item 0) collect x ) |# (loop for item in thecrossingfrequencies for x from 0 to (length thecrossingfrequencies) collect (omif (< item 0) nil x) ) #| (loop for item in thecrossingfrequencies for x from 0 to (length thecrossingfrequencies) if (< item 0) collect x ) |# ))) (thepeakfrequenciesfiltered (remove nil (subs-posn thezerocrossings thepeakfrequencies nil))) (thepeakpointlist (mat-trans (list thepeakfrequenciesfiltered (x-transfer points thepeakfrequenciesfiltered decimals)))) (thefilteredpeakpointlist (min-x-distance thepeakpointlist mindistance-factor)) ;(thefilteredpeakpointlist thepeakpointlist) (theminfilteredpeakpointlist (min-x-val thefilteredpeakpointlist 200 14000)) (thesortedpointlist (sort-list theminfilteredpeakpointlist :test test :key 'second)) (thesortedsortedpointlist (sort-list thesortedpointlist :test sort :key 'first)) (thetranspeakpoints (mat-trans (first-n thesortedsortedpointlist numpeaks))) ) (values-list (list (om+ (first thetranspeakpoints) 0) (second thetranspeakpoints))) ;hardcoded x-offset )) ;(band-filter '((86.13281 -79.09892) (269.16504 -62.568234) (656.7627 -66.9554)) (list (list 200 14000)) 'Pass) (defmethod! find-n-peaks ((points bpf) (numpeaks integer) (mode t) &key (test '>) (decimals 10) (deltaparam 1) (mindistance-factor 0.01) (filter-window 5) (filter-recursions 3) (sort '<)) (find-n-peaks (point-pairs points) numpeaks mode :test test :decimals decimals :deltaparam deltaparam :mindistance-factor mindistance-factor :filter-window filter-window :filter-recursions filter-recursions :sort sort) ) (defun min-x-const-q-distance (list distance-factor) (remove-duplicates list :test #'(lambda (a b) (< (- (first a) (first b)) (* (first a) distance-factor)) ) )) (defun min-x-distance (list distance) (remove-duplicates list :test #'(lambda (a b) (< (- (first a) (first b)) distance) ) )) (defun min-x-val (list min max) (loop for item in list if (and (> (car item) min) (< (car item) max)) collect item)) (defun min-x-distance-reverse (list distance) (remove-duplicates list :test #'(lambda (a b) (< (- (first b) (first a)) distance) ) )) ;=== averages a bpf-lib into a single bpf (defmethod! bpf-average ((self list)) :icon '(233) (let* ((xpoints (x-points (first self))) (transypointlist (mat-trans (loop for bpf in self collect (y-points bpf)))) (averagedypoints (mapcar #'om-mean transypointlist))) (simple-bpf-from-list xpoints averagedypoints 'bpf (decimals (first self))) )) (defmethod! bpf-average ((self bpf-lib)) (bpf-average (bpf-list self))) ;;======================================================================= ; filter functions borrowed from om-fil ;;======================================================================= (defun sox-debut (list elem) (loop for x in elem collect (om-mean (first-n list (1+ (om* x 2)))))) (defun sox-fin (list elem) (loop for x in elem collect (om-mean (first-n (reverse list) (1+ (om* x 2)))))) (defun sox-median-point (list N) (nth N (sort. list))) (defmethod! sox-median-filter ((data list) (window number) ) :initvals '('(1 2 3 4 5 6) 100 1) :indoc '("list of data" "window size in samples data" "recursion level") :icon '(213) :numouts 1 :doc " Traditional Median filter, where is the data flow to filter and is the parameter to calculate the window delay. The will be (2*window + 1). We will use the median point of the effective window delay" (let ((aux data) (modulo (om// (1+ (om* window 2)) 2))) (x-append (first data) (sox-debut data (arithm-ser 1 (1- modulo) 1)) (loop for i from modulo to (om- (1- (length data)) modulo) collect (sox-median-point (subseq data (om- i modulo) (om+ i (1+ modulo))) window)) (sox-fin data (arithm-ser 1 (1- modulo) 1)) (last-elem data)))) (defmethod! sox-median-filter-rec ((data list) (window number) (deep number)) :initvals '('(1 2 3 4 5 6) 100 1) :indoc '("list of data" "window size in samples data" "recursion level") :icon '(213) :numouts 1 :doc "Recursive sox-median-filter" (let ((aux data)) (dotimes (x deep aux) (setf aux (sox-median-filter aux window)))))