From 36f7b4de0ff5c1b66cd70d53503bd62131a01a9e Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Sat, 26 Jan 2008 00:44:21 +0000 Subject: [PATCH] initial M/V-split of TripleOscillator - lots of debugging and cleanups pending, however basically works :) git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/branches/lmms-mv@676 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 22 + .../triple_oscillator/triple_oscillator.cpp | 1115 +++++++++-------- plugins/triple_oscillator/triple_oscillator.h | 105 +- 3 files changed, 676 insertions(+), 566 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6718a8dd6..3ed5117b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2008-01-26 Tobias Doerffel + + * plugins/triple_oscillator/triple_oscillator.h: + * plugins/triple_oscillator/triple_oscillator.cpp: + initial M/V-split - lots of debugging and cleanups pending, however + basically works :) + + * include/transformable_auto_model.h: + added transformableAutoModel-class which is not used yet but might be + helpful in some cases in the future + + * include/oscillator.h: + * src/lib/oscillator.cpp: + - changed coding-style for enum-constants + - use model for external wave-shape- and modulation-algo-parameter + + * src/widgets/ladspa_control_view.cpp: + added missing header + + * src/widgets/automatable_button.cpp: + update buttons after changing button-group's value + 2008-01-24 Tobias Doerffel * include/types.h: diff --git a/plugins/triple_oscillator/triple_oscillator.cpp b/plugins/triple_oscillator/triple_oscillator.cpp index 1faef3e27..d45ca41b9 100644 --- a/plugins/triple_oscillator/triple_oscillator.cpp +++ b/plugins/triple_oscillator/triple_oscillator.cpp @@ -1,7 +1,7 @@ /* * triple_oscillator.cpp - powerful instrument with three oscillators * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -39,6 +39,7 @@ #include "song_editor.h" #include "tooltip.h" #include "volume_knob.h" +#include "automatable_model_templates.h" #undef SINGLE_SOURCE_COMPILE @@ -56,7 +57,7 @@ plugin::descriptor tripleoscillator_plugin_descriptor = "three powerful oscillators you can modulate " "in several ways" ), "Tobias Doerffel ", - 0x0100, + 0x0110, plugin::Instrument, new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ), NULL @@ -64,424 +65,166 @@ plugin::descriptor tripleoscillator_plugin_descriptor = } - -tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : - instrument( _channel_track, &tripleoscillator_plugin_descriptor ) + + +oscillatorObject::oscillatorObject( model * _parent, track * _track ) : + model( _parent ), + m_volumeModel( DEFAULT_VOLUME / NUM_OF_OSCILLATORS, + MIN_VOLUME, MAX_VOLUME, 1.0f, this ), + m_panModel( DEFAULT_PANNING, PANNING_LEFT, PANNING_RIGHT, 1.0f, this ), + m_coarseModel( 0, -2 * NOTES_PER_OCTAVE, 2 * NOTES_PER_OCTAVE, + 1.0f, this ), + m_fineLeftModel( 0.0f, -100.0f, 100.0f, 1.0f, this ), + m_fineRightModel( 0.0f, -100.0f, 100.0f, 1.0f, this ), + m_phaseOffsetModel( 0.0f, 0.0f, 360.0f, 1.0f, this ), + m_stereoPhaseDetuningModel( 0.0f, 0.0f, 360.0f, 1.0f, this ), + m_waveShapeModel( oscillator::SineWave, 0, oscillator::NumWaveShapes, + 1, this ), + m_modulationAlgoModel( oscillator::SignalMix, 0, + oscillator::NumModulationAlgos, 1, this ), + m_sampleBuffer( new sampleBuffer ), + m_volumeLeft( 0.0f ), + m_volumeRight( 0.0f ), + m_detuningLeft( 0.0f ), + m_detuningRight( 0.0f ), + m_phaseOffsetLeft( 0.0f ), + m_phaseOffsetRight( 0.0f ) { - setAutoFillBackground( TRUE ); - QPalette pal; - pal.setBrush( backgroundRole(), - PLUGIN_NAME::getIconPixmap( "artwork" ) ); - setPalette( pal ); + m_volumeModel.setTrack( _track ); + m_panModel.setTrack( _track ); + m_coarseModel.setTrack( _track ); + m_fineLeftModel.setTrack( _track ); + m_fineRightModel.setTrack( _track ); + m_phaseOffsetModel.setTrack( _track ); + m_stereoPhaseDetuningModel.setTrack( _track ); + m_waveShapeModel.setTrack( _track ); + m_modulationAlgoModel.setTrack( _track ); - pixmapButton * pm_osc1_btn = new pixmapButton( this, NULL, NULL ); - pm_osc1_btn->move( 46, 50 ); - pm_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "pm_active" ) ); - pm_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "pm_inactive" ) ); - pm_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); - toolTip::add( pm_osc1_btn, tr( "use phase modulation for " - "modulating oscillator 2 with " - "oscillator 1" ) ); + // Connect knobs with oscillators' inputs + connect( &m_volumeModel, SIGNAL( dataChanged() ), + this, SLOT( updateVolume() ) ); + connect( &m_panModel, SIGNAL( dataChanged() ), + this, SLOT( updateVolume() ) ); + updateVolume(); - pixmapButton * am_osc1_btn = new pixmapButton( this, NULL, NULL ); - am_osc1_btn->move( 86, 50 ); - am_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "am_active" ) ); - am_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "am_inactive" ) ); - am_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); - toolTip::add( am_osc1_btn, tr( "use amplitude modulation for " - "modulating oscillator 2 with " - "oscillator 1" ) ); + connect( &m_coarseModel, SIGNAL( dataChanged() ), + this, SLOT( updateDetuningLeft() ) ); + connect( &m_coarseModel, SIGNAL( dataChanged() ), + this, SLOT( updateDetuningRight() ) ); + connect( &m_fineLeftModel, SIGNAL( dataChanged() ), + this, SLOT( updateDetuningLeft() ) ); + connect( &m_fineRightModel, SIGNAL( dataChanged() ), + this, SLOT( updateDetuningRight() ) ); + updateDetuningLeft(); + updateDetuningRight(); - pixmapButton * mix_osc1_btn = new pixmapButton( this, NULL, NULL ); - mix_osc1_btn->move( 126, 50 ); - mix_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "mix_active" ) ); - mix_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "mix_inactive" ) ); - mix_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( - "btn_mask" ).createHeuristicMask() ) ); - toolTip::add( mix_osc1_btn, tr( "mix output of oscillator 1 & 2" ) ); + connect( &m_phaseOffsetModel, SIGNAL( dataChanged() ), + this, SLOT( updatePhaseOffsetLeft() ) ); + connect( &m_phaseOffsetModel, SIGNAL( dataChanged() ), + this, SLOT( updatePhaseOffsetRight() ) ); + connect( &m_stereoPhaseDetuningModel, SIGNAL( dataChanged() ), + this, SLOT( updatePhaseOffsetLeft() ) ); + updatePhaseOffsetLeft(); + updatePhaseOffsetRight(); - pixmapButton * sync_osc1_btn = new pixmapButton( this, NULL, NULL ); - sync_osc1_btn->move( 166, 50 ); - sync_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "sync_active" ) ); - sync_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "sync_inactive" ) ); - sync_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( - "btn_mask" ).createHeuristicMask() ) ); - toolTip::add( sync_osc1_btn, tr( "synchronize oscillator 1 with " - "oscillator 2" ) ); - - pixmapButton * fm_osc1_btn = new pixmapButton( this, NULL, NULL ); - fm_osc1_btn->move( 206, 50 ); - fm_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "fm_active" ) ); - fm_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "fm_inactive" ) ); - fm_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); - toolTip::add( fm_osc1_btn, tr( "use frequency modulation for " - "modulating oscillator 2 with " - "oscillator 1" ) ); - - m_mod1BtnGrp = new automatableButtonGroup( this, - tr( "Modulation type 1" ), - _channel_track ); - m_mod1BtnGrp->addButton( pm_osc1_btn ); - m_mod1BtnGrp->addButton( am_osc1_btn ); - m_mod1BtnGrp->addButton( mix_osc1_btn ); - m_mod1BtnGrp->addButton( sync_osc1_btn ); - m_mod1BtnGrp->addButton( fm_osc1_btn ); - m_mod1BtnGrp->setInitValue( m_osc[0].m_modulationAlgo ); - - connect( m_mod1BtnGrp, SIGNAL( valueChanged( int ) ), - &m_osc[0], SLOT( modCh( int ) ) ); +} - pixmapButton * pm_osc2_btn = new pixmapButton( this, NULL, NULL ); - pm_osc2_btn->move( 46, 68 ); - pm_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "pm_active" ) ); - pm_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "pm_inactive" ) ); - pm_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); - toolTip::add( pm_osc2_btn, tr( "use phase modulation for " - "modulating oscillator 3 with " - "oscillator 2" ) ); - - pixmapButton * am_osc2_btn = new pixmapButton( this, NULL, NULL ); - am_osc2_btn->move( 86, 68 ); - am_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "am_active" ) ); - am_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "am_inactive" ) ); - am_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); - toolTip::add( am_osc2_btn, tr( "use amplitude modulation for " - "modulating oscillator 3 with " - "oscillator 2" ) ); - - pixmapButton * mix_osc2_btn = new pixmapButton( this, NULL, NULL ); - mix_osc2_btn->move( 126, 68 ); - mix_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "mix_active" ) ); - mix_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "mix_inactive" ) ); - mix_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( - "btn_mask" ).createHeuristicMask() ) ); - toolTip::add( mix_osc2_btn, tr("mix output of oscillator 2 & 3" ) ); - - pixmapButton * sync_osc2_btn = new pixmapButton( this, NULL, NULL ); - sync_osc2_btn->move( 166, 68 ); - sync_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "sync_active" ) ); - sync_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "sync_inactive" ) ); - sync_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( - "btn_mask" ).createHeuristicMask() ) ); - toolTip::add( sync_osc2_btn, tr( "synchronize oscillator 2 with " - "oscillator 3" ) ); - - pixmapButton * fm_osc2_btn = new pixmapButton( this, NULL, NULL ); - fm_osc2_btn->move( 206, 68 ); - fm_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "fm_active" ) ); - fm_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "fm_inactive" ) ); - fm_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). - createHeuristicMask() ) ); - toolTip::add( fm_osc2_btn, tr( "use frequency modulation for " - "modulating oscillator 3 with " - "oscillator 2" ) ); - - m_mod2BtnGrp = new automatableButtonGroup( this, - tr( "Modulation type 2" ), - _channel_track ); - m_mod2BtnGrp->addButton( pm_osc2_btn ); - m_mod2BtnGrp->addButton( am_osc2_btn ); - m_mod2BtnGrp->addButton( mix_osc2_btn ); - m_mod2BtnGrp->addButton( sync_osc2_btn ); - m_mod2BtnGrp->addButton( fm_osc2_btn ); - m_mod2BtnGrp->setInitValue( m_osc[1].m_modulationAlgo ); - - connect( m_mod2BtnGrp, SIGNAL( valueChanged( int ) ), - &m_osc[1], SLOT( modCh( int ) ) ); +oscillatorObject::~oscillatorObject() +{ + sharedObject::unref( m_sampleBuffer ); +} + + + + +void oscillatorObject::oscUserDefWaveDblClick( void ) +{ + QString af = m_sampleBuffer->openAudioFile(); + if( af != "" ) + { + m_sampleBuffer->setAudioFile( af ); + // TODO: + //toolTip::add( m_usrWaveBtn, m_sampleBuffer->audioFile() ); + } +} + + + + +void oscillatorObject::updateVolume( void ) +{ + if( m_panModel.value() >= 0.0f ) + { + const float panningFactorLeft = 1.0f - m_panModel.value() + / (float)PANNING_RIGHT; + m_volumeLeft = panningFactorLeft * m_volumeModel.value() / + 100.0f; + m_volumeRight = m_volumeModel.value() / 100.0f; + } + else + { + m_volumeLeft = m_volumeModel.value() / 100.0f; + const float panningFactorRight = 1.0f + m_panModel.value() + / (float)PANNING_RIGHT; + m_volumeRight = panningFactorRight * m_volumeModel.value() / + 100.0f; + } +} + + + + +void oscillatorObject::updateDetuningLeft( void ) +{ + m_detuningLeft = powf( 2.0f, ( (float)m_coarseModel.value() * 100.0f + + (float)m_fineLeftModel.value() ) / 1200.0f ) + / engine::getMixer()->sampleRate(); +} + + + + +void oscillatorObject::updateDetuningRight( void ) +{ + m_detuningRight = powf( 2.0f, ( (float)m_coarseModel.value() * 100.0f + + (float)m_fineRightModel.value() ) / 1200.0f ) + / engine::getMixer()->sampleRate(); +} + + + + +void oscillatorObject::updatePhaseOffsetLeft( void ) +{ + m_phaseOffsetLeft = ( m_phaseOffsetModel.value() + + m_stereoPhaseDetuningModel.value() ) / 360.0f; +} + + + + +void oscillatorObject::updatePhaseOffsetRight( void ) +{ + m_phaseOffsetRight = m_phaseOffsetModel.value() / 360.0f; +} + + + + + + + + +tripleOscillator::tripleOscillator( instrumentTrack * _instrument_track ) : + instrument( _instrument_track, &tripleoscillator_plugin_descriptor ) +{ for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { - // setup volume-knob - m_osc[i].m_volKnob = new volumeKnob( knobSmall_17, this, tr( - "Osc %1 volume" ).arg( i+1 ), _channel_track ); - m_osc[i].m_volKnob->move( 6, 104 + i * 50 ); - m_osc[i].m_volKnob->setRange( MIN_VOLUME, MAX_VOLUME, 1.0f ); - m_osc[i].m_volKnob->setInitValue( DEFAULT_VOLUME - / NUM_OF_OSCILLATORS ); - m_osc[i].m_volKnob->setHintText( tr( "Osc %1 volume:" ).arg( - i+1 ) + " ", "%" ); - m_osc[i].m_volKnob->setWhatsThis( - tr( "With this knob you can set the volume of " - "oscillator %1. When setting a value of 0 the " - "oscillator is turned off. Otherwise you can " - "hear the oscillator as loud as you set it " - "here.").arg( i+1 ) ); + m_osc[i] = new oscillatorObject( this, _instrument_track ); - // setup panning-knob - m_osc[i].m_panKnob = new knob( knobSmall_17, this, - tr( "Osc %1 panning" ).arg( i + 1 ), - _channel_track ); - m_osc[i].m_panKnob->move( 33, 104 + i * 50 ); - m_osc[i].m_panKnob->setRange( PANNING_LEFT, PANNING_RIGHT, - 1.0f ); - m_osc[i].m_panKnob->setInitValue( DEFAULT_PANNING ); - m_osc[i].m_panKnob->setHintText( tr("Osc %1 panning:").arg( - i + 1 ) - + " ", "" ); - m_osc[i].m_panKnob->setWhatsThis( - tr( "With this knob you can set the panning of the " - "oscillator %1. A value of -100 means 100% " - "left and a value of 100 moves oscillator-" - "output right.").arg( i+1 ) ); - - // setup coarse-knob - m_osc[i].m_coarseKnob = new knob( knobSmall_17, this, - tr( "Osc %1 coarse detuning" ).arg( i + 1 ), - _channel_track ); - m_osc[i].m_coarseKnob->move( 66, 104 + i * 50 ); - m_osc[i].m_coarseKnob->setRange( -2 * NOTES_PER_OCTAVE, - 2 * NOTES_PER_OCTAVE, 1.0f ); - m_osc[i].m_coarseKnob->setInitValue( 0.0f ); - m_osc[i].m_coarseKnob->setHintText( - tr( "Osc %1 coarse detuning:" ).arg( i + 1 ) + " ", - " " + tr( "semitones" ) ); - m_osc[i].m_coarseKnob->setWhatsThis( - tr( "With this knob you can set the coarse detuning of " - "oscillator %1. You can detune the oscillator " - "12 semitones (1 octave) up and down. This is " - "useful for creating sounds with a chord." ). - arg( i + 1 ) ); - - // setup knob for left fine-detuning - m_osc[i].m_fineLKnob = new knob( knobSmall_17, this, - tr( "Osc %1 fine detuning left" ).arg( i+1 ), - _channel_track ); - m_osc[i].m_fineLKnob->move( 90, 104 + i * 50 ); - m_osc[i].m_fineLKnob->setRange( -100.0f, 100.0f, 1.0f ); - m_osc[i].m_fineLKnob->setInitValue( 0.0f ); - m_osc[i].m_fineLKnob->setHintText( tr( "Osc %1 fine detuning " - "left:" ).arg( i + 1 ) - + " ", " " + - tr( "cents" ) ); - m_osc[i].m_fineLKnob->setWhatsThis( - tr( "With this knob you can set the fine detuning of " - "oscillator %1 for the left channel. The fine-" - "detuning is ranged between -100 cents and " - "+100 cents. This is useful for creating " - "\"fat\" sounds." ).arg( i + 1 ) ); - - // setup knob for right fine-detuning - m_osc[i].m_fineRKnob = new knob( knobSmall_17, this, - tr( "Osc %1 fine detuning right" - ).arg( i + 1 ), - _channel_track ); - m_osc[i].m_fineRKnob->move( 110, 104 + i * 50 ); - m_osc[i].m_fineRKnob->setRange( -100.0f, 100.0f, 1.0f ); - m_osc[i].m_fineRKnob->setInitValue( 0.0f ); - m_osc[i].m_fineRKnob->setHintText( tr( "Osc %1 fine detuning " - "right:").arg( i + 1 ) + - " ", " " + tr( "cents" ) ); - m_osc[i].m_fineRKnob->setWhatsThis( - tr( "With this knob you can set the fine detuning of " - "oscillator %1 for the right channel. The " - "fine-detuning is ranged between -100 cents " - "and +100 cents. This is useful for creating " - "\"fat\" sounds." ).arg( i+1 ) ); - - // setup phase-offset-knob - m_osc[i].m_phaseOffsetKnob = new knob( knobSmall_17, this, - tr( "Osc %1 phase-" - "offset" ).arg( i+1 ), - _channel_track ); - m_osc[i].m_phaseOffsetKnob->move( 142, 104 + i * 50 ); - m_osc[i].m_phaseOffsetKnob->setRange( 0.0f, 360.0f, 1.0f ); - m_osc[i].m_phaseOffsetKnob->setInitValue( 0.0f ); - m_osc[i].m_phaseOffsetKnob->setHintText( tr( "Osc %1 phase-" - "offset:" ). - arg( i + 1 ) + - " ", " " + tr( "degrees" ) ); - m_osc[i].m_phaseOffsetKnob->setWhatsThis( - tr( "With this knob you can set the phase-offset of " - "oscillator %1. That means you can move the " - "point within an oscillation where the " - "oscillator begins to oscillate. For example " - "if you have a sine-wave and have a phase-" - "offset of 180 degrees the wave will first go " - "down. It's the same with a square-wave." - ).arg( i+1 ) ); - - // setup stereo-phase-detuning-knob - m_osc[i].m_stereoPhaseDetuningKnob = new knob( knobSmall_17, - this, tr( "Osc %1 stereo phase-" - "detuning" ).arg( i+1 ), - _channel_track ); - m_osc[i].m_stereoPhaseDetuningKnob->move( 166, 104 + i * 50 ); - m_osc[i].m_stereoPhaseDetuningKnob->setRange( 0.0f, 360.0f, - 1.0f ); - m_osc[i].m_stereoPhaseDetuningKnob->setInitValue( 0.0f ); - m_osc[i].m_stereoPhaseDetuningKnob->setHintText( tr("Osc %1 " - "stereo phase-" - "detuning:" ). - arg( i + 1 ) + - " ", " " + - tr( "degrees" ) ); - m_osc[i].m_stereoPhaseDetuningKnob->setWhatsThis( - tr( "With this knob you can set the stereo phase-" - "detuning of oscillator %1. The stereo phase-" - "detuning specifies the size of the difference " - "between the phase-offset of left and right " - "channel. This is very good for creating wide " - "stereo-sounds." ).arg( i+1 ) ); - - // Connect knobs with oscillators' inputs - connect( m_osc[i].m_volKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updateVolume() ) ); - connect( m_osc[i].m_panKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updateVolume() ) ); - m_osc[i].updateVolume(); - - connect( m_osc[i].m_coarseKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updateDetuningLeft() ) ); - connect( m_osc[i].m_coarseKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updateDetuningRight() ) ); - connect( m_osc[i].m_fineLKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updateDetuningLeft() ) ); - connect( m_osc[i].m_fineRKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updateDetuningRight() ) ); - m_osc[i].updateDetuningLeft(); - m_osc[i].updateDetuningRight(); - - connect( m_osc[i].m_phaseOffsetKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updatePhaseOffsetLeft() ) ); - connect( m_osc[i].m_phaseOffsetKnob, SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updatePhaseOffsetRight() ) ); - connect( m_osc[i].m_stereoPhaseDetuningKnob, - SIGNAL( valueChanged() ), - &m_osc[i], SLOT( updatePhaseOffsetLeft() ) ); - m_osc[i].updatePhaseOffsetLeft(); - m_osc[i].updatePhaseOffsetRight(); - - pixmapButton * sin_wave_btn = new pixmapButton( this, NULL, - NULL ); - sin_wave_btn->move( 188, 105 + i * 50 ); - sin_wave_btn->setActiveGraphic( embed::getIconPixmap( - "sin_wave_active" ) ); - sin_wave_btn->setInactiveGraphic( embed::getIconPixmap( - "sin_wave_inactive" ) ); - sin_wave_btn->setChecked( TRUE ); - toolTip::add( sin_wave_btn, - tr( "Click here if you want a sine-wave for " - "current oscillator." ) ); - - pixmapButton * triangle_wave_btn = new pixmapButton( this, NULL, - NULL ); - triangle_wave_btn->move( 203, 105 + i * 50 ); - triangle_wave_btn->setActiveGraphic( - embed::getIconPixmap( "triangle_wave_active" ) ); - triangle_wave_btn->setInactiveGraphic( - embed::getIconPixmap( "triangle_wave_inactive" ) ); - toolTip::add( triangle_wave_btn, - tr( "Click here if you want a triangle-wave " - "for current oscillator." ) ); - - pixmapButton * saw_wave_btn = new pixmapButton( this, NULL, - NULL ); - saw_wave_btn->move( 218, 105 + i * 50 ); - saw_wave_btn->setActiveGraphic( embed::getIconPixmap( - "saw_wave_active" ) ); - saw_wave_btn->setInactiveGraphic( embed::getIconPixmap( - "saw_wave_inactive" ) ); - toolTip::add( saw_wave_btn, - tr( "Click here if you want a saw-wave for " - "current oscillator." ) ); - - pixmapButton * sqr_wave_btn = new pixmapButton( this, NULL, - NULL ); - sqr_wave_btn->move( 233, 105 + i * 50 ); - sqr_wave_btn->setActiveGraphic( embed::getIconPixmap( - "square_wave_active" ) ); - sqr_wave_btn->setInactiveGraphic( embed::getIconPixmap( - "square_wave_inactive" ) ); - toolTip::add( sqr_wave_btn, - tr( "Click here if you want a square-wave for " - "current oscillator." ) ); - - pixmapButton * moog_saw_wave_btn = new pixmapButton( this, NULL, - NULL ); - moog_saw_wave_btn->move( 188, 120+i*50 ); - moog_saw_wave_btn->setActiveGraphic( - embed::getIconPixmap( "moog_saw_wave_active" ) ); - moog_saw_wave_btn->setInactiveGraphic( - embed::getIconPixmap( "moog_saw_wave_inactive" ) ); - toolTip::add( moog_saw_wave_btn, - tr( "Click here if you want a moog-saw-wave " - "for current oscillator." ) ); - - pixmapButton * exp_wave_btn = new pixmapButton( this, NULL, - NULL ); - exp_wave_btn->move( 203, 120+i*50 ); - exp_wave_btn->setActiveGraphic( embed::getIconPixmap( - "exp_wave_active" ) ); - exp_wave_btn->setInactiveGraphic( embed::getIconPixmap( - "exp_wave_inactive" ) ); - toolTip::add( exp_wave_btn, - tr( "Click here if you want an exponential " - "wave for current oscillator." ) ); - - pixmapButton * white_noise_btn = new pixmapButton( this, NULL, - NULL ); - white_noise_btn->move( 218, 120+i*50 ); - white_noise_btn->setActiveGraphic( - embed::getIconPixmap( "white_noise_wave_active" ) ); - white_noise_btn->setInactiveGraphic( - embed::getIconPixmap( "white_noise_wave_inactive" ) ); - toolTip::add( white_noise_btn, - tr( "Click here if you want a white-noise for " - "current oscillator." ) ); - - m_osc[i].m_usrWaveBtn = new pixmapButton( this, NULL, NULL ); - m_osc[i].m_usrWaveBtn->move( 233, 120+i*50 ); - m_osc[i].m_usrWaveBtn->setActiveGraphic( embed::getIconPixmap( - "usr_wave_active" ) ); - m_osc[i].m_usrWaveBtn->setInactiveGraphic( embed::getIconPixmap( - "usr_wave_inactive" ) ); - toolTip::add( m_osc[i].m_usrWaveBtn, - tr( "Click here if you want a user-defined " - "wave-shape for current oscillator." ) ); - - m_osc[i].m_waveBtnGrp = new automatableButtonGroup( this, - tr( "Osc %1 wave shape" ).arg( i + 1 ), - _channel_track ); - m_osc[i].m_waveBtnGrp->addButton( sin_wave_btn ); - m_osc[i].m_waveBtnGrp->addButton( triangle_wave_btn ); - m_osc[i].m_waveBtnGrp->addButton( saw_wave_btn ); - m_osc[i].m_waveBtnGrp->addButton( sqr_wave_btn ); - m_osc[i].m_waveBtnGrp->addButton( moog_saw_wave_btn ); - m_osc[i].m_waveBtnGrp->addButton( exp_wave_btn ); - m_osc[i].m_waveBtnGrp->addButton( white_noise_btn ); - m_osc[i].m_waveBtnGrp->addButton( m_osc[i].m_usrWaveBtn ); - - connect( m_osc[i].m_waveBtnGrp, SIGNAL( valueChanged( int ) ), - &m_osc[i], SLOT( oscWaveCh( int ) ) ); - connect( m_osc[i].m_usrWaveBtn, SIGNAL( doubleClicked() ), - &m_osc[i], SLOT( oscUserDefWaveDblClick() ) ); } connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), @@ -500,26 +243,27 @@ tripleOscillator::~tripleOscillator() void tripleOscillator::saveSettings( QDomDocument & _doc, QDomElement & _this ) { - m_mod1BtnGrp->saveSettings( _doc, _this, "modalgo1" ); - m_mod2BtnGrp->saveSettings( _doc, _this, "modalgo2" ); - for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { QString is = QString::number( i ); - m_osc[i].m_volKnob->saveSettings( _doc, _this, "vol" + is ); - m_osc[i].m_panKnob->saveSettings( _doc, _this, "pan" + is ); - m_osc[i].m_coarseKnob->saveSettings( _doc, _this, "coarse" + m_osc[i]->m_volumeModel.saveSettings( _doc, _this, "vol" + is ); + m_osc[i]->m_panModel.saveSettings( _doc, _this, "pan" + is ); + m_osc[i]->m_coarseModel.saveSettings( _doc, _this, "coarse" + is ); - m_osc[i].m_fineLKnob->saveSettings( _doc, _this, "finel" + is ); - m_osc[i].m_fineRKnob->saveSettings( _doc, _this, "finer" + is ); - m_osc[i].m_phaseOffsetKnob->saveSettings( _doc, _this, + m_osc[i]->m_fineLeftModel.saveSettings( _doc, _this, "finel" + + is ); + m_osc[i]->m_fineRightModel.saveSettings( _doc, _this, "finer" + + is ); + m_osc[i]->m_phaseOffsetModel.saveSettings( _doc, _this, "phoffset" + is ); - m_osc[i].m_stereoPhaseDetuningKnob->saveSettings( _doc, _this, + m_osc[i]->m_stereoPhaseDetuningModel.saveSettings( _doc, _this, "stphdetun" + is ); - m_osc[i].m_waveBtnGrp->saveSettings( _doc, _this, + m_osc[i]->m_waveShapeModel.saveSettings( _doc, _this, "wavetype" + is ); + m_osc[i]->m_modulationAlgoModel.saveSettings( _doc, _this, + "modalgo" + is ); _this.setAttribute( "userwavefile" + is, - m_osc[i].m_sampleBuffer->audioFile() ); + m_osc[i]->m_sampleBuffer->audioFile() ); } } @@ -528,24 +272,24 @@ void tripleOscillator::saveSettings( QDomDocument & _doc, QDomElement & _this ) void tripleOscillator::loadSettings( const QDomElement & _this ) { - m_mod1BtnGrp->loadSettings( _this, "modalgo1" ); - m_mod2BtnGrp->loadSettings( _this, "modalgo2" ); - for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { QString is = QString::number( i ); - m_osc[i].m_volKnob->loadSettings( _this, "vol" + is ); - m_osc[i].m_panKnob->loadSettings( _this, "pan" + is ); - m_osc[i].m_coarseKnob->loadSettings( _this, "coarse" + is ); - m_osc[i].m_fineLKnob->loadSettings( _this, "finel" + is ); - m_osc[i].m_fineRKnob->loadSettings( _this, "finer" + is ); - m_osc[i].m_phaseOffsetKnob->loadSettings( _this, + m_osc[i]->m_volumeModel.loadSettings( _this, "vol" + is ); + m_osc[i]->m_panModel.loadSettings( _this, "pan" + is ); + m_osc[i]->m_coarseModel.loadSettings( _this, "coarse" + is ); + m_osc[i]->m_fineLeftModel.loadSettings( _this, "finel" + is ); + m_osc[i]->m_fineRightModel.loadSettings( _this, "finer" + is ); + m_osc[i]->m_phaseOffsetModel.loadSettings( _this, "phoffset" + is ); - m_osc[i].m_stereoPhaseDetuningKnob->loadSettings( _this, + m_osc[i]->m_stereoPhaseDetuningModel.loadSettings( _this, "stphdetun" + is ); - m_osc[i].m_sampleBuffer->setAudioFile( _this.attribute( + m_osc[i]->m_waveShapeModel.loadSettings( _this, "wavetype" + + is ); + m_osc[i]->m_modulationAlgoModel.loadSettings( _this, + "modalgo" + is ); + m_osc[i]->m_sampleBuffer->setAudioFile( _this.attribute( "userwavefile" + is ) ); - m_osc[i].m_waveBtnGrp->loadSettings( _this, "wavetype" + is ); } } @@ -559,7 +303,7 @@ void tripleOscillator::setParameter( const QString & _param, { for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { - m_osc[i].m_sampleBuffer->setAudioFile( _value ); + m_osc[i]->m_sampleBuffer->setAudioFile( _value ); } } } @@ -589,42 +333,42 @@ void tripleOscillator::playNote( notePlayHandle * _n, bool ) if( i == NUM_OF_OSCILLATORS - 1 ) { oscs_l[i] = new oscillator( - m_osc[i].m_waveShape, - m_osc[i].m_modulationAlgo, + m_osc[i]->m_waveShapeModel, + m_osc[i]->m_modulationAlgoModel, _n->frequency(), - m_osc[i].m_detuningLeft, - m_osc[i].m_phaseOffsetLeft, - m_osc[i].m_volumeLeft ); + m_osc[i]->m_detuningLeft, + m_osc[i]->m_phaseOffsetLeft, + m_osc[i]->m_volumeLeft ); oscs_r[i] = new oscillator( - m_osc[i].m_waveShape, - m_osc[i].m_modulationAlgo, + m_osc[i]->m_waveShapeModel, + m_osc[i]->m_modulationAlgoModel, _n->frequency(), - m_osc[i].m_detuningRight, - m_osc[i].m_phaseOffsetRight, - m_osc[i].m_volumeRight ); + m_osc[i]->m_detuningRight, + m_osc[i]->m_phaseOffsetRight, + m_osc[i]->m_volumeRight ); } else { oscs_l[i] = new oscillator( - m_osc[i].m_waveShape, - m_osc[i].m_modulationAlgo, + m_osc[i]->m_waveShapeModel, + m_osc[i]->m_modulationAlgoModel, _n->frequency(), - m_osc[i].m_detuningLeft, - m_osc[i].m_phaseOffsetLeft, - m_osc[i].m_volumeLeft, + m_osc[i]->m_detuningLeft, + m_osc[i]->m_phaseOffsetLeft, + m_osc[i]->m_volumeLeft, oscs_l[i + 1] ); oscs_r[i] = new oscillator( - m_osc[i].m_waveShape, - m_osc[i].m_modulationAlgo, + m_osc[i]->m_waveShapeModel, + m_osc[i]->m_modulationAlgoModel, _n->frequency(), - m_osc[i].m_detuningRight, - m_osc[i].m_phaseOffsetRight, - m_osc[i].m_volumeRight, + m_osc[i]->m_detuningRight, + m_osc[i]->m_phaseOffsetRight, + m_osc[i]->m_volumeRight, oscs_r[i + 1] ); } - oscs_l[i]->setUserWave( m_osc[i].m_sampleBuffer ); - oscs_r[i]->setUserWave( m_osc[i].m_sampleBuffer ); + oscs_l[i]->setUserWave( m_osc[i]->m_sampleBuffer ); + oscs_r[i]->setUserWave( m_osc[i]->m_sampleBuffer ); } @@ -640,7 +384,7 @@ void tripleOscillator::playNote( notePlayHandle * _n, bool ) const fpp_t frames = _n->framesLeftForCurrentPeriod(); sampleFrame * buf = new sampleFrame[frames]; - + osc_l->update( buf, frames, 0 ); osc_r->update( buf, frames, 1 ); @@ -666,12 +410,20 @@ void tripleOscillator::deleteNotePluginData( notePlayHandle * _n ) +pluginView * tripleOscillator::instantiateView( QWidget * _parent ) +{ + return( new tripleOscillatorView( this, _parent ) ); +} + + + + void tripleOscillator::updateAllDetuning( void ) { for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { - m_osc[i].updateDetuningLeft(); - m_osc[i].updateDetuningRight(); + m_osc[i]->updateDetuningLeft(); + m_osc[i]->updateDetuningRight(); } } @@ -679,110 +431,390 @@ void tripleOscillator::updateAllDetuning( void ) - - - -oscillatorObject::oscillatorObject( void ) : - m_waveShape( oscillator::SIN_WAVE ), - m_sampleBuffer( new sampleBuffer ), - m_modulationAlgo( oscillator::MIX ) +tripleOscillatorView::tripleOscillatorView( instrument * _instrument, + QWidget * _parent ) : + instrumentView( _instrument, _parent ) { -} + setAutoFillBackground( TRUE ); + QPalette pal; + pal.setBrush( backgroundRole(), + PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); + + // TODO: clean rewrite using layouts and all that... + pixmapButton * pm_osc1_btn = new pixmapButton( this, NULL ); + pm_osc1_btn->move( 46, 50 ); + pm_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "pm_active" ) ); + pm_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "pm_inactive" ) ); + pm_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + toolTip::add( pm_osc1_btn, tr( "use phase modulation for " + "modulating oscillator 2 with " + "oscillator 1" ) ); + + pixmapButton * am_osc1_btn = new pixmapButton( this, NULL ); + am_osc1_btn->move( 86, 50 ); + am_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_active" ) ); + am_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_inactive" ) ); + am_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + toolTip::add( am_osc1_btn, tr( "use amplitude modulation for " + "modulating oscillator 2 with " + "oscillator 1" ) ); + + pixmapButton * mix_osc1_btn = new pixmapButton( this, NULL ); + mix_osc1_btn->move( 126, 50 ); + mix_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_active" ) ); + mix_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_inactive" ) ); + mix_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); + toolTip::add( mix_osc1_btn, tr( "mix output of oscillator 1 & 2" ) ); + + pixmapButton * sync_osc1_btn = new pixmapButton( this, NULL ); + sync_osc1_btn->move( 166, 50 ); + sync_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_active" ) ); + sync_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_inactive" ) ); + sync_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); + toolTip::add( sync_osc1_btn, tr( "synchronize oscillator 1 with " + "oscillator 2" ) ); + + pixmapButton * fm_osc1_btn = new pixmapButton( this, NULL ); + fm_osc1_btn->move( 206, 50 ); + fm_osc1_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_active" ) ); + fm_osc1_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_inactive" ) ); + fm_osc1_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + toolTip::add( fm_osc1_btn, tr( "use frequency modulation for " + "modulating oscillator 2 with " + "oscillator 1" ) ); + + m_mod1BtnGrp = new automatableButtonGroup( this, + tr( "Modulation type 1" ) ); + m_mod1BtnGrp->addButton( pm_osc1_btn ); + m_mod1BtnGrp->addButton( am_osc1_btn ); + m_mod1BtnGrp->addButton( mix_osc1_btn ); + m_mod1BtnGrp->addButton( sync_osc1_btn ); + m_mod1BtnGrp->addButton( fm_osc1_btn ); + pixmapButton * pm_osc2_btn = new pixmapButton( this, NULL ); + pm_osc2_btn->move( 46, 68 ); + pm_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "pm_active" ) ); + pm_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "pm_inactive" ) ); + pm_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + toolTip::add( pm_osc2_btn, tr( "use phase modulation for " + "modulating oscillator 3 with " + "oscillator 2" ) ); -oscillatorObject::~oscillatorObject() -{ - sharedObject::unref( m_sampleBuffer ); -} + pixmapButton * am_osc2_btn = new pixmapButton( this, NULL ); + am_osc2_btn->move( 86, 68 ); + am_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_active" ) ); + am_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "am_inactive" ) ); + am_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + toolTip::add( am_osc2_btn, tr( "use amplitude modulation for " + "modulating oscillator 3 with " + "oscillator 2" ) ); + + pixmapButton * mix_osc2_btn = new pixmapButton( this, NULL ); + mix_osc2_btn->move( 126, 68 ); + mix_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_active" ) ); + mix_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "mix_inactive" ) ); + mix_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); + toolTip::add( mix_osc2_btn, tr("mix output of oscillator 2 & 3" ) ); + + pixmapButton * sync_osc2_btn = new pixmapButton( this, NULL ); + sync_osc2_btn->move( 166, 68 ); + sync_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_active" ) ); + sync_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "sync_inactive" ) ); + sync_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( + "btn_mask" ).createHeuristicMask() ) ); + toolTip::add( sync_osc2_btn, tr( "synchronize oscillator 2 with " + "oscillator 3" ) ); + + pixmapButton * fm_osc2_btn = new pixmapButton( this, NULL ); + fm_osc2_btn->move( 206, 68 ); + fm_osc2_btn->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_active" ) ); + fm_osc2_btn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "fm_inactive" ) ); + fm_osc2_btn->setMask( QBitmap( PLUGIN_NAME::getIconPixmap( "btn_mask" ). + createHeuristicMask() ) ); + toolTip::add( fm_osc2_btn, tr( "use frequency modulation for " + "modulating oscillator 3 with " + "oscillator 2" ) ); + + m_mod2BtnGrp = new automatableButtonGroup( this, + tr( "Modulation type 2" ) ); + m_mod2BtnGrp->addButton( pm_osc2_btn ); + m_mod2BtnGrp->addButton( am_osc2_btn ); + m_mod2BtnGrp->addButton( mix_osc2_btn ); + m_mod2BtnGrp->addButton( sync_osc2_btn ); + m_mod2BtnGrp->addButton( fm_osc2_btn ); - - -void oscillatorObject::oscWaveCh( int _n ) -{ - m_waveShape = static_cast( _n ); -} - - - - -void oscillatorObject::oscUserDefWaveDblClick( void ) -{ - QString af = m_sampleBuffer->openAudioFile(); - if( af != "" ) + for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { - m_sampleBuffer->setAudioFile( af ); - toolTip::add( m_usrWaveBtn, m_sampleBuffer->audioFile() ); + // setup volume-knob + volumeKnob * vk = new volumeKnob( knobSmall_17, this, tr( + "Osc %1 volume" ).arg( i+1 ) ); + vk->move( 6, 104 + i * 50 ); + vk->setHintText( tr( "Osc %1 volume:" ).arg( + i+1 ) + " ", "%" ); + vk->setWhatsThis( + tr( "With this knob you can set the volume of " + "oscillator %1. When setting a value of 0 the " + "oscillator is turned off. Otherwise you can " + "hear the oscillator as loud as you set it " + "here.").arg( i+1 ) ); + + // setup panning-knob + knob * pk = new knob( knobSmall_17, this, + tr( "Osc %1 panning" ).arg( i + 1 ) ); + pk->move( 33, 104 + i * 50 ); + pk->setHintText( tr("Osc %1 panning:").arg( i + 1 ) + " ", "" ); + pk->setWhatsThis( + tr( "With this knob you can set the panning of the " + "oscillator %1. A value of -100 means 100% " + "left and a value of 100 moves oscillator-" + "output right.").arg( i+1 ) ); + + // setup coarse-knob + knob * ck = new knob( knobSmall_17, this, + tr( "Osc %1 coarse detuning" ).arg( i + 1 ) ); + ck->move( 66, 104 + i * 50 ); + ck->setHintText( tr( "Osc %1 coarse detuning:" ).arg( i + 1 ) + + " ", " " + tr( "semitones" ) ); + ck->setWhatsThis( + tr( "With this knob you can set the coarse detuning of " + "oscillator %1. You can detune the oscillator " + "12 semitones (1 octave) up and down. This is " + "useful for creating sounds with a chord." ). + arg( i + 1 ) ); + + // setup knob for left fine-detuning + knob * flk = new knob( knobSmall_17, this, + tr( "Osc %1 fine detuning left" ).arg( i+1 ) ); + flk->move( 90, 104 + i * 50 ); + flk->setHintText( tr( "Osc %1 fine detuning left:" ). + arg( i + 1 ) + " ", + " " + tr( "cents" ) ); + flk->setWhatsThis( + tr( "With this knob you can set the fine detuning of " + "oscillator %1 for the left channel. The fine-" + "detuning is ranged between -100 cents and " + "+100 cents. This is useful for creating " + "\"fat\" sounds." ).arg( i + 1 ) ); + + // setup knob for right fine-detuning + knob * frk = new knob( knobSmall_17, this, + tr( "Osc %1 fine detuning right" ).arg( i + 1 ) ); + frk->move( 110, 104 + i * 50 ); + frk->setHintText( tr( "Osc %1 fine detuning right:" ). + arg( i + 1 ) + " ", + " " + tr( "cents" ) ); + frk->setWhatsThis( + tr( "With this knob you can set the fine detuning of " + "oscillator %1 for the right channel. The " + "fine-detuning is ranged between -100 cents " + "and +100 cents. This is useful for creating " + "\"fat\" sounds." ).arg( i+1 ) ); + + // setup phase-offset-knob + knob * pok = new knob( knobSmall_17, this, + tr( "Osc %1 phase-offset" ).arg( i+1 ) ); + pok->move( 142, 104 + i * 50 ); + pok->setHintText( tr( "Osc %1 phase-offset:" ). + arg( i + 1 ) + " ", + " " + tr( "degrees" ) ); + pok->setWhatsThis( + tr( "With this knob you can set the phase-offset of " + "oscillator %1. That means you can move the " + "point within an oscillation where the " + "oscillator begins to oscillate. For example " + "if you have a sine-wave and have a phase-" + "offset of 180 degrees the wave will first go " + "down. It's the same with a square-wave." + ).arg( i+1 ) ); + + // setup stereo-phase-detuning-knob + knob * spdk = new knob( knobSmall_17, this, + tr( "Osc %1 stereo phase-detuning" ).arg( i+1 ) ); + spdk->move( 166, 104 + i * 50 ); + spdk->setHintText( tr("Osc %1 stereo phase-detuning:" ). + arg( i + 1 ) + " ", + " " + tr( "degrees" ) ); + spdk->setWhatsThis( + tr( "With this knob you can set the stereo phase-" + "detuning of oscillator %1. The stereo phase-" + "detuning specifies the size of the difference " + "between the phase-offset of left and right " + "channel. This is very good for creating wide " + "stereo-sounds." ).arg( i+1 ) ); + + + pixmapButton * sin_wave_btn = new pixmapButton( this, NULL ); + sin_wave_btn->move( 188, 105 + i * 50 ); + sin_wave_btn->setActiveGraphic( embed::getIconPixmap( + "sin_wave_active" ) ); + sin_wave_btn->setInactiveGraphic( embed::getIconPixmap( + "sin_wave_inactive" ) ); + toolTip::add( sin_wave_btn, + tr( "Click here if you want a sine-wave for " + "current oscillator." ) ); + + pixmapButton * triangle_wave_btn = + new pixmapButton( this, NULL ); + triangle_wave_btn->move( 203, 105 + i * 50 ); + triangle_wave_btn->setActiveGraphic( + embed::getIconPixmap( "triangle_wave_active" ) ); + triangle_wave_btn->setInactiveGraphic( + embed::getIconPixmap( "triangle_wave_inactive" ) ); + toolTip::add( triangle_wave_btn, + tr( "Click here if you want a triangle-wave " + "for current oscillator." ) ); + + pixmapButton * saw_wave_btn = new pixmapButton( this, NULL ); + saw_wave_btn->move( 218, 105 + i * 50 ); + saw_wave_btn->setActiveGraphic( embed::getIconPixmap( + "saw_wave_active" ) ); + saw_wave_btn->setInactiveGraphic( embed::getIconPixmap( + "saw_wave_inactive" ) ); + toolTip::add( saw_wave_btn, + tr( "Click here if you want a saw-wave for " + "current oscillator." ) ); + + pixmapButton * sqr_wave_btn = new pixmapButton( this, NULL ); + sqr_wave_btn->move( 233, 105 + i * 50 ); + sqr_wave_btn->setActiveGraphic( embed::getIconPixmap( + "square_wave_active" ) ); + sqr_wave_btn->setInactiveGraphic( embed::getIconPixmap( + "square_wave_inactive" ) ); + toolTip::add( sqr_wave_btn, + tr( "Click here if you want a square-wave for " + "current oscillator." ) ); + + pixmapButton * moog_saw_wave_btn = + new pixmapButton( this, NULL ); + moog_saw_wave_btn->move( 188, 120+i*50 ); + moog_saw_wave_btn->setActiveGraphic( + embed::getIconPixmap( "moog_saw_wave_active" ) ); + moog_saw_wave_btn->setInactiveGraphic( + embed::getIconPixmap( "moog_saw_wave_inactive" ) ); + toolTip::add( moog_saw_wave_btn, + tr( "Click here if you want a moog-saw-wave " + "for current oscillator." ) ); + + pixmapButton * exp_wave_btn = new pixmapButton( this, NULL ); + exp_wave_btn->move( 203, 120+i*50 ); + exp_wave_btn->setActiveGraphic( embed::getIconPixmap( + "exp_wave_active" ) ); + exp_wave_btn->setInactiveGraphic( embed::getIconPixmap( + "exp_wave_inactive" ) ); + toolTip::add( exp_wave_btn, + tr( "Click here if you want an exponential " + "wave for current oscillator." ) ); + + pixmapButton * white_noise_btn = new pixmapButton( this, NULL ); + white_noise_btn->move( 218, 120+i*50 ); + white_noise_btn->setActiveGraphic( + embed::getIconPixmap( "white_noise_wave_active" ) ); + white_noise_btn->setInactiveGraphic( + embed::getIconPixmap( "white_noise_wave_inactive" ) ); + toolTip::add( white_noise_btn, + tr( "Click here if you want a white-noise for " + "current oscillator." ) ); + + pixmapButton * uwb = new pixmapButton( this, NULL ); + uwb->move( 233, 120+i*50 ); + uwb->setActiveGraphic( embed::getIconPixmap( + "usr_wave_active" ) ); + uwb->setInactiveGraphic( embed::getIconPixmap( + "usr_wave_inactive" ) ); + toolTip::add( uwb, tr( "Click here if you want a user-defined " + "wave-shape for current oscillator." ) ); + + automatableButtonGroup * wsbg = + new automatableButtonGroup( this, + tr( "Osc %1 wave shape" ).arg( i + 1 ) ); + wsbg->addButton( sin_wave_btn ); + wsbg->addButton( triangle_wave_btn ); + wsbg->addButton( saw_wave_btn ); + wsbg->addButton( sqr_wave_btn ); + wsbg->addButton( moog_saw_wave_btn ); + wsbg->addButton( exp_wave_btn ); + wsbg->addButton( white_noise_btn ); + wsbg->addButton( uwb ); + +/* connect( m_osc[i].m_usrWaveBtn, SIGNAL( doubleClicked() ), + &m_osc[i], SLOT( oscUserDefWaveDblClick() ) );*/ + + m_oscKnobs[i] = oscillatorKnobs( vk, pk, ck, flk, frk, pok, + spdk, uwb, wsbg ); + } } -void oscillatorObject::modCh( int _n ) +tripleOscillatorView::~tripleOscillatorView() { - m_modulationAlgo = static_cast( _n ); } -void oscillatorObject::updateVolume( void ) +void tripleOscillatorView::modelChanged( void ) { - if( m_panKnob->value() >= 0.0f ) + tripleOscillator * t = castModel(); + m_mod1BtnGrp->setModel( &t->m_osc[0]->m_modulationAlgoModel ); + m_mod2BtnGrp->setModel( &t->m_osc[1]->m_modulationAlgoModel ); + + for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { - float panningFactorLeft = 1.0f - m_panKnob->value() - / (float)PANNING_RIGHT; - m_volumeLeft = panningFactorLeft * m_volKnob->value() / 100.0f; - m_volumeRight = m_volKnob->value() / 100.0f; + m_oscKnobs[i].m_volKnob->setModel( + &t->m_osc[i]->m_volumeModel ); + m_oscKnobs[i].m_panKnob->setModel( + &t->m_osc[i]->m_panModel ); + m_oscKnobs[i].m_coarseKnob->setModel( + &t->m_osc[i]->m_coarseModel ); + m_oscKnobs[i].m_fineLeftKnob->setModel( + &t->m_osc[i]->m_fineLeftModel ); + m_oscKnobs[i].m_fineRightKnob->setModel( + &t->m_osc[i]->m_fineRightModel ); + m_oscKnobs[i].m_phaseOffsetKnob->setModel( + &t->m_osc[i]->m_phaseOffsetModel ); + m_oscKnobs[i].m_stereoPhaseDetuningKnob->setModel( + &t->m_osc[i]->m_stereoPhaseDetuningModel ); + m_oscKnobs[i].m_waveShapeBtnGrp->setModel( + &t->m_osc[i]->m_waveShapeModel ); + connect( m_oscKnobs[i].m_userWaveButton, + SIGNAL( doubleClicked() ), + t->m_osc[i], SLOT( oscUserDefWaveDblClick() ) ); } - else - { - m_volumeLeft = m_volKnob->value() / 100.0f; - float panningFactorRight = 1.0f + m_panKnob->value() - / (float)PANNING_RIGHT; - m_volumeRight = panningFactorRight * m_volKnob->value() - / 100.0f; - } -} - - - - -void oscillatorObject::updateDetuningLeft( void ) -{ - m_detuningLeft = powf( 2.0f, ( (float)m_coarseKnob->value() * 100.0f - + (float)m_fineLKnob->value() ) / 1200.0f ) - / engine::getMixer()->sampleRate(); -} - - - - -void oscillatorObject::updateDetuningRight( void ) -{ - m_detuningRight = powf( 2.0f, ( (float)m_coarseKnob->value() * 100.0f - + (float)m_fineRKnob->value() ) / 1200.0f ) - / engine::getMixer()->sampleRate(); -} - - - - -void oscillatorObject::updatePhaseOffsetLeft( void ) -{ - m_phaseOffsetLeft = ( m_phaseOffsetKnob->value() + - m_stereoPhaseDetuningKnob->value() ) / 360.0f; -} - - - - -void oscillatorObject::updatePhaseOffsetRight( void ) -{ - m_phaseOffsetRight = m_phaseOffsetKnob->value() / 360.0f; } @@ -792,7 +824,7 @@ extern "C" { // neccessary for getting instance out of shared lib -plugin * lmms_plugin_main( void * _data ) +plugin * lmms_plugin_main( model *, void * _data ) { return( new tripleOscillator( static_cast( _data ) ) ); @@ -801,8 +833,5 @@ plugin * lmms_plugin_main( void * _data ) } -#undef setChecked - - #include "triple_oscillator.moc" diff --git a/plugins/triple_oscillator/triple_oscillator.h b/plugins/triple_oscillator/triple_oscillator.h index 56650386d..9ee038a90 100644 --- a/plugins/triple_oscillator/triple_oscillator.h +++ b/plugins/triple_oscillator/triple_oscillator.h @@ -2,7 +2,7 @@ * triple_oscillator.h - declaration of class tripleOscillator a powerful * instrument-plugin with 3 oscillators * - * Copyright (c) 2004-2007 Tobias Doerffel + * Copyright (c) 2004-2008 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -28,7 +28,9 @@ #include "instrument.h" +#include "instrument_view.h" #include "oscillator.h" +#include "automatable_model.h" class automatableButtonGroup; @@ -41,25 +43,29 @@ class volumeKnob; const int NUM_OF_OSCILLATORS = 3; -class oscillatorObject : public QObject +class oscillatorObject : public model { Q_OBJECT +public: + oscillatorObject( model * _parent, track * _track ); + virtual ~oscillatorObject(); + + private: - oscillator::waveShapes m_waveShape; - volumeKnob * m_volKnob; - knob * m_panKnob; - knob * m_coarseKnob; - knob * m_fineLKnob; - knob * m_fineRKnob; - knob * m_phaseOffsetKnob; - knob * m_stereoPhaseDetuningKnob; - automatableButtonGroup * m_waveBtnGrp; - pixmapButton * m_usrWaveBtn; + floatModel m_volumeModel; + floatModel m_panModel; + floatModel m_coarseModel; + floatModel m_fineLeftModel; + floatModel m_fineRightModel; + floatModel m_phaseOffsetModel; + floatModel m_stereoPhaseDetuningModel; + intModel m_waveShapeModel; + intModel m_modulationAlgoModel; sampleBuffer * m_sampleBuffer; - oscillator::modulationAlgos m_modulationAlgo; float m_volumeLeft; float m_volumeRight; + // normalized detuning -> x/sampleRate float m_detuningLeft; float m_detuningRight; @@ -67,18 +73,13 @@ private: float m_phaseOffsetLeft; float m_phaseOffsetRight; - oscillatorObject( void ); - virtual ~oscillatorObject(); - friend class tripleOscillator; + friend class tripleOscillatorView; private slots: - void oscWaveCh( int _n ); void oscUserDefWaveDblClick( void ); - void modCh( int _n ); - void updateVolume( void ); void updateDetuningLeft( void ); void updateDetuningRight( void ); @@ -94,7 +95,7 @@ class tripleOscillator : public instrument { Q_OBJECT public: - tripleOscillator( instrumentTrack * _channel ); + tripleOscillator( instrumentTrack * _track ); virtual ~tripleOscillator(); virtual void FASTCALL playNote( notePlayHandle * _n, @@ -116,6 +117,8 @@ public: return( 128 ); } + virtual pluginView * instantiateView( QWidget * _parent ); + protected slots: void updateAllDetuning( void ); @@ -124,7 +127,7 @@ protected slots: private: instrumentTrack * m_instrumentTrack; - oscillatorObject m_osc[NUM_OF_OSCILLATORS]; + oscillatorObject * m_osc[NUM_OF_OSCILLATORS]; struct oscPtr { @@ -132,10 +135,66 @@ private: oscillator * oscRight; } ; - automatableButtonGroup * m_mod1BtnGrp; - automatableButtonGroup * m_mod2BtnGrp; + + friend class tripleOscillatorView; } ; + +class tripleOscillatorView : public instrumentView +{ +public: + tripleOscillatorView( instrument * _instrument, QWidget * _parent ); + virtual ~tripleOscillatorView(); + + +private: + virtual void modelChanged( void ); + + automatableButtonGroup * m_mod1BtnGrp; + automatableButtonGroup * m_mod2BtnGrp; + + struct oscillatorKnobs + { + oscillatorKnobs( volumeKnob * v, + knob * p, + knob * c, + knob * fl, + knob * fr, + knob * po, + knob * spd, + pixmapButton * uwb, + automatableButtonGroup * wsbg ) : + m_volKnob( v ), + m_panKnob( p ), + m_coarseKnob( c ), + m_fineLeftKnob( fl ), + m_fineRightKnob( fr ), + m_phaseOffsetKnob( po ), + m_stereoPhaseDetuningKnob( spd ), + m_userWaveButton( uwb ), + m_waveShapeBtnGrp( wsbg ) + { + } + oscillatorKnobs() + { + } + volumeKnob * m_volKnob; + knob * m_panKnob; + knob * m_coarseKnob; + knob * m_fineLeftKnob; + knob * m_fineRightKnob; + knob * m_phaseOffsetKnob; + knob * m_stereoPhaseDetuningKnob; + pixmapButton * m_userWaveButton; + automatableButtonGroup * m_waveShapeBtnGrp; + + } ; + + oscillatorKnobs m_oscKnobs[NUM_OF_OSCILLATORS]; +} ; + + + #endif