SidInstrument.cpp 24 KB

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