Work-in-progress repo for ambisonics extensions for OM-SoX
Alexander Nguyen
21 hours ago d6bb375789821f4e4e175465f50e77e8a6b1aaf7
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
; ********************************************************************
; 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)
 
;;; Sox-contrast ===============================================
 
(defmethod! sox-contrast ((amount number) &key sox-append)
  :icon 30
  :initvals '(50 nil)
  :indoc (list "amount (percent)" *sox-append-doc*)
  :doc "Comparable to compression sox-contrast makes an audio signal sound louder (using a time-domain transferfunction). 
 
<amount> controls the amount of the effect (0-100%). Note that an amount of 0 still gives a significant contrast enhancement."
 
  (let* ((thestring (format nil "contrast ~d" amount)))
    (sox-concat sox-append thestring))
  )
 
 
;;; Sox-loudness ===============================================
 
(defmethod! sox-loudness ((gain number) &key reference sox-append)
  :icon 30
  :initvals '(-10 nil)
  :indoc (list "gain (in dB)" "reference-gain" *sox-append-doc*)
  :doc "Loudness control - similar to sox-level, but provides equalisation for the human auditory system.
 
The gain is adjusted by the value for <gain> (usually negative) and the signal equalised according to ISO 226 w.r.t. a reference level of 65dB.
An alternative reference level <reference> may be given if the original audio has been equalised for some other optimal level."
 
  (let* ((thestring (format nil " loudness ~d" gain)))
    (when reference
      (setf thestring (concatenate 'string thestring 
                                   (format nil " ~d" reference))))
    (sox-concat sox-append thestring))
  )
 
;;; sox-amplitude ===========================================
 
(defmethod! sox-amplitude ((amplitude number) &key sox-append)
            :icon 30
            :initvals '(1)
            :indoc (list "amplitude factor (linear)" *sox-append-doc*)
            :doc "Scales the amplitude of the audio by a factor given in <amplitude>.
 
NB: Negative values for <amplitude> are possible. This results in phase-inversion of the audio."
 
            (let* ((thestring (format nil "vol ~d" amplitude)))
              (sox-concat sox-append thestring))
            )
 
 
;;; sox-level ===============================================
 
