sid_instrument.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. /*
  2. * sid_instrument.cpp - ResID based software-synthesizer
  3. *
  4. * Copyright (c) 2008 Csaba Hruska <csaba.hruska/at/gmail.com>
  5. * Attila Herman <attila589/at/gmail.com>
  6. *
  7. * This file is part of LMMS - https://lmms.io
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2 of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public
  20. * License along with this program (see COPYING); if not, write to the
  21. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  22. * Boston, MA 02110-1301 USA.
  23. *
  24. */
  25. #include <QPainter>
  26. #include <QDomElement>
  27. #include <cmath>
  28. #include <cstdio>
  29. #include "sid.h"
  30. #include "sid_instrument.h"
  31. #include "Engine.h"
  32. #include "InstrumentTrack.h"
  33. #include "Knob.h"
  34. #include "Mixer.h"
  35. #include "NotePlayHandle.h"
  36. #include "PixmapButton.h"
  37. #include "ToolTip.h"
  38. #include "embed.cpp"
  39. #define C64_PAL_CYCLES_PER_SEC 985248
  40. #define NUMSIDREGS 0x19
  41. #define SIDWRITEDELAY 9 // lda $xxxx,x 4 cycles, sta $d400,x 5 cycles
  42. #define SIDWAVEDELAY 4 // and $xxxx,x 4 cycles extra
  43. unsigned char sidorder[] =
  44. {0x15,0x16,0x18,0x17,
  45. 0x05,0x06,0x02,0x03,0x00,0x01,0x04,
  46. 0x0c,0x0d,0x09,0x0a,0x07,0x08,0x0b,
  47. 0x13,0x14,0x10,0x11,0x0e,0x0f,0x12};
  48. static const char *attackTime[16] = { "2 mS", "8 mS", "16 mS", "24 mS",
  49. "38 mS", "56 mS", "68 mS", "80 mS",
  50. "100 mS", "250 mS", "500 mS", "800 mS",
  51. "1 S", "3 S", "5 S", "8 S" };
  52. static const char *decRelTime[16] = { "6 mS", "24 mS", "48 mS", "72 mS",
  53. "114 mS", "168 mS", "204 mS", "240 mS",
  54. "300 mS", "750 mS", "1.5 S", "2.4 S",
  55. "3 S", "9 S", "15 S", "24 S" };
  56. // release time time in ms
  57. static const int relTime[16] = { 6, 24, 48, 72, 114, 168, 204, 240, 300, 750,
  58. 1500, 2400, 3000, 9000, 15000, 24000 };
  59. extern "C"
  60. {
  61. Plugin::Descriptor PLUGIN_EXPORT sid_plugin_descriptor =
  62. {
  63. STRINGIFY( PLUGIN_NAME ),
  64. "SID",
  65. QT_TRANSLATE_NOOP( "pluginBrowser", "Emulation of the MOS6581 and MOS8580 "
  66. "SID.\nThis chip was used in the Commodore 64 computer." ),
  67. "Csaba Hruska <csaba.hruska/at/gmail.com>"
  68. "Attila Herman <attila589/at/gmail.com>",
  69. 0x0100,
  70. Plugin::Instrument,
  71. new PluginPixmapLoader( "logo" ),
  72. NULL,
  73. NULL
  74. } ;
  75. }
  76. voiceObject::voiceObject( Model * _parent, int _idx ) :
  77. Model( _parent ),
  78. m_pulseWidthModel( 2048.0f, 0.0f, 4095.0f, 1.0f, this,
  79. tr( "Voice %1 pulse width" ).arg( _idx+1 ) ),
  80. m_attackModel( 8.0f, 0.0f, 15.0f, 1.0f, this,
  81. tr( "Voice %1 attack" ).arg( _idx+1 ) ),
  82. m_decayModel( 8.0f, 0.0f, 15.0f, 1.0f, this,
  83. tr( "Voice %1 decay" ).arg( _idx+1 ) ),
  84. m_sustainModel( 15.0f, 0.0f, 15.0f, 1.0f, this,
  85. tr( "Voice %1 sustain" ).arg( _idx+1 ) ),
  86. m_releaseModel( 8.0f, 0.0f, 15.0f, 1.0f, this,
  87. tr( "Voice %1 release" ).arg( _idx+1 ) ),
  88. m_coarseModel( 0.0f, -24.0, 24.0, 1.0f, this,
  89. tr( "Voice %1 coarse detuning" ).arg( _idx+1 ) ),
  90. m_waveFormModel( TriangleWave, 0, NumWaveShapes-1, this,
  91. tr( "Voice %1 wave shape" ).arg( _idx+1 ) ),
  92. m_syncModel( false, this, tr( "Voice %1 sync" ).arg( _idx+1 ) ),
  93. m_ringModModel( false, this, tr( "Voice %1 ring modulate" ).arg( _idx+1 ) ),
  94. m_filteredModel( false, this, tr( "Voice %1 filtered" ).arg( _idx+1 ) ),
  95. m_testModel( false, this, tr( "Voice %1 test" ).arg( _idx+1 ) )
  96. {
  97. }
  98. voiceObject::~voiceObject()
  99. {
  100. }
  101. sidInstrument::sidInstrument( InstrumentTrack * _instrument_track ) :
  102. Instrument( _instrument_track, &sid_plugin_descriptor ),
  103. // filter
  104. m_filterFCModel( 1024.0f, 0.0f, 2047.0f, 1.0f, this, tr( "Cutoff" ) ),
  105. m_filterResonanceModel( 8.0f, 0.0f, 15.0f, 1.0f, this, tr( "Resonance" ) ),
  106. m_filterModeModel( LowPass, 0, NumFilterTypes-1, this, tr( "Filter type" )),
  107. // misc
  108. m_voice3OffModel( false, this, tr( "Voice 3 off" ) ),
  109. m_volumeModel( 15.0f, 0.0f, 15.0f, 1.0f, this, tr( "Volume" ) ),
  110. m_chipModel( sidMOS8580, 0, NumChipModels-1, this, tr( "Chip model" ) )
  111. {
  112. for( int i = 0; i < 3; ++i )
  113. {
  114. m_voice[i] = new voiceObject( this, i );
  115. }
  116. }
  117. sidInstrument::~sidInstrument()
  118. {
  119. }
  120. void sidInstrument::saveSettings( QDomDocument & _doc,
  121. QDomElement & _this )
  122. {
  123. // voices
  124. for( int i = 0; i < 3; ++i )
  125. {
  126. const QString is = QString::number( i );
  127. m_voice[i]->m_pulseWidthModel.saveSettings(
  128. _doc, _this, "pulsewidth" + is );
  129. m_voice[i]->m_attackModel.saveSettings(
  130. _doc, _this, "attack" + is );
  131. m_voice[i]->m_decayModel.saveSettings(
  132. _doc, _this, "decay" + is );
  133. m_voice[i]->m_sustainModel.saveSettings(
  134. _doc, _this, "sustain" + is );
  135. m_voice[i]->m_releaseModel.saveSettings(
  136. _doc, _this, "release" + is );
  137. m_voice[i]->m_coarseModel.saveSettings(
  138. _doc, _this, "coarse" + is );
  139. m_voice[i]->m_waveFormModel.saveSettings(
  140. _doc, _this,"waveform" + is );
  141. m_voice[i]->m_syncModel.saveSettings(
  142. _doc, _this, "sync" + is );
  143. m_voice[i]->m_ringModModel.saveSettings(
  144. _doc, _this, "ringmod" + is );
  145. m_voice[i]->m_filteredModel.saveSettings(
  146. _doc, _this,"filtered" + is );
  147. m_voice[i]->m_testModel.saveSettings(
  148. _doc, _this, "test" + is );
  149. }
  150. // filter
  151. m_filterFCModel.saveSettings( _doc, _this, "filterFC" );
  152. m_filterResonanceModel.saveSettings( _doc, _this, "filterResonance" );
  153. m_filterModeModel.saveSettings( _doc, _this, "filterMode" );
  154. // misc
  155. m_voice3OffModel.saveSettings( _doc, _this, "voice3Off" );
  156. m_volumeModel.saveSettings( _doc, _this, "volume" );
  157. m_chipModel.saveSettings( _doc, _this, "chipModel" );
  158. }
  159. void sidInstrument::loadSettings( const QDomElement & _this )
  160. {
  161. // voices
  162. for( int i = 0; i < 3; ++i )
  163. {
  164. const QString is = QString::number( i );
  165. m_voice[i]->m_pulseWidthModel.loadSettings( _this, "pulsewidth" + is );
  166. m_voice[i]->m_attackModel.loadSettings( _this, "attack" + is );
  167. m_voice[i]->m_decayModel.loadSettings( _this, "decay" + is );
  168. m_voice[i]->m_sustainModel.loadSettings( _this, "sustain" + is );
  169. m_voice[i]->m_releaseModel.loadSettings( _this, "release" + is );
  170. m_voice[i]->m_coarseModel.loadSettings( _this, "coarse" + is );
  171. m_voice[i]->m_waveFormModel.loadSettings( _this, "waveform" + is );
  172. m_voice[i]->m_syncModel.loadSettings( _this, "sync" + is );
  173. m_voice[i]->m_ringModModel.loadSettings( _this, "ringmod" + is );
  174. m_voice[i]->m_filteredModel.loadSettings( _this, "filtered" + is );
  175. m_voice[i]->m_testModel.loadSettings( _this, "test" + is );
  176. }
  177. // filter
  178. m_filterFCModel.loadSettings( _this, "filterFC" );
  179. m_filterResonanceModel.loadSettings( _this, "filterResonance" );
  180. m_filterModeModel.loadSettings( _this, "filterMode" );
  181. // misc
  182. m_voice3OffModel.loadSettings( _this, "voice3Off" );
  183. m_volumeModel.loadSettings( _this, "volume" );
  184. m_chipModel.loadSettings( _this, "chipModel" );
  185. }
  186. QString sidInstrument::nodeName() const
  187. {
  188. return( sid_plugin_descriptor.name );
  189. }
  190. f_cnt_t sidInstrument::desiredReleaseFrames() const
  191. {
  192. const float samplerate = Engine::mixer()->processingSampleRate();
  193. int maxrel = 0;
  194. for( int i = 0 ; i < 3 ; ++i )
  195. {
  196. if( maxrel < m_voice[i]->m_releaseModel.value() )
  197. maxrel = (int)m_voice[i]->m_releaseModel.value();
  198. }
  199. return f_cnt_t( float(relTime[maxrel])*samplerate/1000.0 );
  200. }
  201. static int sid_fillbuffer(unsigned char* sidreg, cSID *sid, int tdelta, short *ptr, int samples)
  202. {
  203. int tdelta2;
  204. int result;
  205. int total = 0;
  206. int c;
  207. // customly added
  208. int residdelay = 0;
  209. int badline = rand() % NUMSIDREGS;
  210. for (c = 0; c < NUMSIDREGS; c++)
  211. {
  212. unsigned char o = sidorder[c];
  213. // Extra delay for loading the waveform (and mt_chngate,x)
  214. if ((o == 4) || (o == 11) || (o == 18))
  215. {
  216. tdelta2 = SIDWAVEDELAY;
  217. result = sid->clock(tdelta2, ptr, samples);
  218. total += result;
  219. ptr += result;
  220. samples -= result;
  221. tdelta -= SIDWAVEDELAY;
  222. }
  223. // Possible random badline delay once per writing
  224. if ((badline == c) && (residdelay))
  225. {
  226. tdelta2 = residdelay;
  227. result = sid->clock(tdelta2, ptr, samples);
  228. total += result;
  229. ptr += result;
  230. samples -= result;
  231. tdelta -= residdelay;
  232. }
  233. sid->write(o, sidreg[o]);
  234. tdelta2 = SIDWRITEDELAY;
  235. result = sid->clock(tdelta2, ptr, samples);
  236. total += result;
  237. ptr += result;
  238. samples -= result;
  239. tdelta -= SIDWRITEDELAY;
  240. }
  241. result = sid->clock(tdelta, ptr, samples);
  242. total += result;
  243. return total;
  244. }
  245. void sidInstrument::playNote( NotePlayHandle * _n,
  246. sampleFrame * _working_buffer )
  247. {
  248. const f_cnt_t tfp = _n->totalFramesPlayed();
  249. const int clockrate = C64_PAL_CYCLES_PER_SEC;
  250. const int samplerate = Engine::mixer()->processingSampleRate();
  251. if ( tfp == 0 )
  252. {
  253. cSID *sid = new cSID();
  254. sid->set_sampling_parameters( clockrate, SAMPLE_FAST, samplerate );
  255. sid->set_chip_model( MOS8580 );
  256. sid->enable_filter( true );
  257. sid->reset();
  258. _n->m_pluginData = sid;
  259. }
  260. const fpp_t frames = _n->framesLeftForCurrentPeriod();
  261. const f_cnt_t offset = _n->noteOffset();
  262. cSID *sid = static_cast<cSID *>( _n->m_pluginData );
  263. int delta_t = clockrate * frames / samplerate + 4;
  264. short buf[frames];
  265. unsigned char sidreg[NUMSIDREGS];
  266. for (int c = 0; c < NUMSIDREGS; c++)
  267. {
  268. sidreg[c] = 0x00;
  269. }
  270. if( (ChipModel)m_chipModel.value() == sidMOS6581 )
  271. {
  272. sid->set_chip_model( MOS6581 );
  273. }
  274. else
  275. {
  276. sid->set_chip_model( MOS8580 );
  277. }
  278. // voices
  279. reg8 data8 = 0;
  280. reg8 data16 = 0;
  281. reg8 base = 0;
  282. float freq = 0.0;
  283. float note = 0.0;
  284. for( reg8 i = 0 ; i < 3 ; ++i )
  285. {
  286. base = i*7;
  287. // freq ( Fn = Fout / Fclk * 16777216 ) + coarse detuning
  288. freq = _n->frequency();
  289. note = 69.0 + 12.0 * log( freq / 440.0 ) / log( 2 );
  290. note += m_voice[i]->m_coarseModel.value();
  291. freq = 440.0 * pow( 2.0, (note-69.0)/12.0 );
  292. data16 = int( freq / float(clockrate) * 16777216.0 );
  293. sidreg[base+0] = data16&0x00FF;
  294. sidreg[base+1] = (data16>>8)&0x00FF;
  295. // pw
  296. data16 = (int)m_voice[i]->m_pulseWidthModel.value();
  297. sidreg[base+2] = data16&0x00FF;
  298. sidreg[base+3] = (data16>>8)&0x000F;
  299. // control: wave form, (test), ringmod, sync, gate
  300. data8 = _n->isReleased()?0:1;
  301. data8 += m_voice[i]->m_syncModel.value()?2:0;
  302. data8 += m_voice[i]->m_ringModModel.value()?4:0;
  303. data8 += m_voice[i]->m_testModel.value()?8:0;
  304. switch( m_voice[i]->m_waveFormModel.value() )
  305. {
  306. default: break;
  307. case voiceObject::NoiseWave: data8 += 128; break;
  308. case voiceObject::SquareWave: data8 += 64; break;
  309. case voiceObject::SawWave: data8 += 32; break;
  310. case voiceObject::TriangleWave: data8 += 16; break;
  311. }
  312. sidreg[base+4] = data8&0x00FF;
  313. // ad
  314. data16 = (int)m_voice[i]->m_attackModel.value();
  315. data8 = (data16&0x0F)<<4;
  316. data16 = (int)m_voice[i]->m_decayModel.value();
  317. data8 += (data16&0x0F);
  318. sidreg[base+5] = data8&0x00FF;
  319. // sr
  320. data16 = (int)m_voice[i]->m_sustainModel.value();
  321. data8 = (data16&0x0F)<<4;
  322. data16 = (int)m_voice[i]->m_releaseModel.value();
  323. data8 += (data16&0x0F);
  324. sidreg[base+6] = data8&0x00FF;
  325. }
  326. // filtered
  327. // FC (FilterCutoff)
  328. data16 = (int)m_filterFCModel.value();
  329. sidreg[21] = data16&0x0007;
  330. sidreg[22] = (data16>>3)&0x00FF;
  331. // res, filt ex,3,2,1
  332. data16 = (int)m_filterResonanceModel.value();
  333. data8 = (data16&0x000F)<<4;
  334. data8 += m_voice[2]->m_filteredModel.value()?4:0;
  335. data8 += m_voice[1]->m_filteredModel.value()?2:0;
  336. data8 += m_voice[0]->m_filteredModel.value()?1:0;
  337. sidreg[23] = data8&0x00FF;
  338. // mode vol
  339. data16 = (int)m_volumeModel.value();
  340. data8 = data16&0x000F;
  341. data8 += m_voice3OffModel.value()?128:0;
  342. switch( m_filterModeModel.value() )
  343. {
  344. default: break;
  345. case LowPass: data8 += 16; break;
  346. case BandPass: data8 += 32; break;
  347. case HighPass: data8 += 64; break;
  348. }
  349. sidreg[24] = data8&0x00FF;
  350. int num = sid_fillbuffer(sidreg, sid,delta_t,buf, frames);
  351. if(num!=frames)
  352. printf("!!!Not enough samples\n");
  353. for( fpp_t frame = 0; frame < frames; ++frame )
  354. {
  355. sample_t s = float(buf[frame])/32768.0;
  356. for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
  357. {
  358. _working_buffer[frame+offset][ch] = s;
  359. }
  360. }
  361. instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
  362. }
  363. void sidInstrument::deleteNotePluginData( NotePlayHandle * _n )
  364. {
  365. delete static_cast<cSID *>( _n->m_pluginData );
  366. }
  367. PluginView * sidInstrument::instantiateView( QWidget * _parent )
  368. {
  369. return( new sidInstrumentView( this, _parent ) );
  370. }
  371. class sidKnob : public Knob
  372. {
  373. public:
  374. sidKnob( QWidget * _parent ) :
  375. Knob( knobStyled, _parent )
  376. {
  377. setFixedSize( 16, 16 );
  378. setCenterPointX( 7.5 );
  379. setCenterPointY( 7.5 );
  380. setInnerRadius( 2 );
  381. setOuterRadius( 8 );
  382. setTotalAngle( 270.0 );
  383. setLineWidth( 2 );
  384. }
  385. };
  386. sidInstrumentView::sidInstrumentView( Instrument * _instrument,
  387. QWidget * _parent ) :
  388. InstrumentView( _instrument, _parent )
  389. {
  390. setAutoFillBackground( true );
  391. QPalette pal;
  392. pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
  393. setPalette( pal );
  394. m_volKnob = new sidKnob( this );
  395. m_volKnob->setHintText( tr( "Volume:" ), "" );
  396. m_volKnob->move( 7, 64 );
  397. m_resKnob = new sidKnob( this );
  398. m_resKnob->setHintText( tr( "Resonance:" ), "" );
  399. m_resKnob->move( 7 + 28, 64 );
  400. m_cutKnob = new sidKnob( this );
  401. m_cutKnob->setHintText( tr( "Cutoff frequency:" ), "Hz" );
  402. m_cutKnob->move( 7 + 2*28, 64 );
  403. PixmapButton * hp_btn = new PixmapButton( this, NULL );
  404. hp_btn->move( 140, 77 );
  405. hp_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "hpred" ) );
  406. hp_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "hp" ) );
  407. ToolTip::add( hp_btn, tr( "High-Pass filter ") );
  408. PixmapButton * bp_btn = new PixmapButton( this, NULL );
  409. bp_btn->move( 164, 77 );
  410. bp_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "bpred" ) );
  411. bp_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "bp" ) );
  412. ToolTip::add( bp_btn, tr( "Band-Pass filter ") );
  413. PixmapButton * lp_btn = new PixmapButton( this, NULL );
  414. lp_btn->move( 185, 77 );
  415. lp_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "lpred" ) );
  416. lp_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "lp" ) );
  417. ToolTip::add( lp_btn, tr( "Low-Pass filter ") );
  418. m_passBtnGrp = new automatableButtonGroup( this );
  419. m_passBtnGrp->addButton( hp_btn );
  420. m_passBtnGrp->addButton( bp_btn );
  421. m_passBtnGrp->addButton( lp_btn );
  422. m_offButton = new PixmapButton( this, NULL );
  423. m_offButton->setCheckable( true );
  424. m_offButton->move( 207, 77 );
  425. m_offButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "3offred" ) );
  426. m_offButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "3off" ) );
  427. ToolTip::add( m_offButton, tr( "Voice3 Off ") );
  428. PixmapButton * mos6581_btn = new PixmapButton( this, NULL );
  429. mos6581_btn->move( 170, 59 );
  430. mos6581_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "6581red" ) );
  431. mos6581_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "6581" ) );
  432. ToolTip::add( mos6581_btn, tr( "MOS6581 SID ") );
  433. PixmapButton * mos8580_btn = new PixmapButton( this, NULL );
  434. mos8580_btn->move( 207, 59 );
  435. mos8580_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "8580red" ) );
  436. mos8580_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "8580" ) );
  437. ToolTip::add( mos8580_btn, tr( "MOS8580 SID ") );
  438. m_sidTypeBtnGrp = new automatableButtonGroup( this );
  439. m_sidTypeBtnGrp->addButton( mos6581_btn );
  440. m_sidTypeBtnGrp->addButton( mos8580_btn );
  441. for( int i = 0; i < 3; i++ )
  442. {
  443. Knob *ak = new sidKnob( this );
  444. ak->setHintText( tr("Attack:"), "" );
  445. ak->move( 7, 114 + i*50 );
  446. ak->setWhatsThis( tr ( "Attack rate determines how rapidly the output "
  447. "of Voice %1 rises from zero to peak amplitude." ).arg( i+1 ) );
  448. Knob *dk = new sidKnob( this );
  449. dk->setHintText( tr("Decay:") , "" );
  450. dk->move( 7 + 28, 114 + i*50 );
  451. dk->setWhatsThis( tr ( "Decay rate determines how rapidly the output "
  452. "falls from the peak amplitude to the selected Sustain level." ) );
  453. Knob *sk = new sidKnob( this );
  454. sk->setHintText( tr("Sustain:"), "" );
  455. sk->move( 7 + 2*28, 114 + i*50 );
  456. sk->setWhatsThis( tr ( "Output of Voice %1 will remain at the selected "
  457. "Sustain amplitude as long as the note is held." ).arg( i+1 ) );
  458. Knob *rk = new sidKnob( this );
  459. rk->setHintText( tr("Release:"), "" );
  460. rk->move( 7 + 3*28, 114 + i*50 );
  461. rk->setWhatsThis( tr ( "The output of of Voice %1 will fall from "
  462. "Sustain amplitude to zero amplitude at the selected Release "
  463. "rate." ).arg( i+1 ) );
  464. Knob *pwk = new sidKnob( this );
  465. pwk->setHintText( tr("Pulse Width:"), "" );
  466. pwk->move( 7 + 4*28, 114 + i*50 );
  467. pwk->setWhatsThis( tr ( "The Pulse Width resolution allows the width "
  468. "to be smoothly swept with no discernable stepping. The Pulse "
  469. "waveform on Oscillator %1 must be selected to have any audible"
  470. " effect." ).arg( i+1 ) );
  471. Knob *crsk = new sidKnob( this );
  472. crsk->setHintText( tr("Coarse:"), " semitones" );
  473. crsk->move( 147, 114 + i*50 );
  474. crsk->setWhatsThis( tr ( "The Coarse detuning allows to detune Voice "
  475. "%1 one octave up or down." ).arg( i+1 ) );
  476. PixmapButton * pulse_btn = new PixmapButton( this, NULL );
  477. pulse_btn->move( 187, 101 + i*50 );
  478. pulse_btn->setActiveGraphic(
  479. PLUGIN_NAME::getIconPixmap( "pulsered" ) );
  480. pulse_btn->setInactiveGraphic(
  481. PLUGIN_NAME::getIconPixmap( "pulse" ) );
  482. ToolTip::add( pulse_btn, tr( "Pulse Wave" ) );
  483. PixmapButton * triangle_btn = new PixmapButton( this, NULL );
  484. triangle_btn->move( 168, 101 + i*50 );
  485. triangle_btn->setActiveGraphic(
  486. PLUGIN_NAME::getIconPixmap( "trianglered" ) );
  487. triangle_btn->setInactiveGraphic(
  488. PLUGIN_NAME::getIconPixmap( "triangle" ) );
  489. ToolTip::add( triangle_btn, tr( "Triangle Wave" ) );
  490. PixmapButton * saw_btn = new PixmapButton( this, NULL );
  491. saw_btn->move( 207, 101 + i*50 );
  492. saw_btn->setActiveGraphic(
  493. PLUGIN_NAME::getIconPixmap( "sawred" ) );
  494. saw_btn->setInactiveGraphic(
  495. PLUGIN_NAME::getIconPixmap( "saw" ) );
  496. ToolTip::add( saw_btn, tr( "SawTooth" ) );
  497. PixmapButton * noise_btn = new PixmapButton( this, NULL );
  498. noise_btn->move( 226, 101 + i*50 );
  499. noise_btn->setActiveGraphic(
  500. PLUGIN_NAME::getIconPixmap( "noisered" ) );
  501. noise_btn->setInactiveGraphic(
  502. PLUGIN_NAME::getIconPixmap( "noise" ) );
  503. ToolTip::add( noise_btn, tr( "Noise" ) );
  504. automatableButtonGroup * wfbg =
  505. new automatableButtonGroup( this );
  506. wfbg->addButton( pulse_btn );
  507. wfbg->addButton( triangle_btn );
  508. wfbg->addButton( saw_btn );
  509. wfbg->addButton( noise_btn );
  510. int syncRingWidth[] = { 3, 1, 2 };
  511. PixmapButton * sync_btn = new PixmapButton( this, NULL );
  512. sync_btn->setCheckable( true );
  513. sync_btn->move( 207, 134 + i*50 );
  514. sync_btn->setActiveGraphic(
  515. PLUGIN_NAME::getIconPixmap( "syncred" ) );
  516. sync_btn->setInactiveGraphic(
  517. PLUGIN_NAME::getIconPixmap( "sync" ) );
  518. ToolTip::add( sync_btn, tr( "Sync" ) );
  519. sync_btn->setWhatsThis( tr ( "Sync synchronizes the fundamental "
  520. "frequency of Oscillator %1 with the fundamental frequency of "
  521. "Oscillator %2 producing \"Hard Sync\" effects." ).arg( i+1 )
  522. .arg( syncRingWidth[i] ) );
  523. PixmapButton * ringMod_btn = new PixmapButton( this, NULL );
  524. ringMod_btn->setCheckable( true );
  525. ringMod_btn->move( 170, 116 + i*50 );
  526. ringMod_btn->setActiveGraphic(
  527. PLUGIN_NAME::getIconPixmap( "ringred" ) );
  528. ringMod_btn->setInactiveGraphic(
  529. PLUGIN_NAME::getIconPixmap( "ring" ) );
  530. ToolTip::add( ringMod_btn, tr( "Ring-Mod" ) );
  531. ringMod_btn->setWhatsThis( tr ( "Ring-mod replaces the Triangle "
  532. "Waveform output of Oscillator %1 with a \"Ring Modulated\" "
  533. "combination of Oscillators %1 and %2." ).arg( i+1 )
  534. .arg( syncRingWidth[i] ) );
  535. PixmapButton * filter_btn = new PixmapButton( this, NULL );
  536. filter_btn->setCheckable( true );
  537. filter_btn->move( 207, 116 + i*50 );
  538. filter_btn->setActiveGraphic(
  539. PLUGIN_NAME::getIconPixmap( "filterred" ) );
  540. filter_btn->setInactiveGraphic(
  541. PLUGIN_NAME::getIconPixmap( "filter" ) );
  542. ToolTip::add( filter_btn, tr( "Filtered" ) );
  543. filter_btn->setWhatsThis( tr ( "When Filtered is on, Voice %1 will be "
  544. "processed through the Filter. When Filtered is off, Voice %1 "
  545. "appears directly at the output, and the Filter has no effect on "
  546. "it." ).arg( i+1 ) );
  547. PixmapButton * test_btn = new PixmapButton( this, NULL );
  548. test_btn->setCheckable( true );
  549. test_btn->move( 170, 134 + i*50 );
  550. test_btn->setActiveGraphic(
  551. PLUGIN_NAME::getIconPixmap( "testred" ) );
  552. test_btn->setInactiveGraphic(
  553. PLUGIN_NAME::getIconPixmap( "test" ) );
  554. ToolTip::add( test_btn, tr( "Test" ) );
  555. test_btn->setWhatsThis( tr ( "Test, when set, resets and locks "
  556. "Oscillator %1 at zero until Test is turned off." ).arg( i+1 ) );
  557. m_voiceKnobs[i] = voiceKnobs( ak, dk, sk, rk, pwk, crsk, wfbg,
  558. sync_btn, ringMod_btn, filter_btn, test_btn );
  559. }
  560. }
  561. sidInstrumentView::~sidInstrumentView()
  562. {
  563. }
  564. void sidInstrumentView::updateKnobHint()
  565. {
  566. sidInstrument * k = castModel<sidInstrument>();
  567. for( int i = 0; i < 3; ++i )
  568. {
  569. m_voiceKnobs[i].m_attKnob->setHintText( tr( "Attack:" ) + " ", " (" +
  570. QString::fromLatin1( attackTime[(int)k->m_voice[i]->
  571. m_attackModel.value()] ) + ")" );
  572. ToolTip::add( m_voiceKnobs[i].m_attKnob,
  573. attackTime[(int)k->m_voice[i]->m_attackModel.value()] );
  574. m_voiceKnobs[i].m_decKnob->setHintText( tr( "Decay:" ) + " ", " (" +
  575. QString::fromLatin1( decRelTime[(int)k->m_voice[i]->
  576. m_decayModel.value()] ) + ")" );
  577. ToolTip::add( m_voiceKnobs[i].m_decKnob,
  578. decRelTime[(int)k->m_voice[i]->m_decayModel.value()] );
  579. m_voiceKnobs[i].m_relKnob->setHintText( tr( "Release:" ) + " ", " (" +
  580. QString::fromLatin1( decRelTime[(int)k->m_voice[i]->
  581. m_releaseModel.value()] ) + ")" );
  582. ToolTip::add( m_voiceKnobs[i].m_relKnob,
  583. decRelTime[(int)k->m_voice[i]->m_releaseModel.value()]);
  584. m_voiceKnobs[i].m_pwKnob->setHintText( tr( "Pulse Width:" )+ " ", " (" +
  585. QString::number( (double)k->m_voice[i]->
  586. m_pulseWidthModel.value() / 40.95 ) + "%)" );
  587. ToolTip::add( m_voiceKnobs[i].m_pwKnob,
  588. QString::number( (double)k->m_voice[i]->
  589. m_pulseWidthModel.value() / 40.95 ) + "%" );
  590. }
  591. m_cutKnob->setHintText( tr( "Cutoff frequency:" ) + " ", " (" +
  592. QString::number ( (int) ( 9970.0 / 2047.0 *
  593. (double)k->m_filterFCModel.value() + 30.0 ) ) + "Hz)" );
  594. ToolTip::add( m_cutKnob, QString::number( (int) ( 9970.0 / 2047.0 *
  595. (double)k->m_filterFCModel.value() + 30.0 ) ) + "Hz" );
  596. }
  597. void sidInstrumentView::updateKnobToolTip()
  598. {
  599. sidInstrument * k = castModel<sidInstrument>();
  600. for( int i = 0; i < 3; ++i )
  601. {
  602. ToolTip::add( m_voiceKnobs[i].m_sustKnob,
  603. QString::number( (int)k->m_voice[i]->m_sustainModel.value() ) );
  604. ToolTip::add( m_voiceKnobs[i].m_crsKnob,
  605. QString::number( (int)k->m_voice[i]->m_coarseModel.value() ) +
  606. " semitones" );
  607. }
  608. ToolTip::add( m_volKnob,
  609. QString::number( (int)k->m_volumeModel.value() ) );
  610. ToolTip::add( m_resKnob,
  611. QString::number( (int)k->m_filterResonanceModel.value() ) );
  612. }
  613. void sidInstrumentView::modelChanged()
  614. {
  615. sidInstrument * k = castModel<sidInstrument>();
  616. m_volKnob->setModel( &k->m_volumeModel );
  617. m_resKnob->setModel( &k->m_filterResonanceModel );
  618. m_cutKnob->setModel( &k->m_filterFCModel );
  619. m_passBtnGrp->setModel( &k->m_filterModeModel );
  620. m_offButton->setModel( &k->m_voice3OffModel );
  621. m_sidTypeBtnGrp->setModel( &k->m_chipModel );
  622. for( int i = 0; i < 3; ++i )
  623. {
  624. m_voiceKnobs[i].m_attKnob->setModel(
  625. &k->m_voice[i]->m_attackModel );
  626. m_voiceKnobs[i].m_decKnob->setModel(
  627. &k->m_voice[i]->m_decayModel );
  628. m_voiceKnobs[i].m_sustKnob->setModel(
  629. &k->m_voice[i]->m_sustainModel );
  630. m_voiceKnobs[i].m_relKnob->setModel(
  631. &k->m_voice[i]->m_releaseModel );
  632. m_voiceKnobs[i].m_pwKnob->setModel(
  633. &k->m_voice[i]->m_pulseWidthModel );
  634. m_voiceKnobs[i].m_crsKnob->setModel(
  635. &k->m_voice[i]->m_coarseModel );
  636. m_voiceKnobs[i].m_waveFormBtnGrp->setModel(
  637. &k->m_voice[i]->m_waveFormModel );
  638. m_voiceKnobs[i].m_syncButton->setModel(
  639. &k->m_voice[i]->m_syncModel );
  640. m_voiceKnobs[i].m_ringModButton->setModel(
  641. &k->m_voice[i]->m_ringModModel );
  642. m_voiceKnobs[i].m_filterButton->setModel(
  643. &k->m_voice[i]->m_filteredModel );
  644. m_voiceKnobs[i].m_testButton->setModel(
  645. &k->m_voice[i]->m_testModel );
  646. }
  647. for( int i = 0; i < 3; ++i )
  648. {
  649. connect( &k->m_voice[i]->m_attackModel, SIGNAL( dataChanged() ),
  650. this, SLOT( updateKnobHint() ) );
  651. connect( &k->m_voice[i]->m_decayModel, SIGNAL( dataChanged() ),
  652. this, SLOT( updateKnobHint() ) );
  653. connect( &k->m_voice[i]->m_releaseModel, SIGNAL( dataChanged() ),
  654. this, SLOT( updateKnobHint() ) );
  655. connect( &k->m_voice[i]->m_pulseWidthModel, SIGNAL( dataChanged() ),
  656. this, SLOT( updateKnobHint() ) );
  657. connect( &k->m_voice[i]->m_sustainModel, SIGNAL( dataChanged() ),
  658. this, SLOT( updateKnobToolTip() ) );
  659. connect( &k->m_voice[i]->m_coarseModel, SIGNAL( dataChanged() ),
  660. this, SLOT( updateKnobToolTip() ) );
  661. }
  662. connect( &k->m_volumeModel, SIGNAL( dataChanged() ),
  663. this, SLOT( updateKnobToolTip() ) );
  664. connect( &k->m_filterResonanceModel, SIGNAL( dataChanged() ),
  665. this, SLOT( updateKnobToolTip() ) );
  666. connect( &k->m_filterFCModel, SIGNAL( dataChanged() ),
  667. this, SLOT( updateKnobHint() ) );
  668. updateKnobHint();
  669. updateKnobToolTip();
  670. }
  671. extern "C"
  672. {
  673. // necessary for getting instance out of shared lib
  674. Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
  675. {
  676. return( new sidInstrument(
  677. static_cast<InstrumentTrack *>( _data ) ) );
  678. }
  679. }