No, it doesn’t work with FFT, but it is related to it.
It is a Discreet Fourier transformation that returns for each sample a complex vector, tuned to the carrier frequency. It is basically what I’ve written in my PM.
(setf sig (highpass8 s 15500))
(defun dem (s cf)
(let* ((ref-osc (osc (hz-to-step cf)))
(ref-quad (osc (hz-to-step cf) 1 *table* 90))
(sn (lowpass8 (mult s ref-osc) 15500))
(cs (lowpass8 (mult s ref-quad) 15500 ))
(out (make-array (truncate len)))
(c-1 0) (s-1 1))
(dotimes (i (truncate len))
(let* ((c0 (snd-fetch cs)) (s0 (snd-fetch sn)))
(setf (aref out i)
(atan (+ (* s-1 c0) (* c-1 s0))
(- (* c-1 c0) (* s-1 s0))))
(psetq c-1 c0 s-1 (* -1 s0))))
(setf (aref out 0) 0)
(snd-from-array 0 *sound-srate* out)))
(setf sig (highpass8 (dem sig 30000) 50))
(mult (/ (peak sig ny:all)) sig)
C0/s0 is the current complex pair and c-1/s-1 is the conjugate of the past one. The atan function returns the instant phase for the pair.
This is normally very slow and therefore replaced with a lookup-table or a curve fitting function.
The code is not yet very refined, it should actually be implemented as object/class.
Please note: it works only with a mono track, stereo gives a nice visual C++ runtime error.