Xpressive.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. /*
  2. * Xpressive.cpp - Instrument which uses a mathematical formula parser
  3. *
  4. * Copyright (c) 2016-2017 Orr Dvori
  5. *
  6. * This file is part of LMMS - https://lmms.io
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public
  19. * License along with this program (see COPYING); if not, write to the
  20. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. * Boston, MA 02110-1301 USA.
  22. *
  23. */
  24. #include "Xpressive.h"
  25. #include <QDomElement>
  26. #include "Engine.h"
  27. #include "Graph.h"
  28. #include "GuiApplication.h"
  29. #include "InstrumentTrack.h"
  30. #include "Knob.h"
  31. #include "LedCheckbox.h"
  32. #include "MainWindow.h"
  33. #include "Mixer.h"
  34. #include "NotePlayHandle.h"
  35. #include "Oscillator.h"
  36. #include "PixmapButton.h"
  37. #include "Song.h"
  38. #include "SubWindow.h"
  39. #include "ToolTip.h"
  40. #include "base64.h"
  41. #include "lmms_constants.h"
  42. #include "embed.h"
  43. #include "ExprSynth.h"
  44. #include "plugin_export.h"
  45. extern "C" {
  46. Plugin::Descriptor PLUGIN_EXPORT xpressive_plugin_descriptor = { STRINGIFY(
  47. PLUGIN_NAME), "Xpressive", QT_TRANSLATE_NOOP("PluginBrowser",
  48. "Mathematical expression parser"), "Orr Dvori", 0x0100,
  49. Plugin::Instrument, new PluginPixmapLoader("logo"), NULL, NULL };
  50. }
  51. /*
  52. * nice test:
  53. O1 -> trianglew(2t*f)*(0.5+0.5sinew(12*A1*t+0.5))+sinew(t*f)*(0.5+0.5sinew(12*A1*t))
  54. O2 -> trianglew(2t*f)*(0.5+0.5sinew(12*A1*t))+sinew(t*f)*(0.5+0.5sinew(12*A1*t+0.5))
  55. */
  56. /***********************************************************************
  57. *
  58. * class Xpressive
  59. *
  60. * lmms - plugin
  61. *
  62. ***********************************************************************/
  63. #define GRAPH_LENGTH 4096
  64. Xpressive::Xpressive(InstrumentTrack* instrument_track) :
  65. Instrument(instrument_track, &xpressive_plugin_descriptor),
  66. m_graphO1(-1.0f, 1.0f, 360, this),
  67. m_graphO2(-1.0f, 1.0f, 360, this),
  68. m_graphW1(-1.0f, 1.0f, GRAPH_LENGTH, this),
  69. m_graphW2(-1.0f, 1.0f, GRAPH_LENGTH, this),
  70. m_graphW3(-1.0f, 1.0f, GRAPH_LENGTH, this),
  71. m_rawgraphW1(-1.0f, 1.0f, GRAPH_LENGTH, this),
  72. m_rawgraphW2(-1.0f, 1.0f, GRAPH_LENGTH, this),
  73. m_rawgraphW3(-1.0f, 1.0f, GRAPH_LENGTH, this),
  74. m_selectedGraph(0, 0, 6, this, tr("Selected graph")),
  75. m_parameterA1(1, -1.0f, 1.0f, 0.01f, this, tr("A1")),
  76. m_parameterA2(1, -1.0f, 1.0f, 0.01f, this, tr("A2")),
  77. m_parameterA3(1, -1.0f, 1.0f, 0.01f, this, tr("A3")),
  78. m_smoothW1(0, 0.0f, 70.0f, 1.0f, this, tr("W1 smoothing")),
  79. m_smoothW2(0, 0.0f, 70.0f, 1.0f, this, tr("W2 smoothing")),
  80. m_smoothW3(0, 0.0f, 70.0f, 1.0f, this, tr("W3 smoothing")),
  81. m_interpolateW1(false, this),
  82. m_interpolateW2(false, this),
  83. m_interpolateW3(false, this),
  84. m_panning1( 1, -1.0f, 1.0f, 0.01f, this, tr("Panning 1")),
  85. m_panning2(-1, -1.0f, 1.0f, 0.01f, this, tr("Panning 2")),
  86. m_relTransition(50.0f, 0.0f, 500.0f, 1.0f, this, tr("Rel trans")),
  87. m_W1(GRAPH_LENGTH),
  88. m_W2(GRAPH_LENGTH),
  89. m_W3(GRAPH_LENGTH),
  90. m_exprValid(false, this)
  91. {
  92. m_outputExpression[0]="sinew(integrate(f*(1+0.05sinew(12t))))*(2^(-(1.1+A2)*t)*(0.4+0.1(1+A3)+0.4sinew((2.5+2A1)t))^2)";
  93. m_outputExpression[1]="expw(integrate(f*atan(500t)*2/pi))*0.5+0.12";
  94. }
  95. Xpressive::~Xpressive() {
  96. }
  97. void Xpressive::saveSettings(QDomDocument & _doc, QDomElement & _this) {
  98. // Save plugin version
  99. _this.setAttribute("version", "0.1");
  100. _this.setAttribute("O1", QString(m_outputExpression[0]));
  101. _this.setAttribute("O2", QString(m_outputExpression[1]));
  102. _this.setAttribute("W1", QString(m_wavesExpression[0]));
  103. // Save sample shape base64-encoded
  104. QString sampleString;
  105. base64::encode( (const char*)m_rawgraphW1.samples(),
  106. m_rawgraphW1.length() * sizeof(float), sampleString );
  107. _this.setAttribute( "W1sample", sampleString );
  108. _this.setAttribute("W2", QString(m_wavesExpression[1]));
  109. base64::encode( (const char*)m_rawgraphW2.samples(),
  110. m_rawgraphW2.length() * sizeof(float), sampleString );
  111. _this.setAttribute( "W2sample", sampleString );
  112. _this.setAttribute("W3", QString(m_wavesExpression[2]));
  113. base64::encode( (const char*)m_rawgraphW3.samples(),
  114. m_rawgraphW3.length() * sizeof(float), sampleString );
  115. _this.setAttribute( "W3sample", sampleString );
  116. m_smoothW1.saveSettings(_doc,_this,"smoothW1");
  117. m_smoothW2.saveSettings(_doc,_this,"smoothW2");
  118. m_smoothW3.saveSettings(_doc,_this,"smoothW3");
  119. m_interpolateW1.saveSettings(_doc,_this,"interpolateW1");
  120. m_interpolateW2.saveSettings(_doc,_this,"interpolateW2");
  121. m_interpolateW3.saveSettings(_doc,_this,"interpolateW3");
  122. m_parameterA1.saveSettings(_doc,_this,"A1");
  123. m_parameterA2.saveSettings(_doc,_this,"A2");
  124. m_parameterA3.saveSettings(_doc,_this,"A3");
  125. m_panning1.saveSettings(_doc,_this,"PAN1");
  126. m_panning2.saveSettings(_doc,_this,"PAN2");
  127. m_relTransition.saveSettings(_doc,_this,"RELTRANS");
  128. }
  129. void Xpressive::loadSettings(const QDomElement & _this) {
  130. m_outputExpression[0]=_this.attribute( "O1").toLatin1();
  131. m_outputExpression[1]=_this.attribute( "O2").toLatin1();
  132. m_wavesExpression[0]=_this.attribute( "W1").toLatin1();
  133. m_wavesExpression[1]=_this.attribute( "W2").toLatin1();
  134. m_wavesExpression[2]=_this.attribute( "W3").toLatin1();
  135. m_smoothW1.loadSettings(_this,"smoothW1");
  136. m_smoothW2.loadSettings(_this,"smoothW2");
  137. m_smoothW3.loadSettings(_this,"smoothW3");
  138. m_interpolateW1.loadSettings(_this,"interpolateW1");
  139. m_interpolateW2.loadSettings(_this,"interpolateW2");
  140. m_interpolateW3.loadSettings(_this,"interpolateW3");
  141. m_parameterA1.loadSettings(_this,"A1");
  142. m_parameterA2.loadSettings(_this,"A2");
  143. m_parameterA3.loadSettings(_this,"A3");
  144. m_panning1.loadSettings(_this,"PAN1");
  145. m_panning2.loadSettings(_this,"PAN2");
  146. m_relTransition.loadSettings(_this,"RELTRANS");
  147. int size = 0;
  148. char * dst = 0;
  149. base64::decode( _this.attribute( "W1sample"), &dst, &size );
  150. m_rawgraphW1.setSamples( (float*) dst );
  151. delete[] dst;
  152. base64::decode( _this.attribute( "W2sample"), &dst, &size );
  153. m_rawgraphW2.setSamples( (float*) dst );
  154. delete[] dst;
  155. base64::decode( _this.attribute( "W3sample"), &dst, &size );
  156. m_rawgraphW3.setSamples( (float*) dst );
  157. delete[] dst;
  158. smooth(m_smoothW1.value(),&m_rawgraphW1,&m_graphW1);
  159. smooth(m_smoothW2.value(),&m_rawgraphW2,&m_graphW2);
  160. smooth(m_smoothW3.value(),&m_rawgraphW3,&m_graphW3);
  161. m_W1.copyFrom(&m_graphW1);
  162. m_W2.copyFrom(&m_graphW2);
  163. m_W3.copyFrom(&m_graphW3);
  164. }
  165. QString Xpressive::nodeName() const {
  166. return (xpressive_plugin_descriptor.name);
  167. }
  168. void Xpressive::playNote(NotePlayHandle* nph, sampleFrame* working_buffer) {
  169. m_A1=m_parameterA1.value();
  170. m_A2=m_parameterA2.value();
  171. m_A3=m_parameterA3.value();
  172. if (nph->totalFramesPlayed() == 0 || nph->m_pluginData == NULL) {
  173. ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData(),Engine::mixer()->processingSampleRate());//give the "last" function a whole second
  174. ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData(),Engine::mixer()->processingSampleRate());
  175. auto init_expression_step1 = [this, nph](ExprFront* e) { //lambda function to init exprO1 and exprO2
  176. //add the constants and the variables to the expression.
  177. e->add_constant("key", nph->key());//the key that was pressed.
  178. e->add_constant("bnote", nph->instrumentTrack()->baseNote()); // the base note
  179. e->add_constant("srate", Engine::mixer()->processingSampleRate());// sample rate of the mixer
  180. e->add_constant("v", nph->getVolume() / 255.0); //volume of the note.
  181. e->add_constant("tempo", Engine::getSong()->getTempo());//tempo of the song.
  182. e->add_variable("A1", m_A1);//A1,A2,A3: general purpose input controls.
  183. e->add_variable("A2", m_A2);
  184. e->add_variable("A3", m_A3);
  185. };
  186. init_expression_step1(exprO1);
  187. init_expression_step1(exprO2);
  188. m_W1.setInterpolate(m_interpolateW1.value());//set interpolation according to the user selection.
  189. m_W2.setInterpolate(m_interpolateW2.value());
  190. m_W3.setInterpolate(m_interpolateW3.value());
  191. nph->m_pluginData = new ExprSynth(&m_W1, &m_W2, &m_W3, exprO1, exprO2, nph,
  192. Engine::mixer()->processingSampleRate(), &m_panning1, &m_panning2, m_relTransition.value());
  193. }
  194. ExprSynth *ps = static_cast<ExprSynth*>(nph->m_pluginData);
  195. const fpp_t frames = nph->framesLeftForCurrentPeriod();
  196. const f_cnt_t offset = nph->noteOffset();
  197. ps->renderOutput(frames, working_buffer + offset);
  198. instrumentTrack()->processAudioBuffer(working_buffer, frames + offset, nph);
  199. }
  200. void Xpressive::deleteNotePluginData(NotePlayHandle* nph) {
  201. delete static_cast<ExprSynth *>(nph->m_pluginData);
  202. }
  203. PluginView * Xpressive::instantiateView(QWidget* parent) {
  204. return (new XpressiveView(this, parent));
  205. }
  206. class XpressiveKnob: public Knob {
  207. public:
  208. void setStyle()
  209. {
  210. setFixedSize(29, 29);
  211. setCenterPointX(14.5);
  212. setCenterPointY(14.5);
  213. setInnerRadius(4);
  214. setOuterRadius(9);
  215. setTotalAngle(300.0);
  216. setLineWidth(3);
  217. }
  218. XpressiveKnob(QWidget * _parent, const QString & _name) :
  219. Knob(knobStyled, _parent,_name) {
  220. setStyle();
  221. }
  222. XpressiveKnob(QWidget * _parent) :
  223. Knob(knobStyled, _parent) {
  224. setStyle();
  225. }
  226. };
  227. XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) :
  228. InstrumentViewFixedSize(_instrument, _parent)
  229. {
  230. const int COL_KNOBS = 191;
  231. const int BASE_START = 2;
  232. const int ROW_KNOBSA1 = BASE_START;
  233. const int ROW_KNOBSA2 = BASE_START + 32;
  234. const int ROW_KNOBSA3 = BASE_START + 64;
  235. const int ROW_KNOBSP1 = BASE_START + 100;
  236. const int ROW_KNOBSP2 = BASE_START + 100 + 32;
  237. const int ROW_KNOBREL = BASE_START + 100 + 64;
  238. const int ROW_BTN = BASE_START + 85;
  239. const int ROW_WAVEBTN = BASE_START + 233 - 26;
  240. const int EXPR_TEXT_Y = BASE_START + 102;
  241. const int EXPR_TEXT_H = 90;
  242. setAutoFillBackground(true);
  243. QPalette pal;
  244. pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("artwork"));
  245. setPalette(pal);
  246. m_graph = new Graph(this, Graph::LinearStyle, 180, 81);
  247. m_graph->move(3, BASE_START + 1);
  248. m_graph->setAutoFillBackground(true);
  249. m_graph->setGraphColor(QColor(255, 255, 255));
  250. m_graph->setEnabled(false);
  251. ToolTip::add(m_graph, tr("Draw your own waveform here "
  252. "by dragging your mouse on this graph."));
  253. pal = QPalette();
  254. pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("wavegraph"));
  255. m_graph->setPalette(pal);
  256. PixmapButton * m_w1Btn;
  257. PixmapButton * m_w2Btn;
  258. PixmapButton * m_w3Btn;
  259. PixmapButton * m_o1Btn;
  260. PixmapButton * m_o2Btn;
  261. PixmapButton * m_helpBtn;
  262. m_w1Btn = new PixmapButton(this, NULL);
  263. m_w1Btn->move(3, ROW_BTN);
  264. m_w1Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w1_active"));
  265. m_w1Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w1_inactive"));
  266. ToolTip::add(m_w1Btn, tr("Select oscillator W1"));
  267. m_w2Btn = new PixmapButton(this, NULL);
  268. m_w2Btn->move(26, ROW_BTN);
  269. m_w2Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w2_active"));
  270. m_w2Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w2_inactive"));
  271. ToolTip::add(m_w2Btn, tr("Select oscillator W2"));
  272. m_w3Btn = new PixmapButton(this, NULL);
  273. m_w3Btn->move(49, ROW_BTN);
  274. m_w3Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w3_active"));
  275. m_w3Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w3_inactive"));
  276. ToolTip::add(m_w3Btn, tr("Select oscillator W3"));
  277. m_o1Btn = new PixmapButton(this, NULL);
  278. m_o1Btn->move(79, ROW_BTN);
  279. m_o1Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("o1_active"));
  280. m_o1Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("o1_inactive"));
  281. ToolTip::add(m_o1Btn, tr("Select output O1"));
  282. m_o2Btn = new PixmapButton(this, NULL);
  283. m_o2Btn->move(101, ROW_BTN);
  284. m_o2Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("o2_active"));
  285. m_o2Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("o2_inactive"));
  286. ToolTip::add(m_o2Btn, tr("Select output O2"));
  287. m_helpBtn = new PixmapButton(this, NULL);
  288. m_helpBtn->move(133, ROW_BTN);
  289. m_helpBtn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("help_active"));
  290. m_helpBtn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("help_inactive"));
  291. ToolTip::add(m_helpBtn, tr("Open help window"));
  292. m_selectedGraphGroup = new automatableButtonGroup(this);
  293. m_selectedGraphGroup->addButton(m_w1Btn);
  294. m_selectedGraphGroup->addButton(m_w2Btn);
  295. m_selectedGraphGroup->addButton(m_w3Btn);
  296. m_selectedGraphGroup->addButton(m_o1Btn);
  297. m_selectedGraphGroup->addButton(m_o2Btn);
  298. Xpressive *e = castModel<Xpressive>();
  299. m_selectedGraphGroup->setModel(&e->selectedGraph());
  300. m_sinWaveBtn = new PixmapButton(this, tr("Sine wave"));
  301. m_sinWaveBtn->move(4, ROW_WAVEBTN);
  302. m_sinWaveBtn->setActiveGraphic(embed::getIconPixmap("sin_wave_active"));
  303. m_sinWaveBtn->setInactiveGraphic(embed::getIconPixmap("sin_wave_inactive"));
  304. ToolTip::add(m_sinWaveBtn, tr("Sine wave"));
  305. m_moogWaveBtn = new PixmapButton(this, tr("Moog-saw wave"));
  306. m_moogWaveBtn->move(4, ROW_WAVEBTN-14);
  307. m_moogWaveBtn->setActiveGraphic(
  308. embed::getIconPixmap( "moog_saw_wave_active" ) );
  309. m_moogWaveBtn->setInactiveGraphic(embed::getIconPixmap("moog_saw_wave_inactive"));
  310. ToolTip::add(m_moogWaveBtn, tr("Moog-saw wave"));
  311. m_expWaveBtn = new PixmapButton(this, tr("Exponential wave"));
  312. m_expWaveBtn->move(4 +14, ROW_WAVEBTN-14);
  313. m_expWaveBtn->setActiveGraphic(embed::getIconPixmap( "exp_wave_active" ) );
  314. m_expWaveBtn->setInactiveGraphic(embed::getIconPixmap( "exp_wave_inactive" ) );
  315. ToolTip::add(m_expWaveBtn, tr("Exponential wave"));
  316. m_sawWaveBtn = new PixmapButton(this, tr("Saw wave"));
  317. m_sawWaveBtn->move(4 + 14 * 2, ROW_WAVEBTN-14);
  318. m_sawWaveBtn->setActiveGraphic(embed::getIconPixmap("saw_wave_active"));
  319. m_sawWaveBtn->setInactiveGraphic(embed::getIconPixmap("saw_wave_inactive"));
  320. ToolTip::add(m_sawWaveBtn, tr("Saw wave"));
  321. m_usrWaveBtn = new PixmapButton(this, tr("User-defined wave"));
  322. m_usrWaveBtn->move(4 + 14 * 3, ROW_WAVEBTN-14);
  323. m_usrWaveBtn->setActiveGraphic(embed::getIconPixmap("usr_wave_active"));
  324. m_usrWaveBtn->setInactiveGraphic(embed::getIconPixmap("usr_wave_inactive"));
  325. ToolTip::add(m_usrWaveBtn, tr("User-defined wave"));
  326. m_triangleWaveBtn = new PixmapButton(this, tr("Triangle wave"));
  327. m_triangleWaveBtn->move(4 + 14, ROW_WAVEBTN);
  328. m_triangleWaveBtn->setActiveGraphic(
  329. embed::getIconPixmap("triangle_wave_active"));
  330. m_triangleWaveBtn->setInactiveGraphic(
  331. embed::getIconPixmap("triangle_wave_inactive"));
  332. ToolTip::add(m_triangleWaveBtn, tr("Triangle wave"));
  333. m_sqrWaveBtn = new PixmapButton(this, tr("Square wave"));
  334. m_sqrWaveBtn->move(4 + 14 * 2, ROW_WAVEBTN);
  335. m_sqrWaveBtn->setActiveGraphic(embed::getIconPixmap("square_wave_active"));
  336. m_sqrWaveBtn->setInactiveGraphic(
  337. embed::getIconPixmap("square_wave_inactive"));
  338. ToolTip::add(m_sqrWaveBtn, tr("Square wave"));
  339. m_whiteNoiseWaveBtn = new PixmapButton(this, tr("White noise"));
  340. m_whiteNoiseWaveBtn->move(4 + 14 * 3, ROW_WAVEBTN);
  341. m_whiteNoiseWaveBtn->setActiveGraphic(
  342. embed::getIconPixmap("white_noise_wave_active"));
  343. m_whiteNoiseWaveBtn->setInactiveGraphic(
  344. embed::getIconPixmap("white_noise_wave_inactive"));
  345. ToolTip::add(m_whiteNoiseWaveBtn, tr("White noise"));
  346. m_waveInterpolate = new LedCheckBox("Interpolate", this, tr("WaveInterpolate"),
  347. LedCheckBox::Green);
  348. m_waveInterpolate->move(2, 230);
  349. m_expressionValidToggle = new LedCheckBox("", this, tr("ExpressionValid"),
  350. LedCheckBox::Red);
  351. m_expressionValidToggle->move(168, EXPR_TEXT_Y+EXPR_TEXT_H-2);
  352. m_expressionValidToggle->setEnabled( false );
  353. m_expressionEditor = new QPlainTextEdit(this);
  354. m_expressionEditor->move(3, EXPR_TEXT_Y);
  355. m_expressionEditor->resize(180, EXPR_TEXT_H);
  356. m_generalPurposeKnob[0] = new XpressiveKnob(this,"A1");
  357. m_generalPurposeKnob[0]->setHintText(tr("General purpose 1:"), "");
  358. m_generalPurposeKnob[0]->move(COL_KNOBS, ROW_KNOBSA1);
  359. m_generalPurposeKnob[1] = new XpressiveKnob(this,"A2");
  360. m_generalPurposeKnob[1]->setHintText(tr("General purpose 2:"), "");
  361. m_generalPurposeKnob[1]->move(COL_KNOBS, ROW_KNOBSA2);
  362. m_generalPurposeKnob[2] = new XpressiveKnob(this,"A3");
  363. m_generalPurposeKnob[2]->setHintText(tr("General purpose 3:"), "");
  364. m_generalPurposeKnob[2]->move(COL_KNOBS, ROW_KNOBSA3);
  365. m_panningKnob[0] = new XpressiveKnob(this,"O1 panning");
  366. m_panningKnob[0]->setHintText(tr("O1 panning:"), "");
  367. m_panningKnob[0]->move(COL_KNOBS, ROW_KNOBSP1);
  368. m_panningKnob[1] = new XpressiveKnob(this,"O2 panning");
  369. m_panningKnob[1]->setHintText(tr("O2 panning:"), "");
  370. m_panningKnob[1]->move(COL_KNOBS, ROW_KNOBSP2);
  371. m_relKnob = new XpressiveKnob(this,"Release transition");
  372. m_relKnob->setHintText(tr("Release transition:"), "ms");
  373. m_relKnob->move(COL_KNOBS, ROW_KNOBREL);
  374. m_smoothKnob=new Knob(knobStyled, this, "Smoothness");
  375. m_smoothKnob->setFixedSize(25, 25);
  376. m_smoothKnob->setCenterPointX(12.5);
  377. m_smoothKnob->setCenterPointY(12.5);
  378. m_smoothKnob->setInnerRadius(4);
  379. m_smoothKnob->setOuterRadius(9);
  380. m_smoothKnob->setTotalAngle(280.0);
  381. m_smoothKnob->setLineWidth(3);
  382. m_smoothKnob->setHintText(tr("Smoothness"), "");
  383. m_smoothKnob->move(66, EXPR_TEXT_Y + EXPR_TEXT_H + 4);
  384. connect(m_generalPurposeKnob[0], SIGNAL(sliderMoved(float)), this,
  385. SLOT(expressionChanged()));
  386. connect(m_generalPurposeKnob[1], SIGNAL(sliderMoved(float)), this,
  387. SLOT(expressionChanged()));
  388. connect(m_generalPurposeKnob[2], SIGNAL(sliderMoved(float)), this,
  389. SLOT(expressionChanged()));
  390. connect(m_expressionEditor, SIGNAL(textChanged()), this,
  391. SLOT(expressionChanged()));
  392. connect(m_smoothKnob, SIGNAL(sliderMoved(float)), this,
  393. SLOT(smoothChanged()));
  394. connect(m_graph, SIGNAL(drawn()), this,
  395. SLOT(graphDrawn()));
  396. connect(m_sinWaveBtn, SIGNAL(clicked()), this, SLOT(sinWaveClicked()));
  397. connect(m_triangleWaveBtn, SIGNAL(clicked()), this,
  398. SLOT(triangleWaveClicked()));
  399. connect(m_expWaveBtn, SIGNAL(clicked()), this, SLOT(expWaveClicked()));
  400. connect(m_moogWaveBtn, SIGNAL(clicked()), this,
  401. SLOT(moogSawWaveClicked()));
  402. connect(m_sawWaveBtn, SIGNAL(clicked()), this, SLOT(sawWaveClicked()));
  403. connect(m_sqrWaveBtn, SIGNAL(clicked()), this, SLOT(sqrWaveClicked()));
  404. connect(m_whiteNoiseWaveBtn, SIGNAL(clicked()), this,
  405. SLOT(noiseWaveClicked()));
  406. connect(m_usrWaveBtn, SIGNAL(clicked()), this, SLOT(usrWaveClicked()));
  407. connect(m_helpBtn, SIGNAL(clicked()), this, SLOT(helpClicked()));
  408. connect(m_w1Btn, SIGNAL(clicked()), this, SLOT(updateLayout()));
  409. connect(m_w2Btn, SIGNAL(clicked()), this, SLOT(updateLayout()));
  410. connect(m_w3Btn, SIGNAL(clicked()), this, SLOT(updateLayout()));
  411. connect(m_o1Btn, SIGNAL(clicked()), this, SLOT(updateLayout()));
  412. connect(m_o2Btn, SIGNAL(clicked()), this, SLOT(updateLayout()));
  413. updateLayout();
  414. }
  415. XpressiveView::~XpressiveView()
  416. {
  417. }
  418. void XpressiveView::expressionChanged() {
  419. Xpressive * e = castModel<Xpressive>();
  420. QByteArray text = m_expressionEditor->toPlainText().toLatin1();
  421. switch (m_selectedGraphGroup->model()->value()) {
  422. case W1_EXPR:
  423. e->wavesExpression(0) = text;
  424. break;
  425. case W2_EXPR:
  426. e->wavesExpression(1) = text;
  427. break;
  428. case W3_EXPR:
  429. e->wavesExpression(2) = text;
  430. break;
  431. case O1_EXPR:
  432. e->outputExpression(0) = text;
  433. break;
  434. case O2_EXPR:
  435. e->outputExpression(1) = text;
  436. break;
  437. }
  438. if (m_wave_expr)
  439. m_graph->setEnabled(m_smoothKnob->model()->value() == 0 && text.size() == 0);
  440. if (text.size()>0)
  441. {
  442. const unsigned int sample_rate=m_raw_graph->length();
  443. ExprFront expr(text.constData(),sample_rate);
  444. float t=0;
  445. const float f=10,key=5,v=0.5;
  446. unsigned int i;
  447. expr.add_variable("t", t);
  448. if (m_output_expr)
  449. {
  450. expr.add_constant("f", f);
  451. expr.add_constant("key", key);
  452. expr.add_constant("rel", 0);
  453. expr.add_constant("trel", 0);
  454. expr.add_constant("bnote",e->instrumentTrack()->baseNote());
  455. expr.add_constant("v", v);
  456. expr.add_constant("tempo", Engine::getSong()->getTempo());
  457. expr.add_constant("A1", e->parameterA1().value());
  458. expr.add_constant("A2", e->parameterA2().value());
  459. expr.add_constant("A3", e->parameterA3().value());
  460. expr.add_cyclic_vector("W1",e->graphW1().samples(),e->graphW1().length());
  461. expr.add_cyclic_vector("W2",e->graphW2().samples(),e->graphW2().length());
  462. expr.add_cyclic_vector("W3",e->graphW3().samples(),e->graphW3().length());
  463. }
  464. expr.setIntegrate(&i,sample_rate);
  465. expr.add_constant("srate",sample_rate);
  466. const bool parse_ok=expr.compile();
  467. if (parse_ok) {
  468. e->exprValid().setValue(0);
  469. const int length = m_raw_graph->length();
  470. float * const samples = new float[length];
  471. for (i = 0; i < length; i++) {
  472. t = i / (float) length;
  473. samples[i] = expr.evaluate();
  474. if (std::isinf(samples[i]) != 0 || std::isnan(samples[i]) != 0)
  475. samples[i] = 0;
  476. }
  477. m_raw_graph->setSamples(samples);
  478. delete[] samples;
  479. if (m_wave_expr)
  480. {
  481. smoothChanged();
  482. }
  483. else
  484. {
  485. Engine::getSong()->setModified();
  486. }
  487. }
  488. else
  489. {
  490. e->exprValid().setValue(1);
  491. if (m_output_expr)
  492. m_raw_graph->clear();
  493. }
  494. }
  495. else
  496. {
  497. e->exprValid().setValue(0);
  498. if (m_output_expr)
  499. m_raw_graph->clear();
  500. }
  501. }
  502. void Xpressive::smooth(float smoothness,const graphModel * in,graphModel * out)
  503. {
  504. out->setSamples(in->samples());
  505. if (smoothness>0)
  506. {
  507. const int guass_size = (int)(smoothness * 5) | 1;
  508. const int guass_center = guass_size/2;
  509. const float delta = smoothness;
  510. const float a= 1.0f / (sqrtf(2.0f * F_PI) * delta);
  511. float * const guassian = new float [guass_size];
  512. float sum = 0.0f;
  513. float temp = 0.0f;
  514. int i;
  515. for (i = 0; i < guass_size; i++ )
  516. {
  517. temp = (i - guass_center) / delta;
  518. sum += guassian[i] = a * powf(F_E, -0.5f * temp * temp);
  519. }
  520. for (i = 0; i < guass_size; i++ )
  521. {
  522. guassian[i] = guassian[i] / sum;
  523. }
  524. out->convolve(guassian, guass_size, guass_center);
  525. delete [] guassian;
  526. }
  527. }
  528. void XpressiveView::smoothChanged()
  529. {
  530. Xpressive * e = castModel<Xpressive>();
  531. float smoothness=0;
  532. switch (m_selectedGraphGroup->model()->value()) {
  533. case W1_EXPR:
  534. smoothness=e->smoothW1().value();
  535. break;
  536. case W2_EXPR:
  537. smoothness=e->smoothW2().value();
  538. break;
  539. case W3_EXPR:
  540. smoothness=e->smoothW3().value();
  541. break;
  542. }
  543. Xpressive::smooth(smoothness,m_raw_graph,m_graph->model());
  544. switch (m_selectedGraphGroup->model()->value()) {
  545. case W1_EXPR:
  546. e->W1().copyFrom(m_graph->model());
  547. break;
  548. case W2_EXPR:
  549. e->W2().copyFrom(m_graph->model());
  550. break;
  551. case W3_EXPR:
  552. e->W3().copyFrom(m_graph->model());
  553. break;
  554. }
  555. Engine::getSong()->setModified();
  556. m_graph->setEnabled(m_smoothKnob->model()->value() == 0 && m_expressionEditor->toPlainText().size() == 0);
  557. }
  558. void XpressiveView::graphDrawn()
  559. {
  560. m_raw_graph->setSamples(m_graph->model()->samples());
  561. Xpressive * e = castModel<Xpressive>();
  562. switch (m_selectedGraphGroup->model()->value()) {
  563. case W1_EXPR:
  564. e->W1().copyFrom(m_graph->model());
  565. break;
  566. case W2_EXPR:
  567. e->W2().copyFrom(m_graph->model());
  568. break;
  569. case W3_EXPR:
  570. e->W3().copyFrom(m_graph->model());
  571. break;
  572. }
  573. Engine::getSong()->setModified();
  574. }
  575. void XpressiveView::modelChanged() {
  576. Xpressive * b = castModel<Xpressive>();
  577. m_expressionValidToggle->setModel( &b->exprValid() );
  578. m_generalPurposeKnob[0]->setModel( &b->parameterA1() );
  579. m_generalPurposeKnob[1]->setModel( &b->parameterA2() );
  580. m_generalPurposeKnob[2]->setModel( &b->parameterA3() );
  581. m_panningKnob[0]->setModel( &b->panning1() );
  582. m_panningKnob[1]->setModel( &b->panning2() );
  583. m_relKnob->setModel( &b->relTransition() );
  584. m_selectedGraphGroup->setModel( &b->selectedGraph() );
  585. updateLayout();
  586. }
  587. void XpressiveView::updateLayout() {
  588. Xpressive * e = castModel<Xpressive>();
  589. m_output_expr=false;
  590. m_wave_expr=false;
  591. switch (m_selectedGraphGroup->model()->value()) {
  592. case W1_EXPR:
  593. m_wave_expr=true;
  594. m_graph->setModel(&e->graphW1(), true);
  595. m_raw_graph=&(e->rawgraphW1());
  596. m_expressionEditor->setPlainText(e->wavesExpression(0));
  597. m_smoothKnob->setModel(&e->smoothW1());
  598. m_graph->setEnabled((e->smoothW1().value() == 0 && e->wavesExpression(0).size() == 0));
  599. m_waveInterpolate->setModel(&e->interpolateW1());
  600. m_smoothKnob->show();
  601. m_usrWaveBtn->show();
  602. m_waveInterpolate->show();
  603. break;
  604. case W2_EXPR:
  605. m_wave_expr=true;
  606. m_graph->setModel(&e->graphW2(), true);
  607. m_raw_graph=&(e->rawgraphW2());
  608. m_expressionEditor->setPlainText(e->wavesExpression(1));
  609. m_smoothKnob->setModel(&e->smoothW2());
  610. m_graph->setEnabled((e->smoothW2().value() == 0 && e->wavesExpression(1).size() == 0));
  611. m_waveInterpolate->setModel(&e->interpolateW2());
  612. m_smoothKnob->show();
  613. m_usrWaveBtn->show();
  614. m_waveInterpolate->show();
  615. break;
  616. case W3_EXPR:
  617. m_wave_expr=true;
  618. m_graph->setModel(&e->graphW3(), true);
  619. m_raw_graph=&(e->rawgraphW3());
  620. m_expressionEditor->setPlainText(e->wavesExpression(2));
  621. m_smoothKnob->setModel(&e->smoothW3());
  622. m_graph->setEnabled((e->smoothW3().value() == 0 && e->wavesExpression(2).size() == 0));
  623. m_waveInterpolate->setModel(&e->interpolateW3());
  624. m_smoothKnob->show();
  625. m_usrWaveBtn->show();
  626. m_waveInterpolate->show();
  627. break;
  628. case O1_EXPR:
  629. m_output_expr=true;
  630. m_graph->setModel(&e->graphO1(), true);
  631. m_raw_graph=&(e->graphO1());
  632. m_expressionEditor->setPlainText(e->outputExpression(0));
  633. m_smoothKnob->hide();
  634. m_graph->setEnabled(false);
  635. m_usrWaveBtn->hide();
  636. m_waveInterpolate->hide();
  637. break;
  638. case O2_EXPR:
  639. m_output_expr=true;
  640. m_graph->setModel(&e->graphO2(), true);
  641. m_raw_graph=&(e->graphO2());
  642. m_expressionEditor->setPlainText(e->outputExpression(1));
  643. m_smoothKnob->hide();
  644. m_graph->setEnabled(false);
  645. m_usrWaveBtn->hide();
  646. m_waveInterpolate->hide();
  647. break;
  648. }
  649. }
  650. void XpressiveView::sinWaveClicked() {
  651. if (m_output_expr)
  652. m_expressionEditor->appendPlainText("sinew(integrate(f))");
  653. else
  654. m_expressionEditor->appendPlainText("sinew(t)");
  655. Engine::getSong()->setModified();
  656. }
  657. void XpressiveView::triangleWaveClicked() {
  658. if (m_output_expr)
  659. m_expressionEditor->appendPlainText("trianglew(integrate(f))");
  660. else
  661. m_expressionEditor->appendPlainText("trianglew(t)");
  662. Engine::getSong()->setModified();
  663. }
  664. void XpressiveView::sawWaveClicked() {
  665. if (m_output_expr)
  666. m_expressionEditor->appendPlainText("saww(integrate(f))");
  667. else
  668. m_expressionEditor->appendPlainText("saww(t)");
  669. Engine::getSong()->setModified();
  670. }
  671. void XpressiveView::sqrWaveClicked() {
  672. if (m_output_expr)
  673. m_expressionEditor->appendPlainText("squarew(integrate(f))");
  674. else
  675. m_expressionEditor->appendPlainText("squarew(t)");
  676. Engine::getSong()->setModified();
  677. }
  678. void XpressiveView::noiseWaveClicked() {
  679. m_expressionEditor->appendPlainText("randsv(t*srate,0)");
  680. Engine::getSong()->setModified();
  681. }
  682. void XpressiveView::moogSawWaveClicked()
  683. {
  684. if (m_output_expr)
  685. m_expressionEditor->appendPlainText("moogsaww(integrate(f))");
  686. else
  687. m_expressionEditor->appendPlainText("moogsaww(t)");
  688. Engine::getSong()->setModified();
  689. }
  690. void XpressiveView::expWaveClicked()
  691. {
  692. if (m_output_expr)
  693. m_expressionEditor->appendPlainText("expw(integrate(f))");
  694. else
  695. m_expressionEditor->appendPlainText("expw(t)");
  696. Engine::getSong()->setModified();
  697. }
  698. void XpressiveView::usrWaveClicked() {
  699. m_expressionEditor->setPlainText("");
  700. QString fileName = m_raw_graph->setWaveToUser();
  701. smoothChanged();
  702. Engine::getSong()->setModified();
  703. }
  704. QString XpressiveHelpView::s_helpText=
  705. "<b>O1, O2</b> - Two output waves. Panning is controlled by PN1 and PN2.<br>"
  706. "<b>W1, W2, W3</b> - Wave samples evaluated by expression. In these samples, t variable ranges [0,1).<br>"
  707. "These waves can be used as functions inside the output waves (O1, O2). The wave period is 1.<br>"
  708. "<h4>Available variables:</h4><br>"
  709. "<b>t</b> - Time in seconds.<br>"
  710. "<b>f</b> - Note's pitched frequency. Available only in the output expressions.<br>"
  711. "<b>key</b> - Note's keyboard key. 0 denotes C0, 48 denotes C4, 96 denotes C8. Available only in the output expressions.<br>"
  712. "<b>bnote</b> - Base note. By default it is 57 which means A5, unless you change it.<br>"
  713. "<b>srate</b> - Sample rate. In wave expression it returns the wave's number of samples.<br>"
  714. "<b>tempo</b> - Song's Tempo. Available only in the output expressions.<br>"
  715. "<b>v</b> - Note's volume. Note that the output is already multiplied by the volume. Available only in the output expressions.<br>"
  716. "<b>rel</b> - Gives 0.0 while the key is held, and 1.0 after the key release. Available only in the output expressions.<br>"
  717. "<b>trel</b> - Time after release. While the note is held, it gives 0.0. Afterwards, it starts counting seconds.<br>"
  718. "The time it takes to shift from 0.0 to 1.0 after key release is determined by the REL knob<br>"
  719. "<b>seed</b> - A random value that remains consistent in the lifetime of a single wave. Meant to be used with <b>randsv</b><br>"
  720. "<b>A1, A2, A3</b> - General purpose knobs. You can reference them only in O1 and O2. In range [-1,1].<br>"
  721. "<h4>Available functions:</h4><br>"
  722. "<b>W1, W2, W3</b> - As mentioned before. You can reference them only in O1 and O2.<br>"
  723. "<b>cent(x)</b> - Gives pow(2,x/1200), so you can multiply it with the f variable to pitch the frequency.<br>"
  724. "100 cents equals one semitone<br>"
  725. "<b>semitone(x)</b> - Gives pow(2,x/12), so you can multiply it with the f variable to pitch the frequency.<br>"
  726. "<b>last(n)</b> - 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.<br>"
  727. "<b>integrate(x)</b> - Integrates x by delta t (It sums values and divides them by sample rate).<br>"
  728. "If you use notes with automated frequency, you should use:<br>"
  729. "sinew(integrate(f)) instead of sinew(t*f)<br>"
  730. "<b>randv(x)</b> - A random vector. Each cell is reference by an integer index in the range [0,2^31]<br>"
  731. "Each evaluation of an expression results in different random vector.<br>"
  732. "Although, it remains consistent in the lifetime of a single wave.<br>"
  733. "If you want a single random values you can use randv(0),randv(1)... <br>"
  734. "and every reference to randv(a) will give you the same value."
  735. "If you want a random wave you can use randv(t*srate).<br>"
  736. "Each random value is in the range [-1,1).<br>"
  737. "<b>randsv(x,seed)</b> - works exactly like randv(x),<br>"
  738. "except that it lets you to select the seed manualy,<br>"
  739. "if you want to try different random values and make it consistent in each evaluation.<br>"
  740. "<b>sinew(x)</b> - A sine wave with period of 1 (In contrast to real sine wave which have a period of 2*pi).<br>"
  741. "<b>trianglew(x)</b> - A triangle wave with period of 1.<br>"
  742. "<b>squarew(x)</b> - A square wave with period of 1.<br>"
  743. "<b>saww(x)</b> - A saw wave with period of 1.<br>"
  744. "<b>clamp(min_val,x,max_val)</b> - If x is in range of (min_val,max_val) it returns x. Otherwise if it's greater than max_val it returns max_val, else returns min_val.<br>"
  745. "<b>abs, sin, cos, tan, cot, asin, acos, atan, atan2, sinh, cosh, tanh, asinh, acosh, atanh, sinc, "
  746. "hypot, exp, log, log2, log10, logn, pow, sqrt, min, max, floor, ceil, round, trunc, frac, "
  747. "avg, sgn, mod, etc. are also available.</b><br>"
  748. "<b>Operands + - * / % ^ &gt; &lt; &gt;= &lt;= == != &amp; | are also available.</b><br>"
  749. "<b>Amplitude Modulation</b> - W1(t*f)*(1+W2(t*f))<br>"
  750. "<b>Ring Modulation</b> - W1(t * f)*W2(t * f)<br>"
  751. "<b>Mix Modulation</b> - 0.5*( W1(t * f) + W2(t * f) )<br>"
  752. "<b>Frequency Modulation</b> - [vol1]*W1( integrate( f + srate*[vol2]*W2( integrate(f) ) ) )<br>"
  753. "<b>Phase Modulation</b> - [vol1]*W1( integrate(f) + [vol2]*W2( integrate(f) ) )<br>"
  754. ;
  755. XpressiveHelpView::XpressiveHelpView():QTextEdit(s_helpText)
  756. {
  757. setWindowTitle ( "Xpressive Help" );
  758. setTextInteractionFlags ( Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse );
  759. gui->mainWindow()->addWindowedWidget( this );
  760. parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false );
  761. parentWidget()->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) );
  762. parentWidget()->setFixedSize( 300, 500);
  763. // No maximize button
  764. Qt::WindowFlags flags = parentWidget()->windowFlags();
  765. flags &= ~Qt::WindowMaximizeButtonHint;
  766. parentWidget()->setWindowFlags( flags );
  767. }
  768. void XpressiveView::helpClicked() {
  769. XpressiveHelpView::getInstance()->show();
  770. }
  771. extern "C" {
  772. // necessary for getting instance out of shared lib
  773. PLUGIN_EXPORT Plugin * lmms_plugin_main(Model *m, void *) {
  774. return (new Xpressive(static_cast<InstrumentTrack *>(m)));
  775. }
  776. }