Equal Loudness Curves Implementation

Matthew McCabe's icon

hi everyone,

i'm currently searching for a way to implement the good ole' equal loudness curves in Max/MSP... short of digging up ISO data or using some kind of crudely-drawn table lookup, the only way i can see doing this is to implement the equations:

i'm not a super-huge math guy, and it appears that in this paper they give equations with constants that are undefined...

has anyone had success in implementing an amplitude scaling function based on the curves? i'm looking into some kind of db to A-weight conversion, or something like that, but i'm currently at a loss.

Ideas are welcome... i just want the amplitude to follow the equal loudness curves for a pure tone generated by cycle~...

-matt

mzed's icon

Quote: mccabem@ufl.edu wrote on Tue, 13 May 2008 12:31
----------------------------------------------------
> hi everyone,
>
> i'm currently searching for a way to implement the good ole' equal loudness curves in Max/MSP... short of digging up ISO data or using some kind of crudely-drawn table lookup, the only way i can see doing this is to implement the equations:
>
>

Look in the examples folder /examples/spatialization/panning/

mz

Stefan Tiedje's icon

Matthew McCabe schrieb:
> has anyone had success in implementing an amplitude scaling function
> based on the curves? i'm looking into some kind of db to A-weight
> conversion, or something like that, but i'm currently at a loss.
>
> Ideas are welcome... i just want the amplitude to follow the equal
> loudness curves for a pure tone generated by cycle~...

I think you don't need the exact curve. Just take the distance between
the different curves for the same phon value. Then you can linearly push
the low frequencies to accommodate the lower sensibility of the ear. To
do it correct, you need to measure the sound pressure in the real world
though, but a simple volume dependent onpole~ might already come close...

Stefan

--
Stefan Tiedje------------x-------
--_____-----------|--------------
--(_|_ ----|-----|-----()-------
-- _|_)----|-----()--------------
----------()--------www.ccmix.com

dodgeroo's icon

it is also nice to use peek~ where you either draw your own curves
into a buffer or use some of the example curves that have been made by
some folks on the list... i think if you search "hanning" you will
come up with an example. You could also make the curves in your
favourite program like protools or MatLab. I find this is the most
efficient way of doing panning especially when you want the panning to
happen very quickly.

cheers,

Carey

On Wed, May 14, 2008 at 7:41 AM, Stefan Tiedje wrote:
> Matthew McCabe schrieb:
>
>
> > has anyone had success in implementing an amplitude scaling function
> > based on the curves? i'm looking into some kind of db to A-weight
> > conversion, or something like that, but i'm currently at a loss.
> >
> > Ideas are welcome... i just want the amplitude to follow the equal
> > loudness curves for a pure tone generated by cycle~...
> >
>
> I think you don't need the exact curve. Just take the distance between the
> different curves for the same phon value. Then you can linearly push the low
> frequencies to accommodate the lower sensibility of the ear. To do it
> correct, you need to measure the sound pressure in the real world though,
> but a simple volume dependent onpole~ might already come close...
>
> Stefan
>
> --
> Stefan Tiedje------------x-------
> --_____-----------|--------------
> --(_|_ ----|-----|-----()-------
> -- _|_)----|-----()--------------
> ----------()--------www.ccmix.com
>
>
>
>

John MacCallum's icon

I think the OP is asking about the Fletcher-Munson equal-loudness curves which don't have anything to do with panning (http://en.wikipedia.org/wiki/Fletcher–Munson_curves) but rather filtering the spectrum of a sound to adjust for the fact that our ears are more sensitive to certain frequency ranges and less to others. Correct me if I'm wrong.

I don't know of an implementation in Max, but I sure would like one :)

JM

Peter Ostry's icon

Quote: mccabem@ufl.edu wrote on Tue, 13 May 2008 21:31
----------------------------------------------------
i'm looking into some kind of db to A-weight conversion, or something like that, but i'm currently at a loss.
----------------------------------------------------

