TripleOscillator.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /*
  2. * TripleOscillator.cpp - powerful instrument with three oscillators
  3. *
  4. * Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
  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 <QDomDocument>
  25. #include <QBitmap>
  26. #include <QPainter>
  27. #include "TripleOscillator.h"
  28. #include "AudioEngine.h"
  29. #include "AutomatableButton.h"
  30. #include "debug.h"
  31. #include "Engine.h"
  32. #include "InstrumentTrack.h"
  33. #include "Knob.h"
  34. #include "NotePlayHandle.h"
  35. #include "PixmapButton.h"
  36. #include "SampleBuffer.h"
  37. #include "ToolTip.h"
  38. #include "embed.h"
  39. #include "plugin_export.h"
  40. extern "C"
  41. {
  42. Plugin::Descriptor PLUGIN_EXPORT tripleoscillator_plugin_descriptor =
  43. {
  44. STRINGIFY( PLUGIN_NAME ),
  45. "TripleOscillator",
  46. QT_TRANSLATE_NOOP( "PluginBrowser",
  47. "Three powerful oscillators you can modulate "
  48. "in several ways" ),
  49. "Tobias Doerffel <tobydox/at/users.sf.net>",
  50. 0x0110,
  51. Plugin::Instrument,
  52. new PluginPixmapLoader( "logo" ),
  53. nullptr,
  54. nullptr,
  55. } ;
  56. }
  57. OscillatorObject::OscillatorObject( Model * _parent, int _idx ) :
  58. Model( _parent ),
  59. m_volumeModel( DefaultVolume / NUM_OF_OSCILLATORS, MinVolume,
  60. MaxVolume, 1.0f, this, tr( "Osc %1 volume" ).arg( _idx+1 ) ),
  61. m_panModel( DefaultPanning, PanningLeft, PanningRight, 1.0f, this,
  62. tr( "Osc %1 panning" ).arg( _idx+1 ) ),
  63. m_coarseModel( -_idx*KeysPerOctave,
  64. -2 * KeysPerOctave, 2 * KeysPerOctave, 1.0f, this,
  65. tr( "Osc %1 coarse detuning" ).arg( _idx+1 ) ),
  66. m_fineLeftModel( 0.0f, -100.0f, 100.0f, 1.0f, this,
  67. tr( "Osc %1 fine detuning left" ).arg( _idx+1 ) ),
  68. m_fineRightModel( 0.0f, -100.0f, 100.0f, 1.0f, this,
  69. tr( "Osc %1 fine detuning right" ).arg( _idx + 1 ) ),
  70. m_phaseOffsetModel( 0.0f, 0.0f, 360.0f, 1.0f, this,
  71. tr( "Osc %1 phase-offset" ).arg( _idx+1 ) ),
  72. m_stereoPhaseDetuningModel( 0.0f, 0.0f, 360.0f, 1.0f, this,
  73. tr( "Osc %1 stereo phase-detuning" ).arg( _idx+1 ) ),
  74. m_waveShapeModel( Oscillator::SineWave, 0,
  75. Oscillator::NumWaveShapes-1, this,
  76. tr( "Osc %1 wave shape" ).arg( _idx+1 ) ),
  77. m_modulationAlgoModel( Oscillator::SignalMix, 0,
  78. Oscillator::NumModulationAlgos-1, this,
  79. tr( "Modulation type %1" ).arg( _idx+1 ) ),
  80. m_useWaveTableModel(true),
  81. m_sampleBuffer( new SampleBuffer ),
  82. m_volumeLeft( 0.0f ),
  83. m_volumeRight( 0.0f ),
  84. m_detuningLeft( 0.0f ),
  85. m_detuningRight( 0.0f ),
  86. m_phaseOffsetLeft( 0.0f ),
  87. m_phaseOffsetRight( 0.0f ),
  88. m_useWaveTable( true )
  89. {
  90. // Connect knobs with Oscillators' inputs
  91. connect( &m_volumeModel, SIGNAL( dataChanged() ),
  92. this, SLOT( updateVolume() ), Qt::DirectConnection );
  93. connect( &m_panModel, SIGNAL( dataChanged() ),
  94. this, SLOT( updateVolume() ), Qt::DirectConnection );
  95. updateVolume();
  96. connect( &m_coarseModel, SIGNAL( dataChanged() ),
  97. this, SLOT( updateDetuningLeft() ), Qt::DirectConnection );
  98. connect( &m_coarseModel, SIGNAL( dataChanged() ),
  99. this, SLOT( updateDetuningRight() ), Qt::DirectConnection );
  100. connect( &m_fineLeftModel, SIGNAL( dataChanged() ),
  101. this, SLOT( updateDetuningLeft() ), Qt::DirectConnection );
  102. connect( &m_fineRightModel, SIGNAL( dataChanged() ),
  103. this, SLOT( updateDetuningRight() ), Qt::DirectConnection );
  104. updateDetuningLeft();
  105. updateDetuningRight();
  106. connect( &m_phaseOffsetModel, SIGNAL( dataChanged() ),
  107. this, SLOT( updatePhaseOffsetLeft() ), Qt::DirectConnection );
  108. connect( &m_phaseOffsetModel, SIGNAL( dataChanged() ),
  109. this, SLOT( updatePhaseOffsetRight() ), Qt::DirectConnection );
  110. connect( &m_stereoPhaseDetuningModel, SIGNAL( dataChanged() ),
  111. this, SLOT( updatePhaseOffsetLeft() ), Qt::DirectConnection );
  112. connect ( &m_useWaveTableModel, SIGNAL(dataChanged()),
  113. this, SLOT( updateUseWaveTable()));
  114. updatePhaseOffsetLeft();
  115. updatePhaseOffsetRight();
  116. }
  117. OscillatorObject::~OscillatorObject()
  118. {
  119. sharedObject::unref( m_sampleBuffer );
  120. }
  121. void OscillatorObject::oscUserDefWaveDblClick()
  122. {
  123. QString af = m_sampleBuffer->openAndSetWaveformFile();
  124. if( af != "" )
  125. {
  126. // TODO:
  127. //ToolTip::add( m_usrWaveBtn, m_sampleBuffer->audioFile() );
  128. }
  129. }
  130. void OscillatorObject::updateVolume()
  131. {
  132. if( m_panModel.value() >= 0.0f )
  133. {
  134. const float panningFactorLeft = 1.0f - m_panModel.value()
  135. / (float)PanningRight;
  136. m_volumeLeft = panningFactorLeft * m_volumeModel.value() /
  137. 100.0f;
  138. m_volumeRight = m_volumeModel.value() / 100.0f;
  139. }
  140. else
  141. {
  142. m_volumeLeft = m_volumeModel.value() / 100.0f;
  143. const float panningFactorRight = 1.0f + m_panModel.value()
  144. / (float)PanningRight;
  145. m_volumeRight = panningFactorRight * m_volumeModel.value() /
  146. 100.0f;
  147. }
  148. }
  149. void OscillatorObject::updateDetuningLeft()
  150. {
  151. m_detuningLeft = powf( 2.0f, ( (float)m_coarseModel.value() * 100.0f
  152. + (float)m_fineLeftModel.value() ) / 1200.0f )
  153. / Engine::audioEngine()->processingSampleRate();
  154. }
  155. void OscillatorObject::updateDetuningRight()
  156. {
  157. m_detuningRight = powf( 2.0f, ( (float)m_coarseModel.value() * 100.0f
  158. + (float)m_fineRightModel.value() ) / 1200.0f )
  159. / Engine::audioEngine()->processingSampleRate();
  160. }
  161. void OscillatorObject::updatePhaseOffsetLeft()
  162. {
  163. m_phaseOffsetLeft = ( m_phaseOffsetModel.value() +
  164. m_stereoPhaseDetuningModel.value() ) / 360.0f;
  165. }
  166. void OscillatorObject::updatePhaseOffsetRight()
  167. {
  168. m_phaseOffsetRight = m_phaseOffsetModel.value() / 360.0f;
  169. }
  170. void OscillatorObject::updateUseWaveTable()
  171. {
  172. m_useWaveTable = m_useWaveTableModel.value();
  173. }
  174. TripleOscillator::TripleOscillator( InstrumentTrack * _instrument_track ) :
  175. Instrument( _instrument_track, &tripleoscillator_plugin_descriptor )
  176. {
  177. for( int i = 0; i < NUM_OF_OSCILLATORS; ++i )
  178. {
  179. m_osc[i] = new OscillatorObject( this, i );
  180. }
  181. connect( Engine::audioEngine(), SIGNAL( sampleRateChanged() ),
  182. this, SLOT( updateAllDetuning() ) );
  183. }
  184. TripleOscillator::~TripleOscillator()
  185. {
  186. }
  187. void TripleOscillator::saveSettings( QDomDocument & _doc, QDomElement & _this )
  188. {
  189. for( int i = 0; i < NUM_OF_OSCILLATORS; ++i )
  190. {
  191. QString is = QString::number( i );
  192. m_osc[i]->m_volumeModel.saveSettings( _doc, _this, "vol" + is );
  193. m_osc[i]->m_panModel.saveSettings( _doc, _this, "pan" + is );
  194. m_osc[i]->m_coarseModel.saveSettings( _doc, _this, "coarse"
  195. + is );
  196. m_osc[i]->m_fineLeftModel.saveSettings( _doc, _this, "finel" +
  197. is );
  198. m_osc[i]->m_fineRightModel.saveSettings( _doc, _this, "finer" +
  199. is );
  200. m_osc[i]->m_phaseOffsetModel.saveSettings( _doc, _this,
  201. "phoffset" + is );
  202. m_osc[i]->m_stereoPhaseDetuningModel.saveSettings( _doc, _this,
  203. "stphdetun" + is );
  204. m_osc[i]->m_waveShapeModel.saveSettings( _doc, _this,
  205. "wavetype" + is );
  206. m_osc[i]->m_modulationAlgoModel.saveSettings( _doc, _this,
  207. "modalgo" + QString::number( i+1 ) );
  208. m_osc[i]->m_useWaveTableModel.saveSettings( _doc, _this,
  209. "useWaveTable" + QString::number (i+1 ) );
  210. _this.setAttribute( "userwavefile" + is,
  211. m_osc[i]->m_sampleBuffer->audioFile() );
  212. }
  213. }
  214. void TripleOscillator::loadSettings( const QDomElement & _this )
  215. {
  216. for( int i = 0; i < NUM_OF_OSCILLATORS; ++i )
  217. {
  218. const QString is = QString::number( i );
  219. m_osc[i]->m_volumeModel.loadSettings( _this, "vol" + is );
  220. m_osc[i]->m_panModel.loadSettings( _this, "pan" + is );
  221. m_osc[i]->m_coarseModel.loadSettings( _this, "coarse" + is );
  222. m_osc[i]->m_fineLeftModel.loadSettings( _this, "finel" + is );
  223. m_osc[i]->m_fineRightModel.loadSettings( _this, "finer" + is );
  224. m_osc[i]->m_phaseOffsetModel.loadSettings( _this,
  225. "phoffset" + is );
  226. m_osc[i]->m_stereoPhaseDetuningModel.loadSettings( _this,
  227. "stphdetun" + is );
  228. m_osc[i]->m_waveShapeModel.loadSettings( _this, "wavetype" +
  229. is );
  230. m_osc[i]->m_modulationAlgoModel.loadSettings( _this,
  231. "modalgo" + QString::number( i+1 ) );
  232. m_osc[i]->m_useWaveTableModel.loadSettings( _this,
  233. "useWaveTable" + QString::number (i+1 ) );
  234. m_osc[i]->m_sampleBuffer->setAudioFile( _this.attribute(
  235. "userwavefile" + is ) );
  236. }
  237. }
  238. QString TripleOscillator::nodeName() const
  239. {
  240. return( tripleoscillator_plugin_descriptor.name );
  241. }
  242. void TripleOscillator::playNote( NotePlayHandle * _n,
  243. sampleFrame * _working_buffer )
  244. {
  245. if( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
  246. {
  247. Oscillator * oscs_l[NUM_OF_OSCILLATORS];
  248. Oscillator * oscs_r[NUM_OF_OSCILLATORS];
  249. for( int i = NUM_OF_OSCILLATORS - 1; i >= 0; --i )
  250. {
  251. // the last oscs needs no sub-oscs...
  252. if( i == NUM_OF_OSCILLATORS - 1 )
  253. {
  254. oscs_l[i] = new Oscillator(
  255. &m_osc[i]->m_waveShapeModel,
  256. &m_osc[i]->m_modulationAlgoModel,
  257. _n->frequency(),
  258. m_osc[i]->m_detuningLeft,
  259. m_osc[i]->m_phaseOffsetLeft,
  260. m_osc[i]->m_volumeLeft );
  261. oscs_l[i]->setUseWaveTable(m_osc[i]->m_useWaveTable);
  262. oscs_r[i] = new Oscillator(
  263. &m_osc[i]->m_waveShapeModel,
  264. &m_osc[i]->m_modulationAlgoModel,
  265. _n->frequency(),
  266. m_osc[i]->m_detuningRight,
  267. m_osc[i]->m_phaseOffsetRight,
  268. m_osc[i]->m_volumeRight );
  269. oscs_r[i]->setUseWaveTable(m_osc[i]->m_useWaveTable);
  270. }
  271. else
  272. {
  273. oscs_l[i] = new Oscillator(
  274. &m_osc[i]->m_waveShapeModel,
  275. &m_osc[i]->m_modulationAlgoModel,
  276. _n->frequency(),
  277. m_osc[i]->m_detuningLeft,
  278. m_osc[i]->m_phaseOffsetLeft,
  279. m_osc[i]->m_volumeLeft,
  280. oscs_l[i + 1] );
  281. oscs_l[i]->setUseWaveTable(m_osc[i]->m_useWaveTable);
  282. oscs_r[i] = new Oscillator(
  283. &m_osc[i]->m_waveShapeModel,
  284. &m_osc[i]->m_modulationAlgoModel,
  285. _n->frequency(),
  286. m_osc[i]->m_detuningRight,
  287. m_osc[i]->m_phaseOffsetRight,
  288. m_osc[i]->m_volumeRight,
  289. oscs_r[i + 1] );
  290. oscs_r[i]->setUseWaveTable(m_osc[i]->m_useWaveTable);
  291. }
  292. oscs_l[i]->setUserWave( m_osc[i]->m_sampleBuffer );
  293. oscs_r[i]->setUserWave( m_osc[i]->m_sampleBuffer );
  294. }
  295. _n->m_pluginData = new oscPtr;
  296. static_cast<oscPtr *>( _n->m_pluginData )->oscLeft = oscs_l[0];
  297. static_cast< oscPtr *>( _n->m_pluginData )->oscRight =
  298. oscs_r[0];
  299. }
  300. Oscillator * osc_l = static_cast<oscPtr *>( _n->m_pluginData )->oscLeft;
  301. Oscillator * osc_r = static_cast<oscPtr *>( _n->m_pluginData )->oscRight;
  302. const fpp_t frames = _n->framesLeftForCurrentPeriod();
  303. const f_cnt_t offset = _n->noteOffset();
  304. osc_l->update( _working_buffer + offset, frames, 0 );
  305. osc_r->update( _working_buffer + offset, frames, 1 );
  306. applyFadeIn(_working_buffer, _n);
  307. applyRelease( _working_buffer, _n );
  308. instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
  309. }
  310. void TripleOscillator::deleteNotePluginData( NotePlayHandle * _n )
  311. {
  312. delete static_cast<Oscillator *>( static_cast<oscPtr *>(
  313. _n->m_pluginData )->oscLeft );
  314. delete static_cast<Oscillator *>( static_cast<oscPtr *>(
  315. _n->m_pluginData )->oscRight );
  316. delete static_cast<oscPtr *>( _n->m_pluginData );
  317. }
  318. PluginView * TripleOscillator::instantiateView( QWidget * _parent )
  319. {
  320. return new TripleOscillatorView( this, _parent );
  321. }
  322. void TripleOscillator::updateAllDetuning()
  323. {
  324. for( int i = 0; i < NUM_OF_OSCILLATORS; ++i )
  325. {
  326. m_osc[i]->updateDetuningLeft();
  327. m_osc[i]->updateDetuningRight();
  328. }
  329. }
  330. class TripleOscKnob : public Knob
  331. {
  332. public:
  333. TripleOscKnob( QWidget * _parent ) :
  334. Knob( knobStyled, _parent )
  335. {
  336. setFixedSize( 28, 35 );
  337. }
  338. };
  339. // 82, 109
  340. TripleOscillatorView::TripleOscillatorView( Instrument * _instrument,
  341. QWidget * _parent ) :
  342. InstrumentViewFixedSize( _instrument, _parent )
  343. {
  344. setAutoFillBackground( true );
  345. QPalette pal;
  346. pal.setBrush( backgroundRole(),
  347. PLUGIN_NAME::getIconPixmap( "artwork" ) );
  348. setPalette( pal );
  349. const int mod_x = 66;
  350. const int mod1_y = 58;
  351. const int mod2_y = 75;
  352. const int osc_y = 109;
  353. const int osc_h = 52;
  354. // TODO: clean rewrite using layouts and all that...
  355. PixmapButton * pm_osc1_btn = new PixmapButton( this, nullptr );
  356. pm_osc1_btn->move( mod_x, mod1_y );
  357. pm_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  358. "pm_active" ) );
  359. pm_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  360. "pm_inactive" ) );
  361. ToolTip::add( pm_osc1_btn, tr( "Modulate phase of oscillator 1 by oscillator 2" ) );
  362. PixmapButton * am_osc1_btn = new PixmapButton( this, nullptr );
  363. am_osc1_btn->move( mod_x + 35, mod1_y );
  364. am_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  365. "am_active" ) );
  366. am_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  367. "am_inactive" ) );
  368. ToolTip::add( am_osc1_btn, tr( "Modulate amplitude of oscillator 1 by oscillator 2" ) );
  369. PixmapButton * mix_osc1_btn = new PixmapButton( this, nullptr );
  370. mix_osc1_btn->move( mod_x + 70, mod1_y );
  371. mix_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  372. "mix_active" ) );
  373. mix_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  374. "mix_inactive" ) );
  375. ToolTip::add( mix_osc1_btn, tr( "Mix output of oscillators 1 & 2" ) );
  376. PixmapButton * sync_osc1_btn = new PixmapButton( this, nullptr );
  377. sync_osc1_btn->move( mod_x + 105, mod1_y );
  378. sync_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  379. "sync_active" ) );
  380. sync_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  381. "sync_inactive" ) );
  382. ToolTip::add( sync_osc1_btn, tr( "Synchronize oscillator 1 with "
  383. "oscillator 2" ) );
  384. PixmapButton * fm_osc1_btn = new PixmapButton( this, nullptr );
  385. fm_osc1_btn->move( mod_x + 140, mod1_y );
  386. fm_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  387. "fm_active" ) );
  388. fm_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  389. "fm_inactive" ) );
  390. ToolTip::add( fm_osc1_btn, tr( "Modulate frequency of oscillator 1 by oscillator 2" ) );
  391. m_mod1BtnGrp = new automatableButtonGroup( this );
  392. m_mod1BtnGrp->addButton( pm_osc1_btn );
  393. m_mod1BtnGrp->addButton( am_osc1_btn );
  394. m_mod1BtnGrp->addButton( mix_osc1_btn );
  395. m_mod1BtnGrp->addButton( sync_osc1_btn );
  396. m_mod1BtnGrp->addButton( fm_osc1_btn );
  397. PixmapButton * pm_osc2_btn = new PixmapButton( this, nullptr );
  398. pm_osc2_btn->move( mod_x, mod2_y );
  399. pm_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  400. "pm_active" ) );
  401. pm_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  402. "pm_inactive" ) );
  403. ToolTip::add( pm_osc2_btn, tr( "Modulate phase of oscillator 2 by oscillator 3" ) );
  404. PixmapButton * am_osc2_btn = new PixmapButton( this, nullptr );
  405. am_osc2_btn->move( mod_x + 35, mod2_y );
  406. am_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  407. "am_active" ) );
  408. am_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  409. "am_inactive" ) );
  410. ToolTip::add( am_osc2_btn, tr( "Modulate amplitude of oscillator 2 by oscillator 3" ) );
  411. PixmapButton * mix_osc2_btn = new PixmapButton( this, nullptr );
  412. mix_osc2_btn->move( mod_x + 70, mod2_y );
  413. mix_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  414. "mix_active" ) );
  415. mix_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  416. "mix_inactive" ) );
  417. ToolTip::add( mix_osc2_btn, tr("Mix output of oscillators 2 & 3" ) );
  418. PixmapButton * sync_osc2_btn = new PixmapButton( this, nullptr );
  419. sync_osc2_btn->move( mod_x + 105, mod2_y );
  420. sync_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  421. "sync_active" ) );
  422. sync_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  423. "sync_inactive" ) );
  424. ToolTip::add( sync_osc2_btn, tr( "Synchronize oscillator 2 with oscillator 3" ) );
  425. PixmapButton * fm_osc2_btn = new PixmapButton( this, nullptr );
  426. fm_osc2_btn->move( mod_x + 140, mod2_y );
  427. fm_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  428. "fm_active" ) );
  429. fm_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  430. "fm_inactive" ) );
  431. ToolTip::add( fm_osc2_btn, tr( "Modulate frequency of oscillator 2 by oscillator 3" ) );
  432. m_mod2BtnGrp = new automatableButtonGroup( this );
  433. m_mod2BtnGrp->addButton( pm_osc2_btn );
  434. m_mod2BtnGrp->addButton( am_osc2_btn );
  435. m_mod2BtnGrp->addButton( mix_osc2_btn );
  436. m_mod2BtnGrp->addButton( sync_osc2_btn );
  437. m_mod2BtnGrp->addButton( fm_osc2_btn );
  438. for( int i = 0; i < NUM_OF_OSCILLATORS; ++i )
  439. {
  440. int knob_y = osc_y + i * osc_h;
  441. // setup volume-knob
  442. Knob * vk = new Knob( knobStyled, this );
  443. vk->setVolumeKnob( true );
  444. vk->setFixedSize( 28, 35 );
  445. vk->move( 6, knob_y );
  446. vk->setHintText( tr( "Osc %1 volume:" ).arg(
  447. i+1 ), "%" );
  448. // setup panning-knob
  449. Knob * pk = new TripleOscKnob( this );
  450. pk->move( 35, knob_y );
  451. pk->setHintText( tr("Osc %1 panning:").arg( i + 1 ), "" );
  452. // setup coarse-knob
  453. Knob * ck = new TripleOscKnob( this );
  454. ck->move( 82, knob_y );
  455. ck->setHintText( tr( "Osc %1 coarse detuning:" ).arg( i + 1 )
  456. , " " + tr( "semitones" ) );
  457. // setup knob for left fine-detuning
  458. Knob * flk = new TripleOscKnob( this );
  459. flk->move( 111, knob_y );
  460. flk->setHintText( tr( "Osc %1 fine detuning left:" ).
  461. arg( i + 1 ),
  462. " " + tr( "cents" ) );
  463. // setup knob for right fine-detuning
  464. Knob * frk = new TripleOscKnob( this );
  465. frk->move( 140, knob_y );
  466. frk->setHintText( tr( "Osc %1 fine detuning right:" ).
  467. arg( i + 1 ),
  468. " " + tr( "cents" ) );
  469. // setup phase-offset-knob
  470. Knob * pok = new TripleOscKnob( this );
  471. pok->move( 188, knob_y );
  472. pok->setHintText( tr( "Osc %1 phase-offset:" ).
  473. arg( i + 1 ),
  474. " " + tr( "degrees" ) );
  475. // setup stereo-phase-detuning-knob
  476. Knob * spdk = new TripleOscKnob( this );
  477. spdk->move( 217, knob_y );
  478. spdk->setHintText( tr("Osc %1 stereo phase-detuning:" ).
  479. arg( i + 1 ),
  480. " " + tr( "degrees" ) );
  481. int btn_y = 96 + i * osc_h;
  482. PixmapButton * sin_wave_btn = new PixmapButton( this, nullptr );
  483. sin_wave_btn->move( 128, btn_y );
  484. sin_wave_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  485. "sin_shape_active" ) );
  486. sin_wave_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  487. "sin_shape_inactive" ) );
  488. ToolTip::add( sin_wave_btn,
  489. tr( "Sine wave" ) );
  490. PixmapButton * triangle_wave_btn =
  491. new PixmapButton( this, nullptr );
  492. triangle_wave_btn->move( 143, btn_y );
  493. triangle_wave_btn->setActiveGraphic(
  494. PLUGIN_NAME::getIconPixmap( "triangle_shape_active" ) );
  495. triangle_wave_btn->setInactiveGraphic(
  496. PLUGIN_NAME::getIconPixmap( "triangle_shape_inactive" ) );
  497. ToolTip::add( triangle_wave_btn,
  498. tr( "Triangle wave") );
  499. PixmapButton * saw_wave_btn = new PixmapButton( this, nullptr );
  500. saw_wave_btn->move( 158, btn_y );
  501. saw_wave_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  502. "saw_shape_active" ) );
  503. saw_wave_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  504. "saw_shape_inactive" ) );
  505. ToolTip::add( saw_wave_btn,
  506. tr( "Saw wave" ) );
  507. PixmapButton * sqr_wave_btn = new PixmapButton( this, nullptr );
  508. sqr_wave_btn->move( 173, btn_y );
  509. sqr_wave_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  510. "square_shape_active" ) );
  511. sqr_wave_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  512. "square_shape_inactive" ) );
  513. ToolTip::add( sqr_wave_btn,
  514. tr( "Square wave" ) );
  515. PixmapButton * moog_saw_wave_btn =
  516. new PixmapButton( this, nullptr );
  517. moog_saw_wave_btn->move( 188, btn_y );
  518. moog_saw_wave_btn->setActiveGraphic(
  519. PLUGIN_NAME::getIconPixmap( "moog_saw_shape_active" ) );
  520. moog_saw_wave_btn->setInactiveGraphic(
  521. PLUGIN_NAME::getIconPixmap( "moog_saw_shape_inactive" ) );
  522. ToolTip::add( moog_saw_wave_btn,
  523. tr( "Moog-like saw wave" ) );
  524. PixmapButton * exp_wave_btn = new PixmapButton( this, nullptr );
  525. exp_wave_btn->move( 203, btn_y );
  526. exp_wave_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  527. "exp_shape_active" ) );
  528. exp_wave_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  529. "exp_shape_inactive" ) );
  530. ToolTip::add( exp_wave_btn,
  531. tr( "Exponential wave" ) );
  532. PixmapButton * white_noise_btn = new PixmapButton( this, nullptr );
  533. white_noise_btn->move( 218, btn_y );
  534. white_noise_btn->setActiveGraphic(
  535. PLUGIN_NAME::getIconPixmap( "white_noise_shape_active" ) );
  536. white_noise_btn->setInactiveGraphic(
  537. PLUGIN_NAME::getIconPixmap( "white_noise_shape_inactive" ) );
  538. ToolTip::add( white_noise_btn,
  539. tr( "White noise" ) );
  540. PixmapButton * uwb = new PixmapButton( this, nullptr );
  541. uwb->move( 233, btn_y );
  542. uwb->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  543. "usr_shape_active" ) );
  544. uwb->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  545. "usr_shape_inactive" ) );
  546. ToolTip::add( uwb, tr( "User-defined wave" ) );
  547. PixmapButton * uwt = new PixmapButton( this, nullptr );
  548. uwt->move( 110, btn_y );
  549. uwt->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  550. "wavetable_active" ) );
  551. uwt->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  552. "wavetable_inactive" ) );
  553. uwt->setCheckable(true);
  554. ToolTip::add( uwt, tr( "Use alias-free wavetable oscillators." ) );
  555. automatableButtonGroup * wsbg =
  556. new automatableButtonGroup( this );
  557. wsbg->addButton( sin_wave_btn );
  558. wsbg->addButton( triangle_wave_btn );
  559. wsbg->addButton( saw_wave_btn );
  560. wsbg->addButton( sqr_wave_btn );
  561. wsbg->addButton( moog_saw_wave_btn );
  562. wsbg->addButton( exp_wave_btn );
  563. wsbg->addButton( white_noise_btn );
  564. wsbg->addButton( uwb );
  565. m_oscKnobs[i] = OscillatorKnobs( vk, pk, ck, flk, frk, pok,
  566. spdk, uwb, wsbg, uwt );
  567. }
  568. }
  569. TripleOscillatorView::~TripleOscillatorView()
  570. {
  571. }
  572. void TripleOscillatorView::modelChanged()
  573. {
  574. TripleOscillator * t = castModel<TripleOscillator>();
  575. m_mod1BtnGrp->setModel( &t->m_osc[0]->m_modulationAlgoModel );
  576. m_mod2BtnGrp->setModel( &t->m_osc[1]->m_modulationAlgoModel );
  577. for( int i = 0; i < NUM_OF_OSCILLATORS; ++i )
  578. {
  579. m_oscKnobs[i].m_volKnob->setModel(
  580. &t->m_osc[i]->m_volumeModel );
  581. m_oscKnobs[i].m_panKnob->setModel(
  582. &t->m_osc[i]->m_panModel );
  583. m_oscKnobs[i].m_coarseKnob->setModel(
  584. &t->m_osc[i]->m_coarseModel );
  585. m_oscKnobs[i].m_fineLeftKnob->setModel(
  586. &t->m_osc[i]->m_fineLeftModel );
  587. m_oscKnobs[i].m_fineRightKnob->setModel(
  588. &t->m_osc[i]->m_fineRightModel );
  589. m_oscKnobs[i].m_phaseOffsetKnob->setModel(
  590. &t->m_osc[i]->m_phaseOffsetModel );
  591. m_oscKnobs[i].m_stereoPhaseDetuningKnob->setModel(
  592. &t->m_osc[i]->m_stereoPhaseDetuningModel );
  593. m_oscKnobs[i].m_waveShapeBtnGrp->setModel(
  594. &t->m_osc[i]->m_waveShapeModel );
  595. m_oscKnobs[i].m_multiBandWaveTableButton->setModel(
  596. &t->m_osc[i]->m_useWaveTableModel );
  597. connect( m_oscKnobs[i].m_userWaveButton,
  598. SIGNAL( doubleClicked() ),
  599. t->m_osc[i], SLOT( oscUserDefWaveDblClick() ) );
  600. }
  601. }
  602. extern "C"
  603. {
  604. // necessary for getting instance out of shared lib
  605. PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* model, void * )
  606. {
  607. return new TripleOscillator( static_cast<InstrumentTrack *>( model ) );
  608. }
  609. }