NotePlayHandle: send correct MidiNoteOff events if base note changed

When changing an InstrumentTrack's base note while NotePlayHandles are
active, they will send a wrong MidiNoteOff event due to the masterKey()
translation in InstrumentTrack::processOutEvent().

Therefore in NotePlayHandle remember the original base note value and
add the difference between original and current base note to the value
returned by NotePlayHandle::key(). Fixes hanging notes in MIDI-based
instruments such as ZynAddSubFX.

Furthermore some coding style improvements.

Closes #3146975.
This commit is contained in:
Tobias Doerffel
2010-12-31 13:13:45 +01:00
parent 65a0313807
commit a9717c0cc3
6 changed files with 109 additions and 88 deletions

View File

@@ -1,7 +1,7 @@
/*
* InstrumentFunctions.cpp - models for instrument-function-tab
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -167,7 +167,7 @@ void ChordCreator::processNote( notePlayHandle * _n )
// at the same time we only add sub-notes if nothing of the note was
// played yet, because otherwise we would add chord-subnotes every
// time an audio-buffer is rendered...
if( ( ( _n->isBaseNote() &&
if( ( ( _n->isTopNote() &&
_n->instrumentTrack()->isArpeggiatorEnabled() == false ) ||
_n->isPartOfArpeggio() ) &&
_n->totalFramesPlayed() == 0 &&
@@ -288,7 +288,7 @@ Arpeggiator::~Arpeggiator()
void Arpeggiator::processNote( notePlayHandle * _n )
{
const int base_note_key = _n->key();
if( _n->isBaseNote() == false ||
if( _n->isTopNote() == false ||
!m_arpEnabledModel.value() ||
( _n->released() && _n->releaseFramesDone() >=
_n->actualReleaseFramesToDo() ) )

View File

@@ -33,9 +33,8 @@
#include "song.h"
inline notePlayHandle::baseDetuning::baseDetuning(
DetuningHelper * _detuning ) :
m_detuning( _detuning ),
notePlayHandle::BaseDetuning::BaseDetuning( DetuningHelper *detuning ) :
m_detuning( detuning ),
m_value( m_detuning->automationPattern()->valueAt( 0 ) )
{
}
@@ -49,7 +48,7 @@ notePlayHandle::notePlayHandle( InstrumentTrack * _it,
const f_cnt_t _offset,
const f_cnt_t _frames,
const note & _n,
notePlayHandle * _parent,
notePlayHandle *parent,
const bool _part_of_arp ) :
playHandle( NotePlayHandle, _offset ),
note( _n.length(), _n.pos(), _n.key(),
@@ -63,34 +62,34 @@ notePlayHandle::notePlayHandle( InstrumentTrack * _it,
m_releaseFramesToDo( 0 ),
m_releaseFramesDone( 0 ),
m_released( false ),
m_baseNote( _parent == NULL ),
m_topNote( parent == NULL ),
m_partOfArpeggio( _part_of_arp ),
m_muted( false ),
m_bbTrack( NULL ),
#ifdef LMMS_SINGERBOT_SUPPORT
m_patternIndex( 0 ),
#endif
m_origTempo( engine::getSong()->getTempo() )
m_origTempo( engine::getSong()->getTempo() ),
m_origBaseNote( instrumentTrack()->baseNoteModel()->value() )
{
if( m_baseNote )
if( isTopNote() )
{
m_baseDetuning = new baseDetuning( detuning() );
m_baseDetuning = new BaseDetuning( detuning() );
m_instrumentTrack->m_processHandles.push_back( this );
}
else
{
m_baseDetuning = _parent->m_baseDetuning;
m_baseDetuning = parent->m_baseDetuning;
_parent->m_subNotes.push_back( this );
parent->m_subNotes.push_back( this );
// if there was an arp-note added and parent is a base-note
// we set arp-note-flag for indicating that parent is an
// arpeggio-base-note
_parent->m_partOfArpeggio = isPartOfArpeggio() &&
_parent->isBaseNote();
parent->m_partOfArpeggio = isPartOfArpeggio() && parent->isTopNote();
m_bbTrack = _parent->m_bbTrack;
m_bbTrack = parent->m_bbTrack;
#ifdef LMMS_SINGERBOT_SUPPORT
m_patternIndex = _parent->m_patternIndex;
m_patternIndex = parent->m_patternIndex;
#endif
}
@@ -99,12 +98,12 @@ notePlayHandle::notePlayHandle( InstrumentTrack * _it,
setFrames( _frames );
if( !isBaseNote() || !instrumentTrack()->isArpeggiatorEnabled() )
if( !isTopNote() || !instrumentTrack()->isArpeggiatorEnabled() )
{
// send MIDI-note-on-event
m_instrumentTrack->processOutEvent( midiEvent( MidiNoteOn,
m_instrumentTrack->midiPort()->realOutputChannel(),
key(), getMidiVelocity() ),
midiKey(), midiVelocity() ),
midiTime::fromFrames( offset(),
engine::framesPerTick() ) );
}
@@ -117,7 +116,7 @@ notePlayHandle::~notePlayHandle()
{
noteOff( 0 );
if( m_baseNote )
if( isTopNote() )
{
delete m_baseDetuning;
m_instrumentTrack->m_processHandles.removeAll( this );
@@ -151,14 +150,14 @@ void notePlayHandle::setVolume( const volume_t _volume )
note::setVolume( _volume );
m_instrumentTrack->processOutEvent( midiEvent( MidiKeyPressure,
m_instrumentTrack->midiPort()->realOutputChannel(),
key(), getMidiVelocity() ), 0 );
midiKey(), midiVelocity() ), 0 );
}
int notePlayHandle::getMidiVelocity() const
int notePlayHandle::midiVelocity() const
{
int vel = getVolume();
if( m_instrumentTrack->getVolume() < DefaultVolume )
@@ -171,6 +170,14 @@ int notePlayHandle::getMidiVelocity() const
int notePlayHandle::midiKey() const
{
return key() - m_origBaseNote + instrumentTrack()->baseNoteModel()->value();
}
void notePlayHandle::play( sampleFrame * _working_buffer )
{
if( m_muted )
@@ -324,12 +331,12 @@ void notePlayHandle::noteOff( const f_cnt_t _s )
m_releaseFramesToDo = qMax<f_cnt_t>( 0, // 10,
m_instrumentTrack->m_soundShaping.releaseFrames() );
if( !isBaseNote() || !instrumentTrack()->isArpeggiatorEnabled() )
if( !isTopNote() || !instrumentTrack()->isArpeggiatorEnabled() )
{
// send MIDI-note-off-event
m_instrumentTrack->processOutEvent( midiEvent( MidiNoteOff,
m_instrumentTrack->midiPort()->realOutputChannel(),
key(), 0 ),
midiKey(), 0 ),
midiTime::fromFrames( m_framesBeforeRelease,
engine::framesPerTick() ) );
}
@@ -372,8 +379,8 @@ float notePlayHandle::volumeLevel( const f_cnt_t _frame )
bool notePlayHandle::isArpeggioBaseNote() const
{
return isBaseNote() && ( m_partOfArpeggio ||
m_instrumentTrack->isArpeggiatorEnabled() );
return isTopNote() && ( m_partOfArpeggio ||
m_instrumentTrack->isArpeggiatorEnabled() );
}
@@ -456,8 +463,9 @@ bool notePlayHandle::operator==( const notePlayHandle & _nph ) const
offset() == _nph.offset() &&
m_totalFramesPlayed == _nph.m_totalFramesPlayed &&
m_released == _nph.m_released &&
m_baseNote == _nph.m_baseNote &&
m_topNote == _nph.m_topNote &&
m_partOfArpeggio == _nph.m_partOfArpeggio &&
m_origBaseNote == _nph.m_origBaseNote &&
m_muted == _nph.m_muted;
}

View File

@@ -898,8 +898,8 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke )
if( _ke->isAutoRepeat() == false && key_num > -1 )
{
m_pattern->instrumentTrack()->
getPiano()->handleKeyPress( key_num );
m_pattern->instrumentTrack()->pianoModel()->
handleKeyPress( key_num );
_ke->accept();
}
}
@@ -1182,8 +1182,8 @@ void pianoRoll::keyReleaseEvent( QKeyEvent * _ke )
if( _ke->isAutoRepeat() == false && key_num > -1 )
{
m_pattern->instrumentTrack()->
getPiano()->handleKeyRelease( key_num );
m_pattern->instrumentTrack()->pianoModel()->
handleKeyRelease( key_num );
_ke->accept();
}
}