(defmethod! sox-level ((gain number) &key options balance-mode sox-append)
  :icon 30
  :initvals '(0 nil nil nil)
  :menuins '((1 (( "normalize" "normalize" ) ("limit" "limit") ("headroom" "headroom") ("reclaim" "reclaim"))) (2 (("peak" "peak") ("rms" "rms")))) 
  :indoc (list "gain (dB)" "options (applied before gain)" "balance channels in a multichannel-file using peak or rms detection" *sox-append-doc*)
  :doc "Amplify, attenuate, limit, normalize audio to/by <gain>. Optionally 'balance' the gain levels of individual channels in multichannel audio. 
 
<gain> specifies amplfication or attenuation in dB.
 
<options>: 
'limit' will invoke a brickwall limiter, thus preventing the audio from clipping. NB: limiting more than a few dBs can cause audible distortion.
'normalize' will normalize the audio relative to 0dBFS; it is often used to normalize audio to a given level below 0dB.
'headroom' option is used to apply gain to provide head-room for subsequent processing.
'reclaim' option is used after a prior invocation of sox-level with 'headroom': if the headroom is not used by subsequent effects, it can be reclaimed with this option.
 
<balance-mode> specifies how the levels in different channels in multichannel audio are determined in order to change their relative levels.
NB: unlike 'peak' 'rms' might cause clipping in certain channels."
 
  (let* ((thestring (format nil " gain")))
    ;(print balance-mode)
    (cond ((equal balance-mode "peak")     
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -e"))))
          ((equal balance-mode "rms") 
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -b")))))
    ;(print options)
    (cond ((equal options "normalize")     
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -n"))))
          ((equal options "limit") 
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -l"))))
          ((equal options "headroom") 
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -h"))))
          ((equal options "reclaim") 
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -r")))))
      (setf thestring (concatenate 'string thestring 
                                   (format nil " ~d" gain)))
    (sox-concat sox-append thestring))
  )
 
 
 
;;; Sox-Normalize ===============================================
 
; this is included in sox-level
(defmethod! sox-normalize (&key (level 0.0) balance-mode sox-append)
  :icon 30
  :initvals '(0.0 nil nil )
  :menuins '((1 (("peak" "peak") ("rms" "rms")))) 
  :indoc (list "level (dB)" "balance channels in a multichannel-file using peak or rms detection (select from menu)" *sox-append-doc*)
  :doc "Normalize audio or -optionally- all of the individual channels in multichannel audio.
 
<level> specifies the value (in dBFS) to which to normalize.
Optionally 'balance' the individual channels in multichannel audio (i.e. normalize individually) using peak or rms detection."
 
  (let* ((thestring (format nil " gain")))
    (cond ((equal balance-mode "peak")     
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -e"))))
          ((equal balance-mode "rms") 
           (setf thestring (concatenate 'string thestring 
                                     (format nil " -b")))))
    (setf thestring (concatenate 'string thestring 
                                 (format nil " -n ~d" level)))
    (sox-concat sox-append thestring))
  )
 
 
 
; Sox-Overdrive ===============================================
 
(defmethod! sox-overdrive ((drive number) (colour number) &key sox-append)
  :icon 30
  :initvals '(20 20 nil)
  :indoc (list "drive" "colour (amount of even harmonics)" *sox-append-doc*)
  :doc "Apply non-linear distortion to the audio. 
 
The colour parameter controls the amount of even harmonic content in the over-driven output."
 
  (let* ((thestring (format nil " overdrive ~d ~d" drive colour)))
    (sox-concat sox-append thestring))
  )
 
 
;;; Sox-Compand ===============================================
 
(defmethod! sox-comp-format ((attack number) (release number) &key (softknee 6) (makeup-gain 0) transferfunction (minvolume -90) (lookahead 0.0))
  (let* ((thestring (cond ((and softknee minvolume) (format nil "~d,~d ~d:~d," attack release softknee minvolume))
                          (softknee (format nil "~d,~d ~d:" attack release softknee))
                          (minvolume (format nil "~d,~d ~d" attack release minvolume))
                          (t (format nil "~d,~d " attack release))
                          )))
 
    (if (bpf-p transferfunction)
        (progn
          (setf transferpoints (point-pairs transferfunction))
          (setf firstpair (car transferpoints))
          (setf thestring (concatenate 'string thestring 
                                       (format nil "~d,~d" (first firstpair) (second firstpair))))
          (loop for points in (cdr transferpoints) do
                (setf thestring (concatenate 'string thestring
                                             (format nil ",~d,~d" (first points) (second points))))))
      (setf thestring (concatenate 'string thestring (format nil "-70"))))
   
    (setf thestring (concatenate 'string thestring 
                                 (format nil " ~d ~d ~d" (or makeup-gain 0) (or minvolume -90) (or lookahead 0.0))))
    thestring))
 
 
 
(defmethod! sox-compand ((attack number) (release number) &key transferfunction (softknee 6) (makeup-gain -5) (minvolume -90) (lookahead 0.02) (sox-append))
  :icon 30
  :initvals '(0.3 0.8 nil 6 -5  -90 0.02 nil)
  :indoc (list "attack-time (secs)" "release-time (secs)" "transferfunction describing changes from input to output levels over dynamic range of audio (bpf)" "softknee (in dB)" "makeup-gain (in dB)" "an initial level for when companding starts" "A delay in seconds. Allows the compander to effectively operate in a 'predictive' rather than a reactive mode" *sox-append-doc*)
  :doc "Compand (compress and/or expand) the dynamic range of the audio.
 
<attack> and <release> determine the time over which the instantaneous level of the input signal is averaged to determine its volume; <attack> refers to increases in volume and <release> refers to decreases. For most situations, <attack> should be smaller than <release> because the human ear is more sensitive to sudden increases rather than decreases in audio levels. Typical values are 0.3,0.8 seconds.
 
<transferfunction> is a breakpoint function describing compression/expansion over the dynamic range of the input signal.
 
<softknee> will round the points at where adjacent line segments on the transfer function meet by the specified amount.
 
<makeup-gain> is an additional gain in dB to be applied at all points on the transfer function which allows easy adjustment of the overall gain.
 
<minvolume> permits the user to supply a nominal level initially, so that, for example, a very large gain is not applied to initial signal levels before the companding action has begun to operate: it is quite probable that in such an event, the output would be severely clipped while the compander gain properly adjusts itself.
 
<lookahead> is a delay in seconds. The input signal is analysed immediately to control the compander, but it is delayed before being fed to the volume adjuster. Specifying a delay approximately equal to the attack/release times allows the compander to effectively operate in a 'predictive' rather than a reactive mode."
(list "attack-time (secs)" "release-time (secs)" "transferfunction in dB relative to the maximum possible signal amplitude (bpf)" "softknee (in dB)." "makeup-gain (in dB)" "an initial level for when companding starts" "A delay in seconds. Allows the compander to effectively operate in a 'predictive' rather than a reactive mode" *sox-append-doc*)
;Where more than one pair of attack/decay parameters are specified, each input channel is companded separately and the number of pairs must agree with the number of input channels. 
 
  (setf thestring
        (sox-comp-format attack release :softknee softknee :makeup-gain makeup-gain :transferfunction transferfunction 
                         :minvolume minvolume :lookahead lookahead))
  (setf thestring (string+ " compand " thestring))
  (sox-concat sox-append thestring)
  )
 
 
#|
;;; sox-compand needs a method for lists of attacks and releases (for multichannel)!
(defmethod! sox-compand ((attack number) (release number) &key (softknee 6) (makeup-gain -5) transferfunction (minvolume -90) (lookahead 0.3) (sox-append))
  :icon 30
  :initvals '(0.3 0.8 6 -5 nil -90 0.3 nil)
  :indoc '("attack-time (secs)" "release-time (secs)" "softknee in dB" )
  :doc "Compand (compress or expand) the dynamic range of the audio."
  (let* (
         (thestring (format nil "compand ~d,~d ~d:~d," attack release softknee minvolume)))
    (if (bpf-p transferfunction)
        (progn
          (setf transferpoints (point-pairs transferfunction))
          (setf firstpair (car transferpoints))
          ;(print firstpair)
          (setf thestring (concatenate 'string thestring 
                                       (format nil "~d,~d" (first firstpair) (second firstpair))))
          (loop for points in (cdr transferpoints) do
                (setf thestring (concatenate 'string thestring
                                             (format nil ",~d,~d" (first points) (second points))))))
      (setf thestring (concatenate 'string thestring (format nil "-70" attack release softknee)))
          )
      (setf thestring (csoundfileoncatenate 'string thestring 
                                   (format nil " ~d ~d ~d" makeup-gain minvolume lookahead)))
    (when sox-append
      (setf thestring (concatenate 'string thestring 
                                   (format nil " ~a" sox-append))))
    thestring))
|#
 
;;; Sox-MultiCompand ===========================================
 
(defmethod! sox-multi-compand ((attacks list) (releases list) (crossover-freqs list) &key transferfunction softknee makeup-gain minvolume lookahead sox-append)
  :icon 30
  :initvals '((0.005 0.003 0.000625 0.0001 0) (0.8  6 -5 -90 0.3) (100 400 1600 6400 nil) nil (3 3 3 3 3) (-12 -12 -12 -12 -12)  
              (-90 -90 -90 -90 -90) (0.3 0.3 0.3 0.3 0.3) nil)
  :indoc (list "attack-time (secs)" "release-time (secs)" "crossover frequencies (Hz)" "transferfunction describing changes from input to output levels over dynamic range of audio (bpf)" "softknee (in dB)" "makeup-gain (in dB)" "an initial level for when companding starts" "A delay in seconds. Allows the compander to effectively operate in a 'predictive' rather than a reactive mode" *sox-append-doc*)
  :doc "Compand (compress and/or expand) the dynamic range of the audio in individual frequency bands.
 
 
The multi-band compander (sox-multicompand) is similar to the single-band compander (sox-compand) but the audio is first divided into bands using Linkwitz-Riley cross-over filters and a separately specifiable compander run on each band.
See the sox-compand doc for the definition of its parameters.
"
 
  (let* ((mystr "")
         (mystrings
          (loop for att in attacks
                for rel in releases
                counting att into counter
                collect
                (let ((count (1- counter)))
                   (format nil "~s" (sox-comp-format att rel :softknee (nth count softknee) :makeup-gain (nth count makeup-gain)
                               :transferfunction (nth count transferfunction) :minvolume (nth count minvolume) :lookahead (nth count lookahead)))
                  )))
         (mylists (mat-trans (list mystrings crossover-freqs))))
 
    (loop for item in mylists do
                (print item)
                (if (second item)
                (setf mystr (concatenate 'string mystr (format nil "~a ~d " (first item) (second item))))
                 (setf mystr (concatenate 'string mystr (format nil "~a" (first item))))))
    (sox-concat sox-append (format nil " mcompand ~a" mystr)))
  )