Swannel Chap - Cross-fade channel swapper

Swannel Chap by Adam-V
Swaps the left and right channels of a stereo audio track with optional cross-fade or modulation of the swap.

Controls
Modulation Type:
The type of cross-fade or modulation that is to be applied to the selected audio.

  • None
    No cross fade will be applied. The left and right channels will be swapped from the immediate start of the selection through to the end of the selection. The Modulation Length and Modulation Cycles settings ignored for this type.
  • “X-Fade - Lin.”
    The left and right channels will be gradually swapped using a linear contour which starts at the beginning of the selection and spans the percentage of the duration of the selection specified by the Modulation Length leaving the remaining portion of the selected audio fully swapped. The Modulation Cycles setting is ignored for this type.
  • X-Fade - Log.
    The left and right channels will be gradually swapped using a logarithmic contour which starts at the beginning of the selection and spans the percentage of the duration of the selection specified by the Modulation Length leaving the remaining portion of the selected audio fully swapped. The Modulation Cycles setting is ignored for this type.
  • X-Fade - Exp.
    The left and right channels will be gradually swapped using an exponential contour which starts at the beginning of the selection and spans the percentage of the duration of the selection specified by the Modulation Length leaving the remaining portion of the selected audio fully swapped. The Modulation Cycles setting is ignored for this type…
  • Wave - Sine
    The left and right channels will be gradually swapped and returned using a low frequency sine wave contour. The sine frequency is dependent on the chosen Modulation Length and Modulation Cycles settings. Swapping starts at the beginning of the selection and spans the percentage of the duration of the selection specified by the Modulation Length leaving the remaining portion of the selected audio unswapped.
  • Wave - Tri
    The left and right channels will be gradually swapped and returned using a low frequency triangle wave contour. The sine frequency is dependent on the chosen Modulation Length and Modulation Cycles settings. Swapping starts at the beginning of the selection and spans the percentage of the duration of the selection specified by the Modulation Length leaving the remaining portion of the selected audio unswapped.

Modulation Length (X-Fade and Wave Only):
The percentage of the selected audio over which the channel swap is to be applied. The portion of the selected audio after this period may or may not be swapped depending on the chosen Modulation Type. This control has no effect if the “None” Modulation Type is selected.

Modulation Cycles (Wave only):
The number of full modulation cycles to be applied within the chosen modulation length. This control is only used by the “Wave - ???” Modulation Types.

Download
SwannelChap.ny (2.52 KB)

You’ve been busy Adam :stuck_out_tongue:
This is a nice variation on the theme of panning effects.

A couple of very minor errors - you have an extra “)” at the end, and it should be a version 3 plug-in (version 1 plug-ins should work on Audacity 1.2.x but this one won’t because it’s using the multiple-choice widget).

I wonder if it would be worth making the “;control mcyc” parameter “real” (float) rather than integer so that a half wave sine can be used.
Another possible enhancement would be to make all of the “Modulation Type” options capable of periodic cycling. What do you think?

;; function to determine frequency
(defun get-frequency(len cyc)
	(mult (/ 1.0 (get-duration len)) (float cyc))
)

You need to be a bit careful using the variable name “len” as this is already globally assigned to the length of the selection in samples. http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference#Nyquist_Variables

Tip: A simpler way to code this is:

(defun freq (cyc)
  (/ cyc (get-duration 1)))

because (get-duration 1) will return the length of the selection.

Thanks for the heads up about the errors. It’s strange that it still runs with the extra bracket!

I have to admit didn’t even think about the variable name len when I wrote this one. I’ll change it over the weekend. I guess more verbose symbol names would be better even if they are a pain when programming.

I like the idea of the half sine option but I’m not sure I understand what you mean by periodic cycling of the “Modulation Types”.

Cheers,
Adam-V

Nyquist will run up to the point that it hits the error, which in this case is right at the end, so the result that is returned to Audacity from Nyquist is still correct.

What program are you using to write your Nyquist scripts? Does it have syntax highlighting and parentheses matching?
Parentheses matching is almost essential otherwise you are likely to really struggle with mismatched brackets.
I don’t think there are any programs that include full syntax highlighting for Nyquist, or even for XLISP, but there are a few that have syntax highlighting for LISP, which is still useful (e.g. NotePad++ for Windows, SciTE for Linux, also Emacs, Vim, Kate, Limp and others).

