InstrumentTrack: manage MIDI note recording in NotePlayHandle

We must not record notes when receiving external MidiNoteOff events
as e.g. the sustain pedal still might be pressed. State tracking for
features like these is done inside NotePlayHandle so move the recording-
related signal emission from InstrumentTrack to NotePlayHandle.

Closes #168.
This commit is contained in:
Tobias Doerffel
2014-01-26 16:46:12 +01:00
parent 725ff59f0e
commit 4b340f7d5f
4 changed files with 27 additions and 51 deletions

View File

@@ -204,8 +204,8 @@ public:
signals:
void instrumentChanged();
void newNote();
void noteOn( const note & _n );
void noteOff( const note & _n );
void midiNoteOn( const note& );
void midiNoteOff( const note& );
void nameChanged();

View File

@@ -105,6 +105,11 @@ notePlayHandle::notePlayHandle( InstrumentTrack * _it,
setFrames( _frames );
// inform attached components about new MIDI note (used for recording in Piano Roll)
if( m_origin == OriginMidiInput )
{
m_instrumentTrack->midiNoteOn( *this );
}
if( !isTopNote() || !instrumentTrack()->isArpeggioEnabled() )
{
@@ -122,6 +127,13 @@ notePlayHandle::~notePlayHandle()
{
noteOff( 0 );
// inform attached components about MIDI finished (used for recording in Piano Roll)
if( m_origin == OriginMidiInput )
{
setLength( MidiTime( static_cast<f_cnt_t>( totalFramesPlayed() / engine::framesPerTick() ) ) );
m_instrumentTrack->midiNoteOff( *this );
}
if( isTopNote() )
{
delete m_baseDetuning;

View File

@@ -765,15 +765,9 @@ void pianoRoll::setCurrentPattern( pattern * _new_pattern )
// of start-notes and so on...)
resizeEvent( NULL );
connect( m_pattern->instrumentTrack(),
SIGNAL( noteOn( const note & ) ),
this, SLOT( startRecordNote( const note & ) ) );
connect( m_pattern->instrumentTrack(),
SIGNAL( noteOff( const note & ) ),
this, SLOT( finishRecordNote( const note & ) ) );
connect( m_pattern->instrumentTrack()->pianoModel(),
SIGNAL( dataChanged() ),
this, SLOT( update() ) );
connect( m_pattern->instrumentTrack(), SIGNAL( midiNoteOn( const note& ) ), this, SLOT( startRecordNote( const note& ) ) );
connect( m_pattern->instrumentTrack(), SIGNAL( midiNoteOff( const note& ) ), this, SLOT( finishRecordNote( const note& ) ) );
connect( m_pattern->instrumentTrack()->pianoModel(), SIGNAL( dataChanged() ), this, SLOT( update() ) );
setWindowTitle( tr( "Piano-Roll - %1" ).arg( m_pattern->name() ) );

View File

@@ -237,20 +237,16 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti
{
if( m_notes[event.key()] == NULL )
{
// create temporary note
note n;
n.setKey( event.key() );
n.setVolume( event.volume() );
// create (timed) note-play-handle
notePlayHandle* nph = new notePlayHandle( this, time.frames( engine::framesPerTick() ), typeInfo<f_cnt_t>::max() / 2,
n, NULL, false, event.channel() );
notePlayHandle* nph = new notePlayHandle( this, time.frames( engine::framesPerTick() ),
typeInfo<f_cnt_t>::max() / 2,
note( MidiTime(), MidiTime(), event.key(), event.volume() ),
NULL, false, event.channel(),
notePlayHandle::OriginMidiInput );
if( engine::mixer()->addPlayHandle( nph ) )
{
m_notes[event.key()] = nph;
}
emit noteOn( n );
}
eventHandled = true;
@@ -258,28 +254,15 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti
}
case MidiNoteOff:
{
notePlayHandle* nph = m_notes[event.key()];
if( nph != NULL )
if( m_notes[event.key()] != NULL )
{
// create dummy-note which has the same length
// as the played note for sending it later
// to all slots connected to signal noteOff()
// this is for example needed by piano-roll for
// recording notes into a pattern
note n( MidiTime( static_cast<f_cnt_t>( nph->totalFramesPlayed() / engine::framesPerTick() ) ),
0, nph->key(), nph->getVolume(), nph->getPanning() );
emit noteOff( n );
// now do actual note off and remove internal reference to NotePlayHandle (which itself will
// do actual note off and remove internal reference to NotePlayHandle (which itself will
// be deleted later automatically)
nph->noteOff();
m_notes[event.key()]->noteOff();
m_notes[event.key()] = NULL;
}
eventHandled = true;
break;
}
case MidiKeyPressure:
if( m_notes[event.key()] != NULL )
@@ -467,24 +450,11 @@ QString InstrumentTrack::instrumentName() const
void InstrumentTrack::deleteNotePluginData( notePlayHandle * _n )
void InstrumentTrack::deleteNotePluginData( notePlayHandle* n )
{
if( m_instrument != NULL )
{
m_instrument->deleteNotePluginData( _n );
}
// Notes deleted when keys still pressed
if( m_notes[_n->key()] == _n )
{
note done_note( MidiTime( static_cast<f_cnt_t>(
_n->totalFramesPlayed() /
engine::framesPerTick() ) ),
0, _n->key(),
_n->getVolume(), _n->getPanning() );
_n->noteOff();
m_notes[_n->key()] = NULL;
emit noteOff( done_note );
m_instrument->deleteNotePluginData( n );
}
}