私はC++を使ってVSTプラグインを開発しています。プラグインを使用すると、数式を入力することができます。数式は、音を生成するために1秒あたり44100回実行されます。私はこのようなリアルタイムのものには新しく、ユーザーが入力した式を解釈するだけです。ユーザ定義の式を44100回/秒で評価するには
問題は、速く実行できるユーザー定義関数を評価する方法が見つからないということです。私が一番頑張ったのは、ユーザーが入力した式を入力時にRPNに変換してから、関数を使ってRPN式を評価してオーディオを生成することでした。私はRPN評価関数を実装し、それをテストするためにRPN式をハードコードしました。それは正しく評価されているように見えますが、十分に速く実行しているようには見えません。ここで
は、私の評価関数は、カップルのRPNの表現に加えて、次のとおりです。
#include <string>
#include <stack>
#include <deque>
/*
* an RPN expression is stored as a deque of strings
*
* each string is either an operator, a number, or the single variable t
*
* the deque is read from front to back
*/
std::deque<std::string> simpleCase, complexCase;
//simple expression, just the variable t
simpleCase.push_back("t");
//more complex expression, t*(42&(t>>11))
complexCase.push_back("t");
complexCase.push_back("42");
complexCase.push_back("t");
complexCase.push_back("11");
complexCase.push_back(">>");
complexCase.push_back("&");
complexCase.push_back("*");
/*
* The evalRPN function takes an RPN deque, plugs in a supplied t,
* and evaluates it.
*
* The idea is that t increases continually, and that the integer overflow
* causes the output to oscillate between 0 and 255.
*
* t is a double, but I convert it to a uint32_t.
*
* Allowed operators: bitwise logic (&, |, ^), bitshifts (<<, >>),
* and math (+, -, *, /, %)
*
* Allowed vars: t
*
* Supplied numbers are converted from string to char arrays then to an int
*
* This also assumes the RPN is not ill-formatted.
*/
uint8_t evalRPN(std::deque<std::string> rpnExpr, double tVal)
{
std::stack<uint8_t> numberStack;
std::string token;
while(rpnExpr.size() > 0)
{
token = rpnExpr.front();
rpnExpr.pop_front();
if(token.find_first_not_of("") == std::string::npos)
{
//if token is a number
numberStack.push((uint8_t)atoi(token.c_str()));
}
else if (token == "t")
{
numberStack.push((uint8_t)tVal);
}
else
{
uint8_t last = numberStack.top();
numberStack.pop();
uint8_t first = numberStack.top();
numberStack.pop();
if(token == "^")
{
numberStack.push(first^last);
}
else if (token == "&")
{
numberStack.push(first & last);
}
else if (token == "|")
{
numberStack.push(first | last);
}
else if (token == "<<")
{
numberStack.push(first >> last);
}
else if (token == ">>")
{
numberStack.push(first >> last);
}
else if (token == "+")
{
numberStack.push(first + last);
}
else if (token == "-")
{
numberStack.push(first - last);
}
else if (token == "*")
{
numberStack.push(first * last);
}
else if (token == "/")
{
numberStack.push(first/last);
}
else if (token == "%")
{
numberStack.push(first % last);
}
}
}
//assume one left in numberStack
return(numberStack.top());
}
は、私はそれが潜在的に十分に速く走らせるために私のRPN処理で行うことができます任意の最適化はありますか?あるいは、より効率的なRPN計算を扱う別の方法がありますか?
さらに、標準的な数式を表すユーザー入力文字列を取得し、その式を1/44100秒未満で完了するのに十分速く実行するためのC++互換メソッドがありますか?
私は本当にあなたが達成しようとしているのか理解していないが、多分それがお手伝いします:なぜあなたは計算しています同じ表現を何回も繰り返します(正確には44100回)。なぜ結果を保存して一度実行しないのですか? – Rakete1111
これはオプションです。 LLVMはある程度あなたを助けてくれるでしょう。確かに、それは最終的にあなたのインタプリタをコンパイラに変え、残りを心配する必要がありますが、パフォーマンスは良くなるので、余分な作業です。私はVSTやサウンドについて何も知らない。しかし、JITingよりも解釈が間違いなくあなたを遅らせるでしょう。 – Taywee
JITをしたくない場合は、RPN式を何らかのASTなどに分解する必要があります。そのため、1秒間に何千回も文字列を比較しません。 – Taywee