Time Stretch

This plug-in is similar to the Change Speed / Change Pitch / Change Tempo effects.

It has just two controls:

  • Change [Tempo / Pitch / Speed]
  • Stretch factor [0.25 to 4.0, default=1]

This plug-in requires Audacity 3.0.3 or later.
TimeStretch.ny (582 Bytes)

There may be a bug in one of the Nyquist functions used in this plug-in.

The symptom that I’m seeing is that the processed audio may be corrupt, either just at the start, or all the way through.
I’ve only tested on Linux, and I don’t know if this bug appears on other platforms.

If you see this bug:

1. Please report the bug in this forum thread.
2. “Undo” (to restore the original audio), then try applying the effect again (not with “Repeat effect”, but calling up the effect interface from the Effect menu) - I’m finding that it works correctly after a couple of tries.

Works most of the time but intermittent problems (Audacity 3.0.4 , on W8)
Sometimes preview only working in right ear.
Sometimes Nyquist error …
tempo no go on this occasion.png
a time-stretch (tempo) failure.png

Wow, that “unbound function” error is very strange. The PHASEVOCODER function is built into (recent) Nyquist - if it really was “unbound” (not defined) then the effect would never work.

I’ve reported the problem to Roger, so hopefully he will be able to locate the problem. My best guess at present is that there’s an uninitialised variable in the phasevocoder ‘C’ code causing an initialisation problem.

Your Time-Stretch plugin usually works …

Just checking - are you saying that both of those problems occur intermittently when using Audacity 3.0.4?
(the “unbound function” error is expected on versions of Audacity before 3.0.3)

Yes the problems were on the latest Audacity: 3.0.4.

[ I did not see any tell-tale pattern in the faults, but I only tried the plugin for a few minutes ].

I don’t have a fix, but just for the record…

I tried running the phasevocoder function in Nyquist including running some test code in a loop so the function was called dozens of times. No problems.

I tried manually running the effect in Audacity 3.0.4 on Win-10-Pro, and again no problems observed.

The “unbound function - phasevocoder” error could be the result of something unrelated trashing the LISP heap in some way, so it would be interesting to know if other effects are working after this error is encountered.

Of course, some way to reproduce this error reliably would be an enormous help.

While testing to see if I could find a reliable way to reproduce the problem, I saw an error message that hadn’t come up before, and hasn’t happened since, despite running the exact same test many times:

error: In PHASEVOCODER, 1st argument must be a sound or multichannel sound, got NIL
Function: #<Subr-ERROR: #0x555d95acc2c0>
Arguments:
  "In PHASEVOCODER, 1st argument must be a sound or multichannel sound, got NIL"
