Help with iteration functions in Nyquist

Hi all!

Considering I want to do an effect plugin, that makes a function that applies the following to the sound (hypothetical):
1- if the absolute value of a particular sample x is equal or less 0.5, then it is divided by 2;
2- else, the sample value is keeped as it is…

The questions:
1- I imagine I have to do an iteration loop, and use snd-fetch, to access the value of each sample…
2- Please, can you help me posting some script examples that process sounds with ‘do’ loops, as long as mine ones always don’t return audio to Nyquist?..
3- Could I modify the value of a particular sample? Is there a function that allows that?

Please, help me! Thanks!!

Pedro.

You’ll probably get some ideas from this post: http://audacityteam.org/forum/viewtopic.php?f=28&t=7984#p31998

Note that the code is not very efficient, but I think it’s fairly easy to understand.

Thanks, stevethefiddle! I’ll try that code! :slight_smile:

Hey! Look at this fresh script I coded… It works only on mono sounds… Details are explained on it… Thanks, stevethefiddle! :smiley:

;nyquist plug-in
;version 1
;type process
;name "Zero if Below Threshold..."
;action "Zero samples lower than a threshold..."
;info "By Pedrodx, based on script example by stevethefiddle. Works only on mono sounds... It is expected some delay to execute... Use at your own risk..."
;control thr "Threshold [absolute of amplitude]" real "" 0.1 0.0 1.0

(setq maxlen 10000000) ;; maximum length that can be processed (samples)

(setq samplerate (snd-srate s)) ;; find sample rate
(setf common (make-array (snd-length s maxlen)));; initialise array

(do ((n 0 (1+ n)) (v (snd-fetch s) (setq v (snd-fetch s))))

;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)

;; Start the execution part of the "do" loop

(if (< (abs v) thr) (setf (aref common n) 0) (setf (aref common n) v))

) ;; End of "do" loop

;; convert back to sound
(snd-from-array 0 samplerate common)

Hope you find some use for it… I didn’t find yet… :laughing:
See ya!!

Really nasty cross-over distortion ! Nice one pedrodx :smiley:

If you want to make it handle stereo tracks, you can define it as a function, then call the function for each channel.

Stereo tracks are handled as arrays, so you need to call the function like this:

(vector (aref (function) 0)(aref (function) 1))

“vector” makes an initialised vector
(aref sound 0) is the left channel
(aref sound a) is the right channel

If we want it to also work with mono tracks, we need to first check if it is an array or not.
We can do that with:
(arrayp sound) - returns true if sound is an array.

Putting them together you have:

(if (arrayp sound)
(vector (aref (function) 0)(aref (function) 1))
;;else
(function))

The completed code would be something like:

;nyquist plug-in
;version 1
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "Zero Below..."
;action "Zapping your audio..."
;info "By Pedrodx and stevethefiddle."
;control thr "Threshold [absolute of amplitude]" real "" 0.1 0.0 1.0
(setq maxlen 10000000) ;; maximum length that can be processed (samples)

(defun distort (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (< (abs v) thr) (setf (aref common n) 0) (setf (aref common n) v))
))

(if (arrayp s)
(vector 
(snd-from-array 0 (snd-srate (aref s 0)) (distort (aref s 0) thr maxlen ))
(snd-from-array 0 (snd-srate (aref s 1)) (distort (aref s 1) thr maxlen )))
(snd-from-array 0 (snd-srate s) (distort s thr maxlen )))

Great, stevethefiddle!! :smiley:
We could make it generic, as it could distorts samples below a threshold, higher or between two thresholds…

What happens most times is that I imagine how the effect could be applied (i.e., mathematically), but I do not provide a formal name to my “invention”, hehehe

Still, I’m no mathematician at all… I’m in fact, a Bachelor’s in Computing Science…

But I have awesome skills playing string instruments and singing… Ahhh… And drums… I play drums since, at least, 10 years… :wink:

Will update our plugin here, when I have time… Still, studying…

Enjoy!!

;nyquist plug-in
;version 3
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "Sample Zerifier..."
;action "Zapping your audio..."
;info "By pedrodx and stevethefiddle... TODO: be sure that thr2 is greater than thr1. If not, output error message... Need help..."
;control thr-type "Zero samples" choice "below T1,above T1,between T1 and T2,outside T1 and T2" 0
;control thr1 "T1 [absolute of amplitude]" real "" 0.1 0.0 1.0
;control thr2 "T2 [absolute of amplitude]" real "" 0.2 0.0 1.0

