Work-in-progress repo for ambisonics extensions for OM-SoX
Marlon Schumacher
9 days ago 3312b1b854e0dd50ab11b7d648e37fddebfb0479
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
;*********************************************************************
; 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 <list> is the data flow to filter and <window> 
is the parameter to calculate the window delay. The <window delay> 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)))))