void ARMusicalObject::print() const { TYPE_DURATION dur = getDuration(); TYPE_TIMEPOSITION tpos = getRelativeTimePosition(); std::cout << "ARMusicalObject: duration: " << dur.getNumerator() << '/' << dur.getDenominator() << " time pos: " << tpos.getNumerator() << '/' << tpos.getDenominator() << '\n'; }
// ---------------------------------------------------------------------------- TYPE_DURATION GRTempo::getDuration (const char * str) const { int num, denom; TYPE_DURATION duration; if( sscanf( str,"%d/%d", &num, &denom ) == 2 ) { duration.set ( num, denom ); duration.normalize(); } return duration; }
void ARMusicalEvent::setDenominator(int newDenominator) { if (!(newDenominator>=MUSICAL_MIN_DENOMINATOR)) { GuidoWarn("Denominator is too small" ); newDenominator= MUSICAL_MIN_DENOMINATOR; } TYPE_DURATION d (getDuration()); d.setDenominator(newDenominator); setDuration(d); }
ARMusicalEvent::ARMusicalEvent(const TYPE_TIMEPOSITION & relativeTimePositionOfEvent, const TYPE_DURATION & durationOfEvent) : ARMusicalObject(relativeTimePositionOfEvent) { mPoints = 0; assert(durationOfEvent.getNumerator() >= MUSICAL_MIN_NUMERATOR); const int tmp = durationOfEvent.getDenominator(); if (tmp < MUSICAL_MIN_DENOMINATOR) assert(durationOfEvent.getDenominator() >= MUSICAL_MIN_DENOMINATOR); // so now what .... take it out there setDuration ( durationOfEvent ); }
//____________________________________________________________________________________ void GRSingleNote::GetMap( GuidoeElementSelector sel, MapCollector& f, MapInfos& infos ) const { if (sel == kGuidoEvent) { TYPE_DURATION dur = getDuration(); if (dur.getNumerator() == 0) { // notes in chords have a null duration dur = getDurTemplate(); } // const ARNote * ar = getARNote(); // std::cout << "mapped pos: " << ar->getStartTimePosition() << " ar pos: " << ar->getRelativeTimePosition() << " "; // ar->print(); // ARNote and GRNote don't have the same time position in chords // actually chord notes have a wrong time position, it has been corrected in ARMusicalVoice::FinishChord SendMap (f, getARNote()->getStartTimePosition(), dur, kNote, infos); } }
void ARMusicalEvent::setNumerator(int newNumerator) { if (newNumerator<MUSICAL_MIN_NUMERATOR) { newNumerator = MUSICAL_MIN_NUMERATOR; } else if (newNumerator>MUSICAL_MAX_NUMERATOR) { newNumerator = MUSICAL_MAX_NUMERATOR; } // assert(newNumerator>=MUSICAL_MIN_NUMERATOR); // assert(newNumerator<=MUSICAL_MAX_NUMERATOR); TYPE_DURATION d (getDuration()); d.setNumerator(newNumerator); setDuration(d); // ACHTUNG modified by kf for WCHT ... // assert(duration>MIN_DURATION); //## end ARMusicalEvent::setNumerator%858535960.body }
float GRSpring::calcconst(GRNotationElement * grn) { GRGlue * glue; GRTag * tmp; if (grn && (glue = dynamic_cast<GRGlue *>(grn)) != NULL) sconst = glue->getSConst(); else if (grn && (tmp = dynamic_cast<GRTag *>(grn)) != NULL) sconst = tmp->getSConst(); else if (dur == DURATION_0) { if (dynamic_cast<GREmpty *>(grn)) sconst = (isProportionalElement ? 1 : 200.0f); else sconst = (isProportionalElement ? 1 : 20.0f); } else if (grn && (dynamic_cast<GRRest *>(grn))) { // rests are treated as if they were // 8 times shorter -> this results // in a nicer spacing when rests occur ... // this must be adjusted for optimal output! TYPE_DURATION mydur; if ((float) dur>0.125) mydur.set( dur.getNumerator(), dur.getDenominator() * 2); else mydur = dur; sconst = (isProportionalElement ? 1 : defconst(mydur, funcpar)); } else sconst = (isProportionalElement ? 1 : defconst(dur, funcpar)); assert(sconst != 0); return sconst; }
// ---------------------------------------------------------------------------- GRTempo::GRTempo( GRStaff * staff, ARTempo * inAR ) : GRTagARNotationElement( inAR, LSPACE ) { assert(inAR); // Sets the Type -> This tag is a SystemTag. setTagType(GRTag::SYSTEMTAG); mPosition.y -= 2 * LSPACE; // Tempo is usually placed two linespaces above the staff. VGDevice * hdc = gGlobalSettings.gDevice; mBoundingBox.Set (0, -2*LSPACE, 0, 0); if (!mFont) { const NVstring fontname("Times New Roman"); NVstring attrs (""); mFont = FontManager::FindOrCreateFont( 90, &fontname, &attrs); } if (inAR) { FormatStringParserResult::const_iterator assoc; for (assoc = inAR->getTempoMark().begin(); assoc != inAR->getTempoMark().end(); assoc++) { if (assoc->second == FormatStringParser::kSpecial) { TYPE_DURATION duration = getDuration(assoc->first.c_str()); mBoundingBox.right += GetSymbolExtent( kFullHeadSymbol ); if (duration.getNumerator() == 3) { mBoundingBox.right += LSPACE; } } else if( hdc ) { float w, h; const char * str = assoc->first.c_str(); mFont->GetExtent( str, int(assoc->first.size()), &w, &h, hdc ); mBoundingBox.right += w; } } } }
/** \brief Determines wether the given fraction has a power of two in the denominator. the power is tested up to the maxpower ... The routine uses the fact, that the number is power of two, if there is exaclty ONE bit set. 2^0 = 0x0000001 2^1 = 0x0000010 2^2 = 0x0000100 */ bool ARMusicalObject::IsPowerOfTwoDenom(const TYPE_DURATION & dur /*, int maxpower*/) { /* was: int val = dur.getDenominator(); for (int i = 0; i <= maxpower; ++i) { if ( ((1 << i ) & val) == val) return true; } return false; */ // new: const int x = dur.getDenominator(); // if( x == 0 ) return false; // because the denominator can't be 0 return ((x & -x) == x); }
/** Draws the note corresponding to a given symbolic musical duration. */ float GRTempo::DrawNote( VGDevice & hdc, const TYPE_DURATION & noteDur, float xOffset, float yOffset ) const { float offsetX = 0; // - Choose notehead unsigned int theSymbol = kNoneSymbol; if (noteDur>=DURATION_1) { theSymbol = kWholeNoteHeadSymbol; } else if (noteDur == DURATION_2 || noteDur == DURATION_3_4 || noteDur == DURATION_7_8) { theSymbol = kHalfNoteHeadSymbol; } else { theSymbol = kFullHeadSymbol; } // - Choose flag unsigned int theFlagSymbol = kNoneSymbol; if (noteDur==DURATION_8 || noteDur == DURATION_3_16 || noteDur == DURATION_7_32) { theFlagSymbol = GRFlag::H8U; } else if(noteDur==DURATION_16 || noteDur == DURATION_3_32 || noteDur == DURATION_7_64) { theFlagSymbol = GRFlag::H16U; } else if(noteDur == DURATION_32) { theFlagSymbol = GRFlag::H32U; } else if (noteDur == DURATION_64) { theFlagSymbol = GRFlag::H64U; } // - Choose dot unsigned int theDotSymbol = kNoneSymbol; // if (noteDur == DURATION_3_4 || noteDur == DURATION_3_8 || noteDur == DURATION_3_16 || noteDur == DURATION_3_32) { if (noteDur.getNumerator() == 3) { theDotSymbol = kNoteDotSymbol; } // - Setup zoom hdc.selectfont(1); // Not very beautiful but avoid a bug during SVG export const float cueScale = 0.70f; hdc.SetScale(cueScale, cueScale); // - Calculate the position of the head float w, h; hdc.GetMusicFont()->GetExtent(theSymbol, &w, &h, &hdc); float xPos = (xOffset + mPosition.x) / cueScale; float yPos = (yOffset + mPosition.y - w / 2.5f) / cueScale; // - Draw Head hdc.DrawMusicSymbol(xPos, yPos, theSymbol); offsetX = w * cueScale; // - Draw Stem if (theSymbol != kWholeNoteHeadSymbol) { float stemLen = 3 * LSPACE; float stemTagSize = 1; const float stemCharSize = LSPACE * stemTagSize; const float halfStemCharSize = 0.5f * stemCharSize; hdc.DrawMusicSymbol( xPos, yPos, kStemUp1Symbol ); // - Draws until the length has been completed ... float offsy = -halfStemCharSize; while( -offsy < stemLen ) // * mSize) { if(( stemCharSize - offsy ) > stemLen ) // * mSize) { offsy = (-(stemLen) // * mSize) + stemCharSize ); hdc.DrawMusicSymbol( xPos, yPos + offsy, kStemUp2Symbol ); break; } hdc.DrawMusicSymbol( xPos, yPos + offsy, kStemUp2Symbol ); offsy -= halfStemCharSize; } } // - Draw flag if (theFlagSymbol != kNoneSymbol) hdc.DrawMusicSymbol( xPos, yPos - 4 * LSPACE, theFlagSymbol ); // - Draw Dot if (theDotSymbol != kNoneSymbol) { hdc.GetMusicFont()->GetExtent(theDotSymbol, &w, &h, &hdc); hdc.DrawMusicSymbol( xPos + 2 * LSPACE, yPos, theDotSymbol); offsetX += LSPACE; } // - Cleanup hdc.SetScale(1 / cueScale, 1 / cueScale); return offsetX; }
// (JB) \bug There is probably a bug somewhere: with map mode // different than "ISOTROPIC" (proportionnal), beamings polygons between "UP" stems // draw at an incorrect x position, while "DOWN" beams are always ok. // // Too long, needs some code-factorization, if possible. void GRBeam::tellPosition( GObject * gobj, const NVPoint & p_pos) { /* Beams are polygons made of four points: 0 2 ------------------ | | ------------------ 1 3 */ // a new test is performed: if it is a systemTag and // it is not a systemcall (checkpos), than we can just do nothing. if (error || !mAssociated || ( mAssociated->GetCount() == 0 ) || ( tagtype == GRTag::SYSTEMTAG && !mIsSystemCall )) return; GRNotationElement * el = dynamic_cast<GRNotationElement *>(gobj); if (!el || !el->getGRStaff()) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(el->getGRStaff()->getGRSystem()); assert(sse); if (el != sse->endElement) return; GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; GuidoPos pos; GREvent * startEl = GREvent::cast(sse->startElement); GREvent * endEl = GREvent::cast(sse->endElement); // this is the staff to which the beam belongs and who draws it. const GRStaff * beamstaff = sse->startElement->getGRStaff(); PosInfos infos = { dirUP, LSPACE, 1.0f, (endEl == startEl)}; ARBeam * arBeam = getARBeam(); const bool isSpecBeam = arBeam->isGuidoSpecBeam(); if(startEl) infos.stemdir = startEl->getStemDirection(); else if(endEl) infos.stemdir = endEl->getStemDirection(); if(level != 0) return; NVPoint offset = initp0 (sse, startEl, infos); initp1 (sse, infos); offset = initp2 (sse, endEl, infos); initp3 (sse, infos); // ----------------------------------------------------------- // Now, we adjust the stemlengths, according to beamslope ... // we have the start and end-position in st->p // We have to determine the slope and adjust the slope to minimum and maximum ... // ----------------------------------------------------------- float stemWidth = st->p[2].x - st->p[0].x; float slope = (st->p[2].y - st->p[0].y) / stemWidth; // another hack to control the slope when events are on different staves - DF sept 15 2009 if (startEl && endEl && (startEl->getGRStaff() != endEl->getGRStaff())) { while ((slope < -0.20) || (slope > 0.20)) { float shift = (slope < 0) ? -LSPACE/4 : LSPACE/4; st->p[0].y += shift; st->p[1].y += shift; st->p[2].y -= shift; st->p[3].y -= shift; slope = (st->p[2].y - st->p[0].y) / stemWidth; } } bool needsadjust = true; // we have to adjust the slope ONLY if the stemlength // of the first and last element has not been set automatically! // and if we are note in the case of a chained feather beam if ( (startEl && startEl->getStemLengthSet() && endEl && endEl->getStemLengthSet()) || tagtype == SYSTEMTAG || (arBeam && isSpecBeam) || (isFeathered && startEl && startEl->stemHasBeenChanged())) { needsadjust = false; } else slopeAdjust (sse, startEl, endEl, slope, infos); if (arBeam && isSpecBeam) { // then we have to set the length ... if it is not set otherwise ... GRSingleNote * nt = dynamic_cast<GRSingleNote *>(sse->startElement); if(nt && !nt->getStemLengthSet()) { const float myval = arBeam->dy1->getValue(); nt->setStemLength( myval); } nt = dynamic_cast<GRSingleNote *>(sse->endElement); if(nt && !nt->getStemLengthSet()) { float myval; if (arBeam->dy3 && arBeam->dy3->TagIsSet()) myval = arBeam->dy3->getValue(); else myval = arBeam->dy1->getValue(); nt->setStemLength( myval); } } float offsetbeam = 0; // nobeamoffset describes, if no beamoffset is valid: if notes ask for different beam-offsets // then, there is just no offset .... things must be changed manually then .... bool nobeamoffset = false; if(( startEl && startEl->getStemLengthSet()) || ( endEl && endEl->getStemLengthSet())) nobeamoffset = true; for (int counter = 0; counter < 2; ++counter ) { if (counter == 1) { if ((offsetbeam == 0) || nobeamoffset) break; else if (!nobeamoffset) { st->p[0].y -= offsetbeam; st->p[1].y -= offsetbeam; st->p[2].y -= offsetbeam; st->p[3].y -= offsetbeam; offsetbeam = 0; } } pos = sse->startpos; while (pos) { // now we calculate the stem-end-positions ... GuidoPos oldpos = pos; GREvent * sn = GREvent::cast(mAssociated->GetNext(pos)); if (sn) { float rx = sn->getStemStartPos().x - st->p[0].x; if (tagtype == SYSTEMTAG) rx += sn->getGRStaff()->getPosition().x; float disty = st->p[2].y - st->p[0].y; float distx = st->p[2].x - st->p[0].x; float ly = disty / distx * rx; ly += st->p[0].y; float diffy = (float)sn->getStemStartPos().y; GDirection adjustdir=dirAUTO; if (sn->getStemDirection() == dirUP) { diffy += (float)sn->getStemLength(); adjustdir = dirUP; } else if (sn->getStemDirection() == dirDOWN) { adjustdir = dirDOWN; diffy -= (float)sn->getStemLength(); } ly -= diffy; if (tagtype == SYSTEMTAG) ly -= (float)sn->getGRStaff()->getPosition().y; // if we have a beam between grace notes, we don't want an offbase that whould make the stems too long GRNote * gnote = dynamic_cast<GRNote*>(startEl); bool isGrace = gnote ? gnote->isGraceNote() : false; float offbase = isGrace ? 0 : 3.5f * infos.currentLSPACE; if (ly < 0) { if (needsadjust) { if (adjustdir == dirDOWN) { const float newoffs = ly - offbase; if (newoffs < offsetbeam) { if (offsetbeam > 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } ly = -offbase; } else if (ly > -offbase) { const float newoffs = ly + offbase; if (newoffs > offsetbeam) { if (offsetbeam < 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } } } ly = -ly; } else if (needsadjust) { if (adjustdir == dirUP) { const float newoffs = ly + offbase; if (newoffs > offsetbeam) { if (offsetbeam < 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } ly = offbase; } else if (ly < offbase) { const float newoffs = ly - offbase; if (newoffs < offsetbeam) { if (offsetbeam > 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } } } // sn->changeStemLength( ly ); // adjusted - DF sept 15 2009 sn->changeStemLength( ly - infos.currentLSPACE/20 ); // so that the possible next featherd beam knows that he is chained // (and musn't change its slope) sn->setStemChanged(); } if (oldpos == sse->endpos) break; } //endEl->setStemChanged(); } if(!smallerBeams.empty()) { for(std::vector<GRBeam *>::iterator it = smallerBeams.begin(); it < smallerBeams.end(); it++) { (*it)->decLevel(); (*it)->tellPosition((*it)->getEndElement(), (*it)->getEndElement()->getPosition()); } return; } // -- Now we need to add the simplebeams as simplebeamgroups ... NVPoint myp[4]; int dir = st->direction; if (st->dirset) { // then the direction was set explicitly by the user ... GREvent * sn = GREvent::cast(mAssociated->GetHead()); if (sn) dir = sn->getStemDirection(); } else dir = infos.stemdir; bool first = true; pos = sse->startpos; // - These constants define the space and the thickness of additionnal beams. const float yFact1 = 0.75f * infos.currentLSPACE; // was 0.7f const float yFact2 = 0.4f * infos.currentLSPACE; // if we have a feathered beam, we just have to draw the main beam (already done) // and the other simple beams will only depend on the begining and ending // points, regardless of the durations of the inner notes. if(isFeathered) { ARFeatheredBeam * ar = static_cast<ARFeatheredBeam *>(getARBeam()->isARFeatheredBeam()); int begin = 0; int end = 0; GREvent * stemNoteBegin = GREvent::cast(mAssociated->GetHead()); GDirection localDir = stemNoteBegin->getStemDirection(); float yLocalFact1 = yFact1 * localDir * infos.currentSize; float yLocalFact2 = yFact2 * localDir * infos.currentSize; // if the user hasn't set the durations as parameters, // we will take the first and last notes'durations if(!ar->isDurationsSet()) { ar->findDefaultPoints(); } end = ar->getLastBeaming(); begin = ar->getFirstBeaming(); for(int i=1;i<=begin; i++) { myp[0] = st->p[0]; myp[0].y += (i-1) * yLocalFact1; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; myp[2] = st->p[2]; if(end>i ||(end==i && i!=1)) // no need to draw the main beam again. myp[2].y += (i-1) * yLocalFact1; else myp[2].y += (end-1) * yLocalFact1; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); } // if end > begin for(int i=begin; i<end; i++) { myp[0] = st->p[0]; myp[0].y += (begin-1) * yLocalFact1; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; myp[2] = st->p[2]; myp[2].y += i * yLocalFact1; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); } // in order to draw the total duration of the beam if(drawDur) { TYPE_TIMEPOSITION begin = ar->getBeginTimePosition(); TYPE_TIMEPOSITION end = ar->getEndTimePosition(); TYPE_DURATION dur = end - begin; int num = dur.getNumerator(); int den = dur.getDenominator(); stringstream out; out << num << '/' << den; st->duration = out.str(); size_t n = st->duration.length(); GREvent * ev = dynamic_cast<GREvent *>(mAssociated->GetHead()); const NVPoint p1 = ev->getStemEndPos(); float xBegin = ev->getPosition().x; ev = dynamic_cast<GREvent *>(mAssociated->GetTail()); const NVPoint p2 = ev->getStemEndPos(); float xEnd = ev->getPosition().x + ev->getBoundingBox().Width()/2; int dir = ev->getStemDirection(); float Y1; float Y2; if(dir>0) { Y1 = min(p1.y, p2.y) - LSPACE; if(Y1>=getLastPositionOfBarDuration().first && Y1<getLastPositionOfBarDuration().second+LSPACE/2) Y1 -= LSPACE; Y2 = Y1 - LSPACE/2; getLastPositionOfBarDuration().first = Y2; getLastPositionOfBarDuration().second = Y1; } else { Y1 = max(p1.y, p2.y) + LSPACE; if(Y1>=getLastPositionOfBarDuration().first-LSPACE/2 && Y1<getLastPositionOfBarDuration().second) Y1 += LSPACE; Y2 = Y1 + LSPACE/2; getLastPositionOfBarDuration().first = Y1; getLastPositionOfBarDuration().second = Y2; } if (xBegin > xEnd) { if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) xEnd = sse->endElement->getPosition().x; if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) xBegin = sse->startElement->getPosition().x; } float x = xBegin + (xEnd - xBegin) / 2; float X1 = x - (n - 0.5f) / 2 * LSPACE; float X2 = x + (n - 0.5f) / 2 * LSPACE; st->DurationLine[0] = NVPoint(xBegin, Y1); st->DurationLine[1] = NVPoint(xBegin, Y2); st->DurationLine[2] = NVPoint(X1, Y2); st->DurationLine[3] = NVPoint(X2, Y2); st->DurationLine[4] = NVPoint(xEnd, Y2); st->DurationLine[5] = NVPoint(xEnd, Y1); } } // for beam length adjustment - DF sept 15 2009 const float xadjust = infos.currentLSPACE/10; GDirection lastLocalDir = dirOFF; int previousBeamsCount = 0; while (pos && !isFeathered) { GuidoPos oldpos = pos; GREvent * stemNote = GREvent::cast(mAssociated->GetNext(pos)); if (stemNote) { GDirection localDir = stemNote->getStemDirection(); float yLocalFact1 = yFact1 * localDir * infos.currentSize; float yLocalFact2 = yFact2 * localDir * infos.currentSize; // now we check the number of beams ... if (stemNote->getBeamCount() < stemNote->getNumFaehnchen()) { float beamCount = (float)(stemNote->getBeamCount()); stemNote->incBeamCount(); if (first && (sse->startflag == GRSystemStartEndStruct::OPENLEFT)) { // the additional beam starts at the startElement (glue), we have more beams to draw myp[0] = sse->startElement->getPosition(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[1] = myp[0]; // first = false; // never read (according to clang :-) } else { // the additional beam starts at sn. We have more beams to draw myp[0] = stemNote->getStemStartPos(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[0].y += beamCount * yLocalFact1; if (localDir != dir) myp[0].y -= yLocalFact2; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; } // now we look for the endposition GREvent * sn2 = NULL; GuidoPos tmppos = pos; // partialbeam is set, if the new SimpleBeam only covers part of the masterBeam. int partialbeam = 0; while (tmppos) { GuidoPos oldpos2 = tmppos; GREvent * tmpsn = GREvent::cast(mAssociated->GetNext(tmppos)); if (tmpsn) { if (tmpsn->getBeamCount() < tmpsn->getNumFaehnchen()) { sn2 = tmpsn; sn2->incBeamCount(); continue; } else { partialbeam = 1; break; } } if (oldpos2 == sse->endpos) break; } if (sn2) { if (!partialbeam && sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { // then the position is different ... myp[2] = sse->endElement->getPosition(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y = myp[0].y; } else { // we have an End-Position ... myp[2] = sn2->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y += beamCount * yLocalFact1; } if (localDir != dir) myp[2].y -= yLocalFact2; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; } else { // we do not have an End-Positon single beam ... (meaning a single straight flag) // but only, if it is not open on the left or the right hand side. const float slope = (float)(st->p[2].y - st->p[0].y ) / (float)(st->p[2].x - st->p[0].x); if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) { // then we have to deal with the startposition of the glue-element .... // BUT, you can only set this, if the previous beam had this beamcount at the end .... // how do I know that? not now. // sn is the only element .... and we are open on the left ... if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[1] = myp[0]; myp[2] = stemNote->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += stemNote->getGRStaff()->getPosition(); myp[2].y += beamCount * yLocalFact1; if (localDir != dir) myp[2].y -= yLocalFact2; myp[3] = myp[2]; myp[3].y += yLocalFact2; } else if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { myp[0] = stemNote->getStemEndPos(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[0].y += beamCount * yLocalFact1; if (localDir != dir) myp[0].y -= yLocalFact2; myp[1] = myp[0]; myp[1].y += yLocalFact2; myp[2] = sse->endElement->getPosition(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y = myp[0].y; myp[3].x = myp[2].x; myp[3].y = myp[1].y; } /* 26/11/03 Beaming bug: wrong direction for partial beam (beam-bug.gmn) can be tested but changing this test. startpos check added to correct problem with partial beam going outside a group like in [ _/16 c d/8 ] */ else if( oldpos == sse->endpos || pos == NULL || ((!stemNote->isSyncopated()) && (oldpos != sse->startpos))) { // Partial beams leftward ( using slope) myp[2] = stemNote->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += stemNote->getGRStaff()->getPosition(); if (localDir != dir) myp[2].y -= yLocalFact2; myp[2].y += beamCount * yLocalFact1; myp[3] = myp[2]; myp[3].y += yLocalFact2; myp[0] = myp[2]; myp[0].x -= infos.currentLSPACE; myp[0].y -= slope * infos.currentLSPACE; myp[1] = myp[0]; myp[1].y += yLocalFact2; // ? We are at the end, there is no valid event at the end ... so what do we do? // useless tests: the code was the same and is now outside the test (above) - DF sept 15 2009 /* if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { } else { } */ } else { // Partial beams rightward ( using slope) myp[2] = myp[0]; myp[2].x += infos.currentLSPACE; myp[2].y += slope * infos.currentLSPACE; myp[3] = myp[2]; myp[3].y += yLocalFact2; } } // now we construct a SimpleBeam, we now have to "undo" the systemTag-stuff if (tagtype == SYSTEMTAG) { const NVPoint & offset = beamstaff->getPosition(); myp[0] -= offset; myp[1] -= offset; myp[2] -= offset; myp[3] -= offset; } if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) { myp[0].y = myp[2].y; myp[1].y = myp[3].y; } GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); pos = sse->startpos; oldpos = pos; first = true; lastLocalDir = localDir; previousBeamsCount = stemNote->getBeamCount() - 1; } // a new hack, again to catch stems directions change - DF sept 15 2009 else if (localDir != dir) { // check for stems length NVPoint stemloc = stemNote->getStemStartPos(); if (tagtype == SYSTEMTAG) stemloc += stemNote->getGRStaff()->getPosition(); int beamscount = stemNote->getBeamCount() - 1; if ((beamscount > 0) && (previousBeamsCount > beamscount) && (lastLocalDir != localDir)) { if (localDir == dirUP) stemNote->changeStemLength(stemNote->getStemLength() + (yLocalFact1 * beamscount)); else if (localDir == dirDOWN) stemNote->changeStemLength(stemNote->getStemLength() - (yLocalFact1 * beamscount)); } } } if (oldpos == sse->endpos) break; } GuidoPos stemPos = sse->startpos; while(stemPos) { GREvent * stemNote = GREvent::cast(mAssociated->GetNext(stemPos)); if(stemNote) { GuidoPos tagpos = NULL; if (stemNote->getAssociations()) tagpos = stemNote->getAssociations()->GetHeadPosition(); while(tagpos) { GRNotationElement * tag = stemNote->getAssociations()->GetNext(tagpos); GRTremolo * trem = dynamic_cast<GRTremolo*>(tag); if(trem) { trem->tellPosition(stemNote,stemNote->getPosition()); if(trem->isTwoNotesTremolo()) // in order to force the second pitch (especially the chords) to update { GREvent * secondPitch = dynamic_cast<GREvent*>(mAssociated->GetNext(stemPos)); if(secondPitch) trem->tellPosition(secondPitch, secondPitch->getPosition()); } } } } } // now we have to make sure, that the original positions // for the beam are set for the right staff if (tagtype == SYSTEMTAG) { const NVPoint &offset = beamstaff->getPosition(); st->p[0] -= offset; st->p[1] -= offset; st->p[2] -= offset; st->p[3] -= offset; } }