(setq maxlen 10000000) ;; maximum length that can be processed (samples)

(defun distort-bt (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (< (abs v) thr) (setf (aref common n) 0) (setf (aref common n) v))
))

(defun distort-at (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (> (abs v) thr) (setf (aref common n) 0) (setf (aref common n) v))
))

(defun distort-btt (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (and (> (abs v) thr1) (< (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
))

(defun distort-ott (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (or (< (abs v) thr1) (> (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
))

(if (= thr-type 0)
(if (arrayp s)
(vector 
(snd-from-array 0 (snd-srate (aref s 0)) (distort-bt (aref s 0) thr1 maxlen ))
(snd-from-array 0 (snd-srate (aref s 1)) (distort-bt (aref s 1) thr1 maxlen )))
(snd-from-array 0 (snd-srate s) (distort-bt s thr1 maxlen )))
(if (= thr-type 1)
(if (arrayp s)
(vector 
(snd-from-array 0 (snd-srate (aref s 0)) (distort-at (aref s 0) thr1 maxlen ))
(snd-from-array 0 (snd-srate (aref s 1)) (distort-at (aref s 1) thr1 maxlen )))
(snd-from-array 0 (snd-srate s) (distort-at s thr1 maxlen )))
(if (= thr-type 2)
(if (arrayp s)
(vector 
(snd-from-array 0 (snd-srate (aref s 0)) (distort-btt (aref s 0) thr1 thr2 maxlen ))
(snd-from-array 0 (snd-srate (aref s 1)) (distort-btt (aref s 1) thr1 thr2 maxlen )))
(snd-from-array 0 (snd-srate s) (distort-btt s thr1 thr2 maxlen )))
(if (= thr-type 3)
(if (arrayp s)
(vector 
(snd-from-array 0 (snd-srate (aref s 0)) (distort-ott (aref s 0) thr1 thr2 maxlen ))
(snd-from-array 0 (snd-srate (aref s 1)) (distort-ott (aref s 1) thr1 thr2 maxlen )))
(snd-from-array 0 (snd-srate s) (distort-ott s thr1 thr2 maxlen )))
)
)
)
)

:wink:

Have you tried using this effect “musically”?

I’ve just had a bit of a play with it, and it is possible to create some interesting distortion effects with it.

As it stands, the effect is rather harsh, but applying a low pass filter to the processed signal takes out the excessive “fuzz” and to my ear leaves a more interesting distortion.

Add to this some of the “dry” (unprocessed) signal (as you would with an effect pedal), and use a high pass filter on the dry signal to compensate for the bass boost of the low pass filter, and the distortions become quite subtle in their variety (but can still produce “extreme” if preferred, by adjusting the parameters).

One limitation of the “above T1” effect (which is also common to simple “fuzz box” effects) is that the effect suddenly “switches off” if the signal falls below T1. A way round this would be to track the level (see the Nyquist command “snd-follow”) and then to scale T1 and T2 according to the average peak level (the volume envelope).

Regarding the problem with ensuring that T2 is greater than T1, you could do it with a bit of logic like this:

(setq thrtemp 0) ;initialise thrtemp
(if (and (> thr-type 1)(> thr1 thr2))(setq thrtemp thr2))
(if (> thrtemp 0)(setq thr2 thr1))
(if (> thrtemp 0)(setq thr1 thrtemp))

There is a more important problem re. high memory usage (and limited length).
The only reason that we need to read the samples into an array at all is that I can see no way to adjust sample values in a sound directly (I can’t see any “write” version of “snd-fetch” mentioned in the manual, can you?). However we could repeatedly reuse a smaller array until the sound samples run out.

I’m a bit busy just at the moment, but I’ll come back to this later. (topic bookmarked).

Hi, stevethefiddle!

Sorry I didn’t answer before… I was busy with other things too…

So, when I got back home after a while, I will be concentrated on adding to the plugin the snd-follow feature… I already take a look, and it seems it would smooth well around the threshold regions… Adding to the user flexibility and default values would be great too… I’ll took it today when I go home…

PS.: Maybe I don’t know what low pass and high pass filters applies to the processed sounds… Do they have something to do with the peaks amplitude? Could you explain better, please?
And about the memory issues, they will be necessary, as I tested here with a 4 minutes sound, and I had to discard it over, because the processing makes me wait longer…

Thanks!!

A “Low Pass” filter allows low frequencies to pass through, but attenuates high frequencies.
A “High Pass” filter allows high frequencies to pass through, but attenuates low frequencies.

High pass and low pass filters are applied to “sounds”.
They have 2 main settings: a “cut off” frequency, and a “slope” (“roll off” rate).
The cut off point is usually described as the frequency at which the filter has reduced the amplitude by 3dB.
The “roll off” rate is how rapidly the frequency is blocked beyond the cut off frequency.

For example:
A low pass filter with a 100Hz cut off and a 12dB per octave roll off.
Frequencies below 100Hz will be virtually uninfected, but frequencies above 100Hz will be increasingly blocked.
At 100Hz, the filter will just be starting to work and will have reduced the amount of 100Hz signal by about 3dB.
At 200Hz (one octave above the cut off frequency) the filter will be reducing the level by a further 12 dB (-15dB)
At 400Hz (2 octaves above the cut off frequency) the filter will be reducing the level by a further 12dB (-27dB)
At 800Hz (3 octaves above the cut off frequency) the filter will be reducing the level by a further 12dB (-39dB)
1.6kHz > -51dB
3.2kHz > -63dB

The Nyquist code for a 1st order low pass filter (6dB per octave) is (lp sound frequency)
The code for a second order high pass filter (12dB per octave) is (highpass2 sound frequency)
The code for a 24dB per octave low pass filter is (lowpass4 sound frequency)
The code for a 48dB per octave low pass filter is (lowpass8 sound frequency)
“frequency” is the cut off frequency.

The second order filter has an optional “Q” parameter which can be useful for creating resonance at the cut-off frequency.

Try generating some white noise, then applying some filters to it using the Nyquist prompt.
Example:

(lowpass4 s 400)

I’ve an idea about the memory issue, but at the moment while we are experimenting we can ignore it (just practice on short sound samples).

Looking at the options :

  1. below T1,
  2. above T1,
  3. between T1 and T2,
  4. outside T1 and T2

We can make this more efficient and simplify the interface by just using (3) and (4).
Option (1) is a special case of option (4) where T1 is zero.
Similarly, option (2) is a special case of option (4) where T1 = 1

Hi, stevethefiddle!!

This is what I got, when trying to allow memory optimization:

;nyquist plug-in
;version 3
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "AAASample Zerifier-v2..."
;action "Zapping your audio..."
;info "By pedrodx and stevethefiddle..."
;control thr-type "Zero samples" choice "below T1,above T1,between T1 and T2,outside T1 and T2" 0
;control thr1 "T1 [absolute of amplitude]" real "" 0.1 0.0 1.0
;control thr2 "T2 [absolute of amplitude]" real "" 0.2 0.0 1.0

(setq buf-size 128) ;; size of the array buffer (in samples)

(defun distort (v n common)
(if (= thr-type 0)
(if (< (abs v) thr1) (setf (aref common n) 0) (setf (aref common n) v))
(if (= thr-type 1)
(if (> (abs v) thr1) (setf (aref common n) 0) (setf (aref common n) v))
(if (= thr-type 2)
(if (and (> (abs v) thr1) (< (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
(if (= thr-type 3)
(if (or (< (abs v) thr1) (> (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
)
)
)
)
)

(defun create-sounds-from-buffers (sound)
(setf common (make-array buf-size))
(setq aux 0) ; our aux variable
;(setq naux ; we will capture the number of samples fetched, to process last buffer
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
((not v) n)
(if (>= aux buf-size)
; buffer filled - writes from the array to the sound
((snd-from-array (+ (/ n (snd-srate sound)) (snd-t0 sound)) (snd-srate sound) common)
(setq aux 0)) ; reset aux
; else, fill in the array a bit more
((distort v aux common)
(setq aux (1+ aux))) ; and increment aux
) ; if
) ; do
;) ; setq
; if we didn't processed a buffer until the end, before
; first, we zero the unused part of the buffer
;(do (n aux (1+ n))
;(>= n buf-size)
;(setf (aref common n) 0)
;)
; then, copy the used part to the end of the sound
;(snd-from-array (+ (/ naux (snd-srate sound)) (snd-t0 sound)) (snd-srate sound) common)
) ; defun

; the following block of code ensures T2 is greater than T1
(setq thrtemp 0) ;initialise thrtemp
(if (and (> thr-type 1)(> thr1 thr2))(setq thrtemp thr2))
(if (> thrtemp 0)(setq thr2 thr1))
(if (> thrtemp 0)(setq thr1 thrtemp))

; main function
(if (arrayp s)
(vector 
(create-sounds-from-buffers (aref s 0))
(create-sounds-from-buffers (aref s 1))
)
(create-sounds-from-buffers s)
)

Unfortunately, it doesn’t returned audio… :frowning:
Can you help, please?
PS.: I believe it’s something with the incrementation syntax…

Thanks!!

Hi! I’m here again… :slight_smile:
I’ve tried some memory optimization, and it was good asap to know you’ve got ideas about it… Here is my last code… It brokes in a strange way, I’m using the debug now… But in short, I didn’t saw your last posts, sorry!! :unamused:
I’ll do something maybe today by night and, then, perform some tests on smaller samples… Please, sorry for that… :smiley:

;nyquist plug-in
;version 3
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "AAASample Zerifier-v2..."
;action "Zapping your audio..."
;info "By pedrodx and stevethefiddle..."
;control thr-type "Zero samples" choice "below T1,above T1,between T1 and T2,outside T1 and T2" 0
;control thr1 "T1 [absolute of amplitude]" real "" 0.1 0.0 1.0
;control thr2 "T2 [absolute of amplitude]" real "" 0.2 0.0 1.0

(setq buf-size 128) ; size of the array buffer (in samples)
(setf common (make-array buf-size))

; this function distorts a sample v and puts the result into an array position n
(defun distort (v n)
(if (= thr-type 0)
(if (< (abs v) thr1) (setf (aref common n) 0) (setf (aref common n) v))
(if (= thr-type 1)
(if (> (abs v) thr1) (setf (aref common n) 0) (setf (aref common n) v))
(if (= thr-type 2)
(if (and (> (abs v) thr1) (< (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
(if (= thr-type 3)
(if (or (< (abs v) thr1) (> (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
)
)
)
)
)

; this function return the modulus of the division of n by buf-size
(defun n-modulus (n)
(if (>= n buf-size)
(n-modulus (- n buf-size))
(eval n)
) ; if
) ; defun

; this function generates the distorted sounds, by using the array buffer recursively
(defun create-sound-from-buffers (sound s-srate)
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
((not v) sound)
(setq nm (n-modulus n))
(distort v nm) ; fill in the buffer
(if (and (= nm 0) (> n 0)) ; buffer filled
(snd-from-array 0 s-srate common) ; writes the filled buffer to the sound
) ; if
) ; do
) ; defun

; the following block of code ensures T2 is greater than T1
(setq thrtemp 0) ;initialise thrtemp
(if (and (> thr-type 1)(> thr1 thr2))(setq thrtemp thr2))
(if (> thrtemp 0)(setq thr2 thr1))
(if (> thrtemp 0)(setq thr1 thrtemp))

; main function
(if (arrayp s)
(vector 
(create-sound-from-buffers (aref s 0) (snd-srate (aref s 0)))
(create-sound-from-buffers (aref s 1) (snd-srate (aref s 1)))
)
(create-sound-from-buffers s (snd-srate s))
)

See ya!!
PS.: I have a backup of the working code… :wink:

EDIT - Now, I’ll work on the logic of the plugin, based in what I’ll read from your posts…

Hi, stevethefiddle!!

I applied a low pass filter and, then, a high pass filter… Both of these were of first order, and were controlled by the user (cutoff frequencies)… :slight_smile:

;nyquist plug-in
;version 3
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "ASample Zerifier-V2..."
;action "Zapping your audio..."
;info "By pedrodx and stevethefiddle..."
;control thr-type "Zero samples" choice "below T1,above T1,between T1 and T2,outside T1 and T2" 0
;control thr1 "T1 [absolute of amplitude]" real "" 0.1 0.0 1.0
;control thr2 "T2 [absolute of amplitude]" real "" 0.2 0.0 1.0
;control lpfreq "Low pass filter cut off frequency" real "Hertz" 600.0 0.0 2000.0
;control hpfreq "High pass filter cut off frequency" real "Hertz" 300.0 0.0 2000.0

(setq maxlen 10000000) ;; maximum length that can be processed (samples)

(defun distort-bt (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (< (abs v) thr) (setf (aref common n) 0) (setf (aref common n) v))
))

(defun distort-at (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (> (abs v) thr) (setf (aref common n) 0) (setf (aref common n) v))
))

(defun distort-btt (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (and (> (abs v) thr1) (< (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
))

(defun distort-ott (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (or (< (abs v) thr1) (> (abs v) thr2)) (setf (aref common n) 0) (setf (aref common n) v))
))

; the following block of code ensures T2 is greater than T1
(setq thrtemp 0) ;initialise thrtemp
(if (and (> thr-type 1)(> thr1 thr2))(setq thrtemp thr2))
(if (> thrtemp 0)(setq thr2 thr1))
(if (> thrtemp 0)(setq thr1 thrtemp))

(if (= thr-type 0)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-bt (aref s 0) thr1 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-bt (aref s 1) thr1 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-bt s thr1 maxlen)) lpfreq) hpfreq))
(if (= thr-type 1)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-at (aref s 0) thr1 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-at (aref s 1) thr1 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-at s thr1 maxlen)) lpfreq) hpfreq))
(if (= thr-type 2)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-btt (aref s 0) thr1 thr2 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-btt (aref s 1) thr1 thr2 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-btt s thr1 thr2 maxlen)) lpfreq) hpfreq))
(if (= thr-type 3)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-ott (aref s 0) thr1 thr2 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-ott (aref s 1) thr1 thr2 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-ott s thr1 thr2 maxlen)) lpfreq) hpfreq))
)
)
)
)

