Let's Join Together In Completing This Nyquist Prompt For Usage

Hey, everyone.
After having a quick chat with @steve.
Here is an interesting discussion involving Nyquist Prompts…
Only a few people around the around actually know how to script Nyquist Prompts.
This script in particular is set around increasing time-efficiency for a subliminal production (more effective than “silent subs”) because doing these tasks in an ordered effort would manually compound between 5-10 hours.
Here is the matter-in-question for betterment.

Write Nyquist Prompt for audacity to:

  • Dupe 1 track to 640 tracks

  • Progressively lower pitch of EACH track by 0.001-0.639, leaving out the original base track of this task

  • Progressively lower volume of EACH track by 4 dB, leaving out the original base track of this task

  • Mix and rendered to a finalized track, including base track

Which looks somewhat like this:

; Nyquist script to duplicate a track 640 times,
; progressively lower the pitch and volume for each duplicate, 
; and mix the results into a single final track.

; Number of duplicates to create
(setq num-duplicates 640)

; Initialize an empty variable to hold the final mixed result
(setq final-result 0)

; Loop through each duplicate track
(loop for i from 1 to num-duplicates do
  (let* (
         ; Set progressive pitch shift (from 0.001 to 0.639)
         (pitch-shift (/ i 1000.0))  ; Pitch shift is 0.001 for track 1, 0.639 for track 640
         
         ; Set progressive volume reduction (from 4 dB to 4*i dB for track i)
         (volume-reduction (* 4 i))  ; Volume reduces by 4 dB for each duplicate
         
         ; Apply pitch shift and volume reduction
         (processed-track (mult (db-to-linear (* -1 volume-reduction)) 
                               (pitch-shift pitch-shift (aref *track* 0))))  ; Assuming track is the base track
    )
    
    ; Add the processed track to the final result (mixing the tracks)
    (setq final-result (sum final-result processed-track))
)

; Return the mixed result as the final output
final-result

Now, the problem is that the script doesn’t work, at the very least, I can’t make it work. With the overview provided, please improve upon it, be creative, rewrite… whatever you feel is right with it.
(Also, I don’t care if you credit me for it or not, ALL I want is something worth using. I’m saying I don’t mind if you credit yourself for this)
I don’t know if I’m missing anything, let me know. :grin:

640 4dB reductions is -2560db. A 70db cut is effectively silence, so 20 iterations of -4dB would be plenty.

1 Like

Okay then.
Well, it’s important for everything to be together.
So, we would have to lower each track progressively by 0.1 and find a way to compress everything.

This is not valid syntax:

(loop for i from 1 to num-duplicates do

See here for how to write a DO loop: XLISP do

See here for DOTIMES: XLISP dotimes


pitch-shift is not a valid Nyquist command. Perhaps you meant pitshift.


volume-reduction is not a valid Nyquist command. Use scale, or scale-db, or mult.


Note also that if you reduce each loop by 4dB, then after just 24 loops the level will have dropped by 96 dB, which cause the audio to be below the level that can be represented in a standard 16-bit WAV file - effectively it will be absolute silence. In other words, 616 of the loops do nothing other than adding silence.

2 Likes

Can you test it by rescaling with 0.1 dB instead of 4dB?

There’s an old* Nyquist plugin : “Delay with Pitch Change” which is similar specification

https://plugins.audacityteam.org/nyquist-plugins/effect-plugins/delay-and-reverb#delay-with-pitch-change

The results will be flangy.

[* I just checked: it works in Audcaity3 ]

1 Like

Nice find!
Basically, it’s a pseudo-replacement.
But, “flangy” just means that the waves are directly stacking?

What exactly do you mean by that? What units or reference point are you using?
The pitshift function requires the amount of pitch shift to be a ratio. For example:

(setq shift-ratio 1.1)
(setq mix 1.0)
(pitshift *track* shift-ratio mix)

produces an equivalent pitch shift as Audacity’s “Change Pitch” effect with a “Percent change” of 10%.

I’m guessing that you want something like this:

;version 4
;type process

; Nyquist script to duplicate a track 640 times,
; progressively lower the pitch and volume for each duplicate, 
; and mix the results into a single final track.


(setq num-duplicates 640)
(setq final-result 0)
(setq gain-db -0.1)
(setq shift-step 0.001)

(defun process (sig)
  (do ((i 0 (1+ i)))
      ((= i num-duplicates) final-result)
    (let* ((shift-ratio (- 1 (* shift-step i)))
           (processed (pitshift sig shift-ratio 1))
           (processed (scale-db (* gain-db i) processed)))
      (setf final-result (sum final-result processed)))))

;; Apply 'process' function to all selected channels.
(multichan-expand #'process *track*)
2 Likes

If those are changed to …

(setq num-duplicates 20)
(setq final-result 0)
(setq gain-db -1)
(setq shift-step 0.1)

You get Hollywood-style voice disguise …
[before-after]

1 Like

and an interesting “flanger-like” effect with the default settings:

2 Likes

Yes, precisely! Good work! :grinning: :+1:
Go ahead and take credit for all this!
Could you please fine-tune it to include:

  • each track delayed by 0.1 seconds progressively (reducing flanginess and any internal interference because each track should take up space away from each other [to make up for the small dB change])
  • general normalization level of each track (increase coherence, preventing accumalative decoherence)

Note: I’m assuming the pitch changes “0.001-0.0639” are percent-change values.

Having got you started, I’m handing it over to you.

2 Likes

Huh?
:eye: :lips: :eye:

I thought you said the whole point of having an open-discussion/knowledge-sharing was so that the information was publicly available to everyone?

Yes the information in this forum is available to everyone.

You asked for help, and I provided help, but that does not mean that I agree to write all of your Nyquist code for you. At some point you need to learn to do it for yourself, as I did.

2 Likes

I agree, Nyquist is great; this one, however shouldn’t be the example.

Okay, for some reason, I can’t find the function “process” in Documentation.

process is not a standard Nyquist function, it is a function that I defined within the code.

The keyword defun is used for defining a function (See: XLISP defun)

(defun process (sig)
  (do ((i 0 (1+ i)))
      ((= i num-duplicates) final-result)
    (let* ((shift-ratio (- 1 (* shift-step i)))
           (processed (pitshift sig shift-ratio 1))
           (processed (scale-db (* gain-db i) processed)))
      (setf final-result (sum final-result processed)))))
2 Likes

What is wrong with this code?

;version 4
;type process

; Nyquist script to duplicate a track 640 times,
; progressively lower the pitch and volume for each duplicate, 
; normalize levels of each duplicate,
; and mix the results into a single final track.


(setq num-duplicates 640)
(setq final-result 0)
(setq gain-db -0.1)
(setq shift-step 0.001)
;control norm-level "Normalization level" real "" 0.95 0.0 1.0

(defun normalize (signal)
  (let* ((peak-value (if (arrayp signal)
                         (max (peak (aref signal 0) ny:all) (peak (aref signal 1) ny:all))
                         (peak signal ny:all))))
    (scale (/ norm-level peak-value) signal)))


(defun process (sig)
  (do ((i 0 (1+ i)))
      ((= i num-duplicates) final-result)
    (let* ((shift-ratio (- 1 (* shift-step i)))
           (processed (pitshift sig shift-ratio 1))
		   (processed (normalize processed) (* i)))
           (processed (scale-db (* gain-db i) processed)))
      (setf final-result (sum final-result processed))))

;; Apply 'process' function to all selected channels.
(multichan-expand #'process *track*)



Basically, I added to yours as a base-template.

The reason that it crashes is mismatched parentheses. It should be:

(defun process (sig)
  (do ((i 0 (1+ i)))
      ((= i num-duplicates) final-result)
    (let* ((shift-ratio (- 1 (* shift-step i)))
           (processed (pitshift sig shift-ratio 1))
           (processed (normalize processed) (* i))
           (processed (scale-db (* gain-db i) processed)))
      (setf final-result (sum final-result processed)))))

However, the normalize function passes over the audio twice, which means that it must hold the selected audio in ram until the processed audio is returned to the track. The normalize function is applied 640 times, so there will be 640 copies of the audio held in ram, which is extremely costly on memory and will fail on selection that are more than a few seconds long.

Also, use spaces rather than tabs for indentation.

2 Likes