Psudocode implementation of true envelope

I am trying to implement the algorithm described in this paper, I'll quote the relevant portion: http://recherche.ircam.fr/equipes/analyse-synthese/roebel/paper/trueenv_dafx2005.pdf

Let $V_i(k)$ be the cepstral representation of the spectral envelope at iteration $i$, that is the Fourier transform of the filtered cepstrum, and further initialize the iteration using $A_0(k) = \log(|X(k)|)$ and $V_0(k) = -\infty$. The algorithm then iteratively replaces the current target amplitude spectrum according to $$A_i(k) = \max(A_{i-1}(k), V_{i-1}(k))$$ and iteratively applies the cepstral filter to the updated target spectrum $A_i$.

Could someone write a simple pseudocode version of this algorithm?

I think I'm getting confused by exactly what things are named. If I understood correctly, the cepstrum is the inverse fourier transform of the logarithm of the magnitude of the fourier transform of a signal, and, again, if I understood correctly, I was able to implement a smoothed spectrum by zeroing out the samples to the right of the cepstrum, and then taking the fft and exponentiating. However, when I tried to implement this "true envelope" algorithm I was completely lost.

EDIT: as suggested, this is what I think I should do.

v = array of -9999999
a = log(mag(fft(x))
repeat a couple of times:
for k from 0 to a.size():
a[k] = max(a[k], v[k])

//Maybe? Not really sure.
v = ifft(log(mag(fft(a)))
v[from 50 to v.size()] = 0
v = fft(v)
//Do I also have to do something to a?

• Some time ago I implemented a simple version of the true envelope, for feature extraction purposes. It sounds like you are on the right track, but it is not clear what you question actually is. Could you provide your own pseudo-code/code along with an example of why you believe it does not work? – Jean-louis Durrieu Jan 7 '15 at 19:44
• Added pseudocode. My actual C++ code is too messy because I was trying to make it work but just making it worse (and I forgot to commit before), so I can't give you graphs or "wrong" results, sorry. (I'm also not feeling well right now, otherwise I would have made a quick program with just that code :( ) – m fran Jan 8 '15 at 9:53
• Also, it "sounded" wrong. When I multiplied the inverse of the smoothed cepstrum by the spectrum of the signal, I got a somewhat flat (not perfectly) result, and it "sounded" like it. That was not the case with the true envelope, it sounded (and the spectrum looked) basically the same. – m fran Jan 8 '15 at 11:51

As far as I can say, your interpretation is valid, but given the pseudo-code you provide, somehow, there seems to be some confusion with the definition of the quantities.

In my understanding, the $A_i(k)$ are the (real-valued) $\log$-amplitudes. For this reason, you do not need to compute the $\log$ of these values.

Then, the $V(k)$ are actually also $\log$-amplitudes. While I can understand to some extend that you use the same name both for $V$ and its inverse Fourier transform, this may be confusing when trying to understand the algorithm (and debugging it...). In addition, this could be an issue, depending whether the result of the IFT is real or not - this, in turn, depends on whether you "hermitianize" your vector $A$ before the IFT.

A tentative correction for your pseudo-code would be:

v = array of -9999999
a = log(mag(fft(x))
repeat a couple of times:
for k from 0 to a.size():
a[k] = max(a[k], v[k])

vc = ifft(a) // let's assume vc is complex Hermitian, so we just keep the first half of the vector
vc[from 50 to v.size()] = 0
v = fft(vc) // here, be careful that the result is real


I did not try to implement it. Nevertheless, it seems to make sense that way. Let me know if that solves your problem!

• This seems to work quite well, except for something which I think is unrelated to the true envelope and related to my (non) understanding of dsp :(. I expect ifft(exp(v)) to be the impulse response of the filter that models the envelope of the signal, and indeed, if I divide the spectrum of the signal by the true envelope, I get a nice looking flat graph like this: i.imgur.com/p80c6ef.png – m fran Jan 9 '15 at 2:25
• All works well until I try to "correctly" convolve the signal by the inverse filter with FFT, by doing: xPaddedFFT = fft(append(x, zeros(len(x)))); vPaddedFFT = fft(append(ifft(exp(v)), zeros(len(v)))); result = xPaddedFFT / vPaddedFFT; This somewhat fails to make the audio flat, and it seems almost like the same piece of audio is repeated two times. If I don't pad the signals before the multiplication, the spectrum is so flat that I can't easily differentiate between the different vocals I feed to the program. – m fran Jan 9 '15 at 2:38
• A pointer in the correct direction would be appreciated, but I can't thank you enough for the help you already gave me! :) I was really surprised to hear it working that well (even if I think I didn't implement it 100% correctly). – m fran Jan 9 '15 at 2:43
• I think that I see what you want to do, and that's probably a good thing. But, if you have big enough FTs, with a true envelope (smooth in frequency, so short in time), the artefacts should not be annoying, are they? Otherwise, you may need to be careful about the analysis/synthesis windows of your system (where I assume you work with something like a short-term Fourier transform). If they feel like repeated twice, it could be that something is wrong with the reconstruction. It's probably a big effort for a little improvement, so if you are happy with the result, I would not bother too much :D – Jean-louis Durrieu Jan 12 '15 at 22:46
• You are right. I will just stick with the "wrong" method because it sounds "right" anyway. :) Thanks again for all your help! – m fran Jan 13 '15 at 14:49