double BeatGrid::findNthBeat(double dSamples, int n) const { QMutexLocker locker(&m_mutex); if (!isValid() || n == 0) { return -1; } double beatFraction = (dSamples - firstBeatSample()) / m_dBeatLength; double prevBeat = floor(beatFraction); double nextBeat = ceil(beatFraction); // If the position is within 1/100th of the next or previous beat, treat it // as if it is that beat. const double kEpsilon = .01; if (fabs(nextBeat - beatFraction) < kEpsilon) { beatFraction = nextBeat; // If we are going to pretend we were actually on nextBeat then prevBeat // needs to be re-calculated. Since it is floor(beatFraction), that's // the same as nextBeat. We only use prevBeat so no need to increment // nextBeat. prevBeat = nextBeat; } else if (fabs(prevBeat - beatFraction) < kEpsilon) { beatFraction = prevBeat; // If we are going to pretend we were actually on prevBeat then nextBeat // needs to be re-calculated. Since it is ceil(beatFraction), that's // the same as prevBeat. We will only use nextBeat so no need to // decrement prevBeat. nextBeat = prevBeat; } double dClosestBeat; if (n > 0) { // We're going forward, so use ceil to round up to the next multiple of // m_dBeatLength dClosestBeat = nextBeat * m_dBeatLength + firstBeatSample(); n = n - 1; } else { // We're going backward, so use floor to round down to the next multiple // of m_dBeatLength dClosestBeat = prevBeat * m_dBeatLength + firstBeatSample(); n = n + 1; } double dResult = floor(dClosestBeat + n * m_dBeatLength); if (!even(static_cast<int>(dResult))) { dResult--; } return dResult; }
void BeatGrid::translate(double dNumSamples) { QMutexLocker locker(&m_mutex); if (!isValid()) { return; } double newFirstBeatFrames = (firstBeatSample() + dNumSamples) / kFrameSize; m_grid.mutable_first_beat()->set_frame_position(newFirstBeatFrames); locker.unlock(); emit(updated()); }
bool BeatGrid::findPrevNextBeats(double dSamples, double* dpPrevBeatSamples, double* dpNextBeatSamples) const { double dFirstBeatSample; double dBeatLength; { QMutexLocker locker(&m_mutex); if (!isValid()) { *dpPrevBeatSamples = -1.0; *dpNextBeatSamples = -1.0; return false; } dFirstBeatSample = firstBeatSample(); dBeatLength = m_dBeatLength; } double beatFraction = (dSamples - dFirstBeatSample) / dBeatLength; double prevBeat = floor(beatFraction); double nextBeat = ceil(beatFraction); // If the position is within 1/100th of the next or previous beat, treat it // as if it is that beat. const double kEpsilon = .01; if (fabs(nextBeat - beatFraction) < kEpsilon) { beatFraction = nextBeat; // If we are going to pretend we were actually on nextBeat then prevBeatFraction // needs to be re-calculated. Since it is floor(beatFraction), that's // the same as nextBeat. prevBeat = nextBeat; // And nextBeat needs to be incremented. ++nextBeat; } *dpPrevBeatSamples = floor(prevBeat * dBeatLength + dFirstBeatSample); *dpNextBeatSamples = floor(nextBeat * dBeatLength + dFirstBeatSample); if (!even(static_cast<int>(*dpPrevBeatSamples))) { --*dpPrevBeatSamples; } if (!even(static_cast<int>(*dpNextBeatSamples))) { --*dpNextBeatSamples; } return true; }