3-in-1 bugfix special

Fixes bugs: #568, #289 and the incorrect timing for midi-noteoffs (see mailing list)
This commit is contained in:
Vesa
2014-06-13 12:01:15 +03:00
parent 32cfe84dfd
commit a172783cd0
2 changed files with 28 additions and 9 deletions

View File

@@ -61,6 +61,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
m_framesBeforeRelease( 0 ),
m_releaseFramesToDo( 0 ),
m_releaseFramesDone( 0 ),
m_scheduledNoteOff( -1 ),
m_released( false ),
m_hasParent( parent != NULL ),
m_hadChildren( false ),
@@ -100,7 +101,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
m_instrumentTrack->midiNoteOn( *this );
}
if( !isMasterNote() || !instrumentTrack->isArpeggioEnabled() )
if( hasParent() || !instrumentTrack->isArpeggioEnabled() )
{
const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity();
@@ -182,6 +183,15 @@ int NotePlayHandle::midiKey() const
void NotePlayHandle::play( sampleFrame * _working_buffer )
{
if( m_scheduledNoteOff >= 0 ) // always trigger scheduled noteoffs, because they're only scheduled if the note is released
{
m_instrumentTrack->processOutEvent(
MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
MidiTime::fromFrames( m_scheduledNoteOff, engine::framesPerTick() ),
m_scheduledNoteOff );
m_scheduledNoteOff = -1;
}
if( m_muted )
{
return;
@@ -289,9 +299,9 @@ f_cnt_t NotePlayHandle::framesLeft() const
{
return m_framesBeforeRelease;
}
else if( m_released && actualReleaseFramesToDo() >= m_releaseFramesDone )
else if( m_released )
{
return m_framesBeforeRelease + actualReleaseFramesToDo() - m_releaseFramesDone;
return m_framesBeforeRelease + m_releaseFramesToDo - m_releaseFramesDone;
}
return m_frames+actualReleaseFramesToDo()-m_totalFramesPlayed;
}
@@ -330,15 +340,23 @@ void NotePlayHandle::noteOff( const f_cnt_t _s )
// then set some variables indicating release-state
m_framesBeforeRelease = _s;
m_releaseFramesToDo = qMax<f_cnt_t>( 0, m_instrumentTrack->m_soundShaping.releaseFrames() );
m_releaseFramesToDo = qMax<f_cnt_t>( 0, actualReleaseFramesToDo() );
if( hasParent() || !instrumentTrack()->isArpeggioEnabled() )
{
// send MidiNoteOff event
m_instrumentTrack->processOutEvent(
MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
MidiTime::fromFrames( m_framesBeforeRelease, engine::framesPerTick() ),
_s );
f_cnt_t realOffset = offset() + _s; // get actual frameoffset of release, in global time
if( realOffset < engine::mixer()->framesPerPeriod() ) // if release happens during this period, trigger midievent
{
m_instrumentTrack->processOutEvent(
MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
MidiTime::fromFrames( realOffset, engine::framesPerTick() ),
realOffset );
}
else // if release flows over to next period, use m_scheduledNoteOff to trigger it later
{
m_scheduledNoteOff = realOffset - engine::mixer()->framesPerPeriod();
}
}
// inform attached components about MIDI finished (used for recording in Piano Roll)