For example:
If the modulation type is set to “X-fade Lin” and the “Modulation Cycles” is set to one, then it will produce a cross-channel fade (as now).
If the modulation type is set to “X-fade Lin” and the “Modulation Cycles” is set to one, then the result would be similar to using “Wave - Tri” but with a ramp waveform rather than a triangular waveform.


The “Modulation Length” control seems a bit peculiar when applied to “Wave” types.
With “Wave - Tri” is does not appear to do anything.
With “Wave - Sine” it truncates the waveform.
The behaviour that I would have expected (as a user) would be the same as for the X-Fade options - apply up as far as the set %, then continue to the end with no further channel swapping.

Great feedback again Steve. Thank you.

I’m editing the scripts in visual studio which doesn’t really offer syntax hi-lighting for anything non-microsoft without using add-ins. I am investigating other options - it’s just a matter of finding something I’m comfortable with.

Not sure what happened with the modulation length on the wave modulation types. They were functioning as you had expected but I’ve probably introduced a bug at some point when making other changes. I’ll make work properly as soon as I can.

I understand the cycling of the x-fade types now. A great idea which I’ll implement when I do the bug and formatting fixes.

Cheers,
Adam-V

Wow, isn’t that like using an elephant gun on a spider :stuck_out_tongue:

Have a look at Notepad++, it’s free, it’s pretty small, it’s not dissimilar to Microsoft NotePad (on steroids) so it should feel quite familiar, it has syntax highlighting for Lisp built in, has parentheses matching, the indentation can be customised (I use 2 spaces, some prefer 3, but small indentation is useful for Lisp) and other useful features.

For the Wave-Sine option you could try something like:

    ((= 4 ftype) ;Wave Sine
      (setf f (get-frequency leng cyc))
      (let ((end-amp (* 0.5 (1+ (sin (- (* 2 pi cyc)(/ pi 2)))))))
        (setf contour-r 
          (seq 
            (sum  0.5 (mult 0.5 (lfo f leng *table* 270)))
            (const end-amp (- 1 leng)))))
      (setf contour-l (RaiseInverse contour-r)))

This also supports incomplete (decimal) modulation cycles.

A brief explanation [I’ve change the variable name “len” to “leng” to avoid confusion with the Audacity Nyquist global “len”):

When you multiply two sounds, the result has a duration equal to the shortest sound and the resulting sample rate is the maximum sample rate of the sounds.
So we need to pad the modulation wave so that the total length of the modulation wave is (at least) the same length as the selection.

The logical length of the selection is 1.0 so we need to add at least (- 1 leng)
I’ve done that by making a sequence of the generated modulation wave and a constant.

The value of the constant needs to be the same as the final amplitude of the modulation wave “end-amp”.
To calculate “end-amp” we can take the sin of phase angle (* 2 pi cyc), but the phase angle starts at 90 deg. so we first subtract (/ pi 2).
This gives an “amplitude” in the range +/- 1.0, but we need the amplitude in the range 0 to 1.0 so add 1 and divide by 2 to give:

(* 0.5 (1+ (sin (- (* 2 pi cyc)(/ pi 2)))))

Thanks Steve,

I had a look at this last night before I saw your post and I actually ended up performing a diff between the sine and a constant of the full length. It doesn’t handle partial waveforms as your example does though.

Functions to generate sine and pad it

;;; assert full length
(defun pad-contour (wf)
  (diff (snd-const 1.0 0.0 *control-srate* (get-duration 1.0)) (sum 0.5 (mult 0.5 wf))))

;;; generate sine wave
(defun gen-sin-wave (freq dur)
  (lfo freq dur *SINE-TABLE* 270.0))

Generating the two contours for left and right

    ((= 4 ftype) ; Sine
      (setf f (get-frequency dur cyc))
      (setf contour-l (pad-contour (gen-sin-wave f dur)))
      (setf contour-r (inverse contour-l)))

Oh, I made some formatting changes too! These are based on what I have read so far of "COMMON LISP: A Gentle Introduction to Symbolic Computation ".

Cheers,
Adam-V

Hehe, I’m using it because it is my daily code editing environment and I am very used to it! I’ll check out Notepad++ though.

Cheers,
Adam-V