Inverted Rate Change

I’ve been trying for a few hours to make a plugin that when slowed, the pitch is increased, but faster would lower the pitch. For instance, if the speed is twice higher, it would decrease an octave. Here, I tried, but it quadrupled the tempo and doubled pitch, or quartered the tempo and halved the pitch.

;nyquist plug-in
;version 4
;type process
;name "Inverted Speed Rate Change"
;restoresplits 0

;control factor "Stretch factor" float "" 1 0.1 10.0

(let ((slen (get-duration 1))
      (target (get-duration factor))
      map)
  (setf map (abs-env (pwlv 0 target slen)))
    (resample (phasevocoder *track* map 2048 256 1)
                 (* *sound-srate* factor)))

I kept trying to change the code to get this to work, but sometimes it will return a number, do nothing, do the wrong thing, stop on full bar with the applying effect until I hit cancel, or glitch to the crash screen and close. Could you please give me the code to do this? What is the mistake?

I want to make like the tempo move the opposite way the pitch does.

Your code is effectively using two effects:

  1. Phase Vocoder:
    This effect stretches the sound without changing the pitch.

  2. Resample:
    This affects both tempo and pitch, and is a bit counter-intuitive. When you resample to a higher sample rate, the number of samples increases, so when returned from Nyquist back into the audio track, it will occupy a greater length of the track (because the track’s sample rate is unaltered). Thus, increasing the sample rate causes the audio to play lower pitch and slower.
    Conversely, reducing the sample rate causes the audio to play faster and higher.

Let’s take an easy example. Say that we want to slow the track to half speed, and double the frequency.
Consider the resampling first, as this is the only one that affects frequency.

We want “frequency x 2”, so we must resample to half the sample rate.
We know that this will also reduce the length to half the original.
Thus, to stretch the length (using Phase Vocoder, so that it does not change the pitch) to double the original, we must stretch by a factor of 4.

Converting that into code:

We want double the frequency and double the length, so we will call that a “stretch-factor” of 2.

(setf stretch 2.0)

We want to resample to half the original rate, so that’s

(resample <sound> (/ *sound-srate* stretch))

We need to stretch the length (Phase Vocoder) by a factor of 4, so the “map” needs to ramp up from 0 to 4 x .

(setf original-duration (get-duration 1))
(setf map (abs-env (pwlv 0 (* 4  original-duration) original-duration)))

or, more generally, we want “map” to ramp up to 2 x stretch-factor:

(setf original-duration (get-duration 1))
(setf map (abs-env (pwlv 0 (* 2 stretch  original-duration) original-duration)))

But what if we want to stretch to half the frequency, and half the length?

In this case:

(setf stretch 0.5)

Resample to double the sample rate

(resample <sound> (/ *sound-srate* stretch))

Stretch the length by a factor of 0.25

(setf original-duration (get-duration 1))
(setf map (abs-env (pwlv 0 (* 0.5 stretch  original-duration) original-duration)))

Note that the Phase Vocoder now stretches to half of “stretch factor”, whereas previously it was stretching to double the “stretch factor”.

So what is actually going on here?

When we stretch with resample, we change the speed (tempo and frequency) by “factor”.

Then when we stretch with the Phase Vocoder, we need to stretch by 1/factor to get back to the original length, and again to provide the desired tempo stretch. The required amount of stretch is 1/(factor x factor).

Now we can make a small modification to your code:

;nyquist plug-in
;version 4
;type process
;name "Inverted Speed Rate Change"
;restoresplits 0

;control factor "Stretch factor" float "" 1 0.1 10.0

(let ((slen (get-duration 1))
      target
      map)
  (setf target (* slen factor factor))
  (setf map (abs-env (pwlv 0 target slen)))
  (resample (phasevocoder *track* map 2048 256 1)
            (/ *sound-srate* factor)))

Worked, but new question; how would I convert the setting to change in percent instead of times? I tried this;

;nyquist plug-in
;version 4
;type process
;name "Inverted Speed Rate Change"
;restoresplits 0

;control factor "Stretch factor" float "" 100 10 1000

(let ((slen (get-duration 1))
      target
      map)
  (setf target (* slen factor factor 100))
  (setf map (abs-env (pwlv 0 target slen)))
  (resample (phasevocoder *track* map 2048 256 1)
            (/ *sound-srate* factor 0.01)))

But it give me “Nyquist returned nil audio.” when I tried setting 100, for 100% which I wanted to be normal. I tried debug, but the output was blank.

I changed the order and tried both inputs being the same, “100 0.01”, “0.01 100”, “100 100”, and “0.01 0.01”, so it can’t be the math. I want to change 1 to 1/100, and I’m pretty sure it is equal to “0.01”, so I could run “100” as normal, but it did not work in the way I wanted… what do I change to make it normal at 100 instead of 1?

How about:

;control factor "Stretch %" float "" 100 10 1000

(setf factor (/ factor 100))