Hello,
I am looking in JUCE documentation for some classes that could help me with parsing user input String to math equation.
I mean I have text editor component in my application. In that text editor user can provide math equations with variables (something like “pow(a, 2)/(abc)”) and I want to be able to parse it and use my own values for a, b and c.
Are there any helper tools in JUCE for such tasks?
For any help great thanks in advance. Best regards.
There is juce::Expression that can do basic evaluation, but it doesn’t look like it has pow and I don’t see a way to add your own functions. I’ve never used it.
I think it’s a case of sub-classing this JUCE: Expression::Scope Class Reference and you’d implement evaluateFunction to return the answer when given “pow” as the input functionName.
I tested muParser and ginParser (based on muParser) and they both works fantastic.
But I have additional issues. what about calling mu::Parser::Eval() on audio thread?
I know it can throw exceptions. But to be honest I am not good it that subject. Is it safty to use it in audio thread?
To be honest I’ve already tested it on audio thread and it works. But it’s only for tests.
I think it’s fine to use muParser on audio thread, it gets compiled to byte code which is pretty fast. You should call SetExpr on a different thread and then pass your result to the audio thread. Always call Eval once first before you pass it to audio thread, and if it doesn’t throw an exception the first time, it won’t after that. I use it for my plugin Maths:
I have object: dsp::WaveShaper<float, MyWaveShaper> myWaveShaper;
And inside class MyWaveShaper I have object mu::Parser parser
And I call parser.Eval() inside of MyWaveShaper::operator().
Then in processBlock() I call myWaveShaper.process()
Seems like there would be threading issues here. If you’re calling .Eval() from the audio thread, how can you be sure it doesn’t allocate? If you’re calling it on a different thread, how do you avoid data races?
@RolandMR said that he was evaluating on a separate thread and then passing it to the audio thread. This makes sense, but I wanted to hear how he does the passing part, because even this is tricky.
You’d have to look at the source for muparser, but at least in theory Eval is just executing the byte code rather than doing any string parsing etc. It probably uses either the system stack or it’s own stack but that’s deterministic and fine.
Regarding threading, you can either use a spinlock or double buffer. That is, you only pass a ‘parsed’ formula for eval to the audio thread once it’s been fully parsed with variables etc. What you don’t want to do is be in the middle of executing byte code on the audio thread when the formula is being re-parsed on the message thread because…boom.
To be honest. I have impression like there is some issue. Probably it’s data racing as you said. But maybe it’s something different. Of course I don’t like it. But until I use it only in my special debug plugin (not for sale) it is OK for me. It works as I expect. So I have not made any more investigations.
By the way @RolandMR says it should be OK to call parser.Eval() on audio thread (at least I understand his answer like that):
I think it’s fine to use muParser on audio thread, it gets compiled to byte code which is pretty fast. You should call SetExpr on a different thread and then pass your result to the audio thread. Always call Eval once first before you pass it to audio thread, and if it doesn’t throw an exception the first time, it won’t after that.
Of course he mentioned that before I do that I should at least once check if it doesn’t throw exception which I do.