@@ -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()
|
||||
{
|
||||
|
||||
@@ -229,7 +229,7 @@ public:
|
||||
return m_playHandles;
|
||||
}
|
||||
|
||||
void removePlayHandles( track * _track );
|
||||
void removePlayHandles( track * _track, bool removeIPHs = true );
|
||||
|
||||
bool hasNotePlayHandles();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user