btw, I think it sounds much more musical now, but I didn’t have much inspiration to test it now… Could you please give your feedback now?
Thanks!!

Hi, stevethefiddle! Check this one…
It’s a plus… Instead zeroing the particular samples, it perform some kind of offset math, between the old value of the sample and the values of the thresholds… I think it is great to avoid the high slopes, found on the usual method… btw, sorry if I’m expressing wrong (English is not my natural language… :wink: )

So, I’m glad to see what do you think about it… And if you have some suggestions, as the memory optimization, to apply it in larger songs…
Again, thanks!!

;nyquist plug-in
;version 3
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "ASample Zerifier-V3..."
;action "Zapping your audio..."
;info "By pedrodx and stevethefiddle..."
;control thr-type "Zero samples" choice "below T1,above T1,between T1 and T2,outside T1 and T2" 0
;control thr1 "T1 [absolute of amplitude]" real "" 0.1 0.0 1.0
;control thr2 "T2 [absolute of amplitude]" real "" 0.2 0.0 1.0
;control lpfreq "Low pass filter cut off frequency" real "Hertz" 600.0 0.0 2000.0
;control hpfreq "High pass filter cut off frequency" real "Hertz" 300.0 0.0 2000.0

(setq maxlen 10000000) ;; maximum length that can be processed (samples)

