diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index a20aaa3676a..d2a5170b7f9 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -51,6 +51,8 @@ class EXPORT NotePlayHandle : public PlayHandle, public note { OriginPattern, /*! playback of a note from a pattern */ OriginMidiInput, /*! playback of a MIDI note input event */ + OriginNoteStacking, /*! created by note stacking instrument function */ + OriginArpeggio, /*! created by arpeggio instrument function */ OriginCount }; typedef Origins Origin; @@ -60,7 +62,6 @@ class EXPORT NotePlayHandle : public PlayHandle, public note const f_cnt_t frames, const note& noteToPlay, NotePlayHandle* parent = NULL, - const bool isPartOfArp = false, int midiEventChannel = -1, Origin origin = OriginPattern ); virtual ~NotePlayHandle(); @@ -160,27 +161,24 @@ class EXPORT NotePlayHandle : public PlayHandle, public note return m_instrumentTrack; } - /*! Returns whether note is a top note, e.g. is not part of an arpeggio or a chord */ - bool isTopNote() const + /*! Returns whether note has a parent, e.g. is not part of an arpeggio or a chord */ + bool hasParent() const { - return m_topNote; + return m_hasParent; } - /*! Returns whether note is part of an arpeggio playback */ - bool isPartOfArpeggio() const + /*! Returns origin of note */ + Origin origin() const { - return m_partOfArpeggio; + return m_origin; } - /*! Sets whether note is part of an arpeggio playback */ - void setPartOfArpeggio( const bool _on ) + /*! Returns whether note has children */ + bool isMasterNote() const { - m_partOfArpeggio = _on; + return m_subNotes.size() > 0 || m_hadChildren; } - /*! Returns whether note is base note for arpeggio */ - bool isArpeggioBaseNote() const; - /*! Returns whether note is muted */ bool isMuted() const { @@ -268,11 +266,8 @@ class EXPORT NotePlayHandle : public PlayHandle, public note // release of note NotePlayHandleList m_subNotes; // used for chords and arpeggios volatile bool m_released; // indicates whether note is released - bool m_topNote; // indicates whether note is a - // base-note (i.e. no sub-note) - bool m_partOfArpeggio; // indicates whether note is part of - // an arpeggio (either base-note or - // sub-note) + bool m_hasParent; + bool m_hadChildren; bool m_muted; // indicates whether note is muted track* m_bbTrack; // related BB track diff --git a/plugins/lb302/lb302.cpp b/plugins/lb302/lb302.cpp index 28628a27df1..83b824d5207 100644 --- a/plugins/lb302/lb302.cpp +++ b/plugins/lb302/lb302.cpp @@ -713,7 +713,7 @@ void lb302Synth::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer ) { //fpp_t framesPerPeriod = engine::mixer()->framesPerPeriod(); - if( _n->isArpeggioBaseNote() ) + if( _n->isMasterNote() ) { return; } diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp index abf6131afe7..70a94e6f181 100644 --- a/src/core/InstrumentFunctions.cpp +++ b/src/core/InstrumentFunctions.cpp @@ -231,30 +231,24 @@ void InstrumentFunctionNoteStacking::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->isTopNote() && _n->instrumentTrack()->isArpeggioEnabled() == false ) || _n->isPartOfArpeggio() ) && - _n->totalFramesPlayed() == 0 && - m_chordsEnabledModel.value() == true ) + if( ( _n->origin() == NotePlayHandle::OriginArpeggio || ( _n->hasParent() == false && _n->instrumentTrack()->isArpeggioEnabled() == false ) ) && + _n->totalFramesPlayed() == 0 && + m_chordsEnabledModel.value() == true ) { // then insert sub-notes for chord const int selected_chord = m_chordsModel.value(); - for( int octave_cnt = 0; - octave_cnt < m_chordRangeModel.value(); ++octave_cnt ) + for( int octave_cnt = 0; octave_cnt < m_chordRangeModel.value(); ++octave_cnt ) { - const int sub_note_key_base = base_note_key + - octave_cnt * KeysPerOctave; + const int sub_note_key_base = base_note_key + octave_cnt * KeysPerOctave; // if octave_cnt == 1 we're in the first octave and // the base-note is already done, so we don't have to // create it in the following loop, then we loop until // there's a -1 in the interval-array - for( int i = ( octave_cnt == 0 ) ? 1 : 0; - i < chord_table[selected_chord].size(); - ++i ) + for( int i = ( octave_cnt == 0 ) ? 1 : 0; i < chord_table[selected_chord].size(); ++i ) { // add interval to sub-note-key - const int sub_note_key = sub_note_key_base + - (int) chord_table[ - selected_chord][i]; + const int sub_note_key = sub_note_key_base + (int) chord_table[selected_chord][i]; // maybe we're out of range -> let's get outta // here! if( sub_note_key > NumKeys ) @@ -262,16 +256,12 @@ void InstrumentFunctionNoteStacking::processNote( NotePlayHandle * _n ) break; } // create copy of base-note - note note_copy( _n->length(), 0, sub_note_key, - _n->getVolume(), - _n->getPanning(), - _n->detuning() ); + note note_copy( _n->length(), 0, sub_note_key, _n->getVolume(), _n->getPanning(), _n->detuning() ); + // create sub-note-play-handle, only note is // different - new NotePlayHandle( _n->instrumentTrack(), - _n->offset(), - _n->frames(), note_copy, - _n ); + new NotePlayHandle( _n->instrumentTrack(), _n->offset(), _n->frames(), note_copy, + _n, -1, NotePlayHandle::OriginNoteStacking ); } } } @@ -310,10 +300,8 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) : m_arpEnabledModel( false ), m_arpModel( this, tr( "Arpeggio type" ) ), m_arpRangeModel( 1.0f, 1.0f, 9.0f, 1.0f, this, tr( "Arpeggio range" ) ), - m_arpTimeModel( 100.0f, 25.0f, 2000.0f, 1.0f, 2000, this, - tr( "Arpeggio time" ) ), - m_arpGateModel( 100.0f, 1.0f, 200.0f, 1.0f, this, - tr( "Arpeggio gate" ) ), + m_arpTimeModel( 100.0f, 25.0f, 2000.0f, 1.0f, 2000, this, tr( "Arpeggio time" ) ), + m_arpGateModel( 100.0f, 1.0f, 200.0f, 1.0f, this, tr( "Arpeggio gate" ) ), m_arpDirectionModel( this, tr( "Arpeggio direction" ) ), m_arpModeModel( this, tr( "Arpeggio mode" ) ) { @@ -325,10 +313,8 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) : m_arpDirectionModel.addItem( tr( "Up" ), new PixmapLoader( "arp_up" ) ); m_arpDirectionModel.addItem( tr( "Down" ), new PixmapLoader( "arp_down" ) ); - m_arpDirectionModel.addItem( tr( "Up and down" ), - new PixmapLoader( "arp_up_and_down" ) ); - m_arpDirectionModel.addItem( tr( "Random" ), - new PixmapLoader( "arp_random" ) ); + m_arpDirectionModel.addItem( tr( "Up and down" ), new PixmapLoader( "arp_up_and_down" ) ); + m_arpDirectionModel.addItem( tr( "Random" ), new PixmapLoader( "arp_random" ) ); m_arpDirectionModel.setInitValue( ArpDirUp ); m_arpModeModel.addItem( tr( "Free" ), new PixmapLoader( "arp_free" ) ); @@ -349,9 +335,10 @@ InstrumentFunctionArpeggio::~InstrumentFunctionArpeggio() void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) { const int base_note_key = _n->key(); - if( _n->isTopNote() == false || - !m_arpEnabledModel.value() || - ( _n->isReleased() && _n->releaseFramesDone() >= _n->actualReleaseFramesToDo() ) ) + if( _n->origin() == NotePlayHandle::OriginArpeggio || + _n->origin() == NotePlayHandle::OriginNoteStacking || + !m_arpEnabledModel.value() || + ( _n->isReleased() && _n->releaseFramesDone() >= _n->actualReleaseFramesToDo() ) ) { return; } @@ -359,8 +346,8 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) const int selected_arp = m_arpModel.value(); - ConstNotePlayHandleList cnphv = NotePlayHandle::nphsOfInstrumentTrack( - _n->instrumentTrack() ); + ConstNotePlayHandleList cnphv = NotePlayHandle::nphsOfInstrumentTrack( _n->instrumentTrack() ); + if( m_arpModeModel.value() != FreeMode && cnphv.size() == 0 ) { // maybe we're playing only a preset-preview-note? @@ -379,27 +366,23 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) const int total_range = range * cnphv.size(); // number of frames that every note should be played - const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeModel.value() / 1000.0f * - engine::mixer()->processingSampleRate() ); - const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateModel.value() * - arp_frames / 100.0f ); + const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeModel.value() / 1000.0f * engine::mixer()->processingSampleRate() ); + const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateModel.value() * arp_frames / 100.0f ); // used for calculating remaining frames for arp-note, we have to add // arp_frames-1, otherwise the first arp-note will not be setup // correctly... -> arp_frames frames silence at the start of every note! int cur_frame = ( ( m_arpModeModel.value() != FreeMode ) ? - cnphv.first()->totalFramesPlayed() : - _n->totalFramesPlayed() ) + arp_frames - 1; + cnphv.first()->totalFramesPlayed() : + _n->totalFramesPlayed() ) + arp_frames - 1; // used for loop f_cnt_t frames_processed = 0; while( frames_processed < engine::mixer()->framesPerPeriod() ) { - const f_cnt_t remaining_frames_for_cur_arp = arp_frames - - ( cur_frame % arp_frames ); + const f_cnt_t remaining_frames_for_cur_arp = arp_frames - ( cur_frame % arp_frames ); // does current arp-note fill whole audio-buffer? - if( remaining_frames_for_cur_arp > - engine::mixer()->framesPerPeriod() ) + if( remaining_frames_for_cur_arp > engine::mixer()->framesPerPeriod() ) { // then we don't have to do something! break; @@ -413,8 +396,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) // in sorted mode: is it our turn or do we have to be quiet for // now? if( m_arpModeModel.value() == SortMode && - ( ( cur_frame / arp_frames ) % total_range ) / - range != (f_cnt_t) _n->index() ) + ( ( cur_frame / arp_frames ) % total_range ) / range != (f_cnt_t) _n->index() ) { // update counters frames_processed += arp_frames; @@ -439,33 +421,28 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) // once down -> makes 2 * range possible notes... // because we don't play the lower and upper notes // twice, we have to subtract 2 - cur_arp_idx = ( cur_frame / arp_frames ) % - ( range * 2 - 2 ); + cur_arp_idx = ( cur_frame / arp_frames ) % ( range * 2 - 2 ); // if greater than range, we have to play down... // looks like the code for arp_dir==DOWN... :) if( cur_arp_idx >= range ) { - cur_arp_idx = range - cur_arp_idx % - ( range - 1 ) - 1; + cur_arp_idx = range - cur_arp_idx % ( range - 1 ) - 1; } } else if( dir == ArpDirRandom ) { // just pick a random chord-index - cur_arp_idx = (int)( range * ( (float) rand() / - (float) RAND_MAX ) ); + cur_arp_idx = (int)( range * ( (float) rand() / (float) RAND_MAX ) ); } // now calculate final key for our arp-note - const int sub_note_key = base_note_key + (cur_arp_idx / - cur_chord_size ) * - KeysPerOctave + - chord_table[selected_arp][cur_arp_idx % cur_chord_size]; + const int sub_note_key = base_note_key + (cur_arp_idx / cur_chord_size ) * + KeysPerOctave + chord_table[selected_arp][cur_arp_idx % cur_chord_size]; // range-checking if( sub_note_key >= NumKeys || sub_note_key < 0 || - engine::mixer()->criticalXRuns() ) + engine::mixer()->criticalXRuns() ) { continue; } @@ -477,34 +454,20 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) } // create new arp-note - note new_note( MidiTime( 0 ), MidiTime( 0 ), - sub_note_key, - (volume_t) - qRound( _n->getVolume() * vol_level ), - _n->getPanning(), _n->detuning() ); // create sub-note-play-handle, only ptr to note is different // and is_arp_note=true new NotePlayHandle( _n->instrumentTrack(), - ( ( m_arpModeModel.value() != FreeMode ) ? - cnphv.first()->offset() : - _n->offset() ) + - frames_processed, - gated_frames, - new_note, - _n, true ); + ( ( m_arpModeModel.value() != FreeMode ) ? cnphv.first()->offset() : _n->offset() ) + frames_processed, + gated_frames, + note( MidiTime( 0 ), MidiTime( 0 ), sub_note_key, (volume_t) qRound( _n->getVolume() * vol_level ), + _n->getPanning(), _n->detuning() ), + _n, -1, NotePlayHandle::OriginArpeggio ); // update counters frames_processed += arp_frames; cur_frame += arp_frames; } - - // make sure, note is handled as arp-base-note, even if we didn't add a - // sub-note so far - if( m_arpModeModel.value() != FreeMode ) - { - _n->setPartOfArpeggio( true ); - } } diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index fa5f3097419..9ad49de4191 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -49,7 +49,6 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, const f_cnt_t _frames, const note& n, NotePlayHandle *parent, - const bool _part_of_arp, int midiEventChannel, Origin origin ) : PlayHandle( TypeNotePlayHandle, _offset ), @@ -63,8 +62,8 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, m_releaseFramesToDo( 0 ), m_releaseFramesDone( 0 ), m_released( false ), - m_topNote( parent == NULL ), - m_partOfArpeggio( _part_of_arp ), + m_hasParent( parent != NULL ), + m_hadChildren( false ), m_muted( false ), m_bbTrack( NULL ), m_origTempo( engine::getSong()->getTempo() ), @@ -76,7 +75,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, m_midiChannel( midiEventChannel >= 0 ? midiEventChannel : instrumentTrack->midiPort()->realOutputChannel() ), m_origin( origin ) { - if( isTopNote() ) + if( hasParent() == false ) { m_baseDetuning = new BaseDetuning( detuning() ); m_instrumentTrack->m_processHandles.push_back( this ); @@ -86,10 +85,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, m_baseDetuning = parent->m_baseDetuning; parent->m_subNotes.push_back( this ); - // 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_partOfArpeggio = isPartOfArpeggio() && parent->isTopNote(); + parent->m_hadChildren = true; m_bbTrack = parent->m_bbTrack; } @@ -104,7 +100,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, m_instrumentTrack->midiNoteOn( *this ); } - if( !isTopNote() || !instrumentTrack->isArpeggioEnabled() ) + if( !isMasterNote() || !instrumentTrack->isArpeggioEnabled() ) { const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity(); @@ -122,7 +118,7 @@ NotePlayHandle::~NotePlayHandle() { noteOff( 0 ); - if( isTopNote() ) + if( hasParent() == false ) { delete m_baseDetuning; m_instrumentTrack->m_processHandles.removeAll( this ); @@ -209,12 +205,13 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) if( m_released ) { f_cnt_t todo = engine::mixer()->framesPerPeriod(); + // if this note is base-note for arpeggio, always set // m_releaseFramesToDo to bigger value than m_releaseFramesDone // because we do not allow NotePlayHandle::isFinished() to be true // until all sub-notes are completely played and no new ones // are inserted by arpAndChordsTabWidget::processNote() - if( isArpeggioBaseNote() ) + if( isMasterNote() ) { m_releaseFramesToDo = m_releaseFramesDone + 2 * engine::mixer()->framesPerPeriod(); } @@ -274,16 +271,6 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) } } - // if this note is a base-note and there're no more sub-notes left we - // can set m_releaseFramesDone to m_releaseFramesToDo so that - // NotePlayHandle::isFinished() returns true and also this base-note is - // removed from mixer's active note vector - if( m_released && isArpeggioBaseNote() && m_subNotes.size() == 0 ) - { - m_releaseFramesDone = m_releaseFramesToDo; - m_frames = 0; - } - // update internal data m_totalFramesPlayed += engine::mixer()->framesPerPeriod(); } @@ -344,7 +331,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s ) m_framesBeforeRelease = _s; m_releaseFramesToDo = qMax( 0, m_instrumentTrack->m_soundShaping.releaseFrames() ); - if( !isTopNote() || !instrumentTrack()->isArpeggioEnabled() ) + if( hasParent() || !instrumentTrack()->isArpeggioEnabled() ) { // send MidiNoteOff event m_instrumentTrack->processOutEvent( @@ -367,8 +354,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s ) f_cnt_t NotePlayHandle::actualReleaseFramesToDo() const { - return m_instrumentTrack->m_soundShaping.releaseFrames(/* - isArpeggioBaseNote()*/ ); + return m_instrumentTrack->m_soundShaping.releaseFrames(); } @@ -395,19 +381,10 @@ float NotePlayHandle::volumeLevel( const f_cnt_t _frame ) -bool NotePlayHandle::isArpeggioBaseNote() const -{ - return isTopNote() && ( m_partOfArpeggio || m_instrumentTrack->isArpeggioEnabled() ); -} - - - - void NotePlayHandle::mute() { // mute all sub-notes - for( NotePlayHandleList::Iterator it = m_subNotes.begin(); - it != m_subNotes.end(); ++it ) + for( NotePlayHandleList::Iterator it = m_subNotes.begin(); it != m_subNotes.end(); ++it ) { ( *it )->mute(); } @@ -471,10 +448,11 @@ bool NotePlayHandle::operator==( const NotePlayHandle & _nph ) const offset() == _nph.offset() && m_totalFramesPlayed == _nph.m_totalFramesPlayed && m_released == _nph.m_released && - m_topNote == _nph.m_topNote && - m_partOfArpeggio == _nph.m_partOfArpeggio && + m_hasParent == _nph.m_hasParent && m_origBaseNote == _nph.m_origBaseNote && - m_muted == _nph.m_muted; + m_muted == _nph.m_muted && + m_midiChannel == _nph.m_midiChannel && + m_origin == _nph.m_origin; } diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index d6f011e94d9..2a08515b7bb 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -252,7 +252,7 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti NotePlayHandle* nph = new NotePlayHandle( this, time.frames( engine::framesPerTick() ), typeInfo::max() / 2, note( MidiTime(), MidiTime(), event.key(), event.volume( midiPort()->baseVelocity() ) ), - NULL, false, event.channel(), + NULL, event.channel(), NotePlayHandle::OriginMidiInput ); if( engine::mixer()->addPlayHandle( nph ) ) { @@ -431,18 +431,17 @@ f_cnt_t InstrumentTrack::beatLen( NotePlayHandle * _n ) const -void InstrumentTrack::playNote( NotePlayHandle * _n, - sampleFrame * _working_buffer ) +void InstrumentTrack::playNote( NotePlayHandle* n, sampleFrame* workingBuffer ) { // arpeggio- and chord-widget has to do its work -> adding sub-notes // for chords/arpeggios - m_noteStacking.processNote( _n ); - m_arpeggio.processNote( _n ); + m_noteStacking.processNote( n ); + m_arpeggio.processNote( n ); - if( !_n->isArpeggioBaseNote() && m_instrument != NULL ) + if( n->isMasterNote() == false && m_instrument != NULL ) { // all is done, so now lets play the note! - m_instrument->playNote( _n, _working_buffer ); + m_instrument->playNote( n, workingBuffer ); } }