* improved the way, MIDI-events are internally sent and handled

* fixed names of various member methods of notePlayHandle class
* full MIDI velocity when pressing key on test piano
* send volume changes of a notePlayHandle as MidiKeyPressure events
* send pitch changes of instrument track as MidiPitchBend events
* added detection for running MIDI notes
* correct calculation of MIDI key - makes remotePlugins respect base note settings



git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1562 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2008-09-06 22:04:03 +00:00
parent 61bdf0e089
commit 884b9ca671
11 changed files with 263 additions and 114 deletions

View File

@@ -1,3 +1,43 @@
2008-09-06 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* plugins/ladspa_effect/ladspa_subplugin_features.cpp:
* include/ladspa_base.h:
save LADSPA effect filenames without extension and add correct
one (depending on platform built for) when loading settings - fixes
missing effects when loading songs in Windows which were made in Linux
and vice versa
* include/audio_pulseaudio.h:
added information about bad latency when using PulseAudio output
* plugins/vestige/vestige.cpp:
* plugins/vestige/vestige.h:
only use MIDI anymore for controlling VST instruments
* plugins/lb302/lb302.cpp:
* include/note.h:
* include/instrument_track.h:
* include/midi.h:
* include/note_play_handle.h:
* src/tracks/instrument_track.cpp:
* src/core/preset_preview_play_handle.cpp:
* src/core/note_play_handle.cpp:
* src/core/instrument_functions.cpp:
* src/core/piano.cpp:
- improved the way, MIDI-events are internally sent and handled
- fixed names of various member methods of notePlayHandle class
- full MIDI velocity when pressing key on test piano
- send volume changes of a notePlayHandle as MidiKeyPressure events
- send pitch changes of instrument track as MidiPitchBend events
- added detection for running MIDI notes
- correct calculation of MIDI key - makes remotePlugins respect
base note settings
* src/core/midi/midi_port.cpp:
* src/core/midi/midi_alsa_seq.cpp:
fixed broken MIDI-output (when masking output events it didn't match
against correct output MIDI channel)
2008-09-06 Csaba Hruska <csaba.hruska/at/gmail.com>
* plugins/sid/sid_instrument.cpp:

View File

@@ -70,6 +70,8 @@ public:
void processAudioBuffer( sampleFrame * _buf, const fpp_t _frames,
notePlayHandle * _n );
midiEvent applyMasterKey( const midiEvent & _me );
virtual void processInEvent( const midiEvent & _me,
const midiTime & _time );
virtual void processOutEvent( const midiEvent & _me,
@@ -100,9 +102,9 @@ public:
// name-stuff
virtual void setName( const QString & _new_name );
// translate key of given notePlayHandle to absolute key (i.e.
// add global master-pitch and base-note in piano)
int masterKey( notePlayHandle * _n ) const;
// translate given key of a note-event to absolute key (i.e.
// add global master-pitch and base-note of this instrument track)
int masterKey( int _midi_key ) const;
// translate pitch to midi-pitch [0,16383]
inline int midiPitch( void ) const
@@ -181,6 +183,7 @@ protected:
protected slots:
void updateBaseNote( void );
void updatePitch( void );
private:
@@ -188,6 +191,7 @@ private:
midiPort m_midiPort;
notePlayHandle * m_notes[NumKeys];
int m_runningMidiNotes[NumKeys];
intModel m_baseNoteModel;

View File

@@ -81,6 +81,7 @@ enum MidiMetaEvents
const int MidiChannelCount = 16;
const int MidiControllerCount = 128;
const int MidiMaxVelocity = 127;
struct midiEvent
@@ -105,6 +106,14 @@ struct midiEvent
m_data.m_sysExDataLen = _data_len;
}
midiEvent( const midiEvent & _copy ) :
m_type( _copy.m_type ),
m_channel( _copy.m_channel ),
m_data( _copy.m_data ),
m_sysExData( _copy.m_sysExData )
{
}
inline Uint16 key( void ) const
{
return( m_data.m_param[0] );
@@ -125,6 +134,12 @@ struct midiEvent
return( m_data.m_param[1] );
}
inline volume getVolume( void ) const
{
return( velocity() * 100 / MidiMaxVelocity );
}
MidiEventTypes m_type; // MIDI event type
Sint8 m_channel; // MIDI channel
union

