void addNote( Note & n ) { if( !p || n.pos() > lastEnd + DefaultTicksPerTact ) { MidiTime pPos = MidiTime( n.pos().getTact(), 0 ); p = dynamic_cast<Pattern*>( it->createTCO( 0 ) ); p->movePosition( pPos ); } hasNotes = true; lastEnd = n.pos() + n.length(); n.setPos( n.pos( p->startPosition() ) ); p->addNote( n, false ); }
bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, const f_cnt_t _offset, int _tco_num ) { if( ! m_instrument || ! tryLock() ) { return false; } const float frames_per_tick = Engine::framesPerTick(); tcoVector tcos; ::BBTrack * bb_track = NULL; if( _tco_num >= 0 ) { TrackContentObject * tco = getTCO( _tco_num ); tcos.push_back( tco ); bb_track = BBTrack::findBBTrack( _tco_num ); } else { getTCOsInRange( tcos, _start, _start + static_cast<int>( _frames / frames_per_tick ) ); } // Handle automation: detuning for( NotePlayHandleList::Iterator it = m_processHandles.begin(); it != m_processHandles.end(); ++it ) { ( *it )->processMidiTime( _start ); } if ( tcos.size() == 0 ) { unlock(); return false; } bool played_a_note = false; // will be return variable for( tcoVector::Iterator it = tcos.begin(); it != tcos.end(); ++it ) { Pattern* p = dynamic_cast<Pattern*>( *it ); // everything which is not a pattern or muted won't be played if( p == NULL || ( *it )->isMuted() ) { continue; } MidiTime cur_start = _start; if( _tco_num < 0 ) { cur_start -= p->startPosition(); } // get all notes from the given pattern... const NoteVector & notes = p->notes(); // ...and set our index to zero NoteVector::ConstIterator nit = notes.begin(); // very effective algorithm for playing notes that are // posated within the current sample-frame if( cur_start > 0 ) { // skip notes which are posated before start-tact while( nit != notes.end() && ( *nit )->pos() < cur_start ) { ++nit; } } Note * cur_note; while( nit != notes.end() && ( cur_note = *nit )->pos() == cur_start ) { if( cur_note->length() != 0 ) { const f_cnt_t note_frames = cur_note->length().frames( frames_per_tick ); NotePlayHandle* notePlayHandle = NotePlayHandleManager::acquire( this, _offset, note_frames, *cur_note ); notePlayHandle->setBBTrack( bb_track ); // are we playing global song? if( _tco_num < 0 ) { // then set song-global offset of pattern in order to // properly perform the note detuning notePlayHandle->setSongGlobalParentOffset( p->startPosition() ); } Engine::mixer()->addPlayHandle( notePlayHandle ); played_a_note = true; } ++nit; } } unlock(); return played_a_note; }