(defun distort-bt (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (< (abs v) thr) (setf (aref common n) (- thr (abs v))) (setf (aref common n) v)
) ; if
) ; do
) ; defun

(defun distort-at (sound thr mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (> (abs v) thr) (setf (aref common n) (- (abs v) thr)) (setf (aref common n) v)
) ; if
) ; do
) ; defun

(defun distort-btt (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (and (> (abs v) thr1) (< (abs v) thr2)) (setf (aref common n) (- (max (abs v) (/ (+ thr1 thr2) 2)) (min (abs v) (/ (+ thr1 thr2) 2)))) (setf (aref common n) v)
) ; if
) ; do
) ; defun

(defun distort-ott (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (< (abs v) thr1) (setf (aref common n) (- thr2 (abs v)))
(if (> (abs v) thr2) (setf (aref common n) (- (abs v) thr1)) (setf (aref common n) v)
) ; if
) ; if
) ; do
) ; defun

; the following block of code ensures T2 is greater than T1
(setq thrtemp 0) ;initialise thrtemp
(if (and (> thr-type 1)(> thr1 thr2))(setq thrtemp thr2))
(if (> thrtemp 0)(setq thr2 thr1))
(if (> thrtemp 0)(setq thr1 thrtemp))

(if (= thr-type 0)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-bt (aref s 0) thr1 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-bt (aref s 1) thr1 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-bt s thr1 maxlen)) lpfreq) hpfreq))
(if (= thr-type 1)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-at (aref s 0) thr1 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-at (aref s 1) thr1 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-at s thr1 maxlen)) lpfreq) hpfreq))
(if (= thr-type 2)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-btt (aref s 0) thr1 thr2 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-btt (aref s 1) thr1 thr2 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-btt s thr1 thr2 maxlen)) lpfreq) hpfreq))
(if (= thr-type 3)
(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort-ott (aref s 0) thr1 thr2 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort-ott (aref s 1) thr1 thr2 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort-ott s thr1 thr2 maxlen)) lpfreq) hpfreq))
)
)
)
)

