Loudness change when writing/reading fft data from matrix
I’m making a pfft subpatch for spectral freezing. I’ve posted a modified version here without the actual freezing.
The problem is that when the freezing is bypassed (how it loads by default in the attached file) I want the patch to output the signal untouched but have it running through an fft conversion so that when the signal is frozen (data stops being written to the matrix within the columns 0 – 7) there are no discontinuities.
My problem is that the resulting signal is quieter than the original input. I’ve tried this with a ‘dummy’ fft patch doing nothing but fft and inverse fft and the loudness is unaffected.
What difference does it make if the data is coming from a matrix?
Or have I dun goofed?
Interesting… I just noticed that if I remove framedelta~, phasewrap~ and frameaccum~ between cartopol~ and poltocar~ inside a simpler "dummy" pfft patch that just goes direct from cartopol~ and poltocar~ without any other processing, then this loudness change doesn’t happen.
I forgot to mention the pfft~ attributes I’m using: [pfft~ freezeLoudnessTest 1024 4]
Hmmm, this is getting to be quite mysterious.
If you make a pfft~ object as: [pfft~ freeze8slide7.pfft 1024 4] with a toggle on the right inlet the initial unfrozen signal is at the same level, then freeze and unfreeze it and the signal is now quieter.
What could possible by different before and after the freezing? The only thing I can think of is the values coming from frameaccum~.
The phases are no longer aligned due to the per channel phase accumulation – so you lose level / clarity etc. etc. This might improve a bit if you phase lock (phase bash) the vocoder (see miller puckette’s online book or google it). However, if you want exact reconstruction then you should use the exact input phases.
This might be hard to do as you’d need to find a way to get phaseaccum like operation, but with the option of resetting. Also, phaseaccum will drift over time due to accumulated error, so really I would not store differenced phases, but get two frames out at time, and difference them for the freezing, and use exact values for the straight through..
Then you need to design an accumulator with a reset….
If I’m understanding the situation correctly the toggle needs to be synced so that its result happens at the beginning of a window. Whereas the current patch is likely to misalign the phases by changing to and from the frozen data potentially in the middle of a frame.
Using sah~ hasn’t helped though.
I don’t have a problem using the exact input phases when the freezing is bypassed, however there is a discontinuity when switching to the frozen signal that I haven’t been able to get rid of.
If I can get rid of this then the problem for my application is solved. The discontinuity going from the frozen signal back to the unchanged signal is irrelevant though.
Attached is one attempt at a solution albeit with a discontinuity when switching to the frozen signal.
[pfft~ freeze8slide8.pfft 2048 4]
Ok, I’m going to code this up in Java (at least there its clearer whats happening when). I just need a little guidance on the math for the phase accumulation.
So I have the code built to maintain a record of the current fft vector of amplitude, phase values and phase differences (output from framedelta~).
When the toggle is off (0 sent to the object) the amplitude and phase values pass through unchanged and are stored in the object’s buffer.
When the toggle is on the object waits until an index of 0 is reached (start of new vector) and outputs what was previously written to the object’s buffer.
The phase values are computed as follows:
stored phase[i] = stored phase[i] + delta phase[i]
output phase[i] = stored phase[i]
where ‘stored phase’ is initially set to phase values of the fft frame right before the freezing is enabled (ditto for delta phase). ‘i’ represents the bin index.
The phase is then sent to phasewrap~
Looking at the output values before phasewrap~, the values typically increase in the positive or negative direction, I suspect thats fine though.
The problem is I’m getting some distortion, it happens gradually and periodically over the course of a few seconds. Is this the error accumulation you were talking about Alex?
for anyone that is interested, I’ve implemented a real-time spectral freeze for anybody who wants it.
It only seems to work with fft sizes of 2048 or greater with an overlap of 4. I have no idea why though.
use: [pfft~ Freezer 2048 4]