diff --git a/.gitmodules b/.gitmodules index 05fb6b53645..94530a19710 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,7 +18,7 @@ url = https://github.com/lmms/veal [submodule "plugins/Xpressive/exprtk"] path = plugins/Xpressive/exprtk - url = https://github.com/tresf/exprtk + url = https://github.com/ArashPartow/exprtk [submodule "plugins/LadspaEffect/swh/ladspa"] path = plugins/LadspaEffect/swh/ladspa url = https://github.com/swh/ladspa diff --git a/plugins/Xpressive/ExprSynth.cpp b/plugins/Xpressive/ExprSynth.cpp index 90ac1474d07..4e5ba21e826 100644 --- a/plugins/Xpressive/ExprSynth.cpp +++ b/plugins/Xpressive/ExprSynth.cpp @@ -296,30 +296,58 @@ inline unsigned int rotateLeft(unsigned int x, const int b) return x; } -struct RandomVectorFunction : public exprtk::ifunction +struct RandomVectorSeedFunction : public exprtk::ifunction { using exprtk::ifunction::operator(); - RandomVectorFunction(const unsigned int seed) : - exprtk::ifunction(1), - m_rseed(seed) + RandomVectorSeedFunction() : + exprtk::ifunction(2) { exprtk::disable_has_side_effects(*this); } - inline float operator()(const float& index) + static inline float randv(const float& index,int irseed) { if (index < 0 || std::isnan(index) || std::isinf(index)) { return 0; } const unsigned int xi = (unsigned int)index; - const unsigned int si = m_rseed % data_size; - const unsigned int sa = m_rseed / data_size; - unsigned int res=rotateLeft(random_data[(xi + si) % data_size] ^ random_data[(xi / data_size + sa) % data_size],sa % 31 + 1); - res ^= rotateLeft(random_data[(3 * xi + si) % data_size] ^ random_data[(xi / data_size + 2 * sa) % data_size],xi % 31 + 1); + const unsigned int si = irseed % data_size; + const unsigned int sa = irseed / data_size; + unsigned int res=rotateLeft(random_data[(xi + 23 * si + 1) % data_size] ^ random_data[(xi / data_size + sa) % data_size],sa % 31 + 1); + res ^= rotateLeft(random_data[(3 * xi + si + 13) % data_size],(xi+2*si) % 32) ^rotateLeft( random_data[(xi / data_size + 2 * sa) % data_size],xi % 31 + 1); return static_cast(res) / (float)(1 << 31); } - const int data_size=sizeof(random_data)/sizeof(int); + inline float operator()(const float& index,const float& seed) + { + int irseed; + if (seed < 0 || std::isnan(seed) || std::isinf(seed)) + { + irseed=0; + } + else + irseed=(int)seed; + return randv(index,irseed); + } + + static const int data_size=sizeof(random_data)/sizeof(int); +}; +static RandomVectorSeedFunction randsv_func; + +struct RandomVectorFunction : public exprtk::ifunction +{ + using exprtk::ifunction::operator(); + + RandomVectorFunction(const unsigned int seed) : + exprtk::ifunction(1), + m_rseed(seed) + { exprtk::disable_has_side_effects(*this); } + + inline float operator()(const float& index) + { + return RandomVectorSeedFunction::randv(index,m_rseed); + } + const unsigned int m_rseed; }; @@ -340,10 +368,10 @@ static freefunc0 simple_rand class ExprFrontData { public: - ExprFrontData(): + ExprFrontData(int last_func_samples): m_rand_vec(SimpleRandom::generator()), m_integ_func(NULL), - m_last_func(500) + m_last_func(last_func_samples) {} ~ExprFrontData() { @@ -369,6 +397,7 @@ class ExprFrontData RandomVectorFunction m_rand_vec; IntegrateFunction *m_integ_func; LastSampleFunction m_last_func; + }; @@ -489,17 +518,19 @@ struct harmonic_semitone static freefunc1 harmonic_semitone_func; -ExprFront::ExprFront(const char * expr) +ExprFront::ExprFront(const char * expr, int last_func_samples) { m_valid = false; try { - m_data = new ExprFrontData(); + m_data = new ExprFrontData(last_func_samples); m_data->m_expression_string = expr; m_data->m_symbol_table.add_pi(); m_data->m_symbol_table.add_constant("e", F_E); + + m_data->m_symbol_table.add_constant("seed", SimpleRandom::generator() & max_float_integer_mask); m_data->m_symbol_table.add_function("sinew", sin_wave_func); m_data->m_symbol_table.add_function("squarew", square_wave_func); @@ -513,6 +544,7 @@ ExprFront::ExprFront(const char * expr) m_data->m_symbol_table.add_function("semitone", harmonic_semitone_func); m_data->m_symbol_table.add_function("rand", simple_rand); m_data->m_symbol_table.add_function("randv", m_data->m_rand_vec); + m_data->m_symbol_table.add_function("randsv", randsv_func); m_data->m_symbol_table.add_function("last", m_data->m_last_func); } catch(...) @@ -742,7 +774,7 @@ void ExprSynth::renderOutput(fpp_t frames, sampleFrame *buf) } o1 = o1_rawExpr->value(); o2 = o2_rawExpr->value(); - last_func1->setLastSample(o1); + last_func1->setLastSample(o1);//put result in the circular buffer for the "last" function. last_func2->setLastSample(o2); buf[frame][0] = (-pn1 + 0.5) * o1 + (-pn2 + 0.5) * o2; buf[frame][1] = ( pn1 + 0.5) * o1 + ( pn2 + 0.5) * o2; diff --git a/plugins/Xpressive/ExprSynth.h b/plugins/Xpressive/ExprSynth.h index a46aea8c650..bb25fd036dd 100644 --- a/plugins/Xpressive/ExprSynth.h +++ b/plugins/Xpressive/ExprSynth.h @@ -27,6 +27,7 @@ #include #include +#include #include "AutomatableModel.h" #include "Graph.h" #include "Instrument.h" @@ -39,7 +40,7 @@ class ExprFront { public: typedef float (*ff1data_functor)(void*, float); - ExprFront(const char* expr); + ExprFront(const char* expr, int last_func_samples); ~ExprFront(); bool compile(); inline bool isValid() { return m_valid; } @@ -52,6 +53,9 @@ class ExprFront private: ExprFrontData *m_data; bool m_valid; + + static const int max_float_integer_mask=(1<<(std::numeric_limits::digits))-1; + }; class WaveSample diff --git a/plugins/Xpressive/Xpressive.cpp b/plugins/Xpressive/Xpressive.cpp index 5edd1e2044f..0dae72f6845 100644 --- a/plugins/Xpressive/Xpressive.cpp +++ b/plugins/Xpressive/Xpressive.cpp @@ -202,23 +202,24 @@ void Xpressive::playNote(NotePlayHandle* nph, sampleFrame* working_buffer) { if (nph->totalFramesPlayed() == 0 || nph->m_pluginData == NULL) { - ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData()); - ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData()); - - auto init_expression_step1 = [this, nph](ExprFront* e) { - e->add_constant("key", nph->key()); - e->add_constant("bnote", nph->instrumentTrack()->baseNote()); - e->add_constant("srate", Engine::mixer()->processingSampleRate()); - e->add_constant("v", nph->getVolume() / 255.0); - e->add_constant("tempo", Engine::getSong()->getTempo()); - e->add_variable("A1", m_A1); + ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData(),Engine::mixer()->processingSampleRate());//give the "last" function a whole second + ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData(),Engine::mixer()->processingSampleRate()); + + auto init_expression_step1 = [this, nph](ExprFront* e) { //lambda function to init exprO1 and exprO2 + //add the constants and the variables to the expression. + e->add_constant("key", nph->key());//the key that was pressed. + e->add_constant("bnote", nph->instrumentTrack()->baseNote()); // the base note + e->add_constant("srate", Engine::mixer()->processingSampleRate());// sample rate of the mixer + e->add_constant("v", nph->getVolume() / 255.0); //volume of the note. + e->add_constant("tempo", Engine::getSong()->getTempo());//tempo of the song. + e->add_variable("A1", m_A1);//A1,A2,A3: general purpose input controls. e->add_variable("A2", m_A2); e->add_variable("A3", m_A3); }; init_expression_step1(exprO1); init_expression_step1(exprO2); - m_W1.setInterpolate(m_interpolateW1.value()); + m_W1.setInterpolate(m_interpolateW1.value());//set interpolation according to the user selection. m_W2.setInterpolate(m_interpolateW2.value()); m_W3.setInterpolate(m_interpolateW3.value()); nph->m_pluginData = new ExprSynth(&m_W1, &m_W2, &m_W3, exprO1, exprO2, nph, @@ -520,11 +521,11 @@ void XpressiveView::expressionChanged() { if (text.size()>0) { - ExprFront expr(text.constData()); + const unsigned int sample_rate=m_raw_graph->length(); + ExprFront expr(text.constData(),sample_rate); float t=0; const float f=10,key=5,v=0.5; unsigned int i; - const unsigned int sample_rate=m_raw_graph->length(); expr.add_variable("t", t); if (m_output_expr) @@ -776,7 +777,7 @@ void XpressiveView::sqrWaveClicked() { } void XpressiveView::noiseWaveClicked() { - m_expressionEditor->appendPlainText("rand"); + m_expressionEditor->appendPlainText("randsv(t*srate,0)"); Engine::getSong()->setModified(); } @@ -821,13 +822,14 @@ QString XpressiveHelpView::s_helpText= "rel - Gives 0.0 while the key is holded, and 1.0 after the key release. Available only in the output expressions.
" "trel - Time after release. While the note is holded, it gives 0.0. Afterwards, it start counting seconds.
" "The time it takes to shift from 0.0 to 1.0 after key release is determined by the REL knob
" +"seed - A random value that remains consistent in the lifetime of a single wave. meant to be used with randsv
" "A1, A2, A3 - General purpose knobs. You can reference them only in O1 and O2. In range [-1,1].
" "