View File

@@ -94,7 +94,7 @@ public:
void setLength( const midiTime & _length );
void setPos( const midiTime & _pos );
void setKey( const int _key );
void setVolume( const volume _volume = DefaultVolume );
virtual void setVolume( const volume _volume = DefaultVolume );
void setPanning( const panning _panning = DefaultPanning );
void quantizeLength( const int _q_grid );
void quantizePos( const int _q_grid );

View File

@@ -52,9 +52,12 @@ public:
const f_cnt_t _offset,
const f_cnt_t _frames, const note & _n,
notePlayHandle * _parent = NULL,
const bool _arp_note = FALSE );
const bool _part_of_arp = false );
virtual ~notePlayHandle();
virtual void setVolume( const volume _volume = DefaultVolume );
int getMidiVelocity( void ) const;
const float & frequency( void ) const
{
@@ -85,7 +88,7 @@ public:
if( m_released == TRUE )
{
f_cnt_t todo = engine::getMixer()->framesPerPeriod();
if( arpBaseNote() == TRUE )
if( isArpeggioBaseNote() )
{
rftd = rfd + 2 *
engine::getMixer()->framesPerPeriod();
@@ -118,7 +121,7 @@ public:
}
}
if( arpBaseNote() == TRUE && m_subNotes.size() == 0 )
if( isArpeggioBaseNote() && m_subNotes.size() == 0 )
{
rfd = rftd;
}
@@ -184,29 +187,29 @@ public:
// returns whether note is a base-note, e.g. is not part of an arpeggio
// or a chord
inline bool baseNote( void ) const
inline bool isBaseNote( void ) const
{
return( m_baseNote );
}
// returns whether note is part of an arpeggio
inline bool arpNote( void ) const
inline bool isPartOfArpeggio( void ) const
{
return( m_arpNote );
return( m_partOfArpeggio );
}
inline void setArpNote( const bool _on )
inline void setPartOfArpeggio( const bool _on )
{
m_arpNote = _on;
m_partOfArpeggio = _on;
}
// returns whether note is base-note for arpeggio
inline bool arpBaseNote( void ) const
inline bool isArpeggioBaseNote( void ) const
{
return( baseNote() && arpNote() );
return( isBaseNote() && ( m_partOfArpeggio ||
m_instrumentTrack->arpeggiatorEnabled() ) );
}
inline bool muted( void ) const
inline bool isMuted( void ) const
{
return( m_muted );
}
@@ -214,7 +217,7 @@ public:
void mute( void );
// returns index of note-play-handle in vector of note-play-handles
// belonging to this channel
// belonging to this instrument-track - used by arpeggiator
int index( void ) const;
// note-play-handles belonging to given channel, if _all_ph = TRUE,
@@ -255,7 +258,7 @@ public:
}
void processMidiTime( const midiTime & _time );
void resize( const bpm_t _new_bpm );
void resize( const bpm_t _new_tempo );
#if LMMS_SINGERBOT_SUPPORT
int patternIndex( void )
@@ -310,7 +313,7 @@ private:
volatile bool m_released; // indicates whether note is released
bool m_baseNote; // indicates whether note is a
// base-note (i.e. no sub-note)
bool m_arpNote; // indicates whether note is part of
bool m_partOfArpeggio; // indicates whether note is part of
// an arpeggio (either base-note or
// sub-note)
bool m_muted; // indicates whether note is muted
@@ -320,8 +323,8 @@ private:
#endif
// tempo reaction
bpm_t m_orig_bpm; // original bpm
f_cnt_t m_orig_frames; // original m_frames
bpm_t m_origTempo; // original tempo
f_cnt_t m_origFrames; // original m_frames
float m_frequency;
float m_unpitchedFrequency;

View File

