void LoopingControl::slotLoopEndPos(double pos) { if (!m_pTrack) { return; } int newpos = pos; if (newpos != -1 && !even(newpos)) { newpos--; } if (m_iLoopEndSample == newpos) { //nothing to do return; } // Reject if the loop-in is not set, or if the new position is before the // start point (but not -1). if (m_iLoopStartSample == -1 || (newpos != -1 && newpos < m_iLoopStartSample)) { m_pCOLoopEndPosition->set(m_iLoopEndSample); return; } clearActiveBeatLoop(); if (pos == -1.0) { setLoopingEnabled(false); } m_iLoopEndSample = newpos; m_pCOLoopEndPosition->set(newpos); }
void LoopingControl::slotLoopStartPos(double pos) { if (!m_pTrack) { return; } int newpos = pos; if (newpos != -1 && !even(newpos)) { newpos--; } if (m_iLoopStartSample == newpos) { //nothing to do return; } clearActiveBeatLoop(); if (pos == -1.0) { setLoopingEnabled(false); } m_iLoopStartSample = newpos; m_pCOLoopStartPosition->set(newpos); if (m_iLoopEndSample != -1 && m_iLoopEndSample < m_iLoopStartSample) { m_iLoopEndSample = -1; m_pCOLoopEndPosition->set(kNoTrigger); setLoopingEnabled(false); } }
void LoopingControl::trackUnloaded(TrackPointer pTrack) { Q_UNUSED(pTrack); if (m_pTrack) { disconnect(m_pTrack.data(), SIGNAL(beatsUpdated()), this, SLOT(slotUpdatedTrackBeats())); } m_pTrack.clear(); m_pBeats.clear(); clearActiveBeatLoop(); }
void LoopingControl::trackLoaded(TrackPointer pTrack) { if (m_pTrack) { trackUnloaded(m_pTrack); } clearActiveBeatLoop(); if (pTrack) { m_pTrack = pTrack; m_pBeats = m_pTrack->getBeats(); connect(m_pTrack.data(), SIGNAL(beatsUpdated()), this, SLOT(slotUpdatedTrackBeats())); } }
void LoopingControl::slotLoopOut(double val) { if (!m_pTrack) { return; } if (val) { int pos = (m_pQuantizeEnabled->get() > 0.0 && m_pClosestBeat->get() != -1) ? static_cast<int>(floorf(m_pClosestBeat->get())) : m_iCurrentSample; // If the user is trying to set a loop-out before the loop in or without // having a loop-in, then ignore it. if (m_iLoopStartSample == -1 || pos < m_iLoopStartSample) { return; } // If the loop-in and out points are set so close that the loop would be // inaudible (which can happen easily with quantize-to-beat enabled,) // use the smallest pre-defined beatloop instead (when possible) if (pos - m_iLoopStartSample < MINIMUM_AUDIBLE_LOOP_SIZE) { pos = m_iLoopStartSample; if (m_pQuantizeEnabled->get() > 0.0 && m_pBeats) { // 1 would have just returned loop_in, so give 2 to get the beat // following loop_in int nextbeat = m_pBeats->findNthBeat(m_iLoopStartSample, 2); pos += (nextbeat - pos) * s_dBeatSizes[0]; } else { pos += MINIMUM_AUDIBLE_LOOP_SIZE; } } if (pos != -1 && !even(pos)) { pos++; // Increment to avoid shortening too-short loops } clearActiveBeatLoop(); //set loop out position m_iLoopEndSample = pos; m_pCOLoopEndPosition->set(m_iLoopEndSample); // start looping if (m_iLoopStartSample != -1 && m_iLoopEndSample != -1) { setLoopingEnabled(true); } // qDebug() << "set loop_out to " << m_iLoopEndSample; } }
void LoopingControl::slotLoopScale(double scale) { if (m_iLoopStartSample == kNoTrigger || m_iLoopEndSample == kNoTrigger) { return; } int loop_length = m_iLoopEndSample - m_iLoopStartSample; int old_loop_end = m_iLoopEndSample; int samples = m_pTrackSamples->get(); loop_length *= scale; // Abandon loops that are too short of extend beyond the end of the file. if (loop_length < MINIMUM_AUDIBLE_LOOP_SIZE || m_iLoopStartSample + loop_length > samples) { return; } m_iLoopEndSample = m_iLoopStartSample + loop_length; if (!even(m_iLoopEndSample)) { m_iLoopEndSample--; } // TODO(XXX) we could be smarter about taking the active beatloop, scaling // it by the desired amount and trying to find another beatloop that matches // it, but for now we just clear the active beat loop if somebody scales. clearActiveBeatLoop(); // Don't allow 0 samples loop, so one can still manipulate it if (m_iLoopEndSample == m_iLoopStartSample) { if ((m_iLoopEndSample+2) >= samples) m_iLoopStartSample -= 2; else m_iLoopEndSample += 2; } // Do not allow loops to go past the end of the song else if (m_iLoopEndSample > samples) { m_iLoopEndSample = samples; } // Update CO for loop end marker m_pCOLoopEndPosition->set(m_iLoopEndSample); // Reseek if the loop shrank out from under the playposition. if (m_bLoopingEnabled && scale < 1.0) { seekInsideAdjustedLoop( m_iLoopStartSample, old_loop_end, m_iLoopStartSample, m_iLoopEndSample); } }
void LoopingControl::slotLoopIn(double val) { if (!m_pTrack) { return; } if (val) { clearActiveBeatLoop(); // set loop-in position int pos = (m_pQuantizeEnabled->get() > 0.0 && m_pClosestBeat->get() != -1) ? static_cast<int>(floorf(m_pClosestBeat->get())) : m_iCurrentSample; // If we're looping and the loop-in and out points are now so close // that the loop would be inaudible (which can happen easily with // quantize-to-beat enabled,) set the in point to the smallest // pre-defined beatloop size instead (when possible) if (m_bLoopingEnabled && (m_iLoopEndSample - pos) < MINIMUM_AUDIBLE_LOOP_SIZE) { pos = m_iLoopEndSample; if (m_pQuantizeEnabled->get() > 0.0 && m_pBeats) { // 1 would have just returned loop_in, so give 2 to get the beat // following loop_in int nextbeat = m_pBeats->findNthBeat(pos, 2); pos -= (nextbeat - pos) * s_dBeatSizes[0]; } else pos -= MINIMUM_AUDIBLE_LOOP_SIZE; } if (pos != -1 && !even(pos)) { pos--; } m_iLoopStartSample = pos; m_pCOLoopStartPosition->set(m_iLoopStartSample); // Reset the loop out position if it is before the loop in so that loops // cannot be inverted. if (m_iLoopEndSample != -1 && m_iLoopEndSample < m_iLoopStartSample) { m_iLoopEndSample = -1; m_pCOLoopEndPosition->set(kNoTrigger); } // qDebug() << "set loop_in to " << m_iLoopStartSample; } }
void LoopingControl::trackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack) { Q_UNUSED(pOldTrack); if (m_pTrack) { disconnect(m_pTrack.data(), SIGNAL(beatsUpdated()), this, SLOT(slotUpdatedTrackBeats())); } clearActiveBeatLoop(); if (pNewTrack) { m_pTrack = pNewTrack; m_pBeats = m_pTrack->getBeats(); connect(m_pTrack.data(), SIGNAL(beatsUpdated()), this, SLOT(slotUpdatedTrackBeats())); } else { m_pTrack.clear(); m_pBeats.clear(); } }
void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint) { int samples = m_pTrackSamples->get(); if (!m_pTrack || samples == 0) { clearActiveBeatLoop(); return; } if (!m_pBeats) { clearActiveBeatLoop(); return; } // For now we do not handle negative beatloops. if (beats < 0) { clearActiveBeatLoop(); return; } // O(n) search, but there are only ~10-ish beatloop controls so this is // fine. foreach (BeatLoopingControl* pBeatLoopControl, m_beatLoops) { if (pBeatLoopControl->getSize() == beats) { if (m_pActiveBeatLoop != pBeatLoopControl) { if (m_pActiveBeatLoop) { m_pActiveBeatLoop->deactivate(); } m_pActiveBeatLoop = pBeatLoopControl; } pBeatLoopControl->activate(); break; } } // give loop_in and loop_out defaults so we can detect problems int loop_in = -1; int loop_out = -1; // For positive numbers we start from the current position/closest beat and // create the loop around X beats from there. if (beats > 0) { if (keepStartPoint) { loop_in = m_iLoopStartSample; } else { // loop_in is set to the previous beat if quantize is on. The // closest beat might be ahead of play position which would cause a seek. // TODO: If in reverse, should probably choose nextBeat. double cur_pos = getCurrentSample(); double prevBeat = floorf(m_pBeats->findPrevBeat(cur_pos)); if (m_pQuantizeEnabled->get() > 0.0 && prevBeat != -1) { if (beats >= 1.0) { loop_in = prevBeat; } else { // In case of beat length less then 1 beat: // (| - beats, ^ - current track's position): // // ...|...................^........|... // // If we press 1/2 beatloop we want loop from 50% to 100%, // If I press 1/4 beatloop, we want loop from 50% to 75% etc double nextBeat = floorf(m_pBeats->findNextBeat(cur_pos)); double beat_len = nextBeat - prevBeat; double loops_per_beat = 1.0 / beats; double beat_pos = cur_pos - prevBeat; int beat_frac = static_cast<int>(floor((beat_pos / beat_len) * loops_per_beat)); loop_in = prevBeat + beat_len / loops_per_beat * beat_frac; } } else { loop_in = floorf(cur_pos); } if (!even(loop_in)) { loop_in--; } } int fullbeats = static_cast<int>(floorf(beats)); double fracbeats = beats - static_cast<double>(fullbeats); // Now we need to calculate the length of the beatloop. We do this by // taking the current beat and the fullbeats'th beat and measuring the // distance between them. loop_out = loop_in; if (fullbeats > 0) { // Add the length between this beat and the fullbeats'th beat to the // loop_out position; double this_beat = m_pBeats->findNthBeat(loop_in, 1); double nth_beat = m_pBeats->findNthBeat(loop_in, 1 + fullbeats); loop_out += (nth_beat - this_beat); } if (fracbeats > 0) { // Add the fraction of the beat following the current loop_out // position to loop out. double loop_out_beat = m_pBeats->findNthBeat(loop_out, 1); double loop_out_next_beat = m_pBeats->findNthBeat(loop_out, 2); loop_out += (loop_out_next_beat - loop_out_beat) * fracbeats; } } if ((loop_in == -1) || ( loop_out == -1)) return; if (!even(loop_in)) loop_in--; if (!even(loop_out)) loop_out--; if (loop_in == loop_out) { if ((loop_out+2) > samples) { loop_in -= 2; } else { loop_out += 2; } } else if (loop_out > samples) { // Do not allow beat loops to go beyond the end of the track loop_out = samples; } m_iLoopStartSample = loop_in; m_pCOLoopStartPosition->set(loop_in); m_iLoopEndSample = loop_out; m_pCOLoopEndPosition->set(loop_out); setLoopingEnabled(true); }