It is quite easy to find the data for A-weighted sound. The abbrevation is dbA and very common. You will find a load of redundant technical descriptions, here is the curve at Wikipedia:
http://en.wikipedia.org/wiki/A-weighting

But if you have special requirements, read the article at Wikipedia, it contains enough information to tell you that A-weighting is not the ultimate method and that there is no ultimate method at all.

If you make something for yourself, to be used in your environment, be aware that a defined curve for audible sound depends on a room. No standardized method can take the room modes and other acoustical behavior of your (!) room into account. You can buy a reasonable good measurement instrument and measure exactly at the point where you are going to hear the sound. But if your room is sub-optimal and acoustically untreated, you might experience big differences within a couple of centimeters.

You can of course also use your ears, always a good idea when you deal with audio stuff :-)

dodgeroo's icon

oops, too little sleep, too much max... :)

On Wed, May 14, 2008 at 7:34 PM, John MacCallum wrote:
>
> I think the OP is asking about the Fletcher-Munson equal-loudness curves which don't have anything to do with panning (http://en.wikipedia.org/wiki/Fletcher–Munson_curves) but rather filtering the spectrum of a sound to adjust for the fact that our ears are more sensitive to certain frequency ranges and less to others. Correct me if I'm wrong.
>
> I don't know of an implementation in Max, but I sure would like one :)
>
> JM
>

Matthew McCabe's icon

Hi guys --

indeed, i am talking about the equal loudness contours, and not panning. :)

this is a difficult project, indeed... let me go into a bit more detail, maybe it'll be clearer...

i'm involved with a neuropsychological study of pure tone perception, so ideally the subjects will be wearing headphones.

now, i know they are sinful sometimes, but in this situation it is the best way to prevent distractions. the topic of the study demands that we control for volume, since it is pitch perception that is being tested...

so, here's the question... if the amplitude of the headphone output is fixed, say at a particular dB SPL level... perhaps then one of the weighting scales will be appropriate?

