organic.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /*
  2. * organic.cpp - additive synthesizer for organ-like sounds
  3. *
  4. * Copyright (c) 2006-2008 Andreas Brandmaier <andy/at/brandmaier/dot/de>
  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 "organic.h"
  25. #include <QDomElement>
  26. #include <QPainter>
  27. #include "Engine.h"
  28. #include "AudioEngine.h"
  29. #include "InstrumentTrack.h"
  30. #include "Knob.h"
  31. #include "NotePlayHandle.h"
  32. #include "Oscillator.h"
  33. #include "PixmapButton.h"
  34. #include "ToolTip.h"
  35. #include "embed.h"
  36. #include "plugin_export.h"
  37. extern "C"
  38. {
  39. Plugin::Descriptor PLUGIN_EXPORT organic_plugin_descriptor =
  40. {
  41. STRINGIFY( PLUGIN_NAME ),
  42. "Organic",
  43. QT_TRANSLATE_NOOP( "PluginBrowser",
  44. "Additive Synthesizer for organ-like sounds" ),
  45. "Andreas Brandmaier <andreas/at/brandmaier.de>",
  46. 0x0100,
  47. Plugin::Instrument,
  48. new PluginPixmapLoader( "logo" ),
  49. nullptr,
  50. nullptr,
  51. } ;
  52. }
  53. QPixmap * organicInstrumentView::s_artwork = nullptr;
  54. float * organicInstrument::s_harmonics = nullptr;
  55. /***********************************************************************
  56. *
  57. * class OrganicInstrument
  58. *
  59. * lmms - plugin
  60. *
  61. ***********************************************************************/
  62. organicInstrument::organicInstrument( InstrumentTrack * _instrument_track ) :
  63. Instrument( _instrument_track, &organic_plugin_descriptor ),
  64. m_modulationAlgo( Oscillator::SignalMix, Oscillator::SignalMix, Oscillator::SignalMix),
  65. m_fx1Model( 0.0f, 0.0f, 0.99f, 0.01f , this, tr( "Distortion" ) ),
  66. m_volModel( 100.0f, 0.0f, 200.0f, 1.0f, this, tr( "Volume" ) )
  67. {
  68. m_numOscillators = NUM_OSCILLATORS;
  69. m_osc = new OscillatorObject*[ m_numOscillators ];
  70. for (int i=0; i < m_numOscillators; i++)
  71. {
  72. m_osc[i] = new OscillatorObject( this, i );
  73. m_osc[i]->m_numOscillators = m_numOscillators;
  74. // Connect events
  75. connect( &m_osc[i]->m_oscModel, SIGNAL( dataChanged() ),
  76. m_osc[i], SLOT ( oscButtonChanged() ) );
  77. connect( &m_osc[i]->m_harmModel, SIGNAL( dataChanged() ),
  78. m_osc[i], SLOT( updateDetuning() ) );
  79. connect( &m_osc[i]->m_volModel, SIGNAL( dataChanged() ),
  80. m_osc[i], SLOT( updateVolume() ) );
  81. connect( &m_osc[i]->m_panModel, SIGNAL( dataChanged() ),
  82. m_osc[i], SLOT( updateVolume() ) );
  83. connect( &m_osc[i]->m_detuneModel, SIGNAL( dataChanged() ),
  84. m_osc[i], SLOT( updateDetuning() ) );
  85. m_osc[i]->updateVolume();
  86. }
  87. /* m_osc[0]->m_harmonic = log2f( 0.5f ); // one octave below
  88. m_osc[1]->m_harmonic = log2f( 0.75f ); // a fifth below
  89. m_osc[2]->m_harmonic = log2f( 1.0f ); // base freq
  90. m_osc[3]->m_harmonic = log2f( 2.0f ); // first overtone
  91. m_osc[4]->m_harmonic = log2f( 3.0f ); // second overtone
  92. m_osc[5]->m_harmonic = log2f( 4.0f ); // .
  93. m_osc[6]->m_harmonic = log2f( 5.0f ); // .
  94. m_osc[7]->m_harmonic = log2f( 6.0f ); // .*/
  95. if( s_harmonics == nullptr )
  96. {
  97. s_harmonics = new float[ NUM_HARMONICS ];
  98. s_harmonics[0] = log2f( 0.5f );
  99. s_harmonics[1] = log2f( 0.75f );
  100. s_harmonics[2] = log2f( 1.0f );
  101. s_harmonics[3] = log2f( 2.0f );
  102. s_harmonics[4] = log2f( 3.0f );
  103. s_harmonics[5] = log2f( 4.0f );
  104. s_harmonics[6] = log2f( 5.0f );
  105. s_harmonics[7] = log2f( 6.0f );
  106. s_harmonics[8] = log2f( 7.0f );
  107. s_harmonics[9] = log2f( 8.0f );
  108. s_harmonics[10] = log2f( 9.0f );
  109. s_harmonics[11] = log2f( 10.0f );
  110. s_harmonics[12] = log2f( 11.0f );
  111. s_harmonics[13] = log2f( 12.0f );
  112. s_harmonics[14] = log2f( 13.0f );
  113. s_harmonics[15] = log2f( 14.0f );
  114. s_harmonics[16] = log2f( 15.0f );
  115. s_harmonics[17] = log2f( 16.0f );
  116. }
  117. for (int i=0; i < m_numOscillators; i++) {
  118. m_osc[i]->updateVolume();
  119. m_osc[i]->updateDetuning();
  120. }
  121. connect( Engine::audioEngine(), SIGNAL( sampleRateChanged() ),
  122. this, SLOT( updateAllDetuning() ) );
  123. }
  124. organicInstrument::~organicInstrument()
  125. {
  126. delete[] m_osc;
  127. }
  128. void organicInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this )
  129. {
  130. _this.setAttribute( "num_osc", QString::number( m_numOscillators ) );
  131. m_fx1Model.saveSettings( _doc, _this, "foldback" );
  132. m_volModel.saveSettings( _doc, _this, "vol" );
  133. for( int i = 0; i < m_numOscillators; ++i )
  134. {
  135. QString is = QString::number( i );
  136. m_osc[i]->m_volModel.saveSettings( _doc, _this, "vol" + is );
  137. m_osc[i]->m_panModel.saveSettings( _doc, _this, "pan" + is );
  138. m_osc[i]->m_harmModel.saveSettings( _doc, _this, "newharmonic" + is );
  139. m_osc[i]->m_detuneModel.saveSettings( _doc, _this, "newdetune"
  140. + is );
  141. m_osc[i]->m_oscModel.saveSettings( _doc, _this, "wavetype"
  142. + is );
  143. }
  144. }
  145. void organicInstrument::loadSettings( const QDomElement & _this )
  146. {
  147. // m_numOscillators = _this.attribute( "num_osc" ).
  148. // toInt();
  149. for( int i = 0; i < m_numOscillators; ++i )
  150. {
  151. QString is = QString::number( i );
  152. m_osc[i]->m_volModel.loadSettings( _this, "vol" + is );
  153. if( _this.hasAttribute( "detune" + is ) )
  154. {
  155. m_osc[i]->m_detuneModel.setValue( _this.attribute( "detune" ).toInt() * 12 );
  156. }
  157. else
  158. {
  159. m_osc[i]->m_detuneModel.loadSettings( _this, "newdetune" + is );
  160. }
  161. m_osc[i]->m_panModel.loadSettings( _this, "pan" + is );
  162. m_osc[i]->m_oscModel.loadSettings( _this, "wavetype" + is );
  163. if( _this.hasAttribute( "newharmonic" + is ) )
  164. {
  165. m_osc[i]->m_harmModel.loadSettings( _this, "newharmonic" + is );
  166. }
  167. else
  168. {
  169. m_osc[i]->m_harmModel.setValue( static_cast<float>( i ) );
  170. }
  171. }
  172. m_volModel.loadSettings( _this, "vol" );
  173. m_fx1Model.loadSettings( _this, "foldback" );
  174. }
  175. QString organicInstrument::nodeName() const
  176. {
  177. return( organic_plugin_descriptor.name );
  178. }
  179. void organicInstrument::playNote( NotePlayHandle * _n,
  180. sampleFrame * _working_buffer )
  181. {
  182. const fpp_t frames = _n->framesLeftForCurrentPeriod();
  183. const f_cnt_t offset = _n->noteOffset();
  184. if( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
  185. {
  186. Oscillator * oscs_l[NUM_OSCILLATORS];
  187. Oscillator * oscs_r[NUM_OSCILLATORS];
  188. _n->m_pluginData = new oscPtr;
  189. for( int i = m_numOscillators - 1; i >= 0; --i )
  190. {
  191. static_cast<oscPtr *>( _n->m_pluginData )->phaseOffsetLeft[i]
  192. = rand() / ( RAND_MAX + 1.0f );
  193. static_cast<oscPtr *>( _n->m_pluginData )->phaseOffsetRight[i]
  194. = rand() / ( RAND_MAX + 1.0f );
  195. // initialise ocillators
  196. if( i == m_numOscillators - 1 )
  197. {
  198. // create left oscillator
  199. oscs_l[i] = new Oscillator(
  200. &m_osc[i]->m_waveShape,
  201. &m_modulationAlgo,
  202. _n->frequency(),
  203. m_osc[i]->m_detuningLeft,
  204. static_cast<oscPtr *>( _n->m_pluginData )->phaseOffsetLeft[i],
  205. m_osc[i]->m_volumeLeft );
  206. // create right oscillator
  207. oscs_r[i] = new Oscillator(
  208. &m_osc[i]->m_waveShape,
  209. &m_modulationAlgo,
  210. _n->frequency(),
  211. m_osc[i]->m_detuningRight,
  212. static_cast<oscPtr *>( _n->m_pluginData )->phaseOffsetRight[i],
  213. m_osc[i]->m_volumeRight );
  214. }
  215. else
  216. {
  217. // create left oscillator
  218. oscs_l[i] = new Oscillator(
  219. &m_osc[i]->m_waveShape,
  220. &m_modulationAlgo,
  221. _n->frequency(),
  222. m_osc[i]->m_detuningLeft,
  223. static_cast<oscPtr *>( _n->m_pluginData )->phaseOffsetLeft[i],
  224. m_osc[i]->m_volumeLeft,
  225. oscs_l[i + 1] );
  226. // create right oscillator
  227. oscs_r[i] = new Oscillator(
  228. &m_osc[i]->m_waveShape,
  229. &m_modulationAlgo,
  230. _n->frequency(),
  231. m_osc[i]->m_detuningRight,
  232. static_cast<oscPtr *>( _n->m_pluginData )->phaseOffsetRight[i],
  233. m_osc[i]->m_volumeRight,
  234. oscs_r[i + 1] );
  235. }
  236. }
  237. static_cast<oscPtr *>( _n->m_pluginData )->oscLeft = oscs_l[0];
  238. static_cast<oscPtr *>( _n->m_pluginData )->oscRight = oscs_r[0];
  239. }
  240. Oscillator * osc_l = static_cast<oscPtr *>( _n->m_pluginData )->oscLeft;
  241. Oscillator * osc_r = static_cast<oscPtr *>( _n->m_pluginData)->oscRight;
  242. osc_l->update( _working_buffer + offset, frames, 0 );
  243. osc_r->update( _working_buffer + offset, frames, 1 );
  244. // -- fx section --
  245. // fxKnob is [0;1]
  246. float t = m_fx1Model.value();
  247. for (int i=0 ; i < frames + offset ; i++)
  248. {
  249. _working_buffer[i][0] = waveshape( _working_buffer[i][0], t ) *
  250. m_volModel.value() / 100.0f;
  251. _working_buffer[i][1] = waveshape( _working_buffer[i][1], t ) *
  252. m_volModel.value() / 100.0f;
  253. }
  254. // -- --
  255. instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
  256. }
  257. void organicInstrument::deleteNotePluginData( NotePlayHandle * _n )
  258. {
  259. delete static_cast<Oscillator *>( static_cast<oscPtr *>(
  260. _n->m_pluginData )->oscLeft );
  261. delete static_cast<Oscillator *>( static_cast<oscPtr *>(
  262. _n->m_pluginData )->oscRight );
  263. delete static_cast<oscPtr *>( _n->m_pluginData );
  264. }
  265. /*float inline organicInstrument::foldback(float in, float threshold)
  266. {
  267. if (in>threshold || in<-threshold)
  268. {
  269. in= fabs(fabs(fmod(in - threshold, threshold*4)) - threshold*2) - threshold;
  270. }
  271. return in;
  272. }
  273. */
  274. float inline organicInstrument::waveshape(float in, float amount)
  275. {
  276. float k = 2.0f * amount / ( 1.0f - amount );
  277. return( ( 1.0f + k ) * in / ( 1.0f + k * fabs( in ) ) );
  278. }
  279. void organicInstrument::randomiseSettings()
  280. {
  281. for( int i = 0; i < m_numOscillators; i++ )
  282. {
  283. m_osc[i]->m_volModel.setValue( intRand( 0, 100 ) );
  284. m_osc[i]->m_detuneModel.setValue( intRand( -5, 5 ) );
  285. m_osc[i]->m_panModel.setValue( 0 );
  286. m_osc[i]->m_oscModel.setValue( intRand( 0, 5 ) );
  287. }
  288. }
  289. void organicInstrument::updateAllDetuning()
  290. {
  291. for( int i = 0; i < m_numOscillators; ++i )
  292. {
  293. m_osc[i]->updateDetuning();
  294. }
  295. }
  296. int organicInstrument::intRand( int min, int max )
  297. {
  298. // int randn = min+int((max-min)*rand()/(RAND_MAX + 1.0));
  299. // cout << randn << endl;
  300. int randn = ( rand() % (max - min) ) + min;
  301. return( randn );
  302. }
  303. PluginView * organicInstrument::instantiateView( QWidget * _parent )
  304. {
  305. return( new organicInstrumentView( this, _parent ) );
  306. }
  307. class organicKnob : public Knob
  308. {
  309. public:
  310. organicKnob( QWidget * _parent ) :
  311. Knob( knobStyled, _parent )
  312. {
  313. setFixedSize( 21, 21 );
  314. }
  315. };
  316. organicInstrumentView::organicInstrumentView( Instrument * _instrument,
  317. QWidget * _parent ) :
  318. InstrumentViewFixedSize( _instrument, _parent ),
  319. m_oscKnobs( nullptr )
  320. {
  321. organicInstrument * oi = castModel<organicInstrument>();
  322. setAutoFillBackground( true );
  323. QPalette pal;
  324. pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
  325. "artwork" ) );
  326. setPalette( pal );
  327. // setup knob for FX1
  328. m_fx1Knob = new organicKnob( this );
  329. m_fx1Knob->move( 15, 201 );
  330. m_fx1Knob->setFixedSize( 37, 47 );
  331. m_fx1Knob->setHintText( tr( "Distortion:" ), QString() );
  332. m_fx1Knob->setObjectName( "fx1Knob" );
  333. // setup volume-knob
  334. m_volKnob = new organicKnob( this );
  335. m_volKnob->setVolumeKnob( true );
  336. m_volKnob->move( 60, 201 );
  337. m_volKnob->setFixedSize( 37, 47 );
  338. m_volKnob->setHintText( tr( "Volume:" ), "%" );
  339. m_volKnob->setObjectName( "volKnob" );
  340. // randomise
  341. m_randBtn = new PixmapButton( this, tr( "Randomise" ) );
  342. m_randBtn->move( 148, 224 );
  343. m_randBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
  344. "randomise_pressed" ) );
  345. m_randBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
  346. "randomise" ) );
  347. connect( m_randBtn, SIGNAL ( clicked() ),
  348. oi, SLOT( randomiseSettings() ) );
  349. if( s_artwork == nullptr )
  350. {
  351. s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap(
  352. "artwork" ) );
  353. }
  354. }
  355. organicInstrumentView::~organicInstrumentView()
  356. {
  357. delete[] m_oscKnobs;
  358. }
  359. void organicInstrumentView::modelChanged()
  360. {
  361. organicInstrument * oi = castModel<organicInstrument>();
  362. const float y=91.0f;
  363. const float rowHeight = 26.0f;
  364. const float x=53.0f;
  365. const float colWidth = 24.0f;
  366. m_numOscillators = oi->m_numOscillators;
  367. m_fx1Knob->setModel( &oi->m_fx1Model );
  368. m_volKnob->setModel( &oi->m_volModel );
  369. if( m_oscKnobs != nullptr )
  370. {
  371. delete[] m_oscKnobs;
  372. }
  373. m_oscKnobs = new OscillatorKnobs[ m_numOscillators ];
  374. // Create knobs, now that we know how many to make
  375. for( int i = 0; i < m_numOscillators; ++i )
  376. {
  377. // setup harmonic knob
  378. Knob * harmKnob = new organicKnob( this );
  379. harmKnob->move( x + i * colWidth, y - rowHeight );
  380. harmKnob->setObjectName( "harmKnob" );
  381. connect( &oi->m_osc[i]->m_harmModel, SIGNAL( dataChanged() ),
  382. this, SLOT( updateKnobHint() ) );
  383. // setup waveform-knob
  384. Knob * oscKnob = new organicKnob( this );
  385. oscKnob->move( x + i * colWidth, y );
  386. connect( &oi->m_osc[i]->m_oscModel, SIGNAL( dataChanged() ),
  387. this, SLOT( updateKnobHint() ) );
  388. oscKnob->setHintText( tr( "Osc %1 waveform:" ).arg( i + 1 ), QString() );
  389. // setup volume-knob
  390. Knob * volKnob = new Knob( knobStyled, this );
  391. volKnob->setVolumeKnob( true );
  392. volKnob->move( x + i * colWidth, y + rowHeight*1 );
  393. volKnob->setFixedSize( 21, 21 );
  394. volKnob->setHintText( tr( "Osc %1 volume:" ).arg(
  395. i + 1 ), "%" );
  396. // setup panning-knob
  397. Knob * panKnob = new organicKnob( this );
  398. panKnob->move( x + i * colWidth, y + rowHeight*2 );
  399. panKnob->setHintText( tr("Osc %1 panning:").arg(
  400. i + 1 ), "" );
  401. // setup knob for fine-detuning
  402. Knob * detuneKnob = new organicKnob( this );
  403. detuneKnob->move( x + i * colWidth, y + rowHeight*3 );
  404. detuneKnob->setHintText( tr( "Osc %1 stereo detuning" ).arg( i + 1 )
  405. , " " +
  406. tr( "cents" ) );
  407. m_oscKnobs[i] = OscillatorKnobs( harmKnob, volKnob, oscKnob, panKnob, detuneKnob );
  408. // Attach to models
  409. m_oscKnobs[i].m_harmKnob->setModel( &oi->m_osc[i]->m_harmModel );
  410. m_oscKnobs[i].m_volKnob->setModel( &oi->m_osc[i]->m_volModel );
  411. m_oscKnobs[i].m_oscKnob->setModel( &oi->m_osc[i]->m_oscModel );
  412. m_oscKnobs[i].m_panKnob->setModel( &oi->m_osc[i]->m_panModel );
  413. m_oscKnobs[i].m_detuneKnob->setModel( &oi->m_osc[i]->m_detuneModel );
  414. }
  415. updateKnobHint();
  416. }
  417. void organicInstrumentView::updateKnobHint()
  418. {
  419. organicInstrument * oi = castModel<organicInstrument>();
  420. for( int i = 0; i < m_numOscillators; ++i )
  421. {
  422. const float harm = oi->m_osc[i]->m_harmModel.value();
  423. const float wave = oi->m_osc[i]->m_oscModel.value();
  424. m_oscKnobs[i].m_harmKnob->setHintText( tr( "Osc %1 harmonic:" ).arg( i + 1 ), " (" +
  425. HARMONIC_NAMES[ static_cast<int>( harm ) ] + ")" );
  426. m_oscKnobs[i].m_oscKnob->setHintText( tr( "Osc %1 waveform:" ).arg( i + 1 ), " (" +
  427. WAVEFORM_NAMES[ static_cast<int>( wave ) ] + ")" );
  428. }
  429. }
  430. OscillatorObject::OscillatorObject( Model * _parent, int _index ) :
  431. Model( _parent ),
  432. m_waveShape( Oscillator::SineWave, 0, Oscillator::NumWaveShapes-1, this ),
  433. m_oscModel( 0.0f, 0.0f, 5.0f, 1.0f,
  434. this, tr( "Osc %1 waveform" ).arg( _index + 1 ) ),
  435. m_harmModel( static_cast<float>( _index ), 0.0f, 17.0f, 1.0f,
  436. this, tr( "Osc %1 harmonic" ).arg( _index + 1 ) ),
  437. m_volModel( 100.0f, 0.0f, 100.0f, 1.0f,
  438. this, tr( "Osc %1 volume" ).arg( _index + 1 ) ),
  439. m_panModel( DefaultPanning, PanningLeft, PanningRight, 1.0f,
  440. this, tr( "Osc %1 panning" ).arg( _index + 1 ) ),
  441. m_detuneModel( 0.0f, -1200.0f, 1200.0f, 1.0f,
  442. this, tr( "Osc %1 fine detuning left" ).arg( _index + 1 ) )
  443. {
  444. }
  445. OscillatorObject::~OscillatorObject()
  446. {
  447. }
  448. void OscillatorObject::oscButtonChanged()
  449. {
  450. static Oscillator::WaveShapes shapes[] =
  451. {
  452. Oscillator::SineWave,
  453. Oscillator::SawWave,
  454. Oscillator::SquareWave,
  455. Oscillator::TriangleWave,
  456. Oscillator::MoogSawWave,
  457. Oscillator::ExponentialWave
  458. } ;
  459. m_waveShape.setValue( shapes[(int)roundf( m_oscModel.value() )] );
  460. }
  461. void OscillatorObject::updateVolume()
  462. {
  463. m_volumeLeft = ( 1.0f - m_panModel.value() / (float)PanningRight )
  464. * m_volModel.value() / m_numOscillators / 100.0f;
  465. m_volumeRight = ( 1.0f + m_panModel.value() / (float)PanningRight )
  466. * m_volModel.value() / m_numOscillators / 100.0f;
  467. }
  468. void OscillatorObject::updateDetuning()
  469. {
  470. m_detuningLeft = powf( 2.0f, organicInstrument::s_harmonics[ static_cast<int>( m_harmModel.value() ) ]
  471. + (float)m_detuneModel.value() * CENT ) /
  472. Engine::audioEngine()->processingSampleRate();
  473. m_detuningRight = powf( 2.0f, organicInstrument::s_harmonics[ static_cast<int>( m_harmModel.value() ) ]
  474. - (float)m_detuneModel.value() * CENT ) /
  475. Engine::audioEngine()->processingSampleRate();
  476. }
  477. extern "C"
  478. {
  479. // necessary for getting instance out of shared lib
  480. PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
  481. {
  482. return( new organicInstrument( static_cast<InstrumentTrack *>( m ) ) );
  483. }
  484. }
  485. /*
  486. * some notes & ideas for the future of this plugin:
  487. *
  488. * - 32.692 Hz in the bass to 5919.85 Hz of treble in a Hammond organ
  489. * => implement harmonic foldback
  490. *
  491. m_osc[i].m_oscModel->setInitValue( 0.0f );
  492. * - randomize preset
  493. */