@@ -706,7 +706,7 @@ void lb302Synth::playNote( notePlayHandle * _n, bool,
{
fpp_t framesPerPeriod = engine::getMixer()->framesPerPeriod();
if( _n->arpBaseNote() )
if( _n->isArpeggioBaseNote() )
{
return;
}

View File

@@ -187,9 +187,9 @@ void chordCreator::processNote( notePlayHandle * _n )
// at the same time we only add sub-notes if nothing of the note was
// played yet, because otherwise we would add chord-subnotes every
// time an audio-buffer is rendered...
if( ( ( _n->baseNote() &&
if( ( ( _n->isBaseNote() &&
_n->getInstrumentTrack()->arpeggiatorEnabled() == FALSE ) ||
_n->arpNote() ) &&
_n->isPartOfArpeggio() ) &&
_n->totalFramesPlayed() == 0 &&
m_chordsEnabledModel.value() == TRUE )
{
@@ -310,7 +310,7 @@ arpeggiator::~arpeggiator()
void arpeggiator::processNote( notePlayHandle * _n )
{
const int base_note_key = _n->key();
if( _n->baseNote() == FALSE ||
if( _n->isBaseNote() == FALSE ||
!m_arpEnabledModel.value() ||
( _n->released() && _n->releaseFramesDone() >=
_n->actualReleaseFramesToDo() ) )
@@ -467,7 +467,7 @@ void arpeggiator::processNote( notePlayHandle * _n )
// sub-note so far
if( m_arpModeModel.value() != FreeMode )
{
_n->setArpNote( TRUE );
_n->setPartOfArpeggio( true );
}
}

View File

@@ -53,7 +53,7 @@ notePlayHandle::notePlayHandle( instrumentTrack * _it,
const f_cnt_t _frames,
const note & _n,
notePlayHandle * _parent,
const bool _arp_note ) :
const bool _part_of_arp ) :
playHandle( NotePlayHandle, _offset ),
note( _n.length(), _n.pos(), _n.key(),
_n.getVolume(), _n.getPanning(), _n.detuning() ),
@@ -67,13 +67,13 @@ notePlayHandle::notePlayHandle( instrumentTrack * _it,
m_releaseFramesDone( 0 ),
m_released( FALSE ),
m_baseNote( _parent == NULL ),
m_arpNote( _arp_note ),
m_partOfArpeggio( _part_of_arp ),
m_muted( FALSE ),
m_bbTrack( NULL ),
#if LMMS_SINGERBOT_SUPPORT
m_patternIndex( 0 ),
#endif
m_orig_bpm( engine::getSong()->getTempo() )
m_origTempo( engine::getSong()->getTempo() )
{
if( m_baseNote )
{
@@ -88,7 +88,8 @@ notePlayHandle::notePlayHandle( instrumentTrack * _it,
// if there was an arp-note added and parent is a base-note
// we set arp-note-flag for indicating that parent is an
// arpeggio-base-note
_parent->m_arpNote = arpNote() && _parent->baseNote();
_parent->m_partOfArpeggio = isPartOfArpeggio() &&
_parent->isBaseNote();
m_bbTrack = _parent->m_bbTrack;
#if LMMS_SINGERBOT_SUPPORT
@@ -99,16 +100,17 @@ notePlayHandle::notePlayHandle( instrumentTrack * _it,
updateFrequency();
setFrames( _frames );
// send MIDI-note-on-event
m_instrumentTrack->processOutEvent( midiEvent( MidiNoteOn,
if( !isBaseNote() || !getInstrumentTrack()->arpeggiatorEnabled() )
{
// send MIDI-note-on-event
m_instrumentTrack->processOutEvent( midiEvent( MidiNoteOn,
m_instrumentTrack->getMidiPort()->outputChannel(),
key(),
tLimit<Uint16>(
(Uint16) ( ( getVolume() / 100.0f ) *
( m_instrumentTrack->getVolume() / 100.0f ) *
127 ), 0, 127 ) ),
midiTime::fromFrames( offset(),
key(), getMidiVelocity() ),
midiTime::fromFrames( offset(),
engine::framesPerTick() ) );
}
}
@@ -147,6 +149,29 @@ notePlayHandle::~notePlayHandle()
void notePlayHandle::setVolume( const volume _volume )
{
note::setVolume( _volume );
m_instrumentTrack->processOutEvent( midiEvent( MidiKeyPressure,
m_instrumentTrack->getMidiPort()->outputChannel(),
key(), getMidiVelocity() ), 0 );
}
int notePlayHandle::getMidiVelocity( void ) const
{
return tLimit<Uint16>( (Uint16) ( ( getVolume() / 100.0f ) *
( m_instrumentTrack->getVolume() / 100.0f ) *
MidiMaxVelocity ),
0, MidiMaxVelocity );
}
void notePlayHandle::play( bool _try_parallelizing,
sampleFrame * _working_buffer )
{
@@ -180,7 +205,7 @@ void notePlayHandle::play( bool _try_parallelizing,
// because we do not allow notePlayHandle::done() to be true
// until all sub-notes are completely played and no new ones
// are inserted by arpAndChordsTabWidget::processNote()
if( arpBaseNote() == TRUE )
if( isArpeggioBaseNote() )
{
m_releaseFramesToDo = m_releaseFramesDone + 2 *
engine::getMixer()->framesPerPeriod();
@@ -246,7 +271,7 @@ void notePlayHandle::play( bool _try_parallelizing,
// can set m_releaseFramesDone to m_releaseFramesToDo so that
// notePlayHandle::done() returns true and also this base-note is
// removed from mixer's active note vector
if( arpBaseNote() == TRUE && m_subNotes.size() == 0 )
if( isArpeggioBaseNote() && m_subNotes.size() == 0 )
{
m_releaseFramesDone = m_releaseFramesToDo;
}
@@ -301,12 +326,16 @@ void notePlayHandle::noteOff( const f_cnt_t _s )
m_framesBeforeRelease = _s;
m_releaseFramesToDo = tMax<f_cnt_t>( 0, // 10,
m_instrumentTrack->m_soundShaping.releaseFrames() );
// send MIDI-note-off-event
m_instrumentTrack->processOutEvent( midiEvent( MidiNoteOff,
if( !isBaseNote() || !getInstrumentTrack()->arpeggiatorEnabled() )
{
// send MIDI-note-off-event
m_instrumentTrack->processOutEvent( midiEvent( MidiNoteOff,
m_instrumentTrack->getMidiPort()->outputChannel(),
key(), 0 ),
midiTime::fromFrames( m_framesBeforeRelease,
engine::framesPerTick() ) );
}
m_released = TRUE;
}
@@ -317,7 +346,7 @@ void notePlayHandle::noteOff( const f_cnt_t _s )
f_cnt_t notePlayHandle::actualReleaseFramesToDo( void ) const
{
return( m_instrumentTrack->m_soundShaping.releaseFrames(
arpBaseNote() ) );
isArpeggioBaseNote() ) );
}
@@ -330,7 +359,7 @@ void notePlayHandle::setFrames( const f_cnt_t _frames )
{
m_frames = m_instrumentTrack->beatLen( this );
}
m_orig_frames = m_frames;
m_origFrames = m_frames;
}
@@ -421,7 +450,7 @@ bool notePlayHandle::operator==( const notePlayHandle & _nph ) const
m_totalFramesPlayed == _nph.m_totalFramesPlayed &&
m_released == _nph.m_released &&
m_baseNote == _nph.m_baseNote &&
m_arpNote == _nph.m_arpNote &&
m_partOfArpeggio == _nph.m_partOfArpeggio &&
m_muted == _nph.m_muted );
}
@@ -430,14 +459,9 @@ bool notePlayHandle::operator==( const notePlayHandle & _nph ) const
void notePlayHandle::updateFrequency( void )
{
const int base_tone = m_instrumentTrack->baseNoteModel()->value() %
KeysPerOctave;
const int base_octave = m_instrumentTrack->baseNoteModel()->value() /
KeysPerOctave;
const float pitch = ( key() % KeysPerOctave - base_tone +
engine::getSong()->masterPitch() ) / 12.0f +
( key() / KeysPerOctave - base_octave ) +
m_baseDetuning->value() / 12.0f;
const float pitch =
( key() - m_instrumentTrack->baseNoteModel()->value() +
engine::getSong()->masterPitch() ) / 12.0f;
m_frequency = BaseFreq * powf( 2.0f, pitch +
m_instrumentTrack->m_pitchModel.value() / ( 100 * 12.0 ) );
m_unpitchedFrequency = BaseFreq * powf( 2.0f, pitch );
@@ -469,17 +493,17 @@ void notePlayHandle::processMidiTime( const midiTime & _time )
void notePlayHandle::resize( const bpm_t _new_bpm )
void notePlayHandle::resize( const bpm_t _new_tempo )
{
double completed = m_totalFramesPlayed / (double)m_frames;
double new_frames = m_orig_frames * m_orig_bpm / (double)_new_bpm;
double completed = m_totalFramesPlayed / (double) m_frames;
double new_frames = m_origFrames * m_origTempo / (double) _new_tempo;
m_frames = (f_cnt_t)new_frames;
m_totalFramesPlayed = (f_cnt_t)( completed * new_frames );
for( notePlayHandleVector::iterator it = m_subNotes.begin();
it != m_subNotes.end(); ++it )
{
( *it )->resize( _new_bpm );
( *it )->resize( _new_tempo );
}
}

View File

@@ -149,7 +149,7 @@ void piano::setKeyState( int _key, bool _on )
void piano::handleKeyPress( int _key )
{
m_instrumentTrack->processInEvent( midiEvent( MidiNoteOn, 0, _key,
DefaultVolume ), midiTime() );
MidiMaxVelocity ), midiTime() );
m_pressedKeys[_key] = TRUE;
}
@@ -478,26 +478,26 @@ void pianoView::mousePressEvent( QMouseEvent * _me )
if( _me->pos().y() > PIANO_BASE )
{
int y_diff = _me->pos().y() - PIANO_BASE;
volume vol = (volume)( ( float ) y_diff /
int velocity = (int)( ( float ) y_diff /
( ( KEY_ORDER[key_num % KeysPerOctave] ==
WhiteKey ) ?
PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) *
(float) DefaultVolume );
(float) MidiMaxVelocity );
if( y_diff < 0 )
{
vol = 0;
velocity = 0;
}
else if( y_diff > ( ( KEY_ORDER[key_num %
KeysPerOctave] ==
WhiteKey ) ?
PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) )
{
vol = DefaultVolume;
velocity = MidiMaxVelocity;
}
// set note on
m_piano->m_instrumentTrack->processInEvent(
midiEvent( MidiNoteOn, 0, key_num,
vol * 127 / 100 ),
velocity ),
midiTime() );
m_piano->m_pressedKeys[key_num] = TRUE;
m_lastKey = key_num;
@@ -581,22 +581,22 @@ void pianoView::mouseMoveEvent( QMouseEvent * _me )
int key_num = getKeyFromMouse( _me->pos() );
int y_diff = _me->pos().y() - PIANO_BASE;
volume vol = (volume)( (float) y_diff /
int velocity = (int)( (float) y_diff /
( ( KEY_ORDER[key_num % KeysPerOctave] == WhiteKey ) ?
PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) *
(float)DefaultVolume );
(float) MidiMaxVelocity );
// maybe the user moved the mouse-cursor above or under the
// piano-widget while holding left button so check that and
// correct volume if necessary
if( y_diff < 0 )
{
vol = 0;
velocity = 0;
}
else if( y_diff >
( ( KEY_ORDER[key_num % KeysPerOctave] == WhiteKey ) ?
PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) )
{
vol = DefaultVolume;
velocity = MidiMaxVelocity;
}
// is the calculated key different from current key? (could be the
@@ -616,7 +616,8 @@ void pianoView::mouseMoveEvent( QMouseEvent * _me )
if( _me->pos().y() > PIANO_BASE )
{
m_piano->m_instrumentTrack->processInEvent(
midiEvent( MidiNoteOn, 0, key_num, vol ),
midiEvent( MidiNoteOn, 0, key_num,
velocity ),
midiTime() );
m_piano->m_pressedKeys[key_num] = TRUE;
m_lastKey = key_num;
@@ -633,7 +634,8 @@ void pianoView::mouseMoveEvent( QMouseEvent * _me )
else if( m_piano->m_pressedKeys[key_num] == TRUE )
{
m_piano->m_instrumentTrack->processInEvent(
midiEvent( MidiKeyPressure, 0, key_num, vol ),
midiEvent( MidiKeyPressure, 0, key_num,
velocity ),
midiTime() );
}

View File

@@ -170,7 +170,7 @@ presetPreviewPlayHandle::~presetPreviewPlayHandle()
{
s_previewTC->lockData();
// not muted by other preset-preview-handle?
if( m_previewNote->muted() == FALSE )
if( !m_previewNote->isMuted() )
{
// then set according state
s_previewTC->setPreviewNote( NULL );
@@ -193,7 +193,7 @@ void presetPreviewPlayHandle::play( bool _try_parallelizing,
bool presetPreviewPlayHandle::done( void ) const
{
return( m_previewNote->muted() );
return( m_previewNote->isMuted() );
}

View File

@@ -116,12 +116,13 @@ instrumentTrack::instrumentTrack( trackContainer * _tc ) :
connect( &m_baseNoteModel, SIGNAL( dataChanged() ),
this, SLOT( updateBaseNote() ) );
connect( &m_pitchModel, SIGNAL( dataChanged() ),
this, SLOT( updateBaseNote() ) );
this, SLOT( updatePitch() ) );
for( int i = 0; i < NumKeys; ++i )
{
m_notes[i] = NULL;
m_runningMidiNotes[i] = 0;
}
@@ -141,24 +142,6 @@ instrumentTrack::~instrumentTrack()
f_cnt_t instrumentTrack::beatLen( notePlayHandle * _n ) const
{
if( m_instrument != NULL )
{
const f_cnt_t len = m_instrument->beatLen( _n );
if( len > 0 )
{
return( len );
}
}
return( m_soundShaping.envFrames() );
}
void instrumentTrack::processAudioBuffer( sampleFrame * _buf,
const fpp_t _frames,
notePlayHandle * _n )
@@ -197,15 +180,37 @@ void instrumentTrack::processAudioBuffer( sampleFrame * _buf,
midiEvent instrumentTrack::applyMasterKey( const midiEvent & _me )
{
midiEvent copy( _me );
switch( _me.m_type )
{
case MidiNoteOn:
case MidiNoteOff:
case MidiKeyPressure:
copy.key() = masterKey( _me.key() );
break;
default:
break;
}
return copy;
}
void instrumentTrack::processInEvent( const midiEvent & _me,
const midiTime & _time )
{
engine::getMixer()->lock();
switch( _me.m_type )
{
// we don't send MidiNoteOn, MidiNoteOff and MidiKeyPressure
// events to instrument as notePlayHandle will send them on its
// own
case MidiNoteOn:
if( _me.velocity() > 0 )
{
m_instrument->handleMidiEvent( _me, _time );
if( m_notes[_me.key()] == NULL )
{
if( !configManager::inst()->value( "ui",
@@ -217,8 +222,8 @@ void instrumentTrack::processInEvent( const midiEvent & _me,
// create temporary note
note n;
n.setKey( _me.key() );
n.setVolume( _me.velocity() * 100 /
127 );
n.setVolume( _me.getVolume() );
// create (timed) note-play-handle
notePlayHandle * nph = new
notePlayHandle( this,
@@ -231,14 +236,12 @@ void instrumentTrack::processInEvent( const midiEvent & _me,
{
m_notes[_me.key()] = nph;
}
return;
}
break;
}
case MidiNoteOff:
{
m_instrument->handleMidiEvent( _me, _time );
notePlayHandle * n = m_notes[_me.key()];
if( n != NULL )
{
@@ -248,11 +251,13 @@ void instrumentTrack::processInEvent( const midiEvent & _me,
// this is for example needed by piano-roll for
// recording notes into a pattern
note done_note(
midiTime( static_cast<f_cnt_t>(
n->totalFramesPlayed() /
engine::framesPerTick() ) ),
0, n->key(),
n->getVolume(), n->getPanning() );
midiTime( static_cast<f_cnt_t>(
n->totalFramesPlayed() /
engine::framesPerTick() ) ),
0,
n->key(),
n->getVolume(),
n->getPanning() );
n->noteOff();
m_notes[_me.key()] = NULL;
@@ -263,16 +268,16 @@ void instrumentTrack::processInEvent( const midiEvent & _me,
}
case MidiKeyPressure:
if( !m_instrument->handleMidiEvent( _me, _time ) &&
m_notes[_me.key()] != NULL )
if( m_notes[_me.key()] != NULL )
{
m_notes[_me.key()]->setVolume( _me.velocity() *
100 / 127 );
m_notes[_me.key()]->setVolume( _me.getVolume() );
}
break;
case MidiPitchBend:
m_instrument->handleMidiEvent( _me, _time );
// updatePitch() is connected to
// m_pitchModel::dataChanged() which will send out
// MidiPitchBend events
m_pitchModel.setValue( m_pitchModel.minValue() +
_me.m_data.m_param[0] *
m_pitchModel.range() / 16384 );
@@ -291,6 +296,7 @@ void instrumentTrack::processInEvent( const midiEvent & _me,
}
break;
}
engine::getMixer()->unlock();
}
@@ -299,6 +305,8 @@ void instrumentTrack::processInEvent( const midiEvent & _me,
void instrumentTrack::processOutEvent( const midiEvent & _me,
const midiTime & _time )
{
int k;
switch( _me.m_type )
{
case MidiNoteOn:
@@ -310,11 +318,23 @@ void instrumentTrack::processOutEvent( const midiEvent & _me,
if( !configManager::inst()->value( "ui",
"disablechannelactivityindicators" ).toInt() )
{
if( m_notes[_me.key()] != NULL )
if( m_notes[_me.key()] == NULL )
{
return;
emit newNote();
}
emit newNote();
}
k = masterKey( _me.key() );
if( k >= 0 && k < NumKeys )
{
if( m_runningMidiNotes[k] > 0 )
{
m_instrument->handleMidiEvent(
midiEvent( MidiNoteOff, getMidiPort()->outputChannel(), k, 0 ), _time );
}
++m_runningMidiNotes[k];
m_instrument->handleMidiEvent(
midiEvent( MidiNoteOn, getMidiPort()->outputChannel(), k,
_me.velocity() ), _time );
}
break;
@@ -324,12 +344,25 @@ void instrumentTrack::processOutEvent( const midiEvent & _me,
{
m_piano.setKeyState( _me.key(), FALSE );
}
k = masterKey( _me.key() );
if( k >= 0 && k < NumKeys &&
--m_runningMidiNotes[k] <= 0 )
{
m_instrument->handleMidiEvent(
midiEvent( MidiNoteOff, getMidiPort()->outputChannel(), k, 0 ), _time );
}
break;
default:
if( m_instrument != NULL )
{
m_instrument->handleMidiEvent(
applyMasterKey( _me ),
_time );
}
break;
}
m_instrument->handleMidiEvent( _me, _time );
// if appropriate, midi-port does futher routing
m_midiPort.processOutEvent( _me, _time );
}
@@ -337,6 +370,22 @@ void instrumentTrack::processOutEvent( const midiEvent & _me,
f_cnt_t instrumentTrack::beatLen( notePlayHandle * _n ) const
{
if( m_instrument != NULL )
{
const f_cnt_t len = m_instrument->beatLen( _n );
if( len > 0 )
{
return( len );
}
}
return( m_soundShaping.envFrames() );
}
void instrumentTrack::playNote( notePlayHandle * _n, bool _try_parallelizing,
sampleFrame * _working_buffer )
{
@@ -345,7 +394,7 @@ void instrumentTrack::playNote( notePlayHandle * _n, bool _try_parallelizing,
m_chordCreator.processNote( _n );
m_arpeggiator.processNote( _n );
if( _n->arpBaseNote() == FALSE && m_instrument != NULL )
if( !_n->isArpeggioBaseNote() && m_instrument != NULL )
{
// all is done, so now lets play the note!
m_instrument->playNote( _n, _try_parallelizing,
@@ -431,11 +480,22 @@ void instrumentTrack::updateBaseNote( void )
int instrumentTrack::masterKey( notePlayHandle * _n ) const
void instrumentTrack::updatePitch( void )
{
updateBaseNote();
processOutEvent( midiEvent( MidiPitchBend,
getMidiPort()->outputChannel(),
midiPitch() ), 0 );
}
int instrumentTrack::masterKey( int _midi_key ) const
{
int key = m_baseNoteModel.value() + engine::getSong()->masterPitch();
return( tLimit<int>( _n->key() -
( key - Key_A - DefaultOctave * KeysPerOctave ), 0, NumKeys ) );
return( tLimit<int>( _midi_key -
( key - DefaultKey ), 0, NumKeys ) );
}
@@ -986,7 +1046,8 @@ void instrumentTrackView::toggleInstrumentWindow( bool _on )
void instrumentTrackView::activityIndicatorPressed( void )
{
model()->processInEvent( midiEvent( MidiNoteOn, 0, DefaultKey, 127 ),
model()->processInEvent(
midiEvent( MidiNoteOn, 0, DefaultKey, MidiMaxVelocity ),
midiTime() );
}