9 posts

Page

**1**of**1**- KVRer
- 8 posts since 13 Nov, 2017

Hi KVR,

I am currently studying sound engineering and for my final year project I am to design both a minimum phase and linear phase FIR Graphic EQ for perceptual comparison. I have been using matlab to get the coefficients and juce for the plugin implementation. I am something of a newb to C++ although through sheer determination have figured out a simple algorithm which works.

I'll be uploading the code to my github here https://github.com/CultureBunkerRecordings

If anyone would like to have a look please do and any suggestions on how i could conduct listening tests would be excellent also.

Thankyou!!

I am currently studying sound engineering and for my final year project I am to design both a minimum phase and linear phase FIR Graphic EQ for perceptual comparison. I have been using matlab to get the coefficients and juce for the plugin implementation. I am something of a newb to C++ although through sheer determination have figured out a simple algorithm which works.

I'll be uploading the code to my github here https://github.com/CultureBunkerRecordings

If anyone would like to have a look please do and any suggestions on how i could conduct listening tests would be excellent also.

Thankyou!!

- KVRian
- 1344 posts since 26 Apr, 2004, from UK

If you are using JUCE, why not use their filter classes as well?

- KVRer
- 8 posts since 13 Nov, 2017

Hi yes that might be an option although i've never tried the filter class.. I need to implement two graphic eq's with the exact same filter response, one linear phase and one minimum phase. knowing the exact values of the coefficients is essential as my lecturer will provide the code to make the linear phase filter minimum phase..

- KVRer
- 6 posts since 5 Jul, 2018

culturebunker wrote:knowing the exact values of the coefficients is essential as my lecturer will provide the code to make the linear phase filter minimum phase..

OK, so this code your lecturer is providing will take a linear-phase (FIR) filter, and make a minimum-phase equivalent from that? (Presumably using ceptstrum).

If so: a lot of the "minimum-phase filter" literature will assume you're using IIR filters, same with filter libraries. However, if you're using an FIR minimum-phase filter, in terms of implementation it's the same as any other convolution, just with different coefficients (and no need for latency compensation).

I'd also say that whatever your interface is, it might be good to plot the phase response (or even group delay) of the minimum-phase version. If the user's specifying their EQ in an FIR-like way (e.g. linear segments or free-drawn curves) it's pretty easy to create a filter with sharp edges that give a very weird phase response, which may or may not be what you want.

For listening tests: not something I really have expertise on, but I know a couple of people who did audio-psych research, and they said that people can learn to distinguish surprisingly subtle things if they think there's an extra tenner in it for them, but without that they're more likely to decide "eh, my ears just aren't good enough for this" and you get flat results. So if you're testing something like "can you tell which is which", you'll get better results if there's an extra incentive for success. :p

- KVRAF
- 4952 posts since 11 Feb, 2006, from Helsinki, Finland

culturebunker wrote:If anyone would like to have a look please do and any suggestions on how i could conduct listening tests would be excellent also.

Just testing "linear phase" vs. "minimum phase" is probably not very useful unless you actually narrow things down somewhat. In general, linear-phase filters become "audible" when they have sufficiently sharp features somewhere in the middle of the audible range that the "pre-ringing" gets longer/stronger than the backwards masking threshold.

This can also happen with min-max filters and such if there is a discontinuity at the beginning of the impulse response, which can be perceived as a "pre-echo" even at low levels, which is why windowed designs might be preferable, even though their performance in the min-max (or least-squares, whatever) sense is usually significantly worse.

In comparison, minimum-phase filters generally benefit from the stronger forward masking and additionally even though for impulsive sounds and transients the phase-smearing can be quite obvious, it's not necessarily objectionable, so "naive" listeners might not actually pay any attention to it, because we're used to all kinds of causal filtering going on all the time in our normal environment.

For some applications, like resampling filters, the "smearing" with minimum-phase filters can actually become somewhat audible (in terms of smoothing out transients) even though the ringing (of either type of filters) is above 20kHz and therefore essentially inaudible for most listeners, so the pre-ringing is essentially irrelevant (although the pre-echo from min-max filters could still be audible, I suppose). This is typically not really a huge deal if you do it once, but the phase-shifts can cascade with repeated processing.