PS.: Still didn’t tested 100%, and the mathematical logic behind the distort functions might be wrong… Suggestions?

EDIT - It isn’t working allright… What I want to do is interpolate each sample within the nearest threshold value… Will come back later…

Funnily enough, I’ve been looking at the opposite - taking the samples the other side of zero. (positive values become negative and negative values become positive… a little experiment I tried while waiting for a DVD to burn).

Very tied up with work 'till the end of the month, but keep the ideas flowing, I’ll catch up with this after the 31st.
Steve

Hi, steve!

Here is the code, as it is now!

;nyquist plug-in
;version 3
;type process
;categories "http://audacityteam.org/namespace#Distortion"
;name "ASmooth by Threshold..."
;action "Zapping your audio..."
;info "By pedrodx and stevethefiddle..."
;control thr-type "Smooth samples" choice "below T1,above T1,between T1 and T2,outside T1 and T2" 0
;control thr1 "T1 [amplitude]" real "" 0.0 -1.0 1.0
;control thr2 "T2 [amplitude]" real "" 0.0 -1.0 1.0
;control lpfreq "Low pass filter cut off frequency" real "Hertz" 600.0 0.0 2000.0
;control hpfreq "High pass filter cut off frequency" real "Hertz" 300.0 0.0 2000.0

