Watsyn.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. /*
  2. * Watsyn.cpp - a 4-oscillator modulating wavetable synth
  3. *
  4. * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
  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 <QDomElement>
  25. #include "Watsyn.h"
  26. #include "base64.h"
  27. #include "AudioEngine.h"
  28. #include "Engine.h"
  29. #include "InstrumentTrack.h"
  30. #include "ToolTip.h"
  31. #include "Song.h"
  32. #include "lmms_math.h"
  33. #include "interpolation.h"
  34. #include "embed.h"
  35. #include "plugin_export.h"
  36. extern "C"
  37. {
  38. Plugin::Descriptor PLUGIN_EXPORT watsyn_plugin_descriptor =
  39. {
  40. STRINGIFY( PLUGIN_NAME ),
  41. "Watsyn",
  42. QT_TRANSLATE_NOOP( "PluginBrowser",
  43. "4-oscillator modulatable wavetable synth" ),
  44. "Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>",
  45. 0x0100,
  46. Plugin::Instrument,
  47. new PluginPixmapLoader( "logo" ),
  48. nullptr,
  49. nullptr,
  50. } ;
  51. }
  52. WatsynObject::WatsynObject( float * _A1wave, float * _A2wave,
  53. float * _B1wave, float * _B2wave,
  54. int _amod, int _bmod, const sample_rate_t _samplerate, NotePlayHandle * _nph, fpp_t _frames,
  55. WatsynInstrument * _w ) :
  56. m_amod( _amod ),
  57. m_bmod( _bmod ),
  58. m_samplerate( _samplerate ),
  59. m_nph( _nph ),
  60. m_fpp( _frames ),
  61. m_parent( _w )
  62. {
  63. m_abuf = new sampleFrame[_frames];
  64. m_bbuf = new sampleFrame[_frames];
  65. m_lphase[A1_OSC] = 0.0f;
  66. m_lphase[A2_OSC] = 0.0f;
  67. m_lphase[B1_OSC] = 0.0f;
  68. m_lphase[B2_OSC] = 0.0f;
  69. m_rphase[A1_OSC] = 0.0f;
  70. m_rphase[A2_OSC] = 0.0f;
  71. m_rphase[B1_OSC] = 0.0f;
  72. m_rphase[B2_OSC] = 0.0f;
  73. // copy wavegraphs to the synth object to prevent race conditions
  74. memcpy( &m_A1wave, _A1wave, sizeof( m_A1wave ) );
  75. memcpy( &m_A2wave, _A2wave, sizeof( m_A2wave ) );
  76. memcpy( &m_B1wave, _B1wave, sizeof( m_B1wave ) );
  77. memcpy( &m_B2wave, _B2wave, sizeof( m_B2wave ) );
  78. }
  79. WatsynObject::~WatsynObject()
  80. {
  81. delete[] m_abuf;
  82. delete[] m_bbuf;
  83. }
  84. void WatsynObject::renderOutput( fpp_t _frames )
  85. {
  86. if( m_abuf == nullptr )
  87. m_abuf = new sampleFrame[m_fpp];
  88. if( m_bbuf == nullptr )
  89. m_bbuf = new sampleFrame[m_fpp];
  90. for( fpp_t frame = 0; frame < _frames; frame++ )
  91. {
  92. // put phases of 1-series oscs into variables because phase modulation might happen
  93. float A1_lphase = m_lphase[A1_OSC];
  94. float A1_rphase = m_rphase[A1_OSC];
  95. float B1_lphase = m_lphase[B1_OSC];
  96. float B1_rphase = m_rphase[B1_OSC];
  97. ///////////// A-series /////////////////
  98. // A2
  99. sample_t A2_L = linearInterpolate( m_A2wave[ static_cast<int>( m_lphase[A2_OSC] ) ],
  100. m_A2wave[ static_cast<int>( m_lphase[A2_OSC] + 1 ) % WAVELEN ],
  101. fraction( m_lphase[A2_OSC] ) ) * m_parent->m_lvol[A2_OSC];
  102. sample_t A2_R = linearInterpolate( m_A2wave[ static_cast<int>( m_rphase[A2_OSC] ) ],
  103. m_A2wave[ static_cast<int>( m_rphase[A2_OSC] + 1 ) % WAVELEN ],
  104. fraction( m_rphase[A2_OSC] ) ) * m_parent->m_rvol[A2_OSC];
  105. // if phase mod, add to phases
  106. if( m_amod == MOD_PM )
  107. {
  108. A1_lphase = fmodf( A1_lphase + A2_L * PMOD_AMT, WAVELEN );
  109. if( A1_lphase < 0 ) A1_lphase += WAVELEN;
  110. A1_rphase = fmodf( A1_rphase + A2_R * PMOD_AMT, WAVELEN );
  111. if( A1_rphase < 0 ) A1_rphase += WAVELEN;
  112. }
  113. // A1
  114. sample_t A1_L = linearInterpolate( m_A1wave[ static_cast<int>( A1_lphase ) ],
  115. m_A1wave[ static_cast<int>( A1_lphase + 1 ) % WAVELEN ],
  116. fraction( A1_lphase ) ) * m_parent->m_lvol[A1_OSC];
  117. sample_t A1_R = linearInterpolate( m_A1wave[ static_cast<int>( A1_rphase ) ],
  118. m_A1wave[ static_cast<int>( A1_rphase + 1 ) % WAVELEN ],
  119. fraction( A1_rphase ) ) * m_parent->m_rvol[A1_OSC];
  120. ///////////// B-series /////////////////
  121. // B2
  122. sample_t B2_L = linearInterpolate( m_B2wave[ static_cast<int>( m_lphase[B2_OSC] ) ],
  123. m_B2wave[ static_cast<int>( m_lphase[B2_OSC] + 1 ) % WAVELEN ],
  124. fraction( m_lphase[B2_OSC] ) ) * m_parent->m_lvol[B2_OSC];
  125. sample_t B2_R = linearInterpolate( m_B2wave[ static_cast<int>( m_rphase[B2_OSC] ) ],
  126. m_B2wave[ static_cast<int>( m_rphase[B2_OSC] + 1 ) % WAVELEN ],
  127. fraction( m_rphase[B2_OSC] ) ) * m_parent->m_rvol[B2_OSC];
  128. // if crosstalk active, add a1
  129. const float xt = m_parent->m_xtalk.value();
  130. if( xt > 0.0 )
  131. {
  132. B2_L += ( A1_L * xt ) * 0.01f;
  133. B2_R += ( A1_R * xt ) * 0.01f;
  134. }
  135. // if phase mod, add to phases
  136. if( m_bmod == MOD_PM )
  137. {
  138. B1_lphase = fmodf( B1_lphase + B2_L * PMOD_AMT, WAVELEN );
  139. if( B1_lphase < 0 ) B1_lphase += WAVELEN;
  140. B1_rphase = fmodf( B1_rphase + B2_R * PMOD_AMT, WAVELEN );
  141. if( B1_rphase < 0 ) B1_rphase += WAVELEN;
  142. }
  143. // B1
  144. sample_t B1_L = linearInterpolate( m_B1wave[ static_cast<int>( B1_lphase ) % WAVELEN ],
  145. m_B1wave[ static_cast<int>( B1_lphase + 1 ) % WAVELEN ],
  146. fraction( B1_lphase ) ) * m_parent->m_lvol[B1_OSC];
  147. sample_t B1_R = linearInterpolate( m_B1wave[ static_cast<int>( B1_rphase ) % WAVELEN ],
  148. m_B1wave[ static_cast<int>( B1_rphase + 1 ) % WAVELEN ],
  149. fraction( B1_rphase ) ) * m_parent->m_rvol[B1_OSC];
  150. // A-series modulation)
  151. switch( m_amod )
  152. {
  153. case MOD_MIX:
  154. A1_L = ( A1_L + A2_L ) / 2.0;
  155. A1_R = ( A1_R + A2_R ) / 2.0;
  156. break;
  157. case MOD_AM:
  158. A1_L *= qMax( 0.0f, A2_L + 1.0f );
  159. A1_R *= qMax( 0.0f, A2_R + 1.0f );
  160. break;
  161. case MOD_RM:
  162. A1_L *= A2_L;
  163. A1_R *= A2_R;
  164. break;
  165. }
  166. m_abuf[frame][0] = A1_L;
  167. m_abuf[frame][1] = A1_R;
  168. // B-series modulation (other than phase mod)
  169. switch( m_bmod )
  170. {
  171. case MOD_MIX:
  172. B1_L = ( B1_L + B2_L ) / 2.0;
  173. B1_R = ( B1_R + B2_R ) / 2.0;
  174. break;
  175. case MOD_AM:
  176. B1_L *= qMax( 0.0f, B2_L + 1.0f );
  177. B1_R *= qMax( 0.0f, B2_R + 1.0f );
  178. break;
  179. case MOD_RM:
  180. B1_L *= B2_L;
  181. B1_R *= B2_R;
  182. break;
  183. }
  184. m_bbuf[frame][0] = B1_L;
  185. m_bbuf[frame][1] = B1_R;
  186. // update phases
  187. for( int i = 0; i < NUM_OSCS; i++ )
  188. {
  189. m_lphase[i] += ( static_cast<float>( WAVELEN ) / ( m_samplerate / ( m_nph->frequency() * m_parent->m_lfreq[i] ) ) );
  190. m_lphase[i] = fmodf( m_lphase[i], WAVELEN );
  191. m_rphase[i] += ( static_cast<float>( WAVELEN ) / ( m_samplerate / ( m_nph->frequency() * m_parent->m_rfreq[i] ) ) );
  192. m_rphase[i] = fmodf( m_rphase[i], WAVELEN );
  193. }
  194. }
  195. }
  196. WatsynInstrument::WatsynInstrument( InstrumentTrack * _instrument_track ) :
  197. Instrument( _instrument_track, &watsyn_plugin_descriptor ),
  198. a1_vol( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Volume A1" ) ),
  199. a2_vol( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Volume A2" ) ),
  200. b1_vol( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Volume B1" ) ),
  201. b2_vol( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Volume B2" ) ),
  202. a1_pan( 0.0f, -100.0f, 100.0f, 0.1f, this, tr( "Panning A1" ) ),
  203. a2_pan( 0.0f, -100.0f, 100.0f, 0.1f, this, tr( "Panning A2" ) ),
  204. b1_pan( 0.0f, -100.0f, 100.0f, 0.1f, this, tr( "Panning B1" ) ),
  205. b2_pan( 0.0f, -100.0f, 100.0f, 0.1f, this, tr( "Panning B2" ) ),
  206. a1_mult( 8.0f, 1.0, 24.0, 1.0, this, tr( "Freq. multiplier A1" ) ),
  207. a2_mult( 8.0f, 1.0, 24.0, 1.0, this, tr( "Freq. multiplier A2" ) ),
  208. b1_mult( 8.0f, 1.0, 24.0, 1.0, this, tr( "Freq. multiplier B1" ) ),
  209. b2_mult( 8.0f, 1.0, 24.0, 1.0, this, tr( "Freq. multiplier B2" ) ),
  210. a1_ltune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Left detune A1" ) ),
  211. a2_ltune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Left detune A2" ) ),
  212. b1_ltune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Left detune B1" ) ),
  213. b2_ltune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Left detune B2" ) ),
  214. a1_rtune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Right detune A1" ) ),
  215. a2_rtune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Right detune A2" ) ),
  216. b1_rtune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Right detune B1" ) ),
  217. b2_rtune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Right detune B2" ) ),
  218. a1_graph( -1.0f, 1.0f, GRAPHLEN, this ),
  219. a2_graph( -1.0f, 1.0f, GRAPHLEN, this ),
  220. b1_graph( -1.0f, 1.0f, GRAPHLEN, this ),
  221. b2_graph( -1.0f, 1.0f, GRAPHLEN, this ),
  222. m_abmix( 0.0f, -100.0f, 100.0f, 0.1f, this, tr( "A-B Mix" ) ),
  223. m_envAmt( 0.0f, -200.0f, 200.0f, 1.0f, this, tr( "A-B Mix envelope amount" ) ),
  224. m_envAtt( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "A-B Mix envelope attack" ) ),
  225. m_envHold( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "A-B Mix envelope hold" ) ),
  226. m_envDec( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "A-B Mix envelope decay" ) ),
  227. m_xtalk( 0.0f, 0.0f, 100.0f, 0.1f, this, tr( "A1-B2 Crosstalk" ) ),
  228. m_amod( 0, 0, 3, this, tr( "A2-A1 modulation" ) ),
  229. m_bmod( 0, 0, 3, this, tr( "B2-B1 modulation" ) ),
  230. m_selectedGraph( 0, 0, 3, this, tr( "Selected graph" ) )
  231. {
  232. connect( &a1_vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  233. connect( &a2_vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  234. connect( &b1_vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  235. connect( &b2_vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  236. connect( &a1_pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  237. connect( &a2_pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  238. connect( &b1_pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  239. connect( &b2_pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
  240. connect( &a1_mult, SIGNAL( dataChanged() ), this, SLOT( updateFreqA1() ) );
  241. connect( &a2_mult, SIGNAL( dataChanged() ), this, SLOT( updateFreqA2() ) );
  242. connect( &b1_mult, SIGNAL( dataChanged() ), this, SLOT( updateFreqB1() ) );
  243. connect( &b2_mult, SIGNAL( dataChanged() ), this, SLOT( updateFreqB2() ) );
  244. connect( &a1_ltune, SIGNAL( dataChanged() ), this, SLOT( updateFreqA1() ) );
  245. connect( &a2_ltune, SIGNAL( dataChanged() ), this, SLOT( updateFreqA2() ) );
  246. connect( &b1_ltune, SIGNAL( dataChanged() ), this, SLOT( updateFreqB1() ) );
  247. connect( &b2_ltune, SIGNAL( dataChanged() ), this, SLOT( updateFreqB2() ) );
  248. connect( &a1_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreqA1() ) );
  249. connect( &a2_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreqA2() ) );
  250. connect( &b1_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreqB1() ) );
  251. connect( &b2_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreqB2() ) );
  252. connect( &a1_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaveA1() ) );
  253. connect( &a2_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaveA2() ) );
  254. connect( &b1_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaveB1() ) );
  255. connect( &b2_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaveB2() ) );
  256. a1_graph.setWaveToSine();
  257. a2_graph.setWaveToSine();
  258. b1_graph.setWaveToSine();
  259. b2_graph.setWaveToSine();
  260. updateVolumes();
  261. updateFreqA1();
  262. updateFreqA2();
  263. updateFreqB1();
  264. updateFreqB2();
  265. updateWaveA1();
  266. updateWaveA2();
  267. updateWaveB1();
  268. updateWaveB2();
  269. }
  270. WatsynInstrument::~WatsynInstrument()
  271. {
  272. }
  273. void WatsynInstrument::playNote( NotePlayHandle * _n,
  274. sampleFrame * _working_buffer )
  275. {
  276. if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
  277. {
  278. WatsynObject * w = new WatsynObject(
  279. &A1_wave[0],
  280. &A2_wave[0],
  281. &B1_wave[0],
  282. &B2_wave[0],
  283. m_amod.value(), m_bmod.value(),
  284. Engine::audioEngine()->processingSampleRate(), _n,
  285. Engine::audioEngine()->framesPerPeriod(), this );
  286. _n->m_pluginData = w;
  287. }
  288. const fpp_t frames = _n->framesLeftForCurrentPeriod();
  289. const f_cnt_t offset = _n->noteOffset();
  290. sampleFrame * buffer = _working_buffer + offset;
  291. WatsynObject * w = static_cast<WatsynObject *>( _n->m_pluginData );
  292. sampleFrame * abuf = w->abuf();
  293. sampleFrame * bbuf = w->bbuf();
  294. w-> renderOutput( frames );
  295. // envelope parameters
  296. const float envAmt = m_envAmt.value();
  297. const float envAtt = ( m_envAtt.value() * w->samplerate() ) / 1000.0f;
  298. const float envHold = ( m_envHold.value() * w->samplerate() ) / 1000.0f;
  299. const float envDec = ( m_envDec.value() * w->samplerate() ) / 1000.0f;
  300. const float envLen = envAtt + envDec + envHold;
  301. const float tfp_ = static_cast<float>( _n->totalFramesPlayed() );
  302. // if sample-exact is enabled, use sample-exact calculations...
  303. // disabled pending proper implementation of sample-exactness
  304. /* if( engine::audioEngine()->currentQualitySettings().sampleExactControllers )
  305. {
  306. for( fpp_t f=0; f < frames; f++ )
  307. {
  308. const float tfp = tfp_ + f;
  309. // handle mixing envelope
  310. float mixvalue = m_abmix.value( f );
  311. if( envAmt != 0.0f && tfp < envLen )
  312. {
  313. if( tfp < envAtt )
  314. {
  315. mixvalue = qBound( -100.0f, mixvalue + ( tfp / envAtt * envAmt ), 100.0f );
  316. }
  317. else if ( tfp >= envAtt && tfp < envAtt + envHold )
  318. {
  319. mixvalue = qBound( -100.0f, mixvalue + envAmt, 100.0f );
  320. }
  321. else
  322. {
  323. mixvalue = qBound( -100.0f, mixvalue + envAmt - ( ( tfp - ( envAtt + envHold ) ) / envDec * envAmt ), 100.0f );
  324. }
  325. }
  326. // get knob values in sample-exact way
  327. const float bmix = ( ( mixvalue + 100.0 ) / 200.0 );
  328. const float amix = 1.0 - bmix;
  329. // mix a/b streams according to mixing knob
  330. _working_buffer[f][0] = ( abuf[f][0] * amix ) +
  331. ( bbuf[f][0] * bmix );
  332. _working_buffer[f][1] = ( abuf[f][1] * amix ) +
  333. ( bbuf[f][1] * bmix );
  334. }
  335. }
  336. else*/
  337. // if sample-exact is not enabled, use simpler calculations:
  338. // if mix envelope is active, and we haven't gone past the envelope end, use envelope-aware calculation...
  339. if( envAmt != 0.0f && tfp_ < envLen )
  340. {
  341. const float mixvalue_ = m_abmix.value();
  342. for( fpp_t f=0; f < frames; f++ )
  343. {
  344. float mixvalue = mixvalue_;
  345. const float tfp = tfp_ + f;
  346. // handle mixing envelope
  347. if( tfp < envAtt )
  348. {
  349. mixvalue = qBound( -100.0f, mixvalue + ( tfp / envAtt * envAmt ), 100.0f );
  350. }
  351. else if ( tfp >= envAtt && tfp < envAtt + envHold )
  352. {
  353. mixvalue = qBound( -100.0f, mixvalue + envAmt, 100.0f );
  354. }
  355. else
  356. {
  357. mixvalue = qBound( -100.0f, mixvalue + envAmt - ( ( tfp - ( envAtt + envHold ) ) / envDec * envAmt ), 100.0f );
  358. }
  359. // get knob values
  360. const float bmix = ( ( mixvalue + 100.0 ) / 200.0 );
  361. const float amix = 1.0 - bmix;
  362. // mix a/b streams according to mixing knob
  363. buffer[f][0] = ( abuf[f][0] * amix ) +
  364. ( bbuf[f][0] * bmix );
  365. buffer[f][1] = ( abuf[f][1] * amix ) +
  366. ( bbuf[f][1] * bmix );
  367. }
  368. }
  369. // ... mix envelope is inactive or we've past the end of envelope, so use a faster calculation to save cpu
  370. else
  371. {
  372. // get knob values
  373. const float bmix = ( ( m_abmix.value() + 100.0 ) / 200.0 );
  374. const float amix = 1.0 - bmix;
  375. for( fpp_t f=0; f < frames; f++ )
  376. {
  377. // mix a/b streams according to mixing knob
  378. buffer[f][0] = ( abuf[f][0] * amix ) +
  379. ( bbuf[f][0] * bmix );
  380. buffer[f][1] = ( abuf[f][1] * amix ) +
  381. ( bbuf[f][1] * bmix );
  382. }
  383. }
  384. applyRelease( _working_buffer, _n );
  385. instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
  386. }
  387. void WatsynInstrument::deleteNotePluginData( NotePlayHandle * _n )
  388. {
  389. delete static_cast<WatsynObject *>( _n->m_pluginData );
  390. }
  391. void WatsynInstrument::saveSettings( QDomDocument & _doc,
  392. QDomElement & _this )
  393. {
  394. a1_vol.saveSettings( _doc, _this, "a1_vol" );
  395. a2_vol.saveSettings( _doc, _this, "a2_vol" );
  396. b1_vol.saveSettings( _doc, _this, "b1_vol" );
  397. b2_vol.saveSettings( _doc, _this, "b2_vol" );
  398. a1_pan.saveSettings( _doc, _this, "a1_pan" );
  399. a2_pan.saveSettings( _doc, _this, "a2_pan" );
  400. b1_pan.saveSettings( _doc, _this, "b1_pan" );
  401. b2_pan.saveSettings( _doc, _this, "b2_pan" );
  402. a1_mult.saveSettings( _doc, _this, "a1_mult" );
  403. a2_mult.saveSettings( _doc, _this, "a2_mult" );
  404. b1_mult.saveSettings( _doc, _this, "b1_mult" );
  405. b2_mult.saveSettings( _doc, _this, "b2_mult" );
  406. a1_ltune.saveSettings( _doc, _this, "a1_ltune" );
  407. a2_ltune.saveSettings( _doc, _this, "a2_ltune" );
  408. b1_ltune.saveSettings( _doc, _this, "b1_ltune" );
  409. b2_ltune.saveSettings( _doc, _this, "b2_ltune" );
  410. a1_rtune.saveSettings( _doc, _this, "a1_rtune" );
  411. a2_rtune.saveSettings( _doc, _this, "a2_rtune" );
  412. b1_rtune.saveSettings( _doc, _this, "b1_rtune" );
  413. b2_rtune.saveSettings( _doc, _this, "b2_rtune" );
  414. // save graphs
  415. QString sampleString;
  416. base64::encode( (const char *)a1_graph.samples(), a1_graph.length() * sizeof(float), sampleString );
  417. _this.setAttribute( "a1_wave", sampleString );
  418. base64::encode( (const char *)a2_graph.samples(), a2_graph.length() * sizeof(float), sampleString );
  419. _this.setAttribute( "a2_wave", sampleString );
  420. base64::encode( (const char *)b1_graph.samples(), b1_graph.length() * sizeof(float), sampleString );
  421. _this.setAttribute( "b1_wave", sampleString );
  422. base64::encode( (const char *)b2_graph.samples(), b2_graph.length() * sizeof(float), sampleString );
  423. _this.setAttribute( "b2_wave", sampleString );
  424. m_abmix.saveSettings( _doc, _this, "abmix" );
  425. m_envAmt.saveSettings( _doc, _this, "envAmt" );
  426. m_envAtt.saveSettings( _doc, _this, "envAtt" );
  427. m_envHold.saveSettings( _doc, _this, "envHold" );
  428. m_envDec.saveSettings( _doc, _this, "envDec" );
  429. m_xtalk.saveSettings( _doc, _this, "xtalk" );
  430. m_amod.saveSettings( _doc, _this, "amod" );
  431. m_bmod.saveSettings( _doc, _this, "bmod" );
  432. /* m_selectedGraph.saveSettings( _doc, _this, "selgraph" );*/
  433. }
  434. void WatsynInstrument::loadSettings( const QDomElement & _this )
  435. {
  436. a1_vol.loadSettings( _this, "a1_vol" );
  437. a2_vol.loadSettings( _this, "a2_vol" );
  438. b1_vol.loadSettings( _this, "b1_vol" );
  439. b2_vol.loadSettings( _this, "b2_vol" );
  440. a1_pan.loadSettings( _this, "a1_pan" );
  441. a2_pan.loadSettings( _this, "a2_pan" );
  442. b1_pan.loadSettings( _this, "b1_pan" );
  443. b2_pan.loadSettings( _this, "b2_pan" );
  444. a1_mult.loadSettings( _this, "a1_mult" );
  445. a2_mult.loadSettings( _this, "a2_mult" );
  446. b1_mult.loadSettings( _this, "b1_mult" );
  447. b2_mult.loadSettings( _this, "b2_mult" );
  448. a1_ltune.loadSettings( _this, "a1_ltune" );
  449. a2_ltune.loadSettings( _this, "a2_ltune" );
  450. b1_ltune.loadSettings( _this, "b1_ltune" );
  451. b2_ltune.loadSettings( _this, "b2_ltune" );
  452. a1_rtune.loadSettings( _this, "a1_rtune" );
  453. a2_rtune.loadSettings( _this, "a2_rtune" );
  454. b1_rtune.loadSettings( _this, "b1_rtune" );
  455. b2_rtune.loadSettings( _this, "b2_rtune" );
  456. // load graphs
  457. int size = 0;
  458. char * dst = 0;
  459. base64::decode( _this.attribute( "a1_wave"), &dst, &size );
  460. a1_graph.setSamples( (float*) dst );
  461. base64::decode( _this.attribute( "a2_wave"), &dst, &size );
  462. a2_graph.setSamples( (float*) dst );
  463. base64::decode( _this.attribute( "b1_wave"), &dst, &size );
  464. b1_graph.setSamples( (float*) dst );
  465. base64::decode( _this.attribute( "b2_wave"), &dst, &size );
  466. b2_graph.setSamples( (float*) dst );
  467. delete[] dst;
  468. m_abmix.loadSettings( _this, "abmix" );
  469. m_envAmt.loadSettings( _this, "envAmt" );
  470. m_envAtt.loadSettings( _this, "envAtt" );
  471. m_envHold.loadSettings( _this, "envHold" );
  472. m_envDec.loadSettings( _this, "envDec" );
  473. m_xtalk.loadSettings( _this, "xtalk" );
  474. m_amod.loadSettings( _this, "amod" );
  475. m_bmod.loadSettings( _this, "bmod" );
  476. /* m_selectedGraph.loadSettings( _this, "selgraph" );*/
  477. }
  478. QString WatsynInstrument::nodeName() const
  479. {
  480. return( watsyn_plugin_descriptor.name );
  481. }
  482. PluginView * WatsynInstrument::instantiateView( QWidget * _parent )
  483. {
  484. return( new WatsynView( this, _parent ) );
  485. }
  486. void WatsynInstrument::updateVolumes()
  487. {
  488. m_lvol[A1_OSC] = leftCh( a1_vol.value(), a1_pan.value() );
  489. m_rvol[A1_OSC] = rightCh( a1_vol.value(), a1_pan.value() );
  490. m_lvol[A2_OSC] = leftCh( a2_vol.value(), a2_pan.value() );
  491. m_rvol[A2_OSC] = rightCh( a2_vol.value(), a2_pan.value() );
  492. m_lvol[B1_OSC] = leftCh( b1_vol.value(), b1_pan.value() );
  493. m_rvol[B1_OSC] = rightCh( b1_vol.value(), b1_pan.value() );
  494. m_lvol[B2_OSC] = leftCh( b2_vol.value(), b2_pan.value() );
  495. m_rvol[B2_OSC] = rightCh( b2_vol.value(), b2_pan.value() );
  496. }
  497. void WatsynInstrument::updateFreqA1()
  498. {
  499. // calculate frequencies
  500. m_lfreq[A1_OSC] = ( a1_mult.value() / 8 ) * powf( 2, a1_ltune.value() / 1200 );
  501. m_rfreq[A1_OSC] = ( a1_mult.value() / 8 ) * powf( 2, a1_rtune.value() / 1200 );
  502. }
  503. void WatsynInstrument::updateFreqA2()
  504. {
  505. // calculate frequencies
  506. m_lfreq[A2_OSC] = ( a2_mult.value() / 8 ) * powf( 2, a2_ltune.value() / 1200 );
  507. m_rfreq[A2_OSC] = ( a2_mult.value() / 8 ) * powf( 2, a2_rtune.value() / 1200 );
  508. }
  509. void WatsynInstrument::updateFreqB1()
  510. {
  511. // calculate frequencies
  512. m_lfreq[B1_OSC] = ( b1_mult.value() / 8 ) * powf( 2, b1_ltune.value() / 1200 );
  513. m_rfreq[B1_OSC] = ( b1_mult.value() / 8 ) * powf( 2, b1_rtune.value() / 1200 );
  514. }
  515. void WatsynInstrument::updateFreqB2()
  516. {
  517. // calculate frequencies
  518. m_lfreq[B2_OSC] = ( b2_mult.value() / 8 ) * powf( 2, b2_ltune.value() / 1200 );
  519. m_rfreq[B2_OSC] = ( b2_mult.value() / 8 ) * powf( 2, b2_rtune.value() / 1200 );
  520. }
  521. void WatsynInstrument::updateWaveA1()
  522. {
  523. // do sinc+oversampling on the wavetables to improve quality
  524. srccpy( &A1_wave[0], const_cast<float*>( a1_graph.samples() ) );
  525. }
  526. void WatsynInstrument::updateWaveA2()
  527. {
  528. // do sinc+oversampling on the wavetables to improve quality
  529. srccpy( &A2_wave[0], const_cast<float*>( a2_graph.samples() ) );
  530. }
  531. void WatsynInstrument::updateWaveB1()
  532. {
  533. // do sinc+oversampling on the wavetables to improve quality
  534. srccpy( &B1_wave[0], const_cast<float*>( b1_graph.samples() ) );
  535. }
  536. void WatsynInstrument::updateWaveB2()
  537. {
  538. // do sinc+oversampling on the wavetables to improve quality
  539. srccpy( &B2_wave[0], const_cast<float*>( b2_graph.samples() ) );
  540. }
  541. WatsynView::WatsynView( Instrument * _instrument,
  542. QWidget * _parent ) :
  543. InstrumentViewFixedSize( _instrument, _parent )
  544. {
  545. setAutoFillBackground( true );
  546. QPalette pal;
  547. pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
  548. setPalette( pal );
  549. // knobs... lots of em
  550. makeknob( a1_volKnob, 130, A1ROW, tr( "Volume" ), "%", "aKnob" )
  551. makeknob( a2_volKnob, 130, A2ROW, tr( "Volume" ), "%", "aKnob" )
  552. makeknob( b1_volKnob, 130, B1ROW, tr( "Volume" ), "%", "bKnob" )
  553. makeknob( b2_volKnob, 130, B2ROW, tr( "Volume" ), "%", "bKnob" )
  554. makeknob( a1_panKnob, 154, A1ROW, tr( "Panning" ), "", "aKnob" )
  555. makeknob( a2_panKnob, 154, A2ROW, tr( "Panning" ), "", "aKnob" )
  556. makeknob( b1_panKnob, 154, B1ROW, tr( "Panning" ), "", "bKnob" )
  557. makeknob( b2_panKnob, 154, B2ROW, tr( "Panning" ), "", "bKnob" )
  558. makeknob( a1_multKnob, 178, A1ROW, tr( "Freq. multiplier" ), "/8", "aKnob" )
  559. makeknob( a2_multKnob, 178, A2ROW, tr( "Freq. multiplier" ), "/8", "aKnob" )
  560. makeknob( b1_multKnob, 178, B1ROW, tr( "Freq. multiplier" ), "/8", "bKnob" )
  561. makeknob( b2_multKnob, 178, B2ROW, tr( "Freq. multiplier" ), "/8", "bKnob" )
  562. makeknob( a1_ltuneKnob, 202, A1ROW, tr( "Left detune" ), tr( " cents" ), "aKnob" )
  563. makeknob( a2_ltuneKnob, 202, A2ROW, tr( "Left detune" ), tr( " cents" ), "aKnob" )
  564. makeknob( b1_ltuneKnob, 202, B1ROW, tr( "Left detune" ), tr( " cents" ), "bKnob" )
  565. makeknob( b2_ltuneKnob, 202, B2ROW, tr( "Left detune" ), tr( " cents" ), "bKnob" )
  566. makeknob( a1_rtuneKnob, 226, A1ROW, tr( "Right detune" ), tr( " cents" ), "aKnob" )
  567. makeknob( a2_rtuneKnob, 226, A2ROW, tr( "Right detune" ), tr( " cents" ), "aKnob" )
  568. makeknob( b1_rtuneKnob, 226, B1ROW, tr( "Right detune" ), tr( " cents" ), "bKnob" )
  569. makeknob( b2_rtuneKnob, 226, B2ROW, tr( "Right detune" ), tr( " cents" ), "bKnob" )
  570. makeknob( m_abmixKnob, 4, 3, tr( "A-B Mix" ), "", "mixKnob" )
  571. makeknob( m_envAmtKnob, 88, 3, tr( "Mix envelope amount" ), "", "mixenvKnob" )
  572. maketsknob( m_envAttKnob, 88, A1ROW, tr( "Mix envelope attack" ), " ms", "mixenvKnob" )
  573. maketsknob( m_envHoldKnob, 88, A2ROW, tr( "Mix envelope hold" ), " ms", "mixenvKnob" )
  574. maketsknob( m_envDecKnob, 88, B1ROW, tr( "Mix envelope decay" ), " ms", "mixenvKnob" )
  575. makeknob( m_xtalkKnob, 88, B2ROW, tr( "Crosstalk" ), "", "xtalkKnob" )
  576. // let's set volume knobs
  577. a1_volKnob -> setVolumeKnob( true );
  578. a2_volKnob -> setVolumeKnob( true );
  579. b1_volKnob -> setVolumeKnob( true );
  580. b2_volKnob -> setVolumeKnob( true );
  581. m_abmixKnob -> setFixedSize( 31, 31 );
  582. // button groups next.
  583. // graph select buttons
  584. PixmapButton * a1_selectButton = new PixmapButton( this, nullptr );
  585. a1_selectButton -> move( 4, 121 );
  586. a1_selectButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "a1_active" ) );
  587. a1_selectButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "a1_inactive" ) );
  588. ToolTip::add( a1_selectButton, tr( "Select oscillator A1") );
  589. PixmapButton * a2_selectButton = new PixmapButton( this, nullptr );
  590. a2_selectButton -> move( 44, 121 );
  591. a2_selectButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "a2_active" ) );
  592. a2_selectButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "a2_inactive" ) );
  593. ToolTip::add( a2_selectButton, tr( "Select oscillator A2") );
  594. PixmapButton * b1_selectButton = new PixmapButton( this, nullptr );
  595. b1_selectButton -> move( 84, 121 );
  596. b1_selectButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "b1_active" ) );
  597. b1_selectButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "b1_inactive" ) );
  598. ToolTip::add( b1_selectButton, tr( "Select oscillator B1") );
  599. PixmapButton * b2_selectButton = new PixmapButton( this, nullptr );
  600. b2_selectButton -> move( 124, 121 );
  601. b2_selectButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "b2_active" ) );
  602. b2_selectButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "b2_inactive" ) );
  603. ToolTip::add( b2_selectButton, tr( "Select oscillator B2") );
  604. m_selectedGraphGroup = new automatableButtonGroup( this );
  605. m_selectedGraphGroup -> addButton( a1_selectButton );
  606. m_selectedGraphGroup -> addButton( a2_selectButton );
  607. m_selectedGraphGroup -> addButton( b1_selectButton );
  608. m_selectedGraphGroup -> addButton( b2_selectButton );
  609. WatsynInstrument * w = castModel<WatsynInstrument>();
  610. m_selectedGraphGroup -> setModel( &w -> m_selectedGraph);
  611. // A-modulation button group
  612. PixmapButton * amod_mixButton = new PixmapButton( this, nullptr );
  613. amod_mixButton -> move( 4, 50 );
  614. amod_mixButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "amix_active" ) );
  615. amod_mixButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "amix_inactive" ) );
  616. ToolTip::add( amod_mixButton, tr( "Mix output of A2 to A1" ) );
  617. PixmapButton * amod_amButton = new PixmapButton( this, nullptr );
  618. amod_amButton -> move( 4, 66 );
  619. amod_amButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "aam_active" ) );
  620. amod_amButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "aam_inactive" ) );
  621. ToolTip::add( amod_amButton, tr( "Modulate amplitude of A1 by output of A2" ) );
  622. PixmapButton * amod_rmButton = new PixmapButton( this, nullptr );
  623. amod_rmButton -> move( 4, 82 );
  624. amod_rmButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "arm_active" ) );
  625. amod_rmButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "arm_inactive" ) );
  626. ToolTip::add( amod_rmButton, tr( "Ring modulate A1 and A2" ) );
  627. PixmapButton * amod_pmButton = new PixmapButton( this, nullptr );
  628. amod_pmButton -> move( 4, 98 );
  629. amod_pmButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "apm_active" ) );
  630. amod_pmButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "apm_inactive" ) );
  631. ToolTip::add( amod_pmButton, tr( "Modulate phase of A1 by output of A2" ) );
  632. m_aModGroup = new automatableButtonGroup( this );
  633. m_aModGroup -> addButton( amod_mixButton );
  634. m_aModGroup -> addButton( amod_amButton );
  635. m_aModGroup -> addButton( amod_rmButton );
  636. m_aModGroup -> addButton( amod_pmButton );
  637. // B-modulation button group
  638. PixmapButton * bmod_mixButton = new PixmapButton( this, nullptr );
  639. bmod_mixButton -> move( 44, 50 );
  640. bmod_mixButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "bmix_active" ) );
  641. bmod_mixButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "bmix_inactive" ) );
  642. ToolTip::add( bmod_mixButton, tr( "Mix output of B2 to B1" ) );
  643. PixmapButton * bmod_amButton = new PixmapButton( this, nullptr );
  644. bmod_amButton -> move( 44, 66 );
  645. bmod_amButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "bam_active" ) );
  646. bmod_amButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "bam_inactive" ) );
  647. ToolTip::add( bmod_amButton, tr( "Modulate amplitude of B1 by output of B2" ) );
  648. PixmapButton * bmod_rmButton = new PixmapButton( this, nullptr );
  649. bmod_rmButton -> move( 44, 82 );
  650. bmod_rmButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "brm_active" ) );
  651. bmod_rmButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "brm_inactive" ) );
  652. ToolTip::add( bmod_rmButton, tr( "Ring modulate B1 and B2" ) );
  653. PixmapButton * bmod_pmButton = new PixmapButton( this, nullptr );
  654. bmod_pmButton -> move( 44, 98 );
  655. bmod_pmButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "bpm_active" ) );
  656. bmod_pmButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "bpm_inactive" ) );
  657. ToolTip::add( bmod_pmButton, tr( "Modulate phase of B1 by output of B2" ) );
  658. m_bModGroup = new automatableButtonGroup( this );
  659. m_bModGroup -> addButton( bmod_mixButton );
  660. m_bModGroup -> addButton( bmod_amButton );
  661. m_bModGroup -> addButton( bmod_rmButton );
  662. m_bModGroup -> addButton( bmod_pmButton );
  663. // graph widgets
  664. pal = QPalette();
  665. pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap("wavegraph") );
  666. // a1 graph
  667. a1_graph = new Graph( this, Graph::LinearStyle, 224, 105 );
  668. a1_graph->move( 4, 141 );
  669. a1_graph->setAutoFillBackground( true );
  670. a1_graph->setGraphColor( QColor( 0x43, 0xb2, 0xff ) );
  671. ToolTip::add( a1_graph, tr ( "Draw your own waveform here by dragging your mouse on this graph." ) );
  672. a1_graph->setPalette( pal );
  673. // a2 graph
  674. a2_graph = new Graph( this, Graph::LinearStyle, 224, 105 );
  675. a2_graph->move( 4, 141 );
  676. a2_graph->setAutoFillBackground( true );
  677. a2_graph->setGraphColor( QColor( 0x43, 0xb2, 0xff ) );
  678. ToolTip::add( a2_graph, tr ( "Draw your own waveform here by dragging your mouse on this graph." ) );
  679. a2_graph->setPalette( pal );
  680. // b1 graph
  681. b1_graph = new Graph( this, Graph::LinearStyle, 224, 105 );
  682. b1_graph->move( 4, 141 );
  683. b1_graph->setAutoFillBackground( true );
  684. b1_graph->setGraphColor( QColor( 0xfc, 0x54, 0x31 ) );
  685. ToolTip::add( b1_graph, tr ( "Draw your own waveform here by dragging your mouse on this graph." ) );
  686. b1_graph->setPalette( pal );
  687. // b2 graph
  688. b2_graph = new Graph( this, Graph::LinearStyle, 224, 105 );
  689. b2_graph->move( 4, 141 );
  690. b2_graph->setAutoFillBackground( true );
  691. b2_graph->setGraphColor( QColor( 0xfc, 0x54, 0x31 ) );
  692. ToolTip::add( b2_graph, tr ( "Draw your own waveform here by dragging your mouse on this graph." ) );
  693. b2_graph->setPalette( pal );
  694. // misc pushbuttons
  695. // waveform modifications
  696. m_loadButton = new PixmapButton( this, tr( "Load waveform" ) );
  697. m_loadButton -> move ( 173, 121 );
  698. m_loadButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "load_active" ) );
  699. m_loadButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "load_inactive" ) );
  700. ToolTip::add( m_loadButton, tr( "Load a waveform from a sample file" ) );
  701. m_phaseLeftButton = new PixmapButton( this, tr( "Phase left" ) );
  702. m_phaseLeftButton -> move ( 193, 121 );
  703. m_phaseLeftButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "phl_active" ) );
  704. m_phaseLeftButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "phl_inactive" ) );
  705. ToolTip::add( m_phaseLeftButton, tr( "Shift phase by -15 degrees" ) );
  706. m_phaseRightButton = new PixmapButton( this, tr( "Phase right" ) );
  707. m_phaseRightButton -> move ( 210, 121 );
  708. m_phaseRightButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "phr_active" ) );
  709. m_phaseRightButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "phr_inactive" ) );
  710. ToolTip::add( m_phaseRightButton, tr( "Shift phase by +15 degrees" ) );
  711. m_normalizeButton = new PixmapButton( this, tr( "Normalize" ) );
  712. m_normalizeButton -> move ( 230, 121 );
  713. m_normalizeButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "norm_active" ) );
  714. m_normalizeButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "norm_inactive" ) );
  715. ToolTip::add( m_normalizeButton, tr( "Normalize" ) );
  716. m_invertButton = new PixmapButton( this, tr( "Invert" ) );
  717. m_invertButton -> move ( 230, 138 );
  718. m_invertButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "inv_active" ) );
  719. m_invertButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "inv_inactive" ) );
  720. ToolTip::add( m_invertButton, tr( "Invert" ) );
  721. m_smoothButton = new PixmapButton( this, tr( "Smooth" ) );
  722. m_smoothButton -> move ( 230, 155 );
  723. m_smoothButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "smooth_active" ) );
  724. m_smoothButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "smooth_inactive" ) );
  725. ToolTip::add( m_smoothButton, tr( "Smooth" ) );
  726. // waveforms
  727. m_sinWaveButton = new PixmapButton( this, tr( "Sine wave" ) );
  728. m_sinWaveButton -> move ( 230, 176 );
  729. m_sinWaveButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "sin_active" ) );
  730. m_sinWaveButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "sin_inactive" ) );
  731. ToolTip::add( m_sinWaveButton, tr( "Sine wave" ) );
  732. m_triWaveButton = new PixmapButton( this, tr( "Triangle wave" ) );
  733. m_triWaveButton -> move ( 230, 194 );
  734. m_triWaveButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "tri_active" ) );
  735. m_triWaveButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "tri_inactive" ) );
  736. ToolTip::add( m_triWaveButton, tr( "Triangle wave" ) );
  737. m_sawWaveButton = new PixmapButton( this, tr( "Triangle wave" ) );
  738. m_sawWaveButton -> move ( 230, 212 );
  739. m_sawWaveButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "saw_active" ) );
  740. m_sawWaveButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "saw_inactive" ) );
  741. ToolTip::add( m_sawWaveButton, tr( "Saw wave" ) );
  742. m_sqrWaveButton = new PixmapButton( this, tr( "Square wave" ) );
  743. m_sqrWaveButton -> move ( 230, 230 );
  744. m_sqrWaveButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "sqr_active" ) );
  745. m_sqrWaveButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "sqr_inactive" ) );
  746. ToolTip::add( m_sqrWaveButton, tr( "Square wave" ) );
  747. connect( m_sinWaveButton, SIGNAL( clicked() ), this, SLOT( sinWaveClicked() ) );
  748. connect( m_triWaveButton, SIGNAL( clicked() ), this, SLOT( triWaveClicked() ) );
  749. connect( m_sawWaveButton, SIGNAL( clicked() ), this, SLOT( sawWaveClicked() ) );
  750. connect( m_sqrWaveButton, SIGNAL( clicked() ), this, SLOT( sqrWaveClicked() ) );
  751. connect( m_normalizeButton, SIGNAL( clicked() ), this, SLOT( normalizeClicked() ) );
  752. connect( m_invertButton, SIGNAL( clicked() ), this, SLOT( invertClicked() ) );
  753. connect( m_smoothButton, SIGNAL( clicked() ), this, SLOT( smoothClicked() ) );
  754. connect( m_phaseLeftButton, SIGNAL( clicked() ), this, SLOT( phaseLeftClicked() ) );
  755. connect( m_phaseRightButton, SIGNAL( clicked() ), this, SLOT( phaseRightClicked() ) );
  756. connect( m_loadButton, SIGNAL( clicked() ), this, SLOT( loadClicked() ) );
  757. connect( a1_selectButton, SIGNAL( clicked() ), this, SLOT( updateLayout() ) );
  758. connect( a2_selectButton, SIGNAL( clicked() ), this, SLOT( updateLayout() ) );
  759. connect( b1_selectButton, SIGNAL( clicked() ), this, SLOT( updateLayout() ) );
  760. connect( b2_selectButton, SIGNAL( clicked() ), this, SLOT( updateLayout() ) );
  761. updateLayout();
  762. }
  763. WatsynView::~WatsynView()
  764. {
  765. }
  766. void WatsynView::updateLayout()
  767. {
  768. switch( m_selectedGraphGroup->model()->value() )
  769. {
  770. case A1_OSC:
  771. a1_graph->show();
  772. a2_graph->hide();
  773. b1_graph->hide();
  774. b2_graph->hide();
  775. break;
  776. case A2_OSC:
  777. a1_graph->hide();
  778. a2_graph->show();
  779. b1_graph->hide();
  780. b2_graph->hide();
  781. break;
  782. case B1_OSC:
  783. a1_graph->hide();
  784. a2_graph->hide();
  785. b1_graph->show();
  786. b2_graph->hide();
  787. break;
  788. case B2_OSC:
  789. a1_graph->hide();
  790. a2_graph->hide();
  791. b1_graph->hide();
  792. b2_graph->show();
  793. break;
  794. }
  795. }
  796. void WatsynView::sinWaveClicked()
  797. {
  798. switch( m_selectedGraphGroup->model()->value() )
  799. {
  800. case A1_OSC:
  801. a1_graph->model()->setWaveToSine();
  802. Engine::getSong()->setModified();
  803. break;
  804. case A2_OSC:
  805. a2_graph->model()->setWaveToSine();
  806. Engine::getSong()->setModified();
  807. break;
  808. case B1_OSC:
  809. b1_graph->model()->setWaveToSine();
  810. Engine::getSong()->setModified();
  811. break;
  812. case B2_OSC:
  813. b2_graph->model()->setWaveToSine();
  814. Engine::getSong()->setModified();
  815. break;
  816. }
  817. }
  818. void WatsynView::triWaveClicked()
  819. {
  820. switch( m_selectedGraphGroup->model()->value() )
  821. {
  822. case A1_OSC:
  823. a1_graph->model()->setWaveToTriangle();
  824. Engine::getSong()->setModified();
  825. break;
  826. case A2_OSC:
  827. a2_graph->model()->setWaveToTriangle();
  828. Engine::getSong()->setModified();
  829. break;
  830. case B1_OSC:
  831. b1_graph->model()->setWaveToTriangle();
  832. Engine::getSong()->setModified();
  833. break;
  834. case B2_OSC:
  835. b2_graph->model()->setWaveToTriangle();
  836. Engine::getSong()->setModified();
  837. break;
  838. }
  839. }
  840. void WatsynView::sawWaveClicked()
  841. {
  842. switch( m_selectedGraphGroup->model()->value() )
  843. {
  844. case A1_OSC:
  845. a1_graph->model()->setWaveToSaw();
  846. Engine::getSong()->setModified();
  847. break;
  848. case A2_OSC:
  849. a2_graph->model()->setWaveToSaw();
  850. Engine::getSong()->setModified();
  851. break;
  852. case B1_OSC:
  853. b1_graph->model()->setWaveToSaw();
  854. Engine::getSong()->setModified();
  855. break;
  856. case B2_OSC:
  857. b2_graph->model()->setWaveToSaw();
  858. Engine::getSong()->setModified();
  859. break;
  860. }
  861. }
  862. void WatsynView::sqrWaveClicked()
  863. {
  864. switch( m_selectedGraphGroup->model()->value() )
  865. {
  866. case A1_OSC:
  867. a1_graph->model()->setWaveToSquare();
  868. Engine::getSong()->setModified();
  869. break;
  870. case A2_OSC:
  871. a2_graph->model()->setWaveToSquare();
  872. Engine::getSong()->setModified();
  873. break;
  874. case B1_OSC:
  875. b1_graph->model()->setWaveToSquare();
  876. Engine::getSong()->setModified();
  877. break;
  878. case B2_OSC:
  879. b2_graph->model()->setWaveToSquare();
  880. Engine::getSong()->setModified();
  881. break;
  882. }
  883. }
  884. void WatsynView::normalizeClicked()
  885. {
  886. switch( m_selectedGraphGroup->model()->value() )
  887. {
  888. case A1_OSC:
  889. a1_graph->model()->normalize();
  890. Engine::getSong()->setModified();
  891. break;
  892. case A2_OSC:
  893. a2_graph->model()->normalize();
  894. Engine::getSong()->setModified();
  895. break;
  896. case B1_OSC:
  897. b1_graph->model()->normalize();
  898. Engine::getSong()->setModified();
  899. break;
  900. case B2_OSC:
  901. b2_graph->model()->normalize();
  902. Engine::getSong()->setModified();
  903. break;
  904. }
  905. }
  906. void WatsynView::invertClicked()
  907. {
  908. switch( m_selectedGraphGroup->model()->value() )
  909. {
  910. case A1_OSC:
  911. a1_graph->model()->invert();
  912. Engine::getSong()->setModified();
  913. break;
  914. case A2_OSC:
  915. a2_graph->model()->invert();
  916. Engine::getSong()->setModified();
  917. break;
  918. case B1_OSC:
  919. b1_graph->model()->invert();
  920. Engine::getSong()->setModified();
  921. break;
  922. case B2_OSC:
  923. b2_graph->model()->invert();
  924. Engine::getSong()->setModified();
  925. break;
  926. }
  927. }
  928. void WatsynView::smoothClicked()
  929. {
  930. switch( m_selectedGraphGroup->model()->value() )
  931. {
  932. case A1_OSC:
  933. a1_graph->model()->smooth();
  934. Engine::getSong()->setModified();
  935. break;
  936. case A2_OSC:
  937. a2_graph->model()->smooth();
  938. Engine::getSong()->setModified();
  939. break;
  940. case B1_OSC:
  941. b1_graph->model()->smooth();
  942. Engine::getSong()->setModified();
  943. break;
  944. case B2_OSC:
  945. b2_graph->model()->smooth();
  946. Engine::getSong()->setModified();
  947. break;
  948. }
  949. }
  950. void WatsynView::phaseLeftClicked()
  951. {
  952. switch( m_selectedGraphGroup->model()->value() )
  953. {
  954. case A1_OSC:
  955. a1_graph->model()->shiftPhase( -15 );
  956. Engine::getSong()->setModified();
  957. break;
  958. case A2_OSC:
  959. a2_graph->model()->shiftPhase( -15 );
  960. Engine::getSong()->setModified();
  961. break;
  962. case B1_OSC:
  963. b1_graph->model()->shiftPhase( -15 );
  964. Engine::getSong()->setModified();
  965. break;
  966. case B2_OSC:
  967. b2_graph->model()->shiftPhase( -15 );
  968. Engine::getSong()->setModified();
  969. break;
  970. }
  971. }
  972. void WatsynView::phaseRightClicked()
  973. {
  974. switch( m_selectedGraphGroup->model()->value() )
  975. {
  976. case A1_OSC:
  977. a1_graph->model()->shiftPhase( 15 );
  978. Engine::getSong()->setModified();
  979. break;
  980. case A2_OSC:
  981. a2_graph->model()->shiftPhase( 15 );
  982. Engine::getSong()->setModified();
  983. break;
  984. case B1_OSC:
  985. b1_graph->model()->shiftPhase( 15 );
  986. Engine::getSong()->setModified();
  987. break;
  988. case B2_OSC:
  989. b2_graph->model()->shiftPhase( 15 );
  990. Engine::getSong()->setModified();
  991. break;
  992. }
  993. }
  994. void WatsynView::loadClicked()
  995. {
  996. QString fileName;
  997. switch( m_selectedGraphGroup->model()->value() )
  998. {
  999. case A1_OSC:
  1000. a1_graph->model()->setWaveToUser();
  1001. Engine::getSong()->setModified();
  1002. break;
  1003. case A2_OSC:
  1004. a2_graph->model()->setWaveToUser();
  1005. Engine::getSong()->setModified();
  1006. break;
  1007. case B1_OSC:
  1008. b1_graph->model()->setWaveToUser();
  1009. Engine::getSong()->setModified();
  1010. break;
  1011. case B2_OSC:
  1012. b2_graph->model()->setWaveToUser();
  1013. Engine::getSong()->setModified();
  1014. break;
  1015. }
  1016. }
  1017. void WatsynView::modelChanged()
  1018. {
  1019. WatsynInstrument * w = castModel<WatsynInstrument>();
  1020. a1_volKnob -> setModel( &w -> a1_vol );
  1021. a2_volKnob -> setModel( &w -> a2_vol );
  1022. b1_volKnob -> setModel( &w -> b1_vol );
  1023. b2_volKnob -> setModel( &w -> b2_vol );
  1024. a1_panKnob -> setModel( &w -> a1_pan );
  1025. a2_panKnob -> setModel( &w -> a2_pan );
  1026. b1_panKnob -> setModel( &w -> b1_pan );
  1027. b2_panKnob -> setModel( &w -> b2_pan );
  1028. a1_multKnob -> setModel( &w -> a1_mult );
  1029. a2_multKnob -> setModel( &w -> a2_mult );
  1030. b1_multKnob -> setModel( &w -> b1_mult );
  1031. b2_multKnob -> setModel( &w -> b2_mult );
  1032. a1_ltuneKnob -> setModel( &w -> a1_ltune );
  1033. a2_ltuneKnob -> setModel( &w -> a2_ltune );
  1034. b1_ltuneKnob -> setModel( &w -> b1_ltune );
  1035. b2_ltuneKnob -> setModel( &w -> b2_ltune );
  1036. a1_rtuneKnob -> setModel( &w -> a1_rtune );
  1037. a2_rtuneKnob -> setModel( &w -> a2_rtune );
  1038. b1_rtuneKnob -> setModel( &w -> b1_rtune );
  1039. b2_rtuneKnob -> setModel( &w -> b2_rtune );
  1040. m_abmixKnob -> setModel( &w -> m_abmix );
  1041. m_selectedGraphGroup -> setModel( &w -> m_selectedGraph );
  1042. m_aModGroup -> setModel( &w -> m_amod );
  1043. m_bModGroup -> setModel( &w -> m_bmod );
  1044. a1_graph -> setModel( &w -> a1_graph );
  1045. a2_graph -> setModel( &w -> a2_graph );
  1046. b1_graph -> setModel( &w -> b1_graph );
  1047. b2_graph -> setModel( &w -> b2_graph );
  1048. m_envAmtKnob -> setModel( &w -> m_envAmt );
  1049. m_envAttKnob -> setModel( &w -> m_envAtt );
  1050. m_envHoldKnob -> setModel( &w -> m_envHold );
  1051. m_envDecKnob -> setModel( &w -> m_envDec );
  1052. m_xtalkKnob -> setModel( &w -> m_xtalk );
  1053. }
  1054. extern "C"
  1055. {
  1056. // necessary for getting instance out of shared lib
  1057. PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
  1058. {
  1059. return( new WatsynInstrument( static_cast<InstrumentTrack *>( m ) ) );
  1060. }
  1061. }