PEAK and RMS mean values (incoming signal)

themesser's icon

hello MSP experts.
As the title says , I am struggling to get these values right.
Comparing with the values given by the free plugin FreeG, there's a big difference. And I am not even sure if the way I am doing it now have any meaning.
Alternatively, I would like to get these values from the vst plugin, I fooled around with the vst~ object without success.

i uploaded the freeware freeg here for convenience purpose:
https://www.mediafire.com/?hps12soi5os9k7t

and the patch below. Thank in advance for any help I can get!

----------begin_max5_patcher----------
{
    "boxes" : [         {
            "box" :             {
                "maxclass" : "comment",
                "text" : "RMS",
                "patching_rect" : [ 592.0, 440.0, 55.0, 20.0 ],
                "id" : "obj-8",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 0
            }

        }
,         {
            "box" :             {
                "maxclass" : "comment",
                "text" : "peak",
                "patching_rect" : [ 413.0, 445.0, 55.0, 20.0 ],
                "id" : "obj-7",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 0
            }

        }
,         {
            "box" :             {
                "maxclass" : "flonum",
                "patching_rect" : [ 537.0, 440.0, 50.0, 20.0 ],
                "outlettype" : [ "float", "bang" ],
                "id" : "obj-4",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "flonum",
                "patching_rect" : [ 360.0, 445.0, 50.0, 20.0 ],
                "outlettype" : [ "float", "bang" ],
                "id" : "obj-5",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "newobj",
                "text" : "mean",
                "patching_rect" : [ 360.0, 395.0, 41.0, 20.0 ],
                "outlettype" : [ "float", "int" ],
                "id" : "obj-3",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "message",
                "text" : "clear",
                "patching_rect" : [ 469.0, 330.0, 37.0, 18.0 ],
                "outlettype" : [ "" ],
                "id" : "obj-2",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 2,
                "numoutlets" : 1
            }

        }
,         {
            "box" :             {
                "maxclass" : "newobj",
                "text" : "mean",
                "patching_rect" : [ 537.0, 387.0, 41.0, 20.0 ],
                "outlettype" : [ "float", "int" ],
                "id" : "obj-1",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "flonum",
                "patching_rect" : [ 537.0, 336.0, 50.0, 20.0 ],
                "outlettype" : [ "float", "bang" ],
                "id" : "obj-36",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "levelmeter~",
                "patching_rect" : [ 537.0, 242.0, 128.0, 64.0 ],
                "outlettype" : [ "int" ],
                "id" : "obj-35",
                "numinlets" : 1,
                "numoutlets" : 1
            }

        }
,         {
            "box" :             {
                "maxclass" : "flonum",
                "patching_rect" : [ 360.0, 361.0, 50.0, 20.0 ],
                "outlettype" : [ "float", "bang" ],
                "id" : "obj-21",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 1,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "live.meter~",
                "patching_rect" : [ 360.0, 195.0, 16.0, 147.0 ],
                "outlettype" : [ "list" ],
                "id" : "obj-20",
                "numinlets" : 1,
                "numoutlets" : 1
            }

        }
,         {
            "box" :             {
                "maxclass" : "message",
                "text" : "open",
                "patching_rect" : [ 81.0, 254.0, 37.0, 18.0 ],
                "outlettype" : [ "" ],
                "id" : "obj-18",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 2,
                "numoutlets" : 1
            }

        }
,         {
            "box" :             {
                "maxclass" : "message",
                "text" : "plug \"Sonalksis FreeG Mono.vst\"",
                "patching_rect" : [ 75.0, 225.0, 186.0, 18.0 ],
                "outlettype" : [ "" ],
                "id" : "obj-16",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 2,
                "numoutlets" : 1
            }

        }
,         {
            "box" :             {
                "maxclass" : "newobj",
                "text" : "vst~",
                "patching_rect" : [ 36.0, 283.0, 100.0, 20.0 ],
                "outlettype" : [ "signal", "signal", "", "list", "int", "", "" ],
                "id" : "obj-17",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 2,
                "numoutlets" : 7,
                "save" : [ "#N", "vst~", "loaduniqueid", 0, ";" ]
            }

        }
,         {
            "box" :             {
                "maxclass" : "message",
                "text" : "1",
                "patching_rect" : [ 222.0, 15.0, 32.5, 18.0 ],
                "outlettype" : [ "" ],
                "id" : "obj-327",
                "fontname" : "Arial",
                "fontsize" : 12.0,
                "numinlets" : 2,
                "numoutlets" : 1
            }

        }
,         {
            "box" :             {
                "maxclass" : "umenu",
                "types" : [ ],
                "patching_rect" : [ 38.302246, 78.645264, 115.0, 20.0 ],
                "outlettype" : [ "int", "", "" ],
                "presentation" : 1,
                "id" : "obj-322",
                "fontname" : "Arial",
                "framecolor" : [ 1.0, 1.0, 1.0, 1.0 ],
                "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ],
                "fontsize" : 11.595187,
                "numinlets" : 1,
                "presentation_rect" : [ 1039.302246, 705.645264, 115.0, 20.0 ],
                "items" : [ "None", ",", "CoreAudio", "AirPlay", ",", "CoreAudio", "Built-in Output", ",", "CoreAudio", "Aggregate Device", ",", "NonRealTime", ",", "ad_rewire", ",", "Live" ],
                "numoutlets" : 3,
                "bgcolor" : [ 0.847059, 0.647059, 0.388235, 1.0 ]
            }

        }
,         {
            "box" :             {
                "maxclass" : "newobj",
                "text" : "adstatus driver",
                "patching_rect" : [ 38.262329, 52.400452, 87.0, 20.0 ],
                "outlettype" : [ "", "int" ],
                "id" : "obj-321",
                "fontname" : "Arial",
                "fontsize" : 11.595187,
                "numinlets" : 2,
                "numoutlets" : 2
            }

        }
,         {
            "box" :             {
                "maxclass" : "newobj",
                "text" : "adc~ 1 2 3 4 5 6",
                "patching_rect" : [ 15.0, 110.0, 234.0, 20.0 ],
                "outlettype" : [ "signal", "signal", "signal", "signal", "signal", "signal" ],
                "id" : "obj-315",
                "fontname" : "Arial",
                "fontsize" : 11.595187,
                "numinlets" : 1,
                "numoutlets" : 6
            }

        }
],
    "lines" : [         {
            "patchline" :             {
                "source" : [ "obj-1", 0 ],
                "destination" : [ "obj-4", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-3", 0 ],
                "destination" : [ "obj-5", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-2", 0 ],
                "destination" : [ "obj-1", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-2", 0 ],
                "destination" : [ "obj-3", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-21", 0 ],
                "destination" : [ "obj-3", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-36", 0 ],
                "destination" : [ "obj-1", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-327", 0 ],
                "destination" : [ "obj-315", 0 ],
                "hidden" : 0,
                "midpoints" : [ 231.5, 38.0, 24.5, 38.0 ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-322", 0 ],
                "destination" : [ "obj-321", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-322", 0 ],
                "destination" : [ "obj-315", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-321", 0 ],
                "destination" : [ "obj-322", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-16", 0 ],
                "destination" : [ "obj-17", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-315", 0 ],
                "destination" : [ "obj-17", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-18", 0 ],
                "destination" : [ "obj-17", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-315", 0 ],
                "destination" : [ "obj-20", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-20", 0 ],
                "destination" : [ "obj-21", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-315", 0 ],
                "destination" : [ "obj-35", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
,         {
            "patchline" :             {
                "source" : [ "obj-35", 0 ],
                "destination" : [ "obj-36", 0 ],
                "hidden" : 0,
                "midpoints" : [ ]
            }

        }
]
}
-----------end_max5_patcher-----------

Roman Thilenius's icon

average~ ?

themesser's icon

as you can see on the attached images, values returned by the different methods do not match.
So what is the best solution to get the best estimation ?
I need also to freeze the value after x sec, but I guess this is a easy thing to do with a metro and a coll / capture object.

maxmean.jpg
jpg
woyteg's icon

It's hard to help here since there are tons of ways to measure "loudness"/amplitude.
First, taking the mean of a peak value is not good(= what would that mean mean?).
average has an rms mode you might look into.
Taking the mean with [mean] without resetting it, means that you don't have control over the integration time.
However. If you really care for accurate measurements, look at wikipedia on RMS, or the AES/EBU R-128. There you'll be able to research methods for True-peak metering and LU with different integration times. Also there are calibration/testfiles available from them that would enable you to test your max patches for accuracy. All that might be a bit overkill.

Roman Thilenius's icon

...though must say that one could expect that the VST plug-in and the average~ object should create at least similar values.

woyteg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

true. But the integration time used in that plugin is the question. One could find that out via trial end error or by looking for standards, I'm sure one can find papers about that easily.(or does anyone know here maybe?)
Here's a quite simple shot at simple peak and rms(showing two completely different integration times and their results)

themesser's icon

thank you for your support.
I have made a midi interface for my music sequencer, mainly to be able to master the tracks, control vol / pan / drive / fx values individually and globally with master controllers.
Until now I was checking the global loudness with my ears and the vst plugin, now I am looking into adding this function to my max patch.
I have a lot of patterns in my sequencer, and they are not at the same loudness; I am not looking at making them all exactly at the same level, but somewhat that when I play them live, it does not feel like one is louder than another.
Ideally, I would like to get a global RMS value for the loop (so at the end of the loop, store and reset the RMS value, this I can do) so I can make it the same for each pattern.

@WOYTEG : so would it make sense to use the RMS value coming from "average~ 100000 rms" once reaching the end of the loop to compare the loudness of each pattern ?

themesser's icon
Max Patch
Copy patch and select New From Clipboard in Max.

Here is a new take on it, with your suggestions added. what do you think ? more accurate from the snapshot~ or the level meter~ ?

woyteg's icon

Hi!
Let me philosophize again:
With loudness metering there are at least two questions I have to ask myself:
What do I really want to measure?
Do I want to stick to some common standard or do I roll my own?
I guess since you are asking here you have some real interest in it so I'll take it a bit over-serious too;
RMS is typically done this way: Take the square, then the average, then the root.
You'll get different results then using the absolute value and then the average.
I would guess the cycling people implemented something correct with [average x rms], so the question really is the time. now, since you seem to want a single value for a whole sequence, the only standard I can think of is LU-program loudness(again look for R - 128 on the web).
So if you want to keep it simple you might use the following patch, otherwise look into LU-program loudness.
If you just use a really high value for average and take the mean or max, you loose the meaning of your measurement. If you can find out RMS integration times you at least know your value is eg. the maximum/mean RMS of that sequence.(patch is comming)

woyteg's icon
Max Patch
Copy patch and select New From Clipboard in Max.
themesser's icon

hello, thank you for that. What is the [feedback] object ? do I have to install an external library to have it ? Max reports an error, i tried both in Max5 and Max6.1

woyteg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

sry, it's an abstraction, here:

themesser's icon

Hello WOYTEG, thank you very much for your support, I have what I need now, thanks to you.
One last question, what do you mean by

"Correct" Rms, without any windowing, problematic algorithm

better use the one without the square root ?

Roman Thilenius's icon

well lets put it like this.

that some - probably close to industry standard metering - VST plug-in shows different values than your own code in max, should not really be something to worry about.

you said until now you used your ears. using your ears is the best thing you can do. but of course i wont work for batch processing 10,000 files while you are in the bathroom powdering your nose.

if you dont want to follow one of the industry standards measuring and displaying loudness, try this:
- use average~ in rms mode
- use a window of 80 or 200 milliseconds
- for the GUI, experiment with interpolation using line, slide, and delay the display for half the average~ window time

when you thin you found "your way", then use that forever and ignore anything else. ;)
last but not least, averaging and analyzing dB/A values is not the most perfect way of finding the perceived loudness, because perceived loudness does not have a linear connection to gain, voltage, or the geometrical plane of a digital signal.

a 50 Hz sine wave will feel not as loud as a 2000 Hz sine wave of the same power. noise will feel much louder than a few clicks of the same power (or in other words: the peak does matter a lot) an explosion sound will sound not as loud as a distorted version of it at the same power.

so a perfect algorithm would measure not only the overall or windowed average of a sound file, but parts of it individually - plus peak and spectrum.

-110

themesser's icon

so a perfect algorithm would measure not only the overall or windowed average of a sound file, but parts of it individually – plus peak and spectrum.

thank you ROMAN , i will use RMS peak and RMS mean as posted by WOYTEG , with some of my personal spices.
One of the things that you said and is so terribly true, it that the difference between what the ear perceive and what an algorithm translates can be quite noticeable, also acoustic of the room can make the perceived loudness vary, so many factors than need to be adjusted live, but at least, I can now prepare my sets better and avoid huge loudness variations.

woyteg's icon

a 50 Hz sine wave will feel not as loud as a 2000 Hz sine wave of the same power.

Although this is just an approximation to solving that problem, you might consider using an EQ with something like a k-weightening or fletcher-munson curve or the like before measuring RMS.