Open elanhickler opened 6 years ago
Greg would rather have LUFS! If you're going to charge for something, charge for that!
i just added the function rsArray::rootMeanSquare
. (not yet tested, but it's so simple, i can't imagine anything going wrong - edit: at least mathemathically...but i forgot to add some const modifiers in called functions....fixed that). i will look into implementing LUFS next.
https://en.wikipedia.org/wiki/LKFS
maybe, while i'm at it, i could also implement other standardized psychoacoustic loudness measures like dB(A), dB(B), etc...i'll have to hunt down respective standardized filter coeffs and time constants (maybe, if it's for realtime metering rather than computing a single value for the whole array), maybe this one:
http://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.1770-0-200607-S!!PDF-E.pdf
ah - i have found analog transfer functions for the A,B,C,D filters: https://en.wikipedia.org/wiki/A-weighting#Transfer_function_equivalent and the LUFS paper above has coefficients for digital filters at 48kHz. i think, i can translate them all to any sample-rate by BLT in the analog case and frequency-warping (actually also a sort of BLT) in the digital case. i just have to figure out the details...
does rsArray::rootMeanSquare get the peak RMS or does it get an average RMS over the entire array?
I actually need a peak RMS
it's an average over the entire array. peak-rms sounds a bit like an oxymoron. i guess you mean taking the maximum value of a short-time rms signal?
i just added the function getMaxShortTimeRMS. i just implemented this quickly off the cuff and didn't test it yet - so it needs some testing now.
in case you wonder, it's not defined in rsArray because it needs a filter and i don't want rsArray to depend on filters (the rsArray class is lower level and should not not have a dependency on higher level classes - i don't want to break the layered structure of the library...not yet at least)
Thank you! Will test... If I can manage to merge your library with my version... Oh jeez.
maybe just copy the function over to your codebase. it's just a few lines. i'll update my juce soon (not keen on the new vst-sdk dependency, tbh - up to 5.2, juce was more or less self-contained, which is a good thing for a library). there's even a newer version out there now (i think, 5.4 or something). today is integration time for banddiagonal solver into rapt
I cloned your library for my reaper plugin so now just my reaper plugin is synced with your library. But I get an error "unresolved external symbol" for rapt::rsarray::meansquare. I believe I solved this in another version of your library by just making the functions use doubles and not be a template. Can you fix this? Or tell me how to fix it?
https://gitlab.com/Hickler/reaper_seSampleLib
See readme for the other dependencies, just your library which already contains juce and you need seObjectiveReaper. Search for RMS in action.cpp file in the reaper_seSampleLib project to find my usage and where the error is coming from.
oh nevermind, I'm just using getMaxShortTimeRMS function and it builds, no errors.
ok - does it work as expected, too?
not working, seems to be outputting the same value.
my usage:
double AUDIOFUNCTION::getPeakRMS(TAKE & take, double timeWindowForPeakRMS)
{
auto summedAudio = sumChannelModeChannels(take);
if (take.getNumChannelModeChannels() > 1)
for (auto & sample : summedAudio)
sample /= double(take.getNumChannels());
return RAPT::getMaxShortTimeRMS<double>(summedAudio.data(), summedAudio.size(), take.getSampleRate()*timeWindowForPeakRMS);
}
hmm..weird. i just added the test-function
void maxShortTimeRMS()
{
int N = 1000;
std::vector<double> x = createSineWave(N, 1000.0, 48000.0);
double maxRms = RAPT::getMaxShortTimeRMS(&x[0], N, 48); // 48 samples = 1 cycle, rms = 1/sqrt(2)
int dummy = 0;
}
to my test project and it produces a reasonable value. it's a bit inexact (pesumably) due to leakage in my implementation of the moving average but otherwise looks ok. (just in case you wonder about all my int dummy = 0
statements in my code - they are just for setting debug breakpoints mostly because vs sometimes doesn't like breakpoints at a closing brace)
why would I be getting a number near infinity and the same value every time? I checked my audio data, it has normal numbers. Would a 0 value sample mess it up?
hmm - only a zero averaging length could mess it up, as far as i can see. what's your averaging length?
wait - i can now reproduce it - with larger averaging length....
0.5 * samplerate is my averaging length
yes - as said above - i can reproduce it with larger averaging length now. hmm...my i have a bug in my delayline implementation? i will figure it out....
what is a typical averaging length?
I tried 0.01 * samplerate (441 samples) and i get a maxRMS of 0.
0.1 (4410 samples) gives a maxRMS of 2.5029777399088483e+33
So I either get 0 or a giant number!?!?!
ok - i figured it out! when you set up a delayline length greater than currently allocated memory, i re-allocate - and i forgot to initialize with zeros after such re-allocation. how embarrassing! how could this go unnoticed for so long? now, it seems to work.
what's a typical averaging length. hmm...i would probably say something like the reciprocal of the lowest expected frequency would make sense
that's super embarrassing.
...im getting 0 maxRMS every time nowwww
edit: because my audio data is zeroes... wtf... edit: because im dividing by numChannels, and numChannels is 0... wtf...
that's super embarrassing.
yeah, i know. that code is super old
YAYY it's working!
I'm not embarrassed by the way.
i forgot to initialize with zeros after such re-allocation.
actually, i should probably copy the contents of the old delayline...hmm...but i actually assume that such re-allocations are not events that occur during regular processing...dunno
edit: ...or use a std::vector and just resize it - which takes care of all that - plus i can look at the content in the debugger
or use a std::vector and just resize it - which takes care of all that
or wait - does it? i'm actually not quite sure. i think, i've seen it initialize in debug-builds but not in release builds or something. ...which is actually a quite bad idea to do for a compiler - it suggests, all is well and good by "helpfully" initializing in a debug build. if i were a compiler, i'd initialize all uninitialized variables to NaN in debug builds. that would be really helpful
LNK2019 unresolved external symbol
public: static double __cdecl RAPT::rsArray::meanSquare
referenced in
function "public: static double __cdecl RAPT::rsArray::rootMeanSquare<double>
(double const *,int)" (??$rootMeanSquare@N@rsArray@RAPT@@SANPEBNH@Z)
trying to use full waveform RMS as well, ill just not use it for now. Not sure how to fix an unresolved external symbol.. well, you have your meanSquare definition in a .cpp file which is not recommended.
https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl
you need to explicitly instantiate each rapt-template for all datatypes that you want to use. look at
rosic_TemplateInstantiations.cpp
there, i'm doing it myself - from the perspective of rapt, rosic is client code, so to speak. your link assumes that you compile each .cpp file on its own whereas i use a unity build system in which i can make sure, the compiler sees the template definition when it needs it, even though it's in a cpp file. also, defining the templates in the header comes with its own set of problems. in some contexts, the same template gets instantiated multiple times in multiple compilation units - just imagine two .cpp files include the same .h file containing a template function or -class and instantiate the same template for the same datatype in both cpp files - bäm! multiple definition linker error
i know, i know - it's a mess. but that's the price for writing the code in terms of templates. i think, the type independency is worth it, though. ...not mainly to have single and double precision versions (although that's a welcome plus, too) but mainly to be able to make simd-multichannel versions without additional code
I can build a debug version, for some reason I get these unresolved external symbols for release version:
LNK2019 unresolved external symbol "int __cdecl RAPT::rsNextPowerOfTwo<int>(int)" (??$rsNextPowerOfTwo@H@RAPT@@YAHH@Z)
referenced in function
"public: void __cdecl rosic::rsArray<class rosic::rsString>::ensureAllocatedSize(int)" (?ensureAllocatedSize@?$rsArray@VrsString@rosic@@@rosic@@QEAAXH@Z)
reaper_seSampleLib_DynamicLibrary
D:\_PROGRAMMING\reaper_seSampleLib\Builds\VisualStudio2015\include_romos.obj 1
LNK2019 unresolved external symbol
"double __cdecl RAPT::rsWrapToInterval(double,double,double)" (?rsWrapToInterval@RAPT@@YANNNN@Z)
referenced in function
"public: double __cdecl romos::BlitSaw::getDesiredFirstSample(double,double)" (?getDesiredFirstSample@BlitSaw@romos@@QEAANNN@Z)
reaper_seSampleLib_DynamicLibrary
D:\_PROGRAMMING\reaper_seSampleLib\Builds\VisualStudio2015\include_romos.obj 1
Error LNK2019 unresolved external symbol "double __cdecl RAPT::rsRandomUniform(double,double,int)" (?rsRandomUniform@RAPT@@YANNNH@Z)
referenced in function
"protected: virtual void __cdecl romos::ProcessingTest::fillInputSignalArraysRandomly(int)" (?fillInputSignalArraysRandomly@ProcessingTest@romos@@MEAAXH@Z)
reaper_seSampleLib_DynamicLibrary
D:\_PROGRAMMING\reaper_seSampleLib\Builds\VisualStudio2015\include_romos.obj 1
romos.obj? that's my modular system aka liberty, or well, the modular synth code framework, liberty is based on. do you even use that in your reaper plugin? if not, throw it out. do you use a projucer project for this too? if so, throw out the romos juce module
fixed
Like a few posts above, I'm getting error:
LNK2019 unresolved external symbol
"public: static float __cdecl RAPT::rsArray::rootMeanSquare
I looked at rosic_TemplateInstantiations.cpp and everything is writted for classes. I don't know the syntax for instantiating a function.
I tried this, but get error:
Edit: Ok, figured out the syntax. put this in the CPP file above where the function is used.
template float RAPT::rsArray::rootMeanSquare(const float *, int);
Error is still not resolved.
hmm - this:
template float RAPT::rsArray::rootMeanSquare(const float *, int);
looks actually good. however, i have just added an "inline" to the function - maybe try again with the inline (you should then get rid of the instantiation)
still not building 😢
I confirmed that I got the new update and inline is there.
ah - i think, is see what's wrong. the rootMeanSquare function calls the meanSquare function, so you need an instantiation of that inner function as well. i just added
template double RAPT::rsArray::meanSquare(const double *x, int N);
to rosic and also added a little test to confirm that it builds (which it does now, after adding this). if you need it for float, add another instantiation for float. do you actually have a custom (additional) instantiation file in your codebase? the idea for the rapt library is that client code may just provide its own instantiation file, in cases when it needs some additional (or different) template instantiations, that i don't need myself
I need float. So I put that in the cpp file?
if you have your own fork, you can put it there right next to the double instantiation. however, in the long run, i would recommend to just create your own additional cpp file somewhere in your framework/juce-module for the additional instantiations that are specific to your codebase
I don't know the first thing about solving this problem.
Where did you place template double RAPT::rsArray::meanSquare(const double *x, int N)
, what's the exact file name?
Adding my own template instantiation to a cpp file doesn't solve the problem, I don't know how this works or how I can make my own instantiation file.
Edit: How is it that I have not added rosic to my juce modules yet it works by adding an instantiation to a rosic file?
Edit: Ok I tried adding a float instantiation to rosic_TemplateInstantiations.cpp, still having unresolved external symbol build error for meanSquare
How is it that I have not added rosic to my juce modules yet it works by adding an instantiation to a rosic file? Edit: Ok I tried adding a float instantiation to rosic_TemplateInstantiations.cpp, still having unresolved external symbol build error for meanSquare
oh - if you don't compile the rosic module, then placing the instantiation there should not help indeed. maybe i should try this myself with your codebase? an instantiation file is nothing really special - just a regular cpp file inside of which all the required explicit instantiations are collected - and which is compiled as part of one of your juce modules
i'm getting a bunch of compiler errors: so i don't even get to the linker stage
i could fix the ones about the AdvancedLeakDetector by adding using namespace juce;
before the class definition. but the files for the "dockable-windows" stuff are just not there in the codebase. the folder is empty. did you forget to add them and have them only locally?
it's a submodule, not exactly sure how that works.
oookay! i added a template instantiation file to the project and modified the jucer file accordingly. if you re-generate the visual studio project from the jucer file, it should build now
it's a submodule, not exactly sure how that works.
i just manually added the required files to my local copy. i also don't know, how git submodules are supposed to work - if they are supposed to automatically being dragged in and if so, how. i'd perhaps just add copies of the files to the repo. i think, a repo should ideally be self-contained and not depend on external sources. ...that obviously may mean a lot of code duplication...dunno
I need function to do something like
If you need to charge for it, bill Greg @ OrangeTreeSamples!