trackContentObject * bbTrack::createTCO( const MidiTime & _pos ) { // if we're creating a new bbTCO, we colorize it according to the // previous bbTCO, so we have to get all TCOs from 0 to _pos and // pickup the last and take the color if it tcoVector tcos; getTCOsInRange( tcos, 0, _pos ); if( tcos.size() > 0 && dynamic_cast<bbTCO *>( tcos.back() ) != NULL ) { return new bbTCO( this, dynamic_cast<bbTCO *>( tcos.back() )->color() ); } return new bbTCO( this ); }
// play _frames frames of given TCO within starting with _start bool bbTrack::play( const midiTime & _start, const fpp_t _frames, const f_cnt_t _offset, Sint16 _tco_num ) { if( isMuted() ) { return( false ); } if( _tco_num >= 0 ) { return( engine::getBBTrackContainer()->play( _start, _frames, _offset, s_infoMap[this] ) ); } tcoVector tcos; getTCOsInRange( tcos, _start, _start + static_cast<int>( _frames / engine::framesPerTick() ) ); if( tcos.size() == 0 ) { return( false ); } midiTime lastPosition; midiTime lastLen; for( tcoVector::iterator it = tcos.begin(); it != tcos.end(); ++it ) { if( !( *it )->isMuted() && ( *it )->startPosition() >= lastPosition ) { lastPosition = ( *it )->startPosition(); lastLen = ( *it )->length(); } } if( _start - lastPosition < lastLen ) { return( engine::getBBTrackContainer()->play( _start - lastPosition, _frames, _offset, s_infoMap[this] ) ); } return( false ); }
bool AutomationTrack::play( const MidiTime & _start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num ) { if( isMuted() ) { return false; } tcoVector tcos; if( _tco_num >= 0 ) { TrackContentObject * tco = getTCO( _tco_num ); tcos.push_back( tco ); } else { getTCOsInRange( tcos, _start, _start + static_cast<int>( _frames / Engine::framesPerTick()) ); } for( tcoVector::iterator it = tcos.begin(); it != tcos.end(); ++it ) { AutomationPattern * p = dynamic_cast<AutomationPattern *>( *it ); if( p == NULL || ( *it )->isMuted() ) { continue; } MidiTime cur_start = _start; if( _tco_num < 0 ) { cur_start -= p->startPosition(); } p->processMidiTime( cur_start ); } return false; }
bool InstrumentTrack::play( const midiTime & _start, const fpp_t _frames, const f_cnt_t _offset, Sint16 _tco_num ) { 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 ) { 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(); } if( p->isFrozen() && !engine::getSong()->isExporting() ) { if( cur_start > 0 ) { continue; } samplePlayHandle * handle = new samplePlayHandle( p ); handle->setBBTrack( bb_track ); handle->setOffset( _offset ); // send it to the mixer engine::getMixer()->addPlayHandle( handle ); played_a_note = true; continue; } // get all notes from the given pattern... const NoteVector & notes = p->notes(); // ...and set our index to zero NoteVector::ConstIterator nit = notes.begin(); #if LMMS_SINGERBOT_SUPPORT int note_idx = 0; #endif // 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 ) { #if LMMS_SINGERBOT_SUPPORT if( ( *nit )->length() != 0 ) { ++note_idx; } #endif ++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 * note_play_handle = new notePlayHandle( this, _offset, note_frames, *cur_note ); note_play_handle->setBBTrack( bb_track ); #if LMMS_SINGERBOT_SUPPORT note_play_handle->setPatternIndex( note_idx ); #endif engine::getMixer()->addPlayHandle( note_play_handle ); played_a_note = true; #if LMMS_SINGERBOT_SUPPORT ++note_idx; #endif } ++nit; } } return played_a_note; }
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; }