123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- /*
- * sid_instrument.cpp - ResID based software-synthesizer
- *
- * Copyright (c) 2008 Csaba Hruska <csaba.hruska/at/gmail.com>
- * Attila Herman <attila589/at/gmail.com>
- *
- * This file is part of LMMS - https://lmms.io
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program (see COPYING); if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- */
- #include <QPainter>
- #include <QDomElement>
- #include <cmath>
- #include <cstdio>
- #include "sid.h"
- #include "sid_instrument.h"
- #include "Engine.h"
- #include "InstrumentTrack.h"
- #include "Knob.h"
- #include "Mixer.h"
- #include "NotePlayHandle.h"
- #include "PixmapButton.h"
- #include "ToolTip.h"
- #include "embed.cpp"
- #define C64_PAL_CYCLES_PER_SEC 985248
- #define NUMSIDREGS 0x19
- #define SIDWRITEDELAY 9 // lda $xxxx,x 4 cycles, sta $d400,x 5 cycles
- #define SIDWAVEDELAY 4 // and $xxxx,x 4 cycles extra
- unsigned char sidorder[] =
- {0x15,0x16,0x18,0x17,
- 0x05,0x06,0x02,0x03,0x00,0x01,0x04,
- 0x0c,0x0d,0x09,0x0a,0x07,0x08,0x0b,
- 0x13,0x14,0x10,0x11,0x0e,0x0f,0x12};
- static const char *attackTime[16] = { "2 mS", "8 mS", "16 mS", "24 mS",
- "38 mS", "56 mS", "68 mS", "80 mS",
- "100 mS", "250 mS", "500 mS", "800 mS",
- "1 S", "3 S", "5 S", "8 S" };
- static const char *decRelTime[16] = { "6 mS", "24 mS", "48 mS", "72 mS",
- "114 mS", "168 mS", "204 mS", "240 mS",
- "300 mS", "750 mS", "1.5 S", "2.4 S",
- "3 S", "9 S", "15 S", "24 S" };
- // release time time in ms
- static const int relTime[16] = { 6, 24, 48, 72, 114, 168, 204, 240, 300, 750,
- 1500, 2400, 3000, 9000, 15000, 24000 };
- extern "C"
- {
- Plugin::Descriptor PLUGIN_EXPORT sid_plugin_descriptor =
- {
- STRINGIFY( PLUGIN_NAME ),
- "SID",
- QT_TRANSLATE_NOOP( "pluginBrowser", "Emulation of the MOS6581 and MOS8580 "
- "SID.\nThis chip was used in the Commodore 64 computer." ),
- "Csaba Hruska <csaba.hruska/at/gmail.com>"
- "Attila Herman <attila589/at/gmail.com>",
- 0x0100,
- Plugin::Instrument,
- new PluginPixmapLoader( "logo" ),
- NULL,
- NULL
- } ;
- }
- voiceObject::voiceObject( Model * _parent, int _idx ) :
- Model( _parent ),
- m_pulseWidthModel( 2048.0f, 0.0f, 4095.0f, 1.0f, this,
- tr( "Voice %1 pulse width" ).arg( _idx+1 ) ),
- m_attackModel( 8.0f, 0.0f, 15.0f, 1.0f, this,
- tr( "Voice %1 attack" ).arg( _idx+1 ) ),
- m_decayModel( 8.0f, 0.0f, 15.0f, 1.0f, this,
- tr( "Voice %1 decay" ).arg( _idx+1 ) ),
- m_sustainModel( 15.0f, 0.0f, 15.0f, 1.0f, this,
- tr( "Voice %1 sustain" ).arg( _idx+1 ) ),
- m_releaseModel( 8.0f, 0.0f, 15.0f, 1.0f, this,
- tr( "Voice %1 release" ).arg( _idx+1 ) ),
- m_coarseModel( 0.0f, -24.0, 24.0, 1.0f, this,
- tr( "Voice %1 coarse detuning" ).arg( _idx+1 ) ),
- m_waveFormModel( TriangleWave, 0, NumWaveShapes-1, this,
- tr( "Voice %1 wave shape" ).arg( _idx+1 ) ),
- m_syncModel( false, this, tr( "Voice %1 sync" ).arg( _idx+1 ) ),
- m_ringModModel( false, this, tr( "Voice %1 ring modulate" ).arg( _idx+1 ) ),
- m_filteredModel( false, this, tr( "Voice %1 filtered" ).arg( _idx+1 ) ),
- m_testModel( false, this, tr( "Voice %1 test" ).arg( _idx+1 ) )
- {
- }
- voiceObject::~voiceObject()
- {
- }
- sidInstrument::sidInstrument( InstrumentTrack * _instrument_track ) :
- Instrument( _instrument_track, &sid_plugin_descriptor ),
- // filter
- m_filterFCModel( 1024.0f, 0.0f, 2047.0f, 1.0f, this, tr( "Cutoff" ) ),
- m_filterResonanceModel( 8.0f, 0.0f, 15.0f, 1.0f, this, tr( "Resonance" ) ),
- m_filterModeModel( LowPass, 0, NumFilterTypes-1, this, tr( "Filter type" )),
-
- // misc
- m_voice3OffModel( false, this, tr( "Voice 3 off" ) ),
- m_volumeModel( 15.0f, 0.0f, 15.0f, 1.0f, this, tr( "Volume" ) ),
- m_chipModel( sidMOS8580, 0, NumChipModels-1, this, tr( "Chip model" ) )
- {
- for( int i = 0; i < 3; ++i )
- {
- m_voice[i] = new voiceObject( this, i );
- }
- }
- sidInstrument::~sidInstrument()
- {
- }
- void sidInstrument::saveSettings( QDomDocument & _doc,
- QDomElement & _this )
- {
- // voices
- for( int i = 0; i < 3; ++i )
- {
- const QString is = QString::number( i );
- m_voice[i]->m_pulseWidthModel.saveSettings(
- _doc, _this, "pulsewidth" + is );
- m_voice[i]->m_attackModel.saveSettings(
- _doc, _this, "attack" + is );
- m_voice[i]->m_decayModel.saveSettings(
- _doc, _this, "decay" + is );
- m_voice[i]->m_sustainModel.saveSettings(
- _doc, _this, "sustain" + is );
- m_voice[i]->m_releaseModel.saveSettings(
- _doc, _this, "release" + is );
- m_voice[i]->m_coarseModel.saveSettings(
- _doc, _this, "coarse" + is );
- m_voice[i]->m_waveFormModel.saveSettings(
- _doc, _this,"waveform" + is );
- m_voice[i]->m_syncModel.saveSettings(
- _doc, _this, "sync" + is );
- m_voice[i]->m_ringModModel.saveSettings(
- _doc, _this, "ringmod" + is );
- m_voice[i]->m_filteredModel.saveSettings(
- _doc, _this,"filtered" + is );
- m_voice[i]->m_testModel.saveSettings(
- _doc, _this, "test" + is );
- }
- // filter
- m_filterFCModel.saveSettings( _doc, _this, "filterFC" );
- m_filterResonanceModel.saveSettings( _doc, _this, "filterResonance" );
- m_filterModeModel.saveSettings( _doc, _this, "filterMode" );
-
- // misc
- m_voice3OffModel.saveSettings( _doc, _this, "voice3Off" );
- m_volumeModel.saveSettings( _doc, _this, "volume" );
- m_chipModel.saveSettings( _doc, _this, "chipModel" );
- }
- void sidInstrument::loadSettings( const QDomElement & _this )
- {
- // voices
- for( int i = 0; i < 3; ++i )
- {
- const QString is = QString::number( i );
- m_voice[i]->m_pulseWidthModel.loadSettings( _this, "pulsewidth" + is );
- m_voice[i]->m_attackModel.loadSettings( _this, "attack" + is );
- m_voice[i]->m_decayModel.loadSettings( _this, "decay" + is );
- m_voice[i]->m_sustainModel.loadSettings( _this, "sustain" + is );
- m_voice[i]->m_releaseModel.loadSettings( _this, "release" + is );
- m_voice[i]->m_coarseModel.loadSettings( _this, "coarse" + is );
- m_voice[i]->m_waveFormModel.loadSettings( _this, "waveform" + is );
- m_voice[i]->m_syncModel.loadSettings( _this, "sync" + is );
- m_voice[i]->m_ringModModel.loadSettings( _this, "ringmod" + is );
- m_voice[i]->m_filteredModel.loadSettings( _this, "filtered" + is );
- m_voice[i]->m_testModel.loadSettings( _this, "test" + is );
- }
-
- // filter
- m_filterFCModel.loadSettings( _this, "filterFC" );
- m_filterResonanceModel.loadSettings( _this, "filterResonance" );
- m_filterModeModel.loadSettings( _this, "filterMode" );
-
- // misc
- m_voice3OffModel.loadSettings( _this, "voice3Off" );
- m_volumeModel.loadSettings( _this, "volume" );
- m_chipModel.loadSettings( _this, "chipModel" );
- }
- QString sidInstrument::nodeName() const
- {
- return( sid_plugin_descriptor.name );
- }
- f_cnt_t sidInstrument::desiredReleaseFrames() const
- {
- const float samplerate = Engine::mixer()->processingSampleRate();
- int maxrel = 0;
- for( int i = 0 ; i < 3 ; ++i )
- {
- if( maxrel < m_voice[i]->m_releaseModel.value() )
- maxrel = (int)m_voice[i]->m_releaseModel.value();
- }
- return f_cnt_t( float(relTime[maxrel])*samplerate/1000.0 );
- }
- static int sid_fillbuffer(unsigned char* sidreg, cSID *sid, int tdelta, short *ptr, int samples)
- {
- int tdelta2;
- int result;
- int total = 0;
- int c;
- // customly added
- int residdelay = 0;
- int badline = rand() % NUMSIDREGS;
- for (c = 0; c < NUMSIDREGS; c++)
- {
- unsigned char o = sidorder[c];
- // Extra delay for loading the waveform (and mt_chngate,x)
- if ((o == 4) || (o == 11) || (o == 18))
- {
- tdelta2 = SIDWAVEDELAY;
- result = sid->clock(tdelta2, ptr, samples);
- total += result;
- ptr += result;
- samples -= result;
- tdelta -= SIDWAVEDELAY;
- }
- // Possible random badline delay once per writing
- if ((badline == c) && (residdelay))
- {
- tdelta2 = residdelay;
- result = sid->clock(tdelta2, ptr, samples);
- total += result;
- ptr += result;
- samples -= result;
- tdelta -= residdelay;
- }
- sid->write(o, sidreg[o]);
- tdelta2 = SIDWRITEDELAY;
- result = sid->clock(tdelta2, ptr, samples);
- total += result;
- ptr += result;
- samples -= result;
- tdelta -= SIDWRITEDELAY;
- }
- result = sid->clock(tdelta, ptr, samples);
- total += result;
- return total;
- }
- void sidInstrument::playNote( NotePlayHandle * _n,
- sampleFrame * _working_buffer )
- {
- const f_cnt_t tfp = _n->totalFramesPlayed();
- const int clockrate = C64_PAL_CYCLES_PER_SEC;
- const int samplerate = Engine::mixer()->processingSampleRate();
- if ( tfp == 0 )
- {
- cSID *sid = new cSID();
- sid->set_sampling_parameters( clockrate, SAMPLE_FAST, samplerate );
- sid->set_chip_model( MOS8580 );
- sid->enable_filter( true );
- sid->reset();
- _n->m_pluginData = sid;
- }
- const fpp_t frames = _n->framesLeftForCurrentPeriod();
- const f_cnt_t offset = _n->noteOffset();
- cSID *sid = static_cast<cSID *>( _n->m_pluginData );
- int delta_t = clockrate * frames / samplerate + 4;
- short buf[frames];
- unsigned char sidreg[NUMSIDREGS];
- for (int c = 0; c < NUMSIDREGS; c++)
- {
- sidreg[c] = 0x00;
- }
- if( (ChipModel)m_chipModel.value() == sidMOS6581 )
- {
- sid->set_chip_model( MOS6581 );
- }
- else
- {
- sid->set_chip_model( MOS8580 );
- }
- // voices
- reg8 data8 = 0;
- reg8 data16 = 0;
- reg8 base = 0;
- float freq = 0.0;
- float note = 0.0;
- for( reg8 i = 0 ; i < 3 ; ++i )
- {
- base = i*7;
- // freq ( Fn = Fout / Fclk * 16777216 ) + coarse detuning
- freq = _n->frequency();
- note = 69.0 + 12.0 * log( freq / 440.0 ) / log( 2 );
- note += m_voice[i]->m_coarseModel.value();
- freq = 440.0 * pow( 2.0, (note-69.0)/12.0 );
- data16 = int( freq / float(clockrate) * 16777216.0 );
- sidreg[base+0] = data16&0x00FF;
- sidreg[base+1] = (data16>>8)&0x00FF;
- // pw
- data16 = (int)m_voice[i]->m_pulseWidthModel.value();
-
- sidreg[base+2] = data16&0x00FF;
- sidreg[base+3] = (data16>>8)&0x000F;
- // control: wave form, (test), ringmod, sync, gate
- data8 = _n->isReleased()?0:1;
- data8 += m_voice[i]->m_syncModel.value()?2:0;
- data8 += m_voice[i]->m_ringModModel.value()?4:0;
- data8 += m_voice[i]->m_testModel.value()?8:0;
- switch( m_voice[i]->m_waveFormModel.value() )
- {
- default: break;
- case voiceObject::NoiseWave: data8 += 128; break;
- case voiceObject::SquareWave: data8 += 64; break;
- case voiceObject::SawWave: data8 += 32; break;
- case voiceObject::TriangleWave: data8 += 16; break;
- }
- sidreg[base+4] = data8&0x00FF;
- // ad
- data16 = (int)m_voice[i]->m_attackModel.value();
- data8 = (data16&0x0F)<<4;
- data16 = (int)m_voice[i]->m_decayModel.value();
- data8 += (data16&0x0F);
- sidreg[base+5] = data8&0x00FF;
- // sr
- data16 = (int)m_voice[i]->m_sustainModel.value();
- data8 = (data16&0x0F)<<4;
- data16 = (int)m_voice[i]->m_releaseModel.value();
- data8 += (data16&0x0F);
- sidreg[base+6] = data8&0x00FF;
- }
- // filtered
- // FC (FilterCutoff)
- data16 = (int)m_filterFCModel.value();
- sidreg[21] = data16&0x0007;
- sidreg[22] = (data16>>3)&0x00FF;
-
- // res, filt ex,3,2,1
- data16 = (int)m_filterResonanceModel.value();
- data8 = (data16&0x000F)<<4;
- data8 += m_voice[2]->m_filteredModel.value()?4:0;
- data8 += m_voice[1]->m_filteredModel.value()?2:0;
- data8 += m_voice[0]->m_filteredModel.value()?1:0;
- sidreg[23] = data8&0x00FF;
- // mode vol
- data16 = (int)m_volumeModel.value();
- data8 = data16&0x000F;
- data8 += m_voice3OffModel.value()?128:0;
- switch( m_filterModeModel.value() )
- {
- default: break;
- case LowPass: data8 += 16; break;
- case BandPass: data8 += 32; break;
- case HighPass: data8 += 64; break;
- }
- sidreg[24] = data8&0x00FF;
-
- int num = sid_fillbuffer(sidreg, sid,delta_t,buf, frames);
- if(num!=frames)
- printf("!!!Not enough samples\n");
- for( fpp_t frame = 0; frame < frames; ++frame )
- {
- sample_t s = float(buf[frame])/32768.0;
- for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
- {
- _working_buffer[frame+offset][ch] = s;
- }
- }
- instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
- }
- void sidInstrument::deleteNotePluginData( NotePlayHandle * _n )
- {
- delete static_cast<cSID *>( _n->m_pluginData );
- }
- PluginView * sidInstrument::instantiateView( QWidget * _parent )
- {
- return( new sidInstrumentView( this, _parent ) );
- }
- class sidKnob : public Knob
- {
- public:
- sidKnob( QWidget * _parent ) :
- Knob( knobStyled, _parent )
- {
- setFixedSize( 16, 16 );
- setCenterPointX( 7.5 );
- setCenterPointY( 7.5 );
- setInnerRadius( 2 );
- setOuterRadius( 8 );
- setTotalAngle( 270.0 );
- setLineWidth( 2 );
- }
- };
- sidInstrumentView::sidInstrumentView( Instrument * _instrument,
- QWidget * _parent ) :
- InstrumentView( _instrument, _parent )
- {
- setAutoFillBackground( true );
- QPalette pal;
- pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
- setPalette( pal );
- m_volKnob = new sidKnob( this );
- m_volKnob->setHintText( tr( "Volume:" ), "" );
- m_volKnob->move( 7, 64 );
- m_resKnob = new sidKnob( this );
- m_resKnob->setHintText( tr( "Resonance:" ), "" );
- m_resKnob->move( 7 + 28, 64 );
- m_cutKnob = new sidKnob( this );
- m_cutKnob->setHintText( tr( "Cutoff frequency:" ), "Hz" );
- m_cutKnob->move( 7 + 2*28, 64 );
- PixmapButton * hp_btn = new PixmapButton( this, NULL );
- hp_btn->move( 140, 77 );
- hp_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "hpred" ) );
- hp_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "hp" ) );
- ToolTip::add( hp_btn, tr( "High-Pass filter ") );
- PixmapButton * bp_btn = new PixmapButton( this, NULL );
- bp_btn->move( 164, 77 );
- bp_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "bpred" ) );
- bp_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "bp" ) );
- ToolTip::add( bp_btn, tr( "Band-Pass filter ") );
- PixmapButton * lp_btn = new PixmapButton( this, NULL );
- lp_btn->move( 185, 77 );
- lp_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "lpred" ) );
- lp_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "lp" ) );
- ToolTip::add( lp_btn, tr( "Low-Pass filter ") );
- m_passBtnGrp = new automatableButtonGroup( this );
- m_passBtnGrp->addButton( hp_btn );
- m_passBtnGrp->addButton( bp_btn );
- m_passBtnGrp->addButton( lp_btn );
- m_offButton = new PixmapButton( this, NULL );
- m_offButton->setCheckable( true );
- m_offButton->move( 207, 77 );
- m_offButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "3offred" ) );
- m_offButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "3off" ) );
- ToolTip::add( m_offButton, tr( "Voice3 Off ") );
- PixmapButton * mos6581_btn = new PixmapButton( this, NULL );
- mos6581_btn->move( 170, 59 );
- mos6581_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "6581red" ) );
- mos6581_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "6581" ) );
- ToolTip::add( mos6581_btn, tr( "MOS6581 SID ") );
- PixmapButton * mos8580_btn = new PixmapButton( this, NULL );
- mos8580_btn->move( 207, 59 );
- mos8580_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "8580red" ) );
- mos8580_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "8580" ) );
- ToolTip::add( mos8580_btn, tr( "MOS8580 SID ") );
- m_sidTypeBtnGrp = new automatableButtonGroup( this );
- m_sidTypeBtnGrp->addButton( mos6581_btn );
- m_sidTypeBtnGrp->addButton( mos8580_btn );
- for( int i = 0; i < 3; i++ )
- {
- Knob *ak = new sidKnob( this );
- ak->setHintText( tr("Attack:"), "" );
- ak->move( 7, 114 + i*50 );
- ak->setWhatsThis( tr ( "Attack rate determines how rapidly the output "
- "of Voice %1 rises from zero to peak amplitude." ).arg( i+1 ) );
- Knob *dk = new sidKnob( this );
- dk->setHintText( tr("Decay:") , "" );
- dk->move( 7 + 28, 114 + i*50 );
- dk->setWhatsThis( tr ( "Decay rate determines how rapidly the output "
- "falls from the peak amplitude to the selected Sustain level." ) );
- Knob *sk = new sidKnob( this );
- sk->setHintText( tr("Sustain:"), "" );
- sk->move( 7 + 2*28, 114 + i*50 );
- sk->setWhatsThis( tr ( "Output of Voice %1 will remain at the selected "
- "Sustain amplitude as long as the note is held." ).arg( i+1 ) );
- Knob *rk = new sidKnob( this );
- rk->setHintText( tr("Release:"), "" );
- rk->move( 7 + 3*28, 114 + i*50 );
- rk->setWhatsThis( tr ( "The output of of Voice %1 will fall from "
- "Sustain amplitude to zero amplitude at the selected Release "
- "rate." ).arg( i+1 ) );
- Knob *pwk = new sidKnob( this );
- pwk->setHintText( tr("Pulse Width:"), "" );
- pwk->move( 7 + 4*28, 114 + i*50 );
- pwk->setWhatsThis( tr ( "The Pulse Width resolution allows the width "
- "to be smoothly swept with no discernable stepping. The Pulse "
- "waveform on Oscillator %1 must be selected to have any audible"
- " effect." ).arg( i+1 ) );
- Knob *crsk = new sidKnob( this );
- crsk->setHintText( tr("Coarse:"), " semitones" );
- crsk->move( 147, 114 + i*50 );
- crsk->setWhatsThis( tr ( "The Coarse detuning allows to detune Voice "
- "%1 one octave up or down." ).arg( i+1 ) );
- PixmapButton * pulse_btn = new PixmapButton( this, NULL );
- pulse_btn->move( 187, 101 + i*50 );
- pulse_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "pulsered" ) );
- pulse_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "pulse" ) );
- ToolTip::add( pulse_btn, tr( "Pulse Wave" ) );
- PixmapButton * triangle_btn = new PixmapButton( this, NULL );
- triangle_btn->move( 168, 101 + i*50 );
- triangle_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "trianglered" ) );
- triangle_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "triangle" ) );
- ToolTip::add( triangle_btn, tr( "Triangle Wave" ) );
- PixmapButton * saw_btn = new PixmapButton( this, NULL );
- saw_btn->move( 207, 101 + i*50 );
- saw_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "sawred" ) );
- saw_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "saw" ) );
- ToolTip::add( saw_btn, tr( "SawTooth" ) );
- PixmapButton * noise_btn = new PixmapButton( this, NULL );
- noise_btn->move( 226, 101 + i*50 );
- noise_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "noisered" ) );
- noise_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "noise" ) );
- ToolTip::add( noise_btn, tr( "Noise" ) );
- automatableButtonGroup * wfbg =
- new automatableButtonGroup( this );
- wfbg->addButton( pulse_btn );
- wfbg->addButton( triangle_btn );
- wfbg->addButton( saw_btn );
- wfbg->addButton( noise_btn );
- int syncRingWidth[] = { 3, 1, 2 };
- PixmapButton * sync_btn = new PixmapButton( this, NULL );
- sync_btn->setCheckable( true );
- sync_btn->move( 207, 134 + i*50 );
- sync_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "syncred" ) );
- sync_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "sync" ) );
- ToolTip::add( sync_btn, tr( "Sync" ) );
- sync_btn->setWhatsThis( tr ( "Sync synchronizes the fundamental "
- "frequency of Oscillator %1 with the fundamental frequency of "
- "Oscillator %2 producing \"Hard Sync\" effects." ).arg( i+1 )
- .arg( syncRingWidth[i] ) );
- PixmapButton * ringMod_btn = new PixmapButton( this, NULL );
- ringMod_btn->setCheckable( true );
- ringMod_btn->move( 170, 116 + i*50 );
- ringMod_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "ringred" ) );
- ringMod_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "ring" ) );
- ToolTip::add( ringMod_btn, tr( "Ring-Mod" ) );
- ringMod_btn->setWhatsThis( tr ( "Ring-mod replaces the Triangle "
- "Waveform output of Oscillator %1 with a \"Ring Modulated\" "
- "combination of Oscillators %1 and %2." ).arg( i+1 )
- .arg( syncRingWidth[i] ) );
- PixmapButton * filter_btn = new PixmapButton( this, NULL );
- filter_btn->setCheckable( true );
- filter_btn->move( 207, 116 + i*50 );
- filter_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "filterred" ) );
- filter_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "filter" ) );
- ToolTip::add( filter_btn, tr( "Filtered" ) );
- filter_btn->setWhatsThis( tr ( "When Filtered is on, Voice %1 will be "
- "processed through the Filter. When Filtered is off, Voice %1 "
- "appears directly at the output, and the Filter has no effect on "
- "it." ).arg( i+1 ) );
- PixmapButton * test_btn = new PixmapButton( this, NULL );
- test_btn->setCheckable( true );
- test_btn->move( 170, 134 + i*50 );
- test_btn->setActiveGraphic(
- PLUGIN_NAME::getIconPixmap( "testred" ) );
- test_btn->setInactiveGraphic(
- PLUGIN_NAME::getIconPixmap( "test" ) );
- ToolTip::add( test_btn, tr( "Test" ) );
- test_btn->setWhatsThis( tr ( "Test, when set, resets and locks "
- "Oscillator %1 at zero until Test is turned off." ).arg( i+1 ) );
- m_voiceKnobs[i] = voiceKnobs( ak, dk, sk, rk, pwk, crsk, wfbg,
- sync_btn, ringMod_btn, filter_btn, test_btn );
- }
- }
- sidInstrumentView::~sidInstrumentView()
- {
- }
- void sidInstrumentView::updateKnobHint()
- {
- sidInstrument * k = castModel<sidInstrument>();
- for( int i = 0; i < 3; ++i )
- {
- m_voiceKnobs[i].m_attKnob->setHintText( tr( "Attack:" ) + " ", " (" +
- QString::fromLatin1( attackTime[(int)k->m_voice[i]->
- m_attackModel.value()] ) + ")" );
- ToolTip::add( m_voiceKnobs[i].m_attKnob,
- attackTime[(int)k->m_voice[i]->m_attackModel.value()] );
- m_voiceKnobs[i].m_decKnob->setHintText( tr( "Decay:" ) + " ", " (" +
- QString::fromLatin1( decRelTime[(int)k->m_voice[i]->
- m_decayModel.value()] ) + ")" );
- ToolTip::add( m_voiceKnobs[i].m_decKnob,
- decRelTime[(int)k->m_voice[i]->m_decayModel.value()] );
- m_voiceKnobs[i].m_relKnob->setHintText( tr( "Release:" ) + " ", " (" +
- QString::fromLatin1( decRelTime[(int)k->m_voice[i]->
- m_releaseModel.value()] ) + ")" );
- ToolTip::add( m_voiceKnobs[i].m_relKnob,
- decRelTime[(int)k->m_voice[i]->m_releaseModel.value()]);
-
- m_voiceKnobs[i].m_pwKnob->setHintText( tr( "Pulse Width:" )+ " ", " (" +
- QString::number( (double)k->m_voice[i]->
- m_pulseWidthModel.value() / 40.95 ) + "%)" );
- ToolTip::add( m_voiceKnobs[i].m_pwKnob,
- QString::number( (double)k->m_voice[i]->
- m_pulseWidthModel.value() / 40.95 ) + "%" );
- }
- m_cutKnob->setHintText( tr( "Cutoff frequency:" ) + " ", " (" +
- QString::number ( (int) ( 9970.0 / 2047.0 *
- (double)k->m_filterFCModel.value() + 30.0 ) ) + "Hz)" );
- ToolTip::add( m_cutKnob, QString::number( (int) ( 9970.0 / 2047.0 *
- (double)k->m_filterFCModel.value() + 30.0 ) ) + "Hz" );
- }
- void sidInstrumentView::updateKnobToolTip()
- {
- sidInstrument * k = castModel<sidInstrument>();
- for( int i = 0; i < 3; ++i )
- {
- ToolTip::add( m_voiceKnobs[i].m_sustKnob,
- QString::number( (int)k->m_voice[i]->m_sustainModel.value() ) );
- ToolTip::add( m_voiceKnobs[i].m_crsKnob,
- QString::number( (int)k->m_voice[i]->m_coarseModel.value() ) +
- " semitones" );
- }
- ToolTip::add( m_volKnob,
- QString::number( (int)k->m_volumeModel.value() ) );
- ToolTip::add( m_resKnob,
- QString::number( (int)k->m_filterResonanceModel.value() ) );
- }
- void sidInstrumentView::modelChanged()
- {
- sidInstrument * k = castModel<sidInstrument>();
- m_volKnob->setModel( &k->m_volumeModel );
- m_resKnob->setModel( &k->m_filterResonanceModel );
- m_cutKnob->setModel( &k->m_filterFCModel );
- m_passBtnGrp->setModel( &k->m_filterModeModel );
- m_offButton->setModel( &k->m_voice3OffModel );
- m_sidTypeBtnGrp->setModel( &k->m_chipModel );
- for( int i = 0; i < 3; ++i )
- {
- m_voiceKnobs[i].m_attKnob->setModel(
- &k->m_voice[i]->m_attackModel );
- m_voiceKnobs[i].m_decKnob->setModel(
- &k->m_voice[i]->m_decayModel );
- m_voiceKnobs[i].m_sustKnob->setModel(
- &k->m_voice[i]->m_sustainModel );
- m_voiceKnobs[i].m_relKnob->setModel(
- &k->m_voice[i]->m_releaseModel );
- m_voiceKnobs[i].m_pwKnob->setModel(
- &k->m_voice[i]->m_pulseWidthModel );
- m_voiceKnobs[i].m_crsKnob->setModel(
- &k->m_voice[i]->m_coarseModel );
- m_voiceKnobs[i].m_waveFormBtnGrp->setModel(
- &k->m_voice[i]->m_waveFormModel );
- m_voiceKnobs[i].m_syncButton->setModel(
- &k->m_voice[i]->m_syncModel );
- m_voiceKnobs[i].m_ringModButton->setModel(
- &k->m_voice[i]->m_ringModModel );
- m_voiceKnobs[i].m_filterButton->setModel(
- &k->m_voice[i]->m_filteredModel );
- m_voiceKnobs[i].m_testButton->setModel(
- &k->m_voice[i]->m_testModel );
- }
- for( int i = 0; i < 3; ++i )
- {
- connect( &k->m_voice[i]->m_attackModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobHint() ) );
- connect( &k->m_voice[i]->m_decayModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobHint() ) );
- connect( &k->m_voice[i]->m_releaseModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobHint() ) );
- connect( &k->m_voice[i]->m_pulseWidthModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobHint() ) );
- connect( &k->m_voice[i]->m_sustainModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobToolTip() ) );
- connect( &k->m_voice[i]->m_coarseModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobToolTip() ) );
- }
-
- connect( &k->m_volumeModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobToolTip() ) );
- connect( &k->m_filterResonanceModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobToolTip() ) );
- connect( &k->m_filterFCModel, SIGNAL( dataChanged() ),
- this, SLOT( updateKnobHint() ) );
- updateKnobHint();
- updateKnobToolTip();
- }
- extern "C"
- {
- // necessary for getting instance out of shared lib
- Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
- {
- return( new sidInstrument(
- static_cast<InstrumentTrack *>( _data ) ) );
- }
- }
|