mirror of
https://github.com/LMMS/lmms.git
synced 2026-03-14 03:59:35 -04:00
3-in-1 bugfix special
Fixes bugs: #568, #289 and the incorrect timing for midi-noteoffs (see mailing list)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user