Merge pull request #848 from diizy/midioffset

5-in-1 bugfix special
This commit is contained in:
Tobias Doerffel
2014-06-15 23:29:21 +02:00
6 changed files with 57 additions and 24 deletions

View File

@@ -74,7 +74,7 @@ public:
virtual void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 );
virtual void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 );
// silence all running notes played by this track
void silenceAllNotes();
void silenceAllNotes( bool removeIPH = false );
bool isSustainPedalPressed() const
{
@@ -160,6 +160,8 @@ public:
{
return &m_baseNoteModel;
}
int baseNote() const;
Piano *pianoModel()
{

View File

@@ -229,7 +229,7 @@ public:
return m_playHandles;
}
void removePlayHandles( track * _track );
void removePlayHandles( track * _track, bool removeIPHs = true );
bool hasNotePlayHandles();

View File

@@ -94,7 +94,7 @@ public:
/*! Returns whether playback of note is finished and thus handle can be deleted */
virtual bool isFinished() const
{
return m_released && framesLeft() <= 0;
return m_released && framesLeft() <= 0 && m_scheduledNoteOff < 0;
}
/*! Returns number of frames left for playback */
@@ -264,6 +264,7 @@ private:
// played after release
f_cnt_t m_releaseFramesDone; // number of frames done after
// release of note
f_cnt_t m_scheduledNoteOff; // variable for scheduling noteoff at next period
NotePlayHandleList m_subNotes; // used for chords and arpeggios
volatile bool m_released; // indicates whether note is released
bool m_hasParent;

View File

@@ -686,13 +686,13 @@ void Mixer::removePlayHandle( PlayHandle * _ph )
void Mixer::removePlayHandles( track * _track )
void Mixer::removePlayHandles( track * _track, bool removeIPHs )
{
lock();
PlayHandleList::Iterator it = m_playHandles.begin();
while( it != m_playHandles.end() )
{
if( ( *it )->isFromTrack( _track ) )
if( ( *it )->isFromTrack( _track ) && ( removeIPHs || ( *it )->type() != PlayHandle::TypeInstrumentPlayHandle ) )
{
delete *it;
it = m_playHandles.erase( it );

View File

@@ -61,13 +61,14 @@ 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 ),
m_muted( false ),
m_bbTrack( NULL ),
m_origTempo( engine::getSong()->getTempo() ),
m_origBaseNote( instrumentTrack->baseNoteModel()->value() ),
m_origBaseNote( instrumentTrack->baseNote() ),
m_frequency( 0 ),
m_unpitchedFrequency( 0 ),
m_baseDetuning( NULL ),
@@ -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();
@@ -118,7 +119,14 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
NotePlayHandle::~NotePlayHandle()
{
noteOff( 0 );
if( m_scheduledNoteOff >= 0 ) // ensure that scheduled noteoffs get triggered if somehow the nph got destructed prematurely
{
m_instrumentTrack->processOutEvent(
MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
MidiTime::fromFrames( m_scheduledNoteOff, engine::framesPerTick() ),
m_scheduledNoteOff );
}
if( hasParent() == false )
{
delete m_baseDetuning;
@@ -174,7 +182,7 @@ void NotePlayHandle::setPanning( panning_t panning )
int NotePlayHandle::midiKey() const
{
return key() - m_origBaseNote + instrumentTrack()->baseNoteModel()->value();
return key() - m_origBaseNote + instrumentTrack()->baseNote();
}
@@ -182,6 +190,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;
@@ -189,7 +206,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer )
if( m_released == false &&
instrumentTrack()->isSustainPedalPressed() == false &&
m_totalFramesPlayed + engine::mixer()->framesPerPeriod() >= m_frames )
m_totalFramesPlayed + engine::mixer()->framesPerPeriod() > m_frames )
{
noteOff( m_frames - m_totalFramesPlayed );
}
@@ -289,9 +306,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 +347,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)

View File

@@ -135,12 +135,17 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) :
}
int InstrumentTrack::baseNote() const
{
return m_baseNoteModel.value() - engine::getSong()->masterPitch();
}
InstrumentTrack::~InstrumentTrack()
{
// kill all running notes
silenceAllNotes();
// kill all running notes and the iph
silenceAllNotes( true );
// now we're save deleting the instrument
delete m_instrument;
@@ -397,7 +402,7 @@ void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& t
void InstrumentTrack::silenceAllNotes()
void InstrumentTrack::silenceAllNotes( bool removeIPH )
{
engine::mixer()->lock();
for( int i = 0; i < NumKeys; ++i )
@@ -408,7 +413,7 @@ void InstrumentTrack::silenceAllNotes()
// invalidate all NotePlayHandles linked to this track
m_processHandles.clear();
engine::mixer()->removePlayHandles( this );
engine::mixer()->removePlayHandles( this, removeIPH );
engine::mixer()->unlock();
}
@@ -537,7 +542,7 @@ void InstrumentTrack::updatePitchRange()
int InstrumentTrack::masterKey( int _midi_key ) const
{
int key = m_baseNoteModel.value() - engine::getSong()->masterPitch();
int key = baseNote();
return tLimit<int>( _midi_key - ( key - DefaultKey ), 0, NumKeys );
}
@@ -695,7 +700,7 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement
void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement )
{
silenceAllNotes();
silenceAllNotes( true );
engine::mixer()->lock();
@@ -771,7 +776,7 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement
Instrument * InstrumentTrack::loadInstrument( const QString & _plugin_name )
{
silenceAllNotes();
silenceAllNotes( true );
engine::mixer()->lock();
delete m_instrument;