diff --git a/include/AutomationPattern.h b/include/AutomationPattern.h index 149a8954b2d..480b69f6af0 100644 --- a/include/AutomationPattern.h +++ b/include/AutomationPattern.h @@ -76,14 +76,17 @@ class EXPORT AutomationPattern : public TrackContentObject MidiTime timeMapLength() const; void updateLength(); - MidiTime putValue( const MidiTime & _time, const float _value, - const bool _quant_pos = true ); + MidiTime putValue( const MidiTime & time, + const float value, + const bool quantPos = true, + const bool controlKey = false ); - void removeValue( const MidiTime & _time, - const bool _quant_pos = true ); + void removeValue( const MidiTime & time ); - MidiTime setDragValue( const MidiTime & _time, const float _value, - const bool _quant_pos = true ); + MidiTime setDragValue( const MidiTime & time, + const float value, + const bool quantPos = true, + const bool controlKey = false ); void applyDragValue(); diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index 6c9d7b7d383..d800b97c750 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -204,23 +204,34 @@ void AutomationPattern::updateLength() -MidiTime AutomationPattern::putValue( const MidiTime & _time, - const float _value, - const bool _quant_pos ) +MidiTime AutomationPattern::putValue( const MidiTime & time, + const float value, + const bool quantPos, + const bool controlKey ) { cleanObjects(); - MidiTime newTime = _quant_pos ? - Note::quantized( _time, quantization() ) : - _time; + MidiTime newTime = quantPos ? + Note::quantized( time, quantization() ) : + time; - m_timeMap[newTime] = _value; + m_timeMap[ newTime ] = value; timeMap::const_iterator it = m_timeMap.find( newTime ); + + // Remove control points that are covered by the new points + // quantization value. Control Key to override + if( ! controlKey ) + { + for( int i = newTime + 1; i < newTime + quantization(); ++i ) + { + AutomationPattern::removeValue( i ); + } + } if( it != m_timeMap.begin() ) { --it; } - generateTangents(it, 3); + generateTangents( it, 3 ); // we need to maximize our length in case we're part of a hidden // automation track as the user can't resize this pattern @@ -237,18 +248,13 @@ MidiTime AutomationPattern::putValue( const MidiTime & _time, -void AutomationPattern::removeValue( const MidiTime & _time, - const bool _quant_pos ) +void AutomationPattern::removeValue( const MidiTime & time ) { cleanObjects(); - MidiTime newTime = _quant_pos ? - Note::quantized( _time, quantization() ) : - _time; - - m_timeMap.remove( newTime ); - m_tangents.remove( newTime ); - timeMap::const_iterator it = m_timeMap.lowerBound( newTime ); + m_timeMap.remove( time ); + m_tangents.remove( time ); + timeMap::const_iterator it = m_timeMap.lowerBound( time ); if( it != m_timeMap.begin() ) { --it; @@ -267,7 +273,7 @@ void AutomationPattern::removeValue( const MidiTime & _time, /** - * @brief Set the position of the point that is being draged. + * @brief Set the position of the point that is being dragged. * Calling this function will also automatically set m_dragging to true, * which applyDragValue() have to be called to m_dragging. * @param the time(x position) of the point being dragged @@ -275,14 +281,16 @@ void AutomationPattern::removeValue( const MidiTime & _time, * @param true to snip x position * @return */ -MidiTime AutomationPattern::setDragValue( const MidiTime & _time, const float _value, - const bool _quant_pos ) +MidiTime AutomationPattern::setDragValue( const MidiTime & time, + const float value, + const bool quantPos, + const bool controlKey ) { if( m_dragging == false ) { - MidiTime newTime = _quant_pos ? - Note::quantized( _time, quantization() ) : - _time; + MidiTime newTime = quantPos ? + Note::quantized( time, quantization() ) : + time; this->removeValue( newTime ); m_oldTimeMap = m_timeMap; m_dragging = true; @@ -293,10 +301,10 @@ MidiTime AutomationPattern::setDragValue( const MidiTime & _time, const float _v for( timeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); ++it ) { - generateTangents(it, 3); + generateTangents( it, 3 ); } - return this->putValue( _time, _value, _quant_pos ); + return this->putValue( time, value, quantPos, controlKey ); } @@ -648,7 +656,7 @@ void AutomationPattern::processMidiTime( const MidiTime & time ) } else if( valueAt( time ) != value ) { - removeValue( time, false ); + removeValue( time ); } } } diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index fd42090d820..a425b0dea39 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -132,6 +132,17 @@ AutomationEditor::AutomationEditor() : { m_quantizeModel.addItem( "1/" + QString::number( 1 << i ) ); } + for( int i = 0; i < 5; ++i ) + { + m_quantizeModel.addItem( "1/" + + QString::number( ( 1 << i ) * 3 ) ); + } + m_quantizeModel.addItem( "1/192" ); + + connect( &m_quantizeModel, SIGNAL(dataChanged() ), + this, SLOT( setQuantization() ) ); + m_quantizeModel.setValue( m_quantizeModel.findText( "1/8" ) ); + if( s_toolYFlip == NULL ) { s_toolYFlip = new QPixmap( embed::getIconPixmap( @@ -143,9 +154,6 @@ AutomationEditor::AutomationEditor() : "flip_x" ) ); } - connect(&m_quantizeModel, SIGNAL(dataChanged()), this, SLOT(setQuantization())); - m_quantizeModel.setValue( m_quantizeModel.findText( "1/16" ) ); - // add time-line m_timeLine = new TimeLineWidget( VALUES_WIDTH, 0, m_ppt, Engine::getSong()->getPlayPos( @@ -555,7 +563,9 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) MidiTime new_time = m_pattern->setDragValue( value_pos, - level ); + level, true, + mouseEvent->modifiers() & + Qt::ControlModifier ); // reset it so that it can be used for // ops (move, resize) after this @@ -695,7 +705,9 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) // moved properly according to new starting- // time in the time map of pattern m_pattern->setDragValue( MidiTime( pos_ticks ), - level ); + level, true, + mouseEvent->modifiers() & + Qt::ControlModifier ); } Engine::getSong()->setModified(); @@ -706,7 +718,14 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) ( mouseEvent->buttons() & Qt::LeftButton && m_editMode == ERASE ) ) { - m_pattern->removeValue( MidiTime( pos_ticks ) ); + // int resolution needed to improve the sensitivity of + // the erase manoeuvre with zoom levels < 100% + int zoom = m_zoomingXModel.value(); + int resolution = 1 + zoom * zoom; + for( int i = -resolution; i < resolution; ++i ) + { + m_pattern->removeValue( MidiTime( pos_ticks + i ) ); + } } else if( mouseEvent->buttons() & Qt::NoButton && m_editMode == DRAW ) { @@ -2015,8 +2034,22 @@ void AutomationEditor::zoomingYChanged() void AutomationEditor::setQuantization() { - int quantization = DefaultTicksPerTact / (1 << m_quantizeModel.value());; - AutomationPattern::setQuantization(quantization); + int quantization = m_quantizeModel.value(); + if( quantization < 7 ) + { + quantization = 1 << quantization; + } + else if( quantization < 12 ) + { + quantization = 1 << ( quantization - 7 ); + quantization *= 3; + } + else + { + quantization = DefaultTicksPerTact; + } + quantization = DefaultTicksPerTact / quantization; + AutomationPattern::setQuantization( quantization ); } @@ -2325,7 +2358,12 @@ AutomationEditorWindow::AutomationEditorWindow() : quantizationActionsToolBar->addWidget( quantize_lbl ); quantizationActionsToolBar->addWidget( m_quantizeComboBox ); - + m_quantizeComboBox->setToolTip( tr( "Quantization" ) ); + m_quantizeComboBox->setWhatsThis( tr( "Quantization. Sets the smallest " + "step size for the Automation Point. By default " + "this also sets the length, clearing out other " + "points in the range. Press to override " + "this behaviour." ) ); // Setup our actual window setFocusPolicy( Qt::StrongFocus );