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:
@@ -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() ) )
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user