(setq maxlen 10000000) ;; maximum length that can be processed (samples)

(defun mean-val (v1 v2)
(/ (+ v1 v2) 2.0)
)

(defun distort (sound thr1 thr2 mxl)
(setf common (make-array (snd-length sound mxl)));; initialise array
(do ((n 0 (1+ n)) (v (snd-fetch sound) (setq v (snd-fetch sound))))
;; Exit when we run out of samples (v is nil) and return the "common" array
((not v) common)
;; Start the execution part of the "do" loop
(if (= thr-type 0)
(if (< v thr1) (setf (aref common n) (mean-val v thr1)) (setf (aref common n) v))
(if (= thr-type 1)
(if (> v thr1) (setf (aref common n) (mean-val v thr1)) (setf (aref common n) v))
(if (= thr-type 2)
(if (and (> v thr1) (< v thr2)) (setf (aref common n) (mean-val v (mean-val thr1 thr2))) (setf (aref common n) v))
(if (= thr-type 3)
(if (< v thr1) (setf (aref common n) (mean-val v thr1))
(if (> v thr2) (setf (aref common n) (mean-val v thr2)) (setf (aref common n) v)))))))
) ; do
) ; defun

; the following block of code ensures T2 is greater than T1
(setq thrtemp 0) ;initialise thrtemp
(if (and (> thr-type 1)(> thr1 thr2))(setq thrtemp thr2))
(if (> thrtemp 0)(setq thr2 thr1))
(if (> thrtemp 0)(setq thr1 thrtemp))

(if (arrayp s)
(vector 
(hp (lp (snd-from-array 0 (snd-srate (aref s 0)) (distort (aref s 0) thr1 thr2 maxlen)) lpfreq) hpfreq)
(hp (lp (snd-from-array 0 (snd-srate (aref s 1)) (distort (aref s 1) thr1 thr2 maxlen)) lpfreq) hpfreq))
(hp (lp (snd-from-array 0 (snd-srate s) (distort s thr1 thr2 maxlen)) lpfreq) hpfreq)
) ; if

I believe you could try to optimize it now, if you can, of course…
From mine, I can’t do more of this code, I believe, but I’ll try to come back here always as possible!

See ya!!