Function: #<FSubr-LET: #0x555d95ac7890>
Arguments:
  ((TYPES-STRING (NY:TYPE-LIST-AS-STRING (FIRST TYP) MULTI)))
  (ERROR (STRCAT "In " SRC "," (INDEX-TO-STRING INDEX) " argument" (IF (SECOND TYP) (STRCAT " (" (SECOND TYP) ")") "") (IF (EQ (CHAR TYPES-STRING 0) #\i) " must be an " " must be a ") TYPES-STRING ", got " (PARAM-TO-STRING VAL) (IF SECOND-VAL (STRCAT ", and" (PARAM-TO-STRING VAL2)) "")))
Function: #<Closure-NY:ERROR: #0x555d9261f998>
Arguments:
  "PHASEVOCODER"
  1
  ((SOUND) NIL)
  NIL
  T
Function: #<FSubr-COND: #0x555d95acc3b0>
Arguments:
  ((ARRAYP A) (SETF NEWLEN (LENGTH A)) (NY:TYPECHECK (AND LEN (/= LEN NEWLEN)) (ERROR (STRCAT "In " SRC ", two arguments are multichannels of differing length, got " (PARAM-TO-STRING PREV) ", and " (PARAM-TO-STRING A)))) (DOTIMES (I NEWLEN) (SETF CHAN (AREF A I)) (COND ((AND (EQ NONSND (QUOTE NUMBER)) (NUMBERP CHAN))) ((AND (MEMBER (QUOTE SOUND) (CAR TYP)) (SOUNDP CHAN))) ((AND (EQ NONSND (QUOTE STEP)) (NUMBERP CHAN))) ((AND (EQ NONSND (QUOTE POSITIVE)) (NUMBERP CHAN) (> CHAN 0))) ((AND (EQ NONSND (QUOTE POSITIVE-OR-NULL)) (OR (AND (NUMBERP CHAN) (> CHAN 0)) (NULL CHAN)))) ((AND (EQ NONSND (QUOTE NONNEGATIVE)) (NUMBERP CHAN) (>= CHAN 0))) ((AND (EQ NONSND (QUOTE INTEGER)) (INTEGERP CHAN))) ((AND (EQ NONSND (QUOTE STRING)) (STRINGP CHAN))) ((AND (EQ NONSND (QUOTE NULL)) (NULL CHAN))) ((AND (EQ NONSND (QUOTE INT-OR-NULL)) (OR (INTEGERP CHAN) (NULL CHAN)))) (T (NY:ERROR SRC INDEX TYP A T)))) (SETF PREV A) (SETF LEN NEWLEN))
  ((AND (EQ NONSND (QUOTE NUMBER)) (NUMBERP A)))
  ((AND (MEMBER (QUOTE SOUND) (CAR TYP)) (SOUNDP A)))
  ((AND (EQ NONSND (QUOTE STEP)) (NUMBERP A)))
  ((AND (EQ NONSND (QUOTE POSITIVE)) (NUMBERP A) (>= A 0)))
  ((AND (EQ NONSND (QUOTE POSITIVE-OR-NULL)) (OR (AND (NUMBERP A) (> A 0)) (NULL A))))
  ((AND (EQ NONSND (QUOTE NONNEGATIVE)) (NUMBERP A) (>= A 0)))
  ((AND (EQ NONSND (QUOTE INTEGER)) (INTEGERP A)))
  ((AND (EQ NONSND (QUOTE STRING)) (STRINGP A)))
  ((AND (EQ NONSND (QUOTE NULL)) (NULL A)))
  ((AND (EQ NONSND (QUOTE INT-OR-NULL)) (OR (INTEGERP A) (NULL A))))
  (T (NY:ERROR SRC INDEX TYP A T))
Function: #<FSubr-DOLIST: #0x555d95acdc28>
Arguments:
  (A ARGS)
  (SETF TYP (CAR TYPES) TYPES (CDR TYPES))
  (IF (> (LENGTH ARGS) 1) (SETF INDEX (1+ INDEX)))
  (SETF NONSND (CAAR TYP))
  (COND ((ARRAYP A) (SETF NEWLEN (LENGTH A)) (NY:TYPECHECK (AND LEN (/= LEN NEWLEN)) (ERROR (STRCAT "In " SRC ", two arguments are multichannels of differing length, got " (PARAM-TO-STRING PREV) ", and " (PARAM-TO-STRING A)))) (DOTIMES (I NEWLEN) (SETF CHAN (AREF A I)) (COND ((AND (EQ NONSND (QUOTE NUMBER)) (NUMBERP CHAN))) ((AND (MEMBER (QUOTE SOUND) (CAR TYP)) (SOUNDP CHAN))) ((AND (EQ NONSND (QUOTE STEP)) (NUMBERP CHAN))) ((AND (EQ NONSND (QUOTE POSITIVE)) (NUMBERP CHAN) (> CHAN 0))) ((AND (EQ NONSND (QUOTE POSITIVE-OR-NULL)) (OR (AND (NUMBERP CHAN) (> CHAN 0)) (NULL CHAN)))) ((AND (EQ NONSND (QUOTE NONNEGATIVE)) (NUMBERP CHAN) (>= CHAN 0))) ((AND (EQ NONSND (QUOTE INTEGER)) (INTEGERP CHAN))) ((AND (EQ NONSND (QUOTE STRING)) (STRINGP CHAN))) ((AND (EQ NONSND (QUOTE NULL)) (NULL CHAN))) ((AND (EQ NONSND (QUOTE INT-OR-NULL)) (OR (INTEGERP CHAN) (NULL CHAN)))) (T (NY:ERROR SRC INDEX TYP A T)))) (SETF PREV A) (SETF LEN NEWLEN)) ((AND (EQ NONSND (QUOTE NUMBER)) (NUMBERP A))) ((AND (MEMBER (QUOTE SOUND) (CAR TYP)) (SOUNDP A))) ((AND (EQ NONSND (QUOTE STEP)) (NUMBERP A))) ((AND (EQ NONSND (QUOTE POSITIVE)) (NUMBERP A) (>= A 0))) ((AND (EQ NONSND (QUOTE POSITIVE-OR-NULL)) (OR (AND (NUMBERP A) (> A 0)) (NULL A)))) ((AND (EQ NONSND (QUOTE NONNEGATIVE)) (NUMBERP A) (>= A 0))) ((AND (EQ NONSND (QUOTE INTEGER)) (INTEGERP A))) ((AND (EQ NONSND (QUOTE STRING)) (STRINGP A))) ((AND (EQ NONSND (QUOTE NULL)) (NULL A))) ((AND (EQ NONSND (QUOTE INT-OR-NULL)) (OR (INTEGERP A) (NULL A)))) (T (NY:ERROR SRC INDEX TYP A T)))
Function: #<FSubr-LET: #0x555d95ac7890>
Arguments:
  (CHAN LEN NEWLEN RESULT PREV TYP (INDEX 0) NONSND)
  (DOLIST (A ARGS) (SETF TYP (CAR TYPES) TYPES (CDR TYPES)) (IF (> (LENGTH ARGS) 1) (SETF INDEX (1+ INDEX))) (SETF NONSND (CAAR TYP)) (COND ((ARRAYP A) (SETF NEWLEN (LENGTH A)) (NY:TYPECHECK (AND LEN (/= LEN NEWLEN)) (ERROR (STRCAT "In " SRC ", two arguments are multichannels of differing length, got " (PARAM-TO-STRING PREV) ", and " (PARAM-TO-STRING A)))) (DOTIMES (I NEWLEN) (SETF CHAN (AREF A I)) (COND ((AND (EQ NONSND (QUOTE NUMBER)) (NUMBERP CHAN))) ((AND (MEMBER (QUOTE SOUND) (CAR TYP)) (SOUNDP CHAN))) ((AND (EQ NONSND (QUOTE STEP)) (NUMBERP CHAN))) ((AND (EQ NONSND (QUOTE POSITIVE)) (NUMBERP CHAN) (> CHAN 0))) ((AND (EQ NONSND (QUOTE POSITIVE-OR-NULL)) (OR (AND (NUMBERP CHAN) (> CHAN 0)) (NULL CHAN)))) ((AND (EQ NONSND (QUOTE NONNEGATIVE)) (NUMBERP CHAN) (>= CHAN 0))) ((AND (EQ NONSND (QUOTE INTEGER)) (INTEGERP CHAN))) ((AND (EQ NONSND (QUOTE STRING)) (STRINGP CHAN))) ((AND (EQ NONSND (QUOTE NULL)) (NULL CHAN))) ((AND (EQ NONSND (QUOTE INT-OR-NULL)) (OR (INTEGERP CHAN) (NULL CHAN)))) (T (NY:ERROR SRC INDEX TYP A T)))) (SETF PREV A) (SETF LEN NEWLEN)) ((AND (EQ NONSND (QUOTE NUMBER)) (NUMBERP A))) ((AND (MEMBER (QUOTE SOUND) (CAR TYP)) (SOUNDP A))) ((AND (EQ NONSND (QUOTE STEP)) (NUMBERP A))) ((AND (EQ NONSND (QUOTE POSITIVE)) (NUMBERP A) (>= A 0))) ((AND (EQ NONSND (QUOTE POSITIVE-OR-NULL)) (OR (AND (NUMBERP A) (> A 0)) (NULL A)))) ((AND (EQ NONSND (QUOTE NONNEGATIVE)) (NUMBERP A) (>= A 0))) ((AND (EQ NONSND (QUOTE INTEGER)) (INTEGERP A))) ((AND (EQ NONSND (QUOTE STRING)) (STRINGP A))) ((AND (EQ NONSND (QUOTE NULL)) (NULL A))) ((AND (EQ NONSND (QUOTE INT-OR-NULL)) (OR (INTEGERP A) (NULL A)))) (T (NY:ERROR SRC INDEX TYP A T))))
  (COND (LEN (SETF RESULT (MAKE-ARRAY LEN)) (DOTIMES (I LEN) (SETF (AREF RESULT I) (APPLY FN (MAPCAR (FUNCTION (LAMBDA (A) (COND ((ARRAYP A) (AREF A I)) (T A)))) ARGS)))) RESULT) (T (APPLY FN ARGS)))
Function: #<Closure-MULTICHAN-EXPAND-NEW: #0x555d9275fcc0>
Arguments:
  "PHASEVOCODER"
  #<Subr-SND-PHASEVOCODER: #0x555d95acd130>
  (((SOUND) NIL) ((SOUND) "map") ((INTEGER) "fftsize") ((INTEGER) "hopsize") ((INTEGER) "mode"))
  NIL
  #<Sound: #0x555d92526af0>
  2048
  256
  1
Function: #<Subr-APPLY: #0x555d95ac9ac8>
Arguments:
  MULTICHAN-EXPAND-NEW
  ("PHASEVOCODER" #<Subr-SND-PHASEVOCODER: #0x555d95acd130> (((SOUND) NIL) ((SOUND) "map") ((INTEGER) "fftsize") ((INTEGER) "hopsize") ((INTEGER) "mode")) NIL #<Sound: #0x555d92526af0> 2048 256 1)
Function: #<FSubr-IF: #0x555d95aceb10>
Arguments:
  (STRINGP (FIRST ARGS))
  (APPLY (QUOTE MULTICHAN-EXPAND-NEW) ARGS)
  (APPLY (QUOTE MULTICHAN-EXPAND-OLD) ARGS)
Function: #<Closure-MULTICHAN-EXPAND: #0x555d92764a50>
Arguments:
  "PHASEVOCODER"
  #<Subr-SND-PHASEVOCODER: #0x555d95acd130>
  (((SOUND) NIL) ((SOUND) "map") ((INTEGER) "fftsize") ((INTEGER) "hopsize") ((INTEGER) "mode"))
  NIL
  #<Sound: #0x555d92526af0>
  2048
  256
  1
Function: #<Closure-PHASEVOCODER: #0x555d92715bb0>
Arguments:
  NIL
  #<Sound: #0x555d92526af0>
  2048
  256
  1
Function: #<FSubr-SETF: #0x555d95ac75a8>
Arguments:
  *TRACK*
  (PHASEVOCODER *TRACK* MAP 2048 256 1)
Function: #<FSubr-LET: #0x555d95ac7890>
Arguments:
  ((SLEN (GET-DURATION 1)) (TARGET (GET-DURATION FACTOR)) MAP)
  (SETF MAP (ABS-ENV (PWLV 0 TARGET SLEN)))
  (SETF *TRACK* (PHASEVOCODER *TRACK* MAP 2048 256 1))
  (SETF VAL (SND-FETCH (SND-COPY *TRACK*)))
  (IF (/= VAL VAL) (FORMAT T "NaN detected i = ~s~%" I) (TERPRI))
Function: #<FSubr-DOTIMES: #0x555d95acd190>
Arguments:
  (I 5 *TRACK*)
  (FORMAT T "~a) " I)
  (IF (EVENP I) (SETF FACTOR 2) (SETF FACTOR 0.5))
  (LET ((SLEN (GET-DURATION 1)) (TARGET (GET-DURATION FACTOR)) MAP) (SETF MAP (ABS-ENV (PWLV 0 TARGET SLEN))) (SETF *TRACK* (PHASEVOCODER *TRACK* MAP 2048 256 1)) (SETF VAL (SND-FETCH (SND-COPY *TRACK*))) (IF (/= VAL VAL) (FORMAT T "NaN detected i = ~s~%" I) (TERPRI)))
1>

Update: rbd has made a fix, and it looks good here, so hopefully it will be fixed in the next Audacity release.