Exemplo n.º 1
0
/// Initialize ExpandFigurationCommand
/// @author Tom Breton (Tehom)
void
ExpandFigurationCommand::initialise(SegmentSelection selection)
{
    FigurationVector figs;
    int figSourceID = -1;
    bool gotFigSource = false;

    RG_DEBUG << "Initializing ExpandFigurationCommand" << endl;

    // Update, because if we need new IDs they mustn't duplicate old
    // IDs, so we must be up to date on what IDs are there.
    SegmentFigData::SegmentFigDataMap segMap = 
        SegmentFigData::getInvolvedSegments(true, this);
    for (SegmentSelection::iterator i = selection.begin();
         i != selection.end();
         ++i) {
        SegmentFigData& segmentData =
            SegmentFigData::findOrAdd(segMap, *i);
        
        // If it's used here, it's not uninvolved, so unless it's a
        // figuration, it's a chord source.
        if (segmentData.isa(SegmentFigData::Uninvolved)) {
            segmentData.convertType(SegmentFigData::ChordSource);
        }
        segmentData.addTagIfNeeded(*i, this);
        if (gotFigSource ||
            !segmentData.isa(SegmentFigData::FigurationSource))
            { continue; }

        figSourceID = segmentData.getID();
        figs = FigurationSourceMap::getFigurations(*i);
        if (!figs.empty())
            { gotFigSource = true; }
    }
    // If we didn't find a real figuration, there's nothing to do.
    if (!gotFigSource) { return; }

    SourcedFiguration sourcedfigs(figSourceID, figs);
    
    // Expand figuration in each segment in selection except the
    // figuration segment itself.
    for (SegmentSelection::iterator i = selection.begin();
         i != selection.end();
         ++i) {
        Segment *s = (*i);
        SegmentFigData::SegmentFigDataMap::iterator it = segMap.find(*i);
        Q_ASSERT_X(it != segMap.end(),
                   "ExpandFigurationCommand::initialise",
                   "didn't find the segment");
        SegmentFigData& segmentData = it->second;
        
        if (!segmentData.isa(SegmentFigData::ChordSource))
            { continue; }

        // Make a target segment
        Segment *target = s->clone(false);
        // Temporarily attach it to composition so that expand can
        // work.
        m_composition->weakAddSegment(target);

        target->clear();
        target->fillWithRests(s->getEndTime());
        SegmentFigData::addTag(target, this, SegmentID::Target);
        m_newSegments.insert(target);

        /** Add notes to target segment **/
        for (Segment::iterator e = s->begin();
             e != s->end();
             ++e) {
            // Non-notes they don't imply there's a chord here.
            // We add them to target segment in case they are
            // clefs or key changes.
            if ((*e)->isa(SegmentID::EventType)) {
                continue;
            }
            if (!(*e)->isa(Note::EventType)) {
                target->insert(new Event(**e));
            }
        }


        // rawStartTime is the apparent start time before we take bars
        // into account.  We step it along the composition, finding
        // valid places to expand.  Specifically, on bar lines not
        // already part of an expansion.
        timeT rawStartTime = s->getStartTime();
        while (1) {
            timeT figurationStartTime = rawStartTimeToExact(rawStartTime);

            if (rawStartTime >= s->getEndTime())
                { break; }

            timeT timePastFiguration =
                SegmentFigData::expand(sourcedfigs,
                                       ChordSegment(s, segmentData.getID()),
                                       target, figurationStartTime);

            // If we didn't expand, ensure we don't try endlessly at
            // the same place.
            if (timePastFiguration == figurationStartTime) {
                ++timePastFiguration;
            }
            rawStartTime = timePastFiguration;
        }

        // Detach from composition, because SegmentInsertCommand does
        // the actual placing
        m_composition->weakDetachSegment(target);

        
        Command *c =
            new SegmentInsertCommand(m_composition, target, s->getTrack());
        addCommand(c);
    }

}
Exemplo n.º 2
0
// Initialize FitToBeatsCommand
// @author Tom Breton (Tehom)
void
FitToBeatsCommand::initialise(Segment *s)
{
    m_oldTempi.clear();
    m_newTempi.clear();
    m_oldSegments.clear();
    m_newSegments.clear();

    // Get the real times from the beat segment
    vecRealTime beatRealTimes;
    int success = 
        getBeatRealTimes(s, beatRealTimes);
    if(!success) { return; }

    // Store the current tempos
    getCurrentTempi(*m_composition, m_oldTempi);
    tempoT defaultTempo = m_composition->getCompositionDefaultTempo();

    // A temporary copy of the composition.  It is not intended to be
    // a complete copy, it just provides a place for new segments and
    // tempi to live until we have fully copied events to their new
    // state.
    Composition scratchComposition;
    scratchComposition.clear();
    scratchComposition.setCompositionDefaultTempo(defaultTempo);

    
    // Set tempos in scratchComposition such that each observed beat
    // in beatRealTimes takes one beatTime.
    {
        // Starting time is the same for both.
        timeT firstBeatTime = 
            m_composition->getElapsedTimeForRealTime(beatRealTimes[0]);

        unsigned int numBeats = beatRealTimes.size();

        // Get interval between beats from time signature.
        // Get time signature
        TimeSignature timeSig =
            m_composition->getTimeSignatureAt(firstBeatTime);
        timeT beatTime = timeSig.getBeatDuration();

        // We're going to visit the beats in reverse order, and always
        // remembering the next beat (the next beat time-wise, which
        // the iterator visited last time)
        vecRealTime::const_reverse_iterator i = beatRealTimes.rbegin();

        // Treat the final beat specially
        timeT    finalBeatTime = firstBeatTime + ((numBeats - 1) * beatTime);
        RealTime finalRealTime = beatRealTimes.back();
        scratchComposition.addTempoAtTime(finalBeatTime, defaultTempo, -1);
        // Step past it
        ++i;

        // Set up loop variables
        timeT    nextBeatTime = finalBeatTime;
        RealTime nextRealTime = finalRealTime;
        // nextTempo is unused, it will be used if we make ramped
        // tempi.
        /* tempoT   nextTempo    = defaultTempo; */


        // Treat all the other beats.
        while (i != beatRealTimes.rend()) {
            timeT        timeNow = nextBeatTime - beatTime;
            RealTime realTimeNow = *i;
            RealTime realTimeDelta = nextRealTime - realTimeNow;
            // Calculate what tempoT will get us to the right real
            // time.  For now, we use unramped tempi.
            tempoT rampTo = -1;
            tempoT tempo = Composition::timeRatioToTempo(realTimeDelta,
                                                         beatTime, rampTo);
            scratchComposition.addTempoAtTime(timeNow, tempo, rampTo);

            // Step
            nextBeatTime = timeNow;
            nextRealTime = realTimeNow;
            /* nextTempo    = tempo; */
            ++i;
        }
    }
    // We don't try to copy over tempo changes that are outside the
    // range of the groove segment (before or after).  We don't try to
    // correct for accumulated error.

    // Done setting Tempi

    // Collect tempi
    getCurrentTempi(scratchComposition, m_newTempi);


    // Copy all the events to scratchComposition.  The copies will be
    // at the same realtime but not the same timeT.  Even events in
    // the groove segment get copied.
    segmentcontainer &origSegments = m_composition->getSegments();
    for (Composition::iterator i = origSegments.begin();
         i != origSegments.end();
         ++i) {
        Segment * const oldSegment = *i;

        // We'd prefer to just make a segment with no events that's
        // otherwise the same as the old one but we can't.
        Segment *newSegment = oldSegment->clone(false);
        newSegment->clear();

        // Add the segments into appropriate containers.
        // scratchComposition owns the new segments during initialise,
        // but m_newSegments will own them after initialise returns.
        m_oldSegments.insert(oldSegment);
        m_newSegments.insert(newSegment);
        scratchComposition.addSegment(newSegment);

        //Iterate over notes in the old segment.
        const timeT earliestTime = 0;
        for (Segment::iterator j = oldSegment->findTime(earliestTime);
             oldSegment->isBeforeEndMarker(j);
             ++j)  {
            // Get the old-timed event times.
            timeT oldStartTime = (*j)->getAbsoluteTime();
            timeT duration = (*j)->getDuration();

            // Get the real event times.
            RealTime RealStartTime =
                m_composition->getElapsedRealTime(oldStartTime);

            RealTime RealEndTime;
            if (duration == 0) {
                RealEndTime = RealStartTime;
            }
            else {
                timeT oldEndTime = oldStartTime + duration;
                RealEndTime = 
                    m_composition->getElapsedRealTime(oldEndTime);
            }

            // Get the new target times.  Use scratchComposition
            // because its times use the new Tempi.
            timeT newStartTime =
                scratchComposition.getElapsedTimeForRealTime(RealStartTime);
            timeT newDuration;
            if (duration == 0) {
                newDuration = 0;
            }
            else {
                timeT newEndTime =
                    scratchComposition.getElapsedTimeForRealTime(RealEndTime);
                newDuration = newEndTime - newStartTime;
            }

            // Add a parallel event in the new segment.
            newSegment->insert(new Event(**j, newStartTime, newDuration));
        }
    }

    // Detach the segments before scratchComposition goes out of
    // scope.  m_newSegments contains exactly the segments that need
    // to be detached.
    for (segmentcontainer::iterator i = m_newSegments.begin();
         i != m_newSegments.end();
         ++i) {
        scratchComposition.weakDetachSegment(*i);
    }

    // We do the actual swapping of old <-> new in (un)execute.
}