Available functions:


" "W1, W2, W3 - As mentioned before. You can reference them only in O1 and O2.
" "cent(x) - Gives pow(2,x/1200), so you can multiply it with the f variable to pitch the frequency.
" "100 cents equals one semitone
" "semitone(x) - Gives pow(2,x/12), so you can multiply it with the f variable to pitch the frequency.
" -"last(n) - Gives you the last n'th evaluated sample. The argument n must be in the range [1,500], or else, it will return 0.
" +"last(n) - Gives you the last n'th evaluated sample. In O1 and O2 it keeps a whole second. Thus the argument n must be in the range [1,srate], or else, it will return 0.
" "integrate(x) - Integrates x by delta t (It sums values and divides them by sample rate).
" "If you use notes with automated frequency, you should use:
" "sinew(integrate(f)) instead of sinew(t*f)
" @@ -838,6 +840,9 @@ QString XpressiveHelpView::s_helpText= "and every reference to randv(a) will give you the same value." "If you want a random wave you can use randv(t*srate).
" "Each random value is in the range [-1,1).
" +"randsv(x,seed) - works exactly like randv(x),
" +"except that it lets you to select the seed manualy,
" +"if you want to try different random values and make it consistent in each evaluation.
" "sinew(x) - A sine wave with period of 1 (In contrast to real sine wave which have a period of 2*pi).
" "trianglew(x) - A triangle wave with period of 1.
" "squarew(x) - A square wave with period of 1.
" diff --git a/plugins/Xpressive/exprtk b/plugins/Xpressive/exprtk index aad301a6ebb..f32d2b4bbb6 160000 --- a/plugins/Xpressive/exprtk +++ b/plugins/Xpressive/exprtk @@ -1 +1 @@ -Subproject commit aad301a6ebbab769620b0bb0e77713c4659117a6 +Subproject commit f32d2b4bbb640ea4732b8a7fce1bd9717e9c998b