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. }