QString TimeInstantLayer::getFeatureDescription(View *v, QPoint &pos) const { int x = pos.x(); if (!m_model || !m_model->getSampleRate()) return ""; SparseOneDimensionalModel::PointList points = getLocalPoints(v, x); if (points.empty()) { if (!m_model->isReady()) { return tr("In progress"); } else { return tr("No local points"); } } long useFrame = points.begin()->frame; RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); QString text; if (points.begin()->label == "") { text = QString(tr("Time:\t%1\nNo label")) .arg(rt.toText(true).c_str()); } else { text = QString(tr("Time:\t%1\nLabel:\t%2")) .arg(rt.toText(true).c_str()) .arg(points.begin()->label); } pos = QPoint(v->getXForFrame(useFrame), pos.y()); return text; }
bool RealTime::operator >(const RealTime &t) const { if (GetSec() > t.GetSec()) return true; if (GetSec() == t.GetSec() && GetUsec() > t.GetUsec()) return true; return false; }
RealTime RealTime::operator +(const RealTime &t) const { if (GetUsec() + t.GetUsec() >= ONE_MILLION) { return RealTime(GetSec() + t.GetSec() + 1, GetUsec() + t.GetUsec() - ONE_MILLION); } else { return RealTime(GetSec() + t.GetSec(), GetUsec() + t.GetUsec()); } }
void printFeatures(int frame, int sr, int output, Plugin::FeatureSet features, ofstream *out, bool useFrames) { for (unsigned int i = 0; i < features[output].size(); ++i) { if (useFrames) { int displayFrame = frame; if (features[output][i].hasTimestamp) { displayFrame = RealTime::realTime2Frame (features[output][i].timestamp, sr); } (out ? *out : cout) << displayFrame; if (features[output][i].hasDuration) { displayFrame = RealTime::realTime2Frame (features[output][i].duration, sr); (out ? *out : cout) << "," << displayFrame; } (out ? *out : cout) << ":"; } else { RealTime rt = RealTime::frame2RealTime(frame, sr); if (features[output][i].hasTimestamp) { rt = features[output][i].timestamp; } (out ? *out : cout) << rt.toString(); if (features[output][i].hasDuration) { rt = features[output][i].duration; (out ? *out : cout) << "," << rt.toString(); } (out ? *out : cout) << ":"; } for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { (out ? *out : cout) << " " << features[output][i].values[j]; } (out ? *out : cout) << " " << features[output][i].label; (out ? *out : cout) << endl; } }
static Vamp::Plugin::Feature snappedCurveValue(RealTime r, RealTime sn, int i, int n) { stringstream s; Vamp::Plugin::Feature f; f.hasTimestamp = true; f.timestamp = r; f.hasDuration = false; float v = float(i) / float(n); f.values.push_back(v); s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " snap to " << sn.toText(); f.label = s.str(); return f; }
static Vamp::Plugin::Feature noteOrRegion(RealTime r, RealTime d, int i, int n) { stringstream s; Vamp::Plugin::Feature f; f.hasTimestamp = true; f.timestamp = r; f.hasDuration = true; f.duration = d; float v = float(i) / float(n); f.values.push_back(v); s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " dur. " << d.toText(); f.label = s.str(); return f; }
long long RealTime::realTime2Frame(const RealTime &time, unsigned int sr) { if (time < zeroTime) return -realTime2Frame(-time, sr); long long sampleRate = sr; // We like integers. The last term is always zero unless the // sample rate is greater than 1MHz, but hell, you never know... long frame = time.sec * sampleRate + (time.msec() * sampleRate) / 1000 + ((time.usec() - 1000 * time.msec()) * sampleRate) / 1000000 + ((time.nsec - 1000 * time.usec()) * sampleRate) / 1000000000; return frame; }
void SoundDriver::sleep(const RealTime &rt) { // The usleep man page says it's deprecated and we should use // nanosleep. And that's what we did. But it seems quite a few // people don't have nanosleep, so we're reverting to usleep. unsigned long usec = rt.sec * 1000000 + rt.usec(); usleep(usec); }
static Vamp::Plugin::Feature instant(RealTime r, int i, int n) { stringstream s; Vamp::Plugin::Feature f; f.hasTimestamp = true; f.timestamp = r; f.hasDuration = false; s << i+1 << " of " << n << " at " << r.toText(); f.label = s.str(); return f; }
static Vamp::Plugin::Feature gridColumn(RealTime r, int i, int n) { stringstream s; Vamp::Plugin::Feature f; f.hasTimestamp = false; f.hasDuration = false; for (int j = 0; j < 10; ++j) { float v = float(j + i + 2) / float(n + 10); f.values.push_back(v); } s << i+1 << " of " << n << " at " << r.toText(); f.label = s.str(); return f; }
// scan on from a descriptor position bool RIFFAudioFile::scanForward(std::ifstream *file, const RealTime &time) { // sanity if (file == 0) return false; unsigned int totalSamples = m_sampleRate * time.sec + ( ( m_sampleRate * time.usec() ) / 1000000 ); unsigned int totalBytes = totalSamples * m_bytesPerFrame; m_loseBuffer = true; // do the seek file->seekg(totalBytes, std::ios::cur); if (file->eof()) return false; return true; }
void CreateTempoMapFromSegmentCommand::initialise(Segment *s) { m_oldTempi.clear(); m_newTempi.clear(); //!!! need an additional option: per-chord, per-beat, per-bar. // Let's work per-beat for the moment. Even for this, we should // probably use TimeSignature.getDivisions() std::vector<timeT> beatTimeTs; std::vector<RealTime> beatRealTimes; int startBar = m_composition->getBarNumber(s->getStartTime()); int barNo = startBar; int beat = 0; for (Segment::iterator i = s->begin(); s->isBeforeEndMarker(i); ++i) { if ((*i)->isa(Note::EventType)) { bool isNew; TimeSignature sig = m_composition->getTimeSignatureInBar(barNo, isNew); beatTimeTs.push_back(m_composition->getBarStart(barNo) + beat * sig.getBeatDuration()); if (++beat >= sig.getBeatsPerBar()) { ++barNo; beat = 0; } beatRealTimes.push_back(s->getComposition()->getElapsedRealTime ((*i)->getAbsoluteTime())); } } if (beatTimeTs.size() < 2) return ; tempoT prevTempo = 0; // set up m_oldTempi and prevTempo for (int i = m_composition->getTempoChangeNumberAt(*beatTimeTs.begin() - 1) + 1; i <= m_composition->getTempoChangeNumberAt(*beatTimeTs.end() - 1); ++i) { std::pair<timeT, tempoT> tempoChange = m_composition->getTempoChange(i); m_oldTempi[tempoChange.first] = tempoChange.second; if (prevTempo == 0) prevTempo = tempoChange.second; } RG_DEBUG << "starting tempo: " << prevTempo << endl; timeT quarter = Note(Note::Crotchet).getDuration(); for (size_t beat = 1; beat < beatTimeTs.size(); ++beat) { timeT beatTime = beatTimeTs[beat] - beatTimeTs[beat - 1]; RealTime beatRealTime = beatRealTimes[beat] - beatRealTimes[beat - 1]; // Calculate tempo to nearest qpm. // This is 60 / {quarter note duration in seconds} // = 60 / ( {beat in seconds} * {quarter in ticks} / { beat in ticks} ) // = ( 60 * {beat in ticks} ) / ( {beat in seconds} * {quarter in ticks} ) // Precision is deliberately limited to qpm to avoid silly values. double beatSec = double(beatRealTime.sec) + double(beatRealTime.usec() / 1000000.0); double qpm = (60.0 * beatTime) / (beatSec * quarter); tempoT tempo = Composition::getTempoForQpm(int(qpm + 0.001)); RG_DEBUG << "prev beat: " << beatTimeTs[beat] << ", prev beat real time " << beatRealTimes[beat] << endl; RG_DEBUG << "time " << beatTime << ", rt " << beatRealTime << ", beatSec " << beatSec << ", tempo " << tempo << endl; if (tempo != prevTempo) { m_newTempi[beatTimeTs[beat - 1]] = tempo; prevTempo = tempo; } } }
int SegmentMover::mouseMoveEvent(QMouseEvent *e) { // No need to propagate. e->accept(); // If we aren't moving anything, bail. if (!getChangingSegment()) return RosegardenScrollView::NoFollow; QPoint pos = m_canvas->viewportToContents(e->pos()); setSnapTime(e, SnapGrid::SnapToBeat); // If shift isn't being held down if ((e->modifiers() & Qt::ShiftModifier) == 0) { setContextHelp(tr("Hold Shift to avoid snapping to beat grid")); } else { clearContextHelp(); } const SnapGrid &grid = m_canvas->grid(); // Compute how far we've moved vertically. const int startTrackPos = grid.getYBin(m_clickPoint.y()); const int currentTrackPos = grid.getYBin(pos.y()); const int deltaTrack = currentTrackPos - startTrackPos; const int dx = pos.x() - m_clickPoint.x(); Composition &comp = m_doc->getComposition(); CompositionModelImpl::ChangingSegmentSet &changingSegments = m_canvas->getModel()->getChangingSegments(); // For each changing segment, move it for (CompositionModelImpl::ChangingSegmentSet::iterator it = changingSegments.begin(); it != changingSegments.end(); ++it) { ChangingSegmentPtr changingSegment = *it; const timeT newStartTime = grid.snapX(changingSegment->savedRect().x() + dx); const int newX = int(grid.getRulerScale()->getXForTime(newStartTime)); int trackPos = grid.getYBin(changingSegment->savedRect().y()) + deltaTrack; if (trackPos < 0) trackPos = 0; if (trackPos >= (int)comp.getNbTracks()) trackPos = comp.getNbTracks() - 1; const int newY = grid.getYBinCoordinate(trackPos); changingSegment->moveTo(newX, newY); m_changeMade = true; } if (m_changeMade) { // Make sure the segments are redrawn. m_canvas->slotUpdateAll(); } // Draw the guides int guideX = getChangingSegment()->rect().x(); int guideY = getChangingSegment()->rect().y(); m_canvas->drawGuides(guideX, guideY); // Format and draw the text float timeT guideTime = grid.snapX(guideX); RealTime time = comp.getElapsedRealTime(guideTime); int bar, beat, fraction, remainder; comp.getMusicalTimeForAbsoluteTime(guideTime, bar, beat, fraction, remainder); QString timeString = QString("%1.%2s (%3, %4, %5)") .arg(time.sec).arg(time.msec(), 3, 10, QChar('0')) .arg(bar + 1).arg(beat).arg(fraction); m_canvas->drawTextFloat(guideX + 10, guideY - 30, timeString); m_canvas->update(); return RosegardenScrollView::FollowHorizontal | RosegardenScrollView::FollowVertical; }
JNIEXPORT jint JNICALL Java_org_vamp_1plugins_RealTime_msec(JNIEnv *env, jobject obj) { RealTime rt = getRealTime(env, obj); return rt.msec(); }
int SegmentSelector::mouseMoveEvent(QMouseEvent *e) { // No need to propagate. e->accept(); QPoint pos = m_canvas->viewportToContents(e->pos()); m_lastMousePos = pos; // If no buttons are pressed, update the context help and bail. // Note: Mouse tracking must be on for this to work. See // QWidget::setMouseTracking(). if (e->buttons() == Qt::NoButton) { setContextHelpFor(pos, e->modifiers()); return RosegardenScrollView::NoFollow; } // If another tool has taken over, delegate. if (m_dispatchTool) return m_dispatchTool->mouseMoveEvent(e); // We only handle the left button. The middle button is handled by // the dispatch tool (segment pencil) or ignored. if (e->buttons() != Qt::LeftButton) return RosegardenScrollView::NoFollow; // If we aren't moving anything, rubber band. if (!getChangingSegment()) { m_canvas->drawSelectionRectPos2(pos); m_canvas->getModel()->selectionHasChanged(); return RosegardenScrollView::FollowHorizontal | RosegardenScrollView::FollowVertical; } // Moving // If the segment that was clicked on isn't selected, bail. if (!m_canvas->getModel()->isSelected(getChangingSegment()->getSegment())) return RosegardenScrollView::NoFollow; const int dx = pos.x() - m_clickPoint.x(); const int dy = pos.y() - m_clickPoint.y(); const int inertiaDistance = 8; // If we've not already exceeded the inertia distance, and we // still haven't, bail. if (!m_passedInertiaEdge && abs(dx) < inertiaDistance && abs(dy) < inertiaDistance) { return RosegardenScrollView::NoFollow; } m_passedInertiaEdge = true; m_canvas->viewport()->setCursor(Qt::SizeAllCursor); #if 0 // ??? Moving to mouseReleaseEvent(). if (m_segmentCopyMode && !m_segmentQuickCopyDone) { // Make copies of the original Segment(s). These copies will // take the place of the originals as the user drags the // the originals to a new location. MacroCommand *macroCommand = 0; if (m_segmentCopyingAsLink) { macroCommand = new MacroCommand( SegmentQuickLinkCommand::getGlobalName()); } else { macroCommand = new MacroCommand( SegmentQuickCopyCommand::getGlobalName()); } SegmentSelection selectedItems = m_canvas->getSelectedSegments(); // for each selected segment for (SegmentSelection::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) { Segment *segment = *it; Command *command = 0; if (m_segmentCopyingAsLink) { command = new SegmentQuickLinkCommand(segment); } else { // if it's a link, copy as link if (segment->isTrulyLinked()) command = new SegmentQuickLinkCommand(segment); else // copy as a non-link segment command = new SegmentQuickCopyCommand(segment); } macroCommand->addCommand(command); } CommandHistory::getInstance()->addCommand(macroCommand); m_canvas->update(); // Make sure we don't do it again. m_segmentQuickCopyDone = true; } #endif setSnapTime(e, SnapGrid::SnapToBeat); // start move on selected items only once if (!m_selectionMoveStarted) { m_selectionMoveStarted = true; m_canvas->getModel()->startChangeSelection( m_segmentCopyMode ? CompositionModelImpl::ChangeCopy : CompositionModelImpl::ChangeMove); // The call to startChangeSelection() generates a new changing segment. // Get it. ChangingSegmentPtr newChangingSegment = m_canvas->getModel()->findChangingSegment( getChangingSegment()->getSegment()); if (newChangingSegment) { // Toss the local "changing" segment since it isn't going to // be moving at all. Swap it for the same changing segment in // CompositionModelImpl. That one *will* be moving and can be // used to drive the guides. setChangingSegment(newChangingSegment); } } // Display help for the Shift key. setContextHelpFor(pos, e->modifiers()); Composition &comp = m_doc->getComposition(); const int startDragTrackPos = m_canvas->grid().getYBin(m_clickPoint.y()); const int currentTrackPos = m_canvas->grid().getYBin(pos.y()); const int trackDiff = currentTrackPos - startDragTrackPos; CompositionModelImpl::ChangingSegmentSet &changingSegments = m_canvas->getModel()->getChangingSegments(); // For each changing segment for (CompositionModelImpl::ChangingSegmentSet::iterator it = changingSegments.begin(); it != changingSegments.end(); ++it) { ChangingSegmentPtr changingSegment = *it; const timeT newStartTime = m_canvas->grid().snapX( changingSegment->savedRect().x() + dx); const int newX = lround( m_canvas->grid().getRulerScale()->getXForTime(newStartTime)); int newTrackPos = m_canvas->grid().getYBin( changingSegment->savedRect().y()) + trackDiff; // Limit to [0, comp.getNbTracks()-1]. if (newTrackPos < 0) newTrackPos = 0; if (newTrackPos > static_cast<int>(comp.getNbTracks()) - 1) newTrackPos = comp.getNbTracks() - 1; const int newY = m_canvas->grid().getYBinCoordinate(newTrackPos); changingSegment->moveTo(newX, newY); m_changeMade = true; } if (m_changeMade) { // Make sure the segments are redrawn. // Note: The update() call below doesn't cause the segments to be // redrawn. It just updates from the cache. m_canvas->slotUpdateAll(); } // Guides const int guideX = getChangingSegment()->rect().x(); const int guideY = getChangingSegment()->rect().y(); m_canvas->drawGuides(guideX, guideY); // Text Float const timeT guideTime = m_canvas->grid().snapX(guideX); RealTime time = comp.getElapsedRealTime(guideTime); QString msecs; msecs.sprintf("%03d", time.msec()); int bar; int beat; int fraction; int remainder; comp.getMusicalTimeForAbsoluteTime(guideTime, bar, beat, fraction, remainder); QString posString = QString("%1.%2s (%3, %4, %5)"). arg(time.sec).arg(msecs).arg(bar + 1).arg(beat).arg(fraction); m_canvas->drawTextFloat(guideX + 10, guideY - 30, posString); m_canvas->update(); return RosegardenScrollView::FollowHorizontal | RosegardenScrollView::FollowVertical; }
void printFeatures(int frame, int sr, const Plugin::OutputDescriptor &output, int outputNo, const Plugin::FeatureSet &features, ofstream *out, bool useFrames) { static int featureCount = -1; if (features.find(outputNo) == features.end()) return; for (size_t i = 0; i < features.at(outputNo).size(); ++i) { const Plugin::Feature &f = features.at(outputNo).at(i); bool haveRt = false; RealTime rt; if (output.sampleType == Plugin::OutputDescriptor::VariableSampleRate) { rt = f.timestamp; haveRt = true; } else if (output.sampleType == Plugin::OutputDescriptor::FixedSampleRate) { int n = featureCount + 1; if (f.hasTimestamp) { n = int(round(toSeconds(f.timestamp) * output.sampleRate)); } rt = RealTime::fromSeconds(double(n) / output.sampleRate); haveRt = true; featureCount = n; } if (useFrames) { int displayFrame = frame; if (haveRt) { displayFrame = RealTime::realTime2Frame(rt, sr); } (out ? *out : cout) << displayFrame; if (f.hasDuration) { displayFrame = RealTime::realTime2Frame(f.duration, sr); (out ? *out : cout) << "," << displayFrame; } (out ? *out : cout) << ":"; } else { if (!haveRt) { rt = RealTime::frame2RealTime(frame, sr); } (out ? *out : cout) << rt.toString(); if (f.hasDuration) { rt = f.duration; (out ? *out : cout) << "," << rt.toString(); } (out ? *out : cout) << ":"; } for (unsigned int j = 0; j < f.values.size(); ++j) { (out ? *out : cout) << " " << f.values[j]; } (out ? *out : cout) << " " << f.label; (out ? *out : cout) << endl; } }
JNIEXPORT jstring JNICALL Java_org_vamp_1plugins_RealTime_toText(JNIEnv *env, jobject obj) { RealTime rt = getRealTime(env, obj); return env->NewStringUTF(rt.toText().c_str()); }
void TempoDialog::populateTempo() { Composition &comp = m_doc->getComposition(); tempoT tempo = comp.getTempoAtTime(m_tempoTime); std::pair<bool, tempoT> ramping(false, tempo); int tempoChangeNo = comp.getTempoChangeNumberAt(m_tempoTime); if (tempoChangeNo >= 0) { tempo = comp.getTempoChange(tempoChangeNo).second; ramping = comp.getTempoRamping(tempoChangeNo, false); } m_tempoValueSpinBox->setValue(comp.getTempoQpm(tempo)); if (ramping.first) { if (ramping.second) { m_tempoTargetSpinBox->setEnabled(true); m_tempoTargetSpinBox->setValue(comp.getTempoQpm(ramping.second)); m_tempoConstant->setChecked(false); m_tempoRampToNext->setChecked(false); m_tempoRampToTarget->setChecked(true); } else { ramping = comp.getTempoRamping(tempoChangeNo, true); m_tempoTargetSpinBox->setEnabled(false); m_tempoTargetSpinBox->setValue(comp.getTempoQpm(ramping.second)); m_tempoConstant->setChecked(false); m_tempoRampToNext->setChecked(true); m_tempoRampToTarget->setChecked(false); } } else { m_tempoTargetSpinBox->setEnabled(false); m_tempoTargetSpinBox->setValue(comp.getTempoQpm(tempo)); m_tempoConstant->setChecked(true); m_tempoRampToNext->setChecked(false); m_tempoRampToTarget->setChecked(false); } // m_tempoTargetCheckBox->setChecked(ramping.first); m_tempoTargetSpinBox->setEnabled(ramping.first); updateBeatLabels(comp.getTempoQpm(tempo)); if (m_timeEditor) { m_timeEditor->slotSetTime(m_tempoTime); return ; } RealTime tempoTime = comp.getElapsedRealTime(m_tempoTime); QString milliSeconds; milliSeconds.sprintf("%03d", tempoTime.msec()); m_tempoTimeLabel->setText(tr("%1.%2 s,").arg(tempoTime.sec) .arg(milliSeconds)); int barNo = comp.getBarNumber(m_tempoTime); if (comp.getBarStart(barNo) == m_tempoTime) { m_tempoBarLabel->setText (tr("at the start of measure %1.").arg(barNo + 1)); m_tempoChangeStartOfBar->setEnabled(false); } else { m_tempoBarLabel->setText( tr("in the middle of measure %1.").arg(barNo + 1)); m_tempoChangeStartOfBar->setEnabled(true); } m_tempoChangeBefore->setEnabled(false); m_tempoChangeBeforeAt->setEnabled(false); bool havePrecedingTempo = false; if (tempoChangeNo >= 0) { timeT lastTempoTime = comp.getTempoChange(tempoChangeNo).first; if (lastTempoTime < m_tempoTime) { RealTime lastRT = comp.getElapsedRealTime(lastTempoTime); QString lastms; lastms.sprintf("%03d", lastRT.msec()); int lastBar = comp.getBarNumber(lastTempoTime); m_tempoChangeBeforeAt->setText (tr(" (at %1.%2 s, in measure %3)").arg(lastRT.sec) .arg(lastms).arg(lastBar + 1)); m_tempoChangeBeforeAt->show(); m_tempoChangeBefore->setEnabled(true); m_tempoChangeBeforeAt->setEnabled(true); havePrecedingTempo = true; } } if (comp.getTempoChangeCount() > 0) { if (havePrecedingTempo) { m_tempoStatusLabel->hide(); } else { m_tempoStatusLabel->setText (tr("There are no preceding tempo changes.")); } m_tempoChangeGlobal->setEnabled(true); } else { m_tempoStatusLabel->setText (tr("There are no other tempo changes.")); m_tempoChangeGlobal->setEnabled(false); } m_defaultBox->setEnabled(false); }
int RealTime::operator -(const RealTime &t) const { return (GetSec() - t.GetSec()) * 1000 + int((GetUsec() - t.GetUsec()) / 1000.0); }
long RealTime::Sub(const RealTime &t) { return (GetSec() - t.GetSec()) * 1000000 + GetUsec() - t.GetUsec(); }