Also typically for mid to high frequencies phase is generally not very audible, where as for low enough (ie. mostly below 100Hz or so) frequencies it can actually change the perception of the sound quite a bit when the relative phases of the harmonics change. My personal (purely speculative) hypothesis is that the actual waveform can be perceived to some extent when the wavelength is long enough for the neural signalling from the ears not to be entirely smooth in terms of the integration times of the brain, but who knows.

Finally, you should keep in mind that the "cepstrum" approach (which you're probably stuck with unless your filters are very short) to minimum-phase FIR design is a numerical method and care should be taken to measure that the results are sufficiently close to the target response, because spectral aliasing does introduce some error (which can occasionally get non-trivial if one is not careful).

Either way, the point I'm trying to make is that in order to actually come up with some useful data, you should first figure out exactly what you are trying to test. There are applications where conventional wisdom says linear-phase is better, but also applications (eg. music production) where minimum-phase is usually preferred, sometimes even precisely because of the phase-shift they introduce.

<- plugins | forum

- KVRist
- 457 posts since 21 Feb, 2006, from FI

- Code: Select all
`function [minimum] = linphaseFIR2minphaseFIR(linear)`

% Linear phase FIR filter to minimum phase FIR filter.

% It essentially brings all zeros which are outside the unit circle to inside of unit circle.

r = roots(linear);

k = abs(r) > 1.01;

r1 = r(k); % roots outside of unit circle.

r2 = r(~k); % roots on or within the unit circle

s = [1./r1; r2];

minimum=poly(s);

minimum= minimum*sqrt(sum(linear.^2))/sqrt(sum(minimum.^2));

endfunction

- KVRer
- 8 posts since 13 Nov, 2017

Thanks for your responses, I'm not aware of much research done in the application of FIR filters, from what I gather they are easier to implement and inherently stable however less flexible in terms of use hence IIR (minimum phase) are used for Parametric EQ in music production. My interest lies in the pre-ring effect caused by linear phase filters, whether this is noticed by listeners and ultimately if it is favourable.. Having some problems with my convolution code at present i expect it's something to do with zero padding, not all that familiar with juce either, might there be a convolution function I can use? Thanks people!

- KVRer
- 8 posts since 13 Nov, 2017

for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)

buffer.clear (i, 0, buffer.getNumSamples());

int writeDelayStart = write;

int readDelayStart = read;

for (int channel = 0; channel < totalNumInputChannels; ++channel)

{

float* channelData = buffer.getWritePointer (channel);

float* delayData = delayLine.getWritePointer (channel);

write = writeDelayStart;

read = readDelayStart;

for(int sample = 0 ; sample <buffer.getNumSamples(); sample++)

{

float sum = 0;

float sum2 = 0;

delayData[write] = channelData[sample];

zeros[read] = filterCoefs[read];

for (int i = 0; i < delayLength; i++)

{

sum = sum + (delayData[read] * zeros[i]);

}

channelData[sample] = (*gainParam * sum);

++write;

write %= delayLength;

++read;

read %= delayLength;

}

}

}

Here's my bit of processing although it seems not to be doing anything, clean output but no filtering.. any help much appreciated.. the read write bit is confusing me somewhat!

buffer.clear (i, 0, buffer.getNumSamples());

int writeDelayStart = write;

int readDelayStart = read;

for (int channel = 0; channel < totalNumInputChannels; ++channel)

{

float* channelData = buffer.getWritePointer (channel);

float* delayData = delayLine.getWritePointer (channel);

write = writeDelayStart;

read = readDelayStart;

for(int sample = 0 ; sample <buffer.getNumSamples(); sample++)

{

float sum = 0;

float sum2 = 0;

delayData[write] = channelData[sample];

zeros[read] = filterCoefs[read];

for (int i = 0; i < delayLength; i++)

{

sum = sum + (delayData[read] * zeros[i]);

}

channelData[sample] = (*gainParam * sum);

++write;

write %= delayLength;

++read;

read %= delayLength;

}

}

}

Here's my bit of processing although it seems not to be doing anything, clean output but no filtering.. any help much appreciated.. the read write bit is confusing me somewhat!