void song::setTimeSignature() { MidiTime::setTicksPerTact( ticksPerTact() ); emit timeSignatureChanged( m_oldTicksPerTact, ticksPerTact() ); emit dataChanged(); m_oldTicksPerTact = ticksPerTact(); m_vstSyncController.setTimeSignature( getTimeSigModel().getNumerator(), getTimeSigModel().getDenominator() ); }
bool Song::isExportDone() const { if ( m_renderBetweenMarkers ) { return m_exporting == true && m_playPos[Mode_PlaySong].getTicks() >= m_playPos[Mode_PlaySong].m_timeLine->loopEnd().getTicks(); } if( m_exportLoop ) { return m_exporting == true && m_playPos[Mode_PlaySong].getTicks() >= length() * ticksPerTact(); } else { return m_exporting == true && m_playPos[Mode_PlaySong].getTicks() >= ( length() + 1 ) * ticksPerTact(); } }
void song::processNextBuffer() { if( m_playing == false ) { return; } TrackList track_list; int tco_num = -1; switch( m_playMode ) { case Mode_PlaySong: track_list = tracks(); // at song-start we have to reset the LFOs if( m_playPos[Mode_PlaySong] == 0 ) { EnvelopeAndLfoParameters::instances()->reset(); } break; case Mode_PlayTrack: track_list.push_back( m_trackToPlay ); break; case Mode_PlayBB: if( engine::getBBTrackContainer()->numOfBBs() > 0 ) { tco_num = engine::getBBTrackContainer()-> currentBB(); track_list.push_back( bbTrack::findBBTrack( tco_num ) ); } break; case Mode_PlayPattern: if( m_patternToPlay != NULL ) { tco_num = m_patternToPlay->getTrack()-> getTCONum( m_patternToPlay ); track_list.push_back( m_patternToPlay->getTrack() ); } break; default: return; } if( track_list.empty() == true ) { return; } // check for looping-mode and act if necessary timeLine * tl = m_playPos[m_playMode].m_timeLine; bool check_loop = tl != NULL && m_exporting == false && tl->loopPointsEnabled(); if( check_loop ) { if( m_playPos[m_playMode] < tl->loopBegin() || m_playPos[m_playMode] >= tl->loopEnd() ) { m_elapsedMilliSeconds = (tl->loopBegin().getTicks()*60*1000/48)/getTempo(); m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); } } f_cnt_t total_frames_played = 0; const float frames_per_tick = engine::framesPerTick(); while( total_frames_played < engine::mixer()->framesPerPeriod() ) { m_vstSyncController.update(); f_cnt_t played_frames = engine::mixer()->framesPerPeriod() - total_frames_played; float current_frame = m_playPos[m_playMode].currentFrame(); // did we play a tick? if( current_frame >= frames_per_tick ) { int ticks = m_playPos[m_playMode].getTicks() + (int)( current_frame / frames_per_tick ); m_vstSyncController.setAbsolutePosition( ticks ); // did we play a whole tact? if( ticks >= MidiTime::ticksPerTact() ) { // per default we just continue playing even if // there's no more stuff to play // (song-play-mode) int max_tact = m_playPos[m_playMode].getTact() + 2; // then decide whether to go over to next tact // or to loop back to first tact if( m_playMode == Mode_PlayBB ) { max_tact = engine::getBBTrackContainer() ->lengthOfCurrentBB(); } else if( m_playMode == Mode_PlayPattern && m_loopPattern == true && tl != NULL && tl->loopPointsEnabled() == false ) { max_tact = m_patternToPlay->length() .getTact(); } // end of played object reached? if( m_playPos[m_playMode].getTact() + 1 >= max_tact ) { // then start from beginning and keep // offset ticks = ticks % ( max_tact * MidiTime::ticksPerTact() ); // wrap milli second counter m_elapsedMilliSeconds = ( ticks * 60 * 1000 / 48 ) / getTempo(); m_vstSyncController.setAbsolutePosition( ticks ); } } m_playPos[m_playMode].setTicks( ticks ); if( check_loop ) { m_vstSyncController.startCycle( tl->loopBegin().getTicks(), tl->loopEnd().getTicks() ); if( m_playPos[m_playMode] >= tl->loopEnd() ) { m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); m_elapsedMilliSeconds = ((tl->loopBegin().getTicks())*60*1000/48)/getTempo(); } } else { m_vstSyncController.stopCycle(); } current_frame = fmodf( current_frame, frames_per_tick ); m_playPos[m_playMode].setCurrentFrame( current_frame ); } f_cnt_t last_frames = (f_cnt_t)frames_per_tick - (f_cnt_t) current_frame; // skip last frame fraction if( last_frames == 0 ) { ++total_frames_played; m_playPos[m_playMode].setCurrentFrame( current_frame + 1.0f ); continue; } // do we have some samples left in this tick but these are // less then samples we have to play? if( last_frames < played_frames ) { // then set played_samples to remaining samples, the // rest will be played in next loop played_frames = last_frames; } if( (f_cnt_t) current_frame == 0 ) { if( m_playMode == Mode_PlaySong ) { m_globalAutomationTrack->play( m_playPos[m_playMode], played_frames, total_frames_played, tco_num ); } // loop through all tracks and play them for( int i = 0; i < track_list.size(); ++i ) { track_list[i]->play( m_playPos[m_playMode], played_frames, total_frames_played, tco_num ); } } // update frame-counters total_frames_played += played_frames; m_playPos[m_playMode].setCurrentFrame( played_frames + current_frame ); m_elapsedMilliSeconds += (((played_frames/frames_per_tick)*60*1000/48)/getTempo()); m_elapsedTacts = m_playPos[Mode_PlaySong].getTact(); m_elapsedTicks = (m_playPos[Mode_PlaySong].getTicks()%ticksPerTact())/48; } }
void Song::processNextBuffer() { // if not playing, nothing to do if( m_playing == false ) { return; } TrackList trackList; int tcoNum = -1; // track content object number // determine the list of tracks to play and the track content object // (TCO) number switch( m_playMode ) { case Mode_PlaySong: trackList = tracks(); // at song-start we have to reset the LFOs if( m_playPos[Mode_PlaySong] == 0 ) { EnvelopeAndLfoParameters::instances()->reset(); } break; case Mode_PlayBB: if( Engine::getBBTrackContainer()->numOfBBs() > 0 ) { tcoNum = Engine::getBBTrackContainer()-> currentBB(); trackList.push_back( BBTrack::findBBTrack( tcoNum ) ); } break; case Mode_PlayPattern: if( m_patternToPlay != NULL ) { tcoNum = m_patternToPlay->getTrack()-> getTCONum( m_patternToPlay ); trackList.push_back( m_patternToPlay->getTrack() ); } break; default: return; } // if we have no tracks to play, nothing to do if( trackList.empty() == true ) { return; } // check for looping-mode and act if necessary TimeLineWidget * tl = m_playPos[m_playMode].m_timeLine; bool checkLoop = tl != NULL && m_exporting == false && tl->loopPointsEnabled(); if( checkLoop ) { // if looping-mode is enabled and we are outside of the looping // range, go to the beginning of the range if( m_playPos[m_playMode] < tl->loopBegin() || m_playPos[m_playMode] >= tl->loopEnd() ) { setToTime(tl->loopBegin()); m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); emit updateSampleTracks(); } } f_cnt_t framesPlayed = 0; const float framesPerTick = Engine::framesPerTick(); while( framesPlayed < Engine::mixer()->framesPerPeriod() ) { m_vstSyncController.update(); float currentFrame = m_playPos[m_playMode].currentFrame(); // did we play a tick? if( currentFrame >= framesPerTick ) { int ticks = m_playPos[m_playMode].getTicks() + ( int )( currentFrame / framesPerTick ); m_vstSyncController.setAbsolutePosition( ticks ); // did we play a whole tact? if( ticks >= MidiTime::ticksPerTact() ) { // per default we just continue playing even if // there's no more stuff to play // (song-play-mode) int maxTact = m_playPos[m_playMode].getTact() + 2; // then decide whether to go over to next tact // or to loop back to first tact if( m_playMode == Mode_PlayBB ) { maxTact = Engine::getBBTrackContainer() ->lengthOfCurrentBB(); } else if( m_playMode == Mode_PlayPattern && m_loopPattern == true && tl != NULL && tl->loopPointsEnabled() == false ) { maxTact = m_patternToPlay->length() .getTact(); } // end of played object reached? if( m_playPos[m_playMode].getTact() + 1 >= maxTact ) { // then start from beginning and keep // offset ticks %= ( maxTact * MidiTime::ticksPerTact() ); // wrap milli second counter setToTimeByTicks(ticks); m_vstSyncController.setAbsolutePosition( ticks ); } } m_playPos[m_playMode].setTicks( ticks ); if( checkLoop ) { m_vstSyncController.startCycle( tl->loopBegin().getTicks(), tl->loopEnd().getTicks() ); // if looping-mode is enabled and we have got // past the looping range, return to the // beginning of the range if( m_playPos[m_playMode] >= tl->loopEnd() ) { m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); setToTime(tl->loopBegin()); } else if( m_playPos[m_playMode] == tl->loopEnd() - 1 ) { emit updateSampleTracks(); } } else { m_vstSyncController.stopCycle(); } currentFrame = fmodf( currentFrame, framesPerTick ); m_playPos[m_playMode].setCurrentFrame( currentFrame ); } f_cnt_t framesToPlay = Engine::mixer()->framesPerPeriod() - framesPlayed; f_cnt_t framesLeft = ( f_cnt_t )framesPerTick - ( f_cnt_t )currentFrame; // skip last frame fraction if( framesLeft == 0 ) { ++framesPlayed; m_playPos[m_playMode].setCurrentFrame( currentFrame + 1.0f ); continue; } // do we have samples left in this tick but these are less // than samples we have to play? if( framesLeft < framesToPlay ) { // then set framesToPlay to remaining samples, the // rest will be played in next loop framesToPlay = framesLeft; } if( ( f_cnt_t ) currentFrame == 0 ) { processAutomations(trackList, m_playPos[m_playMode], framesToPlay); // loop through all tracks and play them for( int i = 0; i < trackList.size(); ++i ) { trackList[i]->play( m_playPos[m_playMode], framesToPlay, framesPlayed, tcoNum ); } } // update frame-counters framesPlayed += framesToPlay; m_playPos[m_playMode].setCurrentFrame( framesToPlay + currentFrame ); m_elapsedMilliSeconds += MidiTime::ticksToMilliseconds( framesToPlay / framesPerTick, getTempo()); m_elapsedTacts = m_playPos[Mode_PlaySong].getTact(); m_elapsedTicks = ( m_playPos[Mode_PlaySong].getTicks() % ticksPerTact() ) / 48; } }
MidiTime MidiTime::stepPosition( int step ) { return step * ticksPerTact() / stepsPerTact(); }
int MidiTime::stepsPerTact() { int steps = ticksPerTact() / DefaultBeatsPerTact; return qMax( 1, steps ); }
tick_t MidiTime::getTickWithinBar( const TimeSig &sig ) const { return m_ticks % ticksPerTact(sig); }
tick_t MidiTime::ticksPerBeat( const TimeSig &sig ) const { // (number of ticks per bar) divided by (number of beats per bar) return ticksPerTact(sig) / sig.numerator(); }