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:
@@ -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();
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() ) );
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user