Exemple #1
0
bool RG21Loader::load(const QString &fileName, Composition &comp)
{
    m_composition = ∁
    comp.clear();

    QFile file(fileName);
    if (file.open(QIODevice::ReadOnly)) {
        m_stream = new QTextStream(&file);
    } else {
        return false;
    }

    m_studio->unassignAllInstruments();

    while (!m_stream->atEnd()) {

        if (!readNextLine())
            break;

        QString firstToken = m_tokens.first();

        if (firstToken == "Staves" || firstToken == "Staffs") { // nb staves

            m_nbStaves = m_tokens[1].toUInt();

        } else if (firstToken == "Name") { // Staff name

            m_currentStaffName = m_tokens[1]; // we don't do anything with it yet
            m_currentSegment = new Segment;
            ++m_currentSegmentNb;

        } else if (firstToken == "Clef") {

            parseClef();

        } else if (firstToken == "Key") {

            parseKey();

        } else if (firstToken == "Metronome") {

            if (!readNextLine())
                break;
            parseMetronome();

        } else if (firstToken == ":") { // chord

            m_tokens.removeFirst(); // get rid of 1st token ':'
            parseChordItem();

        } else if (firstToken == "Rest") { // rest

            if (!readNextLine())
                break;

            parseRest();

        } else if (firstToken == "Text") {

            if (!readNextLine())
                break;

            parseText();

        } else if (firstToken == "Group") {

            if (!readNextLine())
                break;

            parseGroupStart();

        } else if (firstToken == "Mark") {

            if (m_tokens[1] == "start")
                parseIndicationStart();
            else if (m_tokens[1] == "end")
                closeIndication();

        } else if (firstToken == "Bar") {

            parseBarType();

        } else if (firstToken == "Stave") {

            parseStaveType();

        } else if (firstToken == "End") {

            if (m_inGroup)
                closeGroup();
            else
                closeSegment();

        } else {

            RG_DEBUG << "RG21Loader::parse: Unsupported element type \"" << firstToken << "\", ignoring" << endl;
        }
    }

    delete m_stream;
    m_stream = 0;

    return true;
}
// 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.
}