bbTrack::~bbTrack() { engine::mixer()->removePlayHandles( this ); const int bb = s_infoMap[this]; engine::getBBTrackContainer()->removeBB( bb ); for( infoMap::iterator it = s_infoMap.begin(); it != s_infoMap.end(); ++it ) { if( it.value() > bb ) { --it.value(); } } s_infoMap.remove( this ); // remove us from TC so bbTrackContainer::numOfBBs() returns a smaller // value and thus combobox-updating in bbTrackContainer works well trackContainer()->removeTrack( this ); engine::getBBTrackContainer()->updateComboBox(); }
bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, const f_cnt_t _offset, int _tco_num ) { m_audioPort.effects()->startRunning(); bool played_a_note = false; // will be return variable tcoVector tcos; ::BBTrack * bb_track = NULL; if( _tco_num >= 0 ) { if( _start != 0 ) { return false; } tcos.push_back( getTCO( _tco_num ) ); if (trackContainer() == (TrackContainer*)Engine::getBBTrackContainer()) { bb_track = BBTrack::findBBTrack( _tco_num ); } } else { for( int i = 0; i < numOfTCOs(); ++i ) { TrackContentObject * tco = getTCO( i ); SampleTCO * sTco = dynamic_cast<SampleTCO*>( tco ); float framesPerTick = Engine::framesPerTick(); if( _start >= sTco->startPosition() && _start < sTco->endPosition() ) { if( sTco->isPlaying() == false && _start > sTco->startPosition() + sTco->startTimeOffset() ) { f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() - sTco->startTimeOffset() ); f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() - sTco->startTimeOffset() ); f_cnt_t sampleBufferLength = sTco->sampleBuffer()->frames(); //if the Tco smaller than the sample length we play only until Tco end //else we play the sample to the end but nothing more f_cnt_t samplePlayLength = tcoFrameLength > sampleBufferLength ? sampleBufferLength : tcoFrameLength; //we only play within the sampleBuffer limits if( sampleStart < sampleBufferLength ) { sTco->setSampleStartFrame( sampleStart ); sTco->setSamplePlayLength( samplePlayLength ); tcos.push_back( sTco ); sTco->setIsPlaying( true ); } } } else { sTco->setIsPlaying( false ); } } } for( tcoVector::Iterator it = tcos.begin(); it != tcos.end(); ++it ) { SampleTCO * st = dynamic_cast<SampleTCO *>( *it ); if( !st->isMuted() ) { PlayHandle* handle; if( st->isRecord() ) { if( !Engine::getSong()->isRecording() ) { return played_a_note; } SampleRecordHandle* smpHandle = new SampleRecordHandle( st ); handle = smpHandle; } else { SamplePlayHandle* smpHandle = new SamplePlayHandle( st ); smpHandle->setVolumeModel( &m_volumeModel ); smpHandle->setBBTrack( bb_track ); handle = smpHandle; } handle->setOffset( _offset ); // send it to the mixer Engine::mixer()->addPlayHandle( handle ); played_a_note = true; } } 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 ); if (trackContainer() == (TrackContainer*)Engine::getBBTrackContainer()) { 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 ) { 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; }