i'd like to do this with loudspeakers but it's just not possible... :(

-matt

kjg's icon

> so, here's the question... if the amplitude of the headphone output is fixed, say at a particular dB SPL level... perhaps then one of the weighting scales will be appropriate?

ok, so why not dump maybe three curves (for three fixed dB SPL levels inside the headphones) in buffers and do a lookup what the amplitude scaling factor is for a given frequency?

1 phon is by definition 1 db SPL @ 1kHz.
Say your three dB SPL listening volumes would be 80 70 and 60 dB SPL. this means that when you input 1000 in to your lookups, you want 0, -10, and -20 to come out. Or scaling factors (when the headphones are calibrated to 80 dB SPL), of 1, 0.32 and 0.1 in linear amplitude.

your 8k value should be something like 8 dB or 2.51 while you 63 Hz value should be around 15 dB or 5.6 at 80 dB SPL

the rest of the values you can just get from the curves. before you hurt your brain trying to get all the math exactly right (i am like you, no math wizard _at all_), why don't you just manually put in 10 values for each of the three reference SPLs, linearly interpolate between those values and see if you get all that working?

if this is all working for you, it will be a relatively easy step to get more accurate lookup tables (if you even need them)

You can very easily store your linear amplitude values in buffers if you just scale the values down by a factor 100 and offset by -1. when storing and back again on lookup. This gives you a range of 0 to 200 for your scaling factors which equals -infinity to +46 dB. that should be enough crank up even your 31 Hz at a reference of 60dB SPL.

hope this helps.

regards,
kjg

ps: i used figure 2 on page 6 of the pdf you linked to guesstimate my values. eventually you should do this very accurately, of course.

Peter Ostry's icon

Quote: mccabem@ufl.edu wrote on Thu, 15 May 2008 17:45
----------------------------------------------------
> so, here's the question... if the amplitude of the headphone output is fixed, say at a particular dB SPL level... perhaps then one of the weighting scales will be appropriate?
----------------------------------------------------

If you are going to measure pitch recognition via headphones you are in the low level range and A-weighting fits well. And you can get all curves you need for that. For such a research project I would not experiment on my own because this part of the research is all done, cross-checked a thousand times and ready to use. Better transform existing curves to your system and exchange them in case you find something better.

Despite of my limited experience I don't see the problem in Max/MSP because you know the circumstances and deliver the tones. Of course you have to think about about the signal and the waveform and perhaps you need to look how others do this if you want to compare your findings to theirs. Clean signal ramping, type of waveform etc.

But you say "if the amplitude of the headphone output is fixed". Sounds logical but isn't trivial: Good linear audio interface. Matched headphones for several test persons, frequency-wise, amplitude-wise. How can you rely on the exact sound output of such small speakers? How do you get a definable output from a headphone preamp? What does the preamp do to your exact frequencies and amplitude? Influence of the cables. Might require some expensive gear. Probably special devices for measurement tasks, depending on your requirements.

Matthew McCabe's icon

> But you say "if the amplitude of the headphone output is fixed".
> Sounds logical but isn't trivial: Good linear audio interface.
> Matched headphones for several test persons, frequency-wise,
> amplitude-wise. How can you rely on the exact sound output of such
> small speakers? How do you get a definable output from a headphone
> preamp? What does the preamp do to your exact frequencies and
> amplitude? Influence of the cables. Might require some expensive
> gear. Probably special devices for measurement tasks, depending on
> your requirements.

understandable criticisms all around... we'll be using a MOTU 828mkII with a nice set of Sennheiser headphones.

as for calibration, we'll be at the speech and hearing clinic here at the hospital which has an in-ear microphone that can measure the SPL at the tympanic membrane. so, the level can be re-calibrated every time the equipment is turned on.

i don't think it's 100% necessary to be _exact_, i'm trying to get a "best-effort" implementation of the equal loudness curves... still looking for suggestions if anyone is still reading this thread!

-m

Owen Green's icon

This Matlab script spits out curves based on the current ISO standard:

Assuming it just comes as Matlab source, you should be able to port it.

--
Owen

Matthew McCabe wrote:

> i don't think it's 100% necessary to be _exact_, i'm trying to get a
> "best-effort" implementation of the equal loudness curves... still
> looking for suggestions if anyone is still reading this thread!

gs's icon

I believe this is the MATLAB script that owen wanted to post but I didn't find it in the message so... here it is
If you want to implement it elsewhere you need the 4 tables from the ISO standard and the 2 math relations near the end of the script

function [spl, freq] = iso226(phon);
%
% Generates an Equal Loudness Contour as described in ISO 226
%
% Usage: [SPL FREQ] = ISO226(PHON);
%
% PHON is the phon value in dB SPL that you want the equal
% loudness curve to represent. (1phon = 1dB @ 1kHz)
% SPL is the Sound Pressure Level amplitude returned for
% each of the 29 frequencies evaluated by ISO226.
% FREQ is the returned vector of frequencies that ISO226
% evaluates to generate the contour.
%
% Desc: This function will return the equal loudness contour for
% your desired phon level. The frequencies evaulated in this
% function only span from 20Hz - 12.5kHz, and only 29 selective
% frequencies are covered. This is the limitation of the ISO
% standard.
%
% In addition the valid phon range should be 0 - 90 dB SPL.
% Values outside this range do not have experimental values
% and their contours should be treated as inaccurate.
%
% If more samples are required you should be able to easily
% interpolate these values using spline().
%
% Author: Jeff Tackett 03/01/05

% /---------------------------------------
%%%%%%%%%%%%%%%%% TABLES FROM ISO226 %%%%%%%%%%%%%%%%%
% ---------------------------------------/
f = [20 25 31.5 40 50 63 80 100 125 160 200 250 315 400 500 630 800 ...
1000 1250 1600 2000 2500 3150 4000 5000 6300 8000 10000 12500];

af = [0.532 0.506 0.480 0.455 0.432 0.409 0.387 0.367 0.349 0.330 0.315 ...
0.301 0.288 0.276 0.267 0.259 0.253 0.250 0.246 0.244 0.243 0.243 ...
0.243 0.242 0.242 0.245 0.254 0.271 0.301];

Lu = [-31.6 -27.2 -23.0 -19.1 -15.9 -13.0 -10.3 -8.1 -6.2 -4.5 -3.1 ...
-2.0 -1.1 -0.4 0.0 0.3 0.5 0.0 -2.7 -4.1 -1.0 1.7 ...
2.5 1.2 -2.1 -7.1 -11.2 -10.7 -3.1];

Tf = [ 78.5 68.7 59.5 51.1 44.0 37.5 31.5 26.5 22.1 17.9 14.4 ...
11.4 8.6 6.2 4.4 3.0 2.2 2.4 3.5 1.7 -1.3 -4.2 ...
-6.0 -5.4 -1.5 6.0 12.6 13.9 12.3];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Error Trapping
if((phon < 0) | (phon > 90))
disp('Phon value out of bounds!')
spl = 0;
freq = 0;
else
%Setup user-defined values for equation
Ln = phon;

%Deriving sound pressure level from loudness level (iso226 sect 4.1)
Af=4.47E-3 * (10.^(0.025*Ln) - 1.15) + (0.4*10.^(((Tf+Lu)/10)-9 )).^af;
Lp=((10./af).*log10(Af)) - Lu + 94;

%Return user data
spl = Lp;
freq = f;
end

V.J.'s icon

Sorry to repopen an old thread, but did any have luck implementing the matlab code? I'm not a matlab user, but I'm curious to see if this was a success. I would greatly benefit from this.

Roman Thilenius's icon

if someone would be so kind and explain what f, af, Lu, and Tf means in those matlab tables, it will be very easy to make a max patch out of it.
you basically let your frequency input read from a buffer where you store the table in and control the gain of the tone with it by times.
like somebody said above; start with the numbers, then make a version with interpolation using spline.

the only thing what is a bit dumb is that in a music software context we normally use dbA (20.^n/10) and not dbSPL (10.^n) and it is bit hard to think in dbSPL.

-110 (who is also looking forward to it)

Matthew McCabe's icon

hi everyone -

i actually ended up going with an inverse A-weighted EQ curve and adjusting my pure tone stimulus - it's not ideal but it's an effort. it works pretty well as far as i can hear.

roman: i believe the matlab function above returns an array of gain values based on the desired phon level. it's kind of a conundrum because the end result is going to be dependent on the amount of gain on the signal _after_ it leaves the computer, i.e., how loud headphones or monitors are turned up.

it's a difficult problem...

V.J.'s icon

Roman, it would be extremely appreciated if you were able to make a patch that implemented this! Thanks!!!

ch's icon

A direct and quick translation of the m script to Max can be done quite easily and could give something like that :

Max Patch
Copy patch and select New From Clipboard in Max.

hope this helps
Ch.

V.J.'s icon

Awesome actually. Continued thanks!!

Roman Thilenius's icon

merlingoth wrote on Fri, 03 April 2009 18:59Awesome actually. Continued thanks!!

didnt had the chance to check the max5 patch above but yeah it is really not much more than a table (or buffer) and a *~.

but ...

>because the end result is going to be dependent
>on the amount of gain on the signal _after_ it
>leaves the computer, i.e., how loud headphones
>or monitors are turned up.

that makes it indeed a bit more difficult, i think we forgot that.

at least i understand now why there are 4 lists of coefficients and not only 2 like i would have exspected first.

this reminds me on my try to add a "humidity" parameter to an air absorbtion filter and had to find out that the effect fog has on absorbtion is all but linear.

-110

edit: you might find more help herehttp://www.midnightwalrus.com/Canz3D/

Matthew McCabe's icon

hehe

well, of course you could always use your friendly neighborhood SPL meter and stick a cycle~ at 1khz. the phon level matches the db SPL at 1khz --

in other words, if you're going for 40phon, and you run a cycle~ 1000 out at your selected amplification level, and the meter reads 40db, you're good to go!