void SegmParams::calculateSegmParams(const Segment & s) { //k = (y2-y1)/(x2-x1) k = (s.end().y() - s.start().y() )/(s.end().x() - s.start().x()); //b = y1-k*x1 b = s.start().y() - k * s.start().x(); length = sqrt(abs(abs(s.start().x()) - abs(s.end().x())) + abs(abs(s.start().y()) - abs(s.end().y()))) }
void FieldController::LinesCalibrate( const Segment& topSegment, std::vector<Segment>& modelTopLine ) { std::vector<Segment>::iterator it_modelTopLine = modelTopLine.begin(); while (it_modelTopLine != modelTopLine.end()) { if (it_modelTopLine->start().X() < topSegment.start().X()) it_modelTopLine->start().X() = topSegment.start().X(); if (it_modelTopLine->end().X() > topSegment.end().X()) it_modelTopLine->end().X() = topSegment.end().X(); ++it_modelTopLine; } SortSegmetnsByY(modelTopLine); Segment temp(Vector2F(1.f, 1.f), Vector2F(5.f, 1.f)); bool res = temp.inside(Vector2F(1.f, 1.f)); res = temp.inside(Vector2F(5.f, 1.f)); res = temp.inside(Vector2F(4.f, 1.f)); res = temp.inside(Vector2F(5.1f, 1.f)); res = temp.inside(Vector2F(0.9f, 1.f)); for (int i = 0, i_end = modelTopLine.size(); i < i_end; ++i) { for (int j = i + 1, j_end = modelTopLine.size(); j < j_end; ++j) { bool startInside = (modelTopLine[i].start().X() <= modelTopLine[j].start().X()) && (modelTopLine[j].start().X() <= modelTopLine[i].end().X()); bool endInside = (modelTopLine[i].start().X() <= modelTopLine[j].end().X()) && (modelTopLine[j].end().X() <= modelTopLine[i].end().X()); if (startInside && endInside) { it_modelTopLine = modelTopLine.begin(); std::advance(it_modelTopLine, j); modelTopLine.erase(it_modelTopLine); i_end = j_end = modelTopLine.size(); i = j = 0; } else if (startInside) { modelTopLine[j].start().X() = modelTopLine[i].end().X(); } else if (endInside) { modelTopLine[j].end().X() = modelTopLine[i].start().X(); } else if (modelTopLine[i].start().X() > modelTopLine[j].start().X() && modelTopLine[i].end().X() < modelTopLine[j].end().X()) { modelTopLine.push_back(Segment(modelTopLine[j].start(), Vector2F(modelTopLine[i].start().X(), modelTopLine[j].start().Y()))); modelTopLine.push_back(Segment(Vector2F(modelTopLine[i].end().X(), modelTopLine[j].end().Y()), modelTopLine[j].end())); it_modelTopLine = modelTopLine.begin(); std::advance(it_modelTopLine, j); modelTopLine.erase(it_modelTopLine); i_end = j_end = modelTopLine.size(); } } } }
void SegmentLinker::refreshSegment(Segment *seg) { timeT startTime = seg->getStartTime(); eraseNonIgnored(seg,seg->begin(),seg->end()); //find another segment Segment *sourceSeg = 0; Segment *tempClone = 0; LinkedSegmentParamsList::iterator itr; for (itr = m_linkedSegmentParamsList.begin(); itr!= m_linkedSegmentParamsList.end(); ++itr) { LinkedSegmentParams &linkedSegParams = *itr; Segment *other = linkedSegParams.m_linkedSegment; if (other != seg) { sourceSeg = other; break; } } if (!sourceSeg) { //make a temporary clone tempClone = createLinkedSegment(seg); sourceSeg = tempClone; } timeT sourceSegStartTime = sourceSeg->getStartTime(); Segment::const_iterator segitr; for(segitr=sourceSeg->begin(); segitr!=sourceSeg->end(); ++segitr) { const Event *refEvent = *segitr; timeT refEventTime = refEvent->getAbsoluteTime() - sourceSegStartTime; timeT freshEventTime = refEventTime+startTime; insertMappedEvent(seg,refEvent,freshEventTime, seg->getLinkTransposeParams().m_semitones, seg->getLinkTransposeParams().m_steps); } if (tempClone) { delete tempClone; } }
Segment * Clipboard::newSegment(const EventSelection *copyFrom) { // create with clone function so as to inherit track, instrument etc // but clone as a segment only, even if it's actually a linked segment Segment *s = copyFrom->getSegment().clone(false); s->erase(s->begin(), s->end()); const EventSelection::eventcontainer &events(copyFrom->getSegmentEvents()); for (EventSelection::eventcontainer::const_iterator i = events.begin(); i != events.end(); ++i) { s->insert(new Event(**i)); } m_segments.insert(s); m_partial = true; return s; }
//ostream & operator<<(ostream & os, pair<int, Segment> paral) //{ // os<<"oYparalEntry: [ k="<<paral.first<<" | "<<paral.second<<" ]"; // return os; //} //ostream & operator<<(ostream & os, const multimap<SegmParams, Segment>::iterator normal) //{ // os<<"oKsegmEntry: [ k="<<normal->first<<" | "<<normal->second<<" ]"; // return os; //} void parseAndInit(const string & message, Segment & s)//we should construct a dflt segment before { //incoming format <"fn"/"mk"/"rm">[234,54223;23443,2342] or "quit" mk[3,4;4,5] size_t found_cm = message.find(','); size_t found_sc = message.find(';'); string x_tmp = message.substr(3, found_cm-3); string y_tmp = message.substr(found_cm+1, found_sc - found_cm-1); int x = stoi(x_tmp); int y = stoi(y_tmp); Point st(x, y); s.start() = st; found_cm = message.find(',', found_sc+1); x_tmp = message.substr(found_sc+1, found_cm - found_sc-1); y_tmp = message.substr(found_cm+1, message.length()-1 - found_sc-1); x = stoi(x_tmp); y = stoi(y_tmp); Point en(x, y); s.end() = en; }
// Find evenly-spaced notes // @param firstBeat A note Event performed on the first beat. // @param secondBeat A note Event performed on the second beat. // @param s The segment to look in for further events. // @return Beat-defining data as a BeatEventVector // @author Tom Breton (Tehom) SelectAddEvenNotesCommand::BeatEventVector SelectAddEvenNotesCommand::findBeatEvents(Segment &s, Event *firstBeat, Event *secondBeat) { // Fixed parameters const float marginTimeRatio = 0.77; const float minTimeRatio = marginTimeRatio; const float maxTimeRatio = 1 / minTimeRatio; // Storage for the results. We add the first two beats // immediately. Caller promises us that they make sense. BeatEventVector result; result.push_back(BeatEvent(firstBeat, 0)); result.push_back(BeatEvent(secondBeat, 0)); // State variables tracking the most recent beat we've found. timeT currentBeatTime = secondBeat->getAbsoluteTime(); timeT prevKnownBeatDuration = currentBeatTime - firstBeat->getAbsoluteTime(); if (prevKnownBeatDuration <= 0) { return result; } // State variables tracking the current noteless stretch. It may // be empty. int numSkippedBeats = 0; timeT prevKnownBeatTime = currentBeatTime; /** * We assume the beat-defining notes are separated by roughly the * same time-interval. We handle noteless stretches where we * expect beats by counting the number of beats we missed. We * drop the noteless stretch after the last true beat we find * because it can't do anything useful. Stretches that contain * just notes that are too far from rhythmic expectations are * treated as noteless stretches. **/ // Find beat-defining notes in the segment while (true) { // The time we would expect a new beat if the rhythm and tempo // were exactly constant. timeT expectedNoteTime = currentBeatTime + prevKnownBeatDuration; // An acceptable interval for the next beat. timeT minNextDuration = float(prevKnownBeatDuration) * minTimeRatio; timeT maxNextDuration = float(prevKnownBeatDuration) * maxTimeRatio; timeT minNextNoteTime = currentBeatTime + minNextDuration; timeT maxNextNoteTime = currentBeatTime + maxNextDuration; Segment::const_iterator startRangeIter = s.findTime(minNextNoteTime); Segment::const_iterator endRangeIter = s.findTime(maxNextNoteTime); // Break if there won't be more notes to find. if (startRangeIter == s.end()) { break; } // Candidate variable. NULL means nothing found. Event *nextBeat = 0; // Scoring variable, how much the best candidate note differs // from expectedNoteTime. Smaller is better. timeT nearestMiss = std::numeric_limits<timeT>::max(); for (Segment::const_iterator i = startRangeIter; i != endRangeIter; ++i) { Event *e = *i; // Only consider notes. if (e->isa(Note::EventType)) { const timeT missedBy = std::abs(e->getAbsoluteTime() - expectedNoteTime); // Track the best candidate. if (missedBy < nearestMiss) { nextBeat = e; nearestMiss = missedBy; } } } if (nextBeat) { const timeT nextBeatTime = nextBeat->getAbsoluteTime(); const timeT stretchDuration = nextBeatTime - prevKnownBeatTime; const int numIncludedBeats = numSkippedBeats + 1; // The absolute time of the beat immediately before // nextBeatTime, possibly calculated by BeatInterpolator timeT prevFoundBeatTime = (numSkippedBeats > 0) ? (prevKnownBeatTime + BeatInterpolator:: getLastBeatRelativeTime(stretchDuration, prevKnownBeatDuration, numIncludedBeats)) : currentBeatTime; // Add this beat result.push_back(BeatEvent(nextBeat, numSkippedBeats, BeatInterpolator(stretchDuration, prevKnownBeatDuration, numIncludedBeats))); // Since we'll continue from a known beat, record that we // haven't skipped any beats. numSkippedBeats = 0; // Set variables for the next iteration of the loop. prevKnownBeatDuration = nextBeatTime - prevFoundBeatTime; currentBeatTime = nextBeatTime; prevKnownBeatTime = nextBeatTime; } else { // If we found no candidates, we began or are already in a // noteless stretch. In either case we count one more // missed beat and step forward in time. ++numSkippedBeats; currentBeatTime = expectedNoteTime; } } return result; }
Segment::Segment(const Segment& source) : _myId(_freeID++), _a(source.start()), _b(source.end()){ #ifdef NDEBUG cout << "Segment " << _myId << ": copy constructor. Source: " << source; #endif }
Segment * SegmentJoinCommand::makeSegment(SegmentVec oldSegments) { // We can proceed even if composition is NULL, just normalize // rests will do less. Composition *composition = oldSegments[0]->getComposition(); // Find the leftmost segment's index and the rightmost segment's // index. timeT t0 = oldSegments[0]->getStartTime(); timeT t1 = oldSegments[0]->getEndMarkerTime(); size_t leftmostIndex = 0; size_t rightmostIndex = 0; for (size_t i = 1; i < oldSegments.size(); ++i) { timeT startTime = oldSegments[i]->getStartTime(); if (startTime < t0) { t0 = startTime; leftmostIndex = i; } timeT endMarkerTime = oldSegments[i]->getEndMarkerTime(); if (endMarkerTime > t1) { t1 = endMarkerTime; rightmostIndex = i; } } // Always begin with the leftmost segment to keep in the new segment // any clef or key change found at the start of this segment. Segment *newSegment = oldSegments[leftmostIndex]->clone(false); // drop any events beyond the end marker newSegment->setEndTime(newSegment->getEndMarkerTime()); // that duplicated the leftmost segment; now do the rest // we normalize rests in any overlapping areas timeT overlapStart = 0, overlapEnd = 0; bool haveOverlap = false; for (size_t i = 0; i < oldSegments.size(); ++i) { // Don't add twice the first old segment if (i == leftmostIndex) continue; Segment *s = oldSegments[i]; timeT start = s->getStartTime(), end = s->getEndMarkerTime(); timeT os = 0, oe = 0; bool haveOverlapHere = false; if (start < newSegment->getEndMarkerTime() && end > newSegment->getStartTime()) { haveOverlapHere = true; os = std::max(start, newSegment->getStartTime()); oe = std::min(end, newSegment->getEndMarkerTime()); RG_DEBUG << "overlap here, os = " << os << ", oe = " << oe; } if (haveOverlapHere) { if (haveOverlap) { overlapStart = std::min(overlapStart, os); overlapEnd = std::max(overlapEnd, oe); } else { overlapStart = os; overlapEnd = oe; haveOverlap = true; } } if (start > newSegment->getEndMarkerTime()) { newSegment->setEndMarkerTime(start); } for (Segment::iterator si = s->begin(); ; ++si) { // If we're in the rightmost segment if (i == rightmostIndex) { // Copy all of the events to the end if (si == s->end()) break; } else { // Just copy up to the End Marker of this segment. if (!s->isBeforeEndMarker(si)) break; } // weed out duplicate clefs and keys if ((*si)->isa(Clef::EventType)) { try { Clef newClef(**si); if (newSegment->getClefAtTime ((*si)->getAbsoluteTime() + 1) == newClef) { continue; } } catch (...) { } } if ((*si)->isa(Key::EventType)) { try { Key newKey(**si); if (newSegment->getKeyAtTime ((*si)->getAbsoluteTime() + 1) == newKey) { continue; } } catch (...) { } } newSegment->insert(new Event(**si)); } if (end > newSegment->getEndMarkerTime()) { newSegment->setEndMarkerTime(end); } } if (haveOverlap) { /// normalizeRests doesn't require Composition, but is less /// than ideal without it; newSegment->setComposition(composition); newSegment->normalizeRests(overlapStart, overlapEnd); newSegment->setComposition(0); } return newSegment; }
SegmentSplitCommand::SegmentVec SegmentSplitCommand:: getNewSegments(Segment *segment, timeT splitTime, bool keepLabel) { Segment * newSegmentA = segment->clone(false); Segment * newSegmentB = new Segment(); newSegmentB->setTrack(segment->getTrack()); newSegmentB->setStartTime(splitTime); // !!! Set Composition? Event *clefEvent = 0; Event *keyEvent = 0; // Copy the last occurrence of clef and key // from the left hand side of the split (nb. timesig events // don't appear in segments, only in composition) // Segment::iterator it = segment->findTime(splitTime); while (it != segment->begin()) { --it; if (!clefEvent && (*it)->isa(Clef::EventType)) { clefEvent = new Event(**it, splitTime); } if (!keyEvent && (*it)->isa(Key::EventType)) { keyEvent = new Event(**it, splitTime); } if (clefEvent && keyEvent) break; } // Insert relevant meta info if we've found some // if (clefEvent) newSegmentB->insert(clefEvent); if (keyEvent) newSegmentB->insert(keyEvent); // Copy through the Events // it = segment->findTime(splitTime); if (it != segment->end() && (*it)->getAbsoluteTime() > splitTime) { newSegmentB->fillWithRests((*it)->getAbsoluteTime()); } while (it != segment->end()) { newSegmentB->insert(new Event(**it)); ++it; } newSegmentB->setEndTime(segment->getEndTime()); newSegmentB->setEndMarkerTime(segment->getEndMarkerTime()); // Set labels // std::string label = segment->getLabel(); newSegmentA->setLabel(label); newSegmentB->setLabel(label); if (!keepLabel) { newSegmentA->setLabel(appendLabel(label, qstrtostr(tr("(split)")))); newSegmentB->setLabel(appendLabel(label, qstrtostr(tr("(split)")))); } newSegmentB->setColourIndex(segment->getColourIndex()); newSegmentB->setTranspose(segment->getTranspose()); newSegmentB->setDelay(segment->getDelay()); // Resize left hand Segment // std::vector<Event *> toErase, toInsert; for (Segment::iterator i = newSegmentA->findTime(splitTime); i != newSegmentA->end(); ++i) { if ((*i)->getAbsoluteTime() >= splitTime) break; if ((*i)->getAbsoluteTime() + (*i)->getDuration() > splitTime) { Event *e = new Event(**i, (*i)->getAbsoluteTime(), splitTime - (*i)->getAbsoluteTime()); toErase.push_back(*i); toInsert.push_back(e); } } for (size_t i = 0; i < toErase.size(); ++i) { newSegmentA->eraseSingle(toErase[i]); delete toErase[i]; } for (size_t i = 0; i < toInsert.size(); ++i) { newSegmentA->insert(toInsert[i]); } newSegmentA->setEndTime(splitTime); newSegmentA->setEndMarkerTime(splitTime); SegmentVec segmentVec; segmentVec.reserve(2); segmentVec.push_back(newSegmentA); segmentVec.push_back(newSegmentB); return segmentVec; }
bool Rectangle::overlaps(Segment const& segment) const noexcept { return (contains(segment.start()) || contains(segment.end()) || intersects(segment)); }
bool is_on_line ( const Point & a, const Segment & obj ) { return ( obj.length() == Segment(a, obj.start()).length() + Segment(a, obj.end()).length() ); }
bool belongs_to ( const Point & pt, const Segment & seg ) { return seg.length() == fabs ( Segment( pt, seg.start() ).length() - Segment( pt, seg.end() ).length() ); }
void MatrixMover::handleLeftButtonPress(const MatrixMouseEvent *e) { MATRIX_DEBUG << "MatrixMover::handleLeftButtonPress() : snapped time = " << e->snappedLeftTime << ", el = " << e->element << endl; if (!e->element) return; // Check the scene's current segment (apparently not necessarily the same // segment referred to by the scene's current view segment) for this event; // return if not found, indicating that this event is from some other, // non-active segment. // // I think notation just makes whatever segment active when you click an // event outside the active segment, and I think that's what this code // attempted to do too. I couldn't get that to work at all. This is better // than being able to click on non-active elements to create new events by // accident, and will probably fly. Especially since the multi-segment // matrix is new, and we're defining the terms of how it works. Segment *segment = m_scene->getCurrentSegment(); if (!segment) return; bool found = false; for (Segment::iterator i = segment->begin(); i != segment->end(); ++i) { if ((*i) == e->element->event()) found = true; } if (!found) { MATRIX_DEBUG << "Clicked element not owned by active segment. Returning..." << endl; return; } m_currentViewSegment = e->viewSegment; m_currentElement = e->element; m_clickSnappedLeftTime = e->snappedLeftTime; m_quickCopy = (e->modifiers & Qt::ControlModifier); if (!m_duplicateElements.empty()) { for (size_t i = 0; i < m_duplicateElements.size(); ++i) { delete m_duplicateElements[i]->event(); delete m_duplicateElements[i]; } m_duplicateElements.clear(); } // Add this element and allow movement // EventSelection* selection = m_scene->getSelection(); Event *event = m_currentElement->event(); if (selection) { EventSelection *newSelection; if ((e->modifiers & Qt::ShiftModifier) || selection->contains(event)) { newSelection = new EventSelection(*selection); } else { newSelection = new EventSelection(m_currentViewSegment->getSegment()); } // if the selection already contains the event, remove it from the // selection if shift is pressed if (selection->contains(event)) { if (e->modifiers & Qt::ShiftModifier) { newSelection->removeEvent(event); } } else { newSelection->addEvent(event); } m_scene->setSelection(newSelection, true); selection = newSelection; } else { m_scene->setSingleSelectedEvent(m_currentViewSegment, m_currentElement, true); } long velocity = m_widget->getCurrentVelocity(); event->get<Int>(BaseProperties::VELOCITY, velocity); long pitchOffset = m_currentViewSegment->getSegment().getTranspose(); long pitch = 60; event->get<Int>(BaseProperties::PITCH, pitch); // We used to m_scene->playNote() here, but the new concert pitch matrix was // playing chords the first time I clicked a note. Investigation with // KMidiMon revealed two notes firing nearly simultaneously, and with // segments of 0 transpose, they were simply identical to each other. One // of them came from here, and this was the one sounding at the wrong pitch // in transposed segments. I've simply removed it with no apparent ill side // effects, and a problem solved super cheap. m_lastPlayedPitch = pitch; if (m_quickCopy && selection) { for (EventSelection::eventcontainer::iterator i = selection->getSegmentEvents().begin(); i != selection->getSegmentEvents().end(); ++i) { MatrixElement *duplicate = new MatrixElement (m_scene, new Event(**i), m_widget->isDrumMode(), pitchOffset); m_duplicateElements.push_back(duplicate); } } }
Segment::Segment ( const Segment & seg ) : _a ( seg.start() ), _b ( seg.end() ) { }
void Clipboard::newSegment(const Segment *copyFrom, timeT from, timeT to, bool expandRepeats) { // create with copy ctor so as to inherit track, instrument etc Segment *s = copyFrom->clone(false); // If the segment is within the time range if (from <= s->getStartTime() && to >= s->getEndMarkerTime()) { // Insert the whole thing. m_segments.insert(s); // don't change m_partial as we are inserting a complete segment return; } // Only a portion of the source segment will be used. const timeT segStart = copyFrom->getStartTime(); const timeT segEndMarker = copyFrom->getEndMarkerTime(); timeT segDuration = segEndMarker - segStart; // We can't copy starting prior to the start of the segment. if (from < segStart) from = segStart; int firstRepeat = 0; int lastRepeat = 0; if (!copyFrom->isRepeating() || segDuration <= 0) { expandRepeats = false; } if (expandRepeats) { firstRepeat = (from - segStart) / segDuration; to = std::min(to, copyFrom->getRepeatEndTime()); lastRepeat = (to - segStart) / segDuration; } s->setRepeating(false); if (s->getType() == Segment::Audio) { Composition *c = copyFrom->getComposition(); for (int repeat = firstRepeat; repeat <= lastRepeat; ++repeat) { timeT wrappedFrom = segStart; timeT wrappedTo = segEndMarker; if (!expandRepeats) { wrappedFrom = from; wrappedTo = to; } else { if (repeat == firstRepeat) { wrappedFrom = segStart + (from - segStart) % segDuration; } if (repeat == lastRepeat) { wrappedTo = segStart + (to - segStart) % segDuration; } } if (wrappedFrom > segStart) { if (c) { s->setAudioStartTime (s->getAudioStartTime() + c->getRealTimeDifference(segStart + repeat * segDuration, from)); } s->setStartTime(from); } else { s->setStartTime(segStart + repeat * segDuration); } if (wrappedTo < segEndMarker) { s->setEndMarkerTime(to); if (c) { s->setAudioEndTime (s->getAudioStartTime() + c->getRealTimeDifference(segStart + repeat * segDuration, to)); } } else { s->setEndMarkerTime(segStart + (repeat + 1) * segDuration); } m_segments.insert(s); if (repeat < lastRepeat) { s = copyFrom->clone(false); s->setRepeating(false); } } m_partial = true; return; } // We have a normal (MIDI) segment. s->erase(s->begin(), s->end()); for (int repeat = firstRepeat; repeat <= lastRepeat; ++repeat) { Segment::const_iterator ifrom = copyFrom->begin(); Segment::const_iterator ito = copyFrom->end(); if (!expandRepeats) { ifrom = copyFrom->findTime(from); ito = copyFrom->findTime(to); } else { if (repeat == firstRepeat) { ifrom = copyFrom->findTime (segStart + (from - segStart) % segDuration); } if (repeat == lastRepeat) { ito = copyFrom->findTime (segStart + (to - segStart) % segDuration); } } // For each event in the time range and before the end marker. for (Segment::const_iterator i = ifrom; i != ito && copyFrom->isBeforeEndMarker(i); ++i) { Event *e = (*i)->copyMoving(repeat * segDuration); s->insert(e); } } if (expandRepeats) s->setEndMarkerTime(to); // Make sure the end of the segment doesn't go past the end of the range. // Need to use the end marker time from the original segment, not s, // because its value may depend on the composition it's in. if (segEndMarker > to) s->setEndMarkerTime(to); // Fix the beginning. timeT firstEventTime = s->getStartTime(); // if the beginning was chopped off and the first event isn't at the start if (from > segStart && firstEventTime > from) { // Expand the beginning to the left so that it starts at the expected // time (from). s->fillWithRests(from, firstEventTime); } // Fix zero-length segments. // if s is zero length if (s->getStartTime() == s->getEndMarkerTime()) { // Figure out what start and end time would look right. timeT finalStartTime = ((segStart > from) ? segStart : from); timeT finalEndTime = ((segEndMarker < to) ? segEndMarker : to); // Fill it up so it appears. s->fillWithRests(finalStartTime, finalEndTime); } m_segments.insert(s); m_partial = true; }
const bool checkIfParallel(const Segment & s) { return s.start().x() == s.end().x(); }
Segment(const Segment & s): m_start(s.start()), m_end(s.end()) { }
Segment::Segment(const Segment& segment) : _start(segment.start()), _end(segment.end()), _myID(++_freeID) { #ifndef NDEBUG #endif return; };
double magic_area ( const Segment & seg, const Point & pt ) { return magic_area (seg.start(), seg.end(), pt); }
/// 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); } }
void AddLayerCommand::execute() { if (!m_segment) return; Segment *layer = new Segment(); layer->setTrack(m_segment->getTrack()); layer->setStartTime(m_segment->getStartTime()); m_composition.addSegment(layer); layer->setEndTime(m_segment->getEndTime()); std::string label = m_segment->getLabel(); label += tr(" - layer").toStdString(); layer->setLabel(label); layer->setHighestPlayable(m_segment->getHighestPlayable()); layer->setLowestPlayable(m_segment->getLowestPlayable()); layer->setTranspose(m_segment->getTranspose()); // fill the segment with rests, so we can make them invisible layer->fillWithRests(m_segment->getStartTime(), m_segment->getEndTime()); for (Segment::iterator i = m_segment->begin(); i != m_segment->end(); ++i) { // copy over any clefs or key signatures, as these are needed to // maintain compatibility between segments if ((*i)->isa(Clef::EventType) || (*i)->isa(Key::EventType)) { layer->insert(new Event(**i)); } } // set everything in the layer segment invisible for (Segment::iterator i = layer->begin(); i != layer->end(); ++i) { (*i)->set<Bool>(BaseProperties::INVISIBLE, true); // raise the heights of alternate voice rests to get them out of the // middle of the staff, where they may be easier to deal with if ((*i)->isa(Note::EventRestType)) (*i)->setMaybe<Int>(BaseProperties::DISPLACED_Y, -1000); } // get the total number of colors in the map int maxColors = m_composition.getSegmentColourMap().size(); // get the color index for the segment used as the template for the new // empty one we're creating int index = m_segment->getColourIndex(); // with the default color map (the only one I care about anymore) a // difference of +5 guarantees enough contrast to make the segment changer // widget, raw note ruler, and track headers show enough contrast to be // useful as an indication that this segment is not the same as the one it // is patterned after index += 5; // if we went past the end of the color map, just roll back to 0, because // this will happen so infrequently in use it's not worth a lot of fancy // handling, and anyway 0 will be a contrast from what's sitting on the end // of the standard color map, so it will still be functional if (index > maxColors) index = 0; layer->setColourIndex(index); // now what other gotchas are there? // now m_segment goes from being the input template to what we'll return if // asked m_segment = layer; m_detached = false; }