Beispiel #1
0
void StringData::fretChords(Chord * chord) const
      {
      int   nFret, nNewFret, nTempFret;
      int   nString, nNewString, nTempString;

      if(bFretting)
            return;
      bFretting = true;

      // we need to keep track of each string we allocate ourselves within this algorithm
      bool bUsed[strings()];                    // initially all strings are available
      for(nString=0; nString<strings(); nString++)
            bUsed[nString] = false;
      // we also need the notes sorted in order of string (from highest to lowest) and then pitch
      QMap<int, Note *> sortedNotes;
      int   count = 0;
      // if chord parent is not a segment, the chord is special (usually a grace chord):
      // fret it by itself, ignoring the segment
      if (chord->parent()->type() != Element::Type::SEGMENT)
            sortChordNotes(sortedNotes, chord, &count);
      else {
            // scan each chord of seg from same staff as 'chord', inserting each of its notes in sortedNotes
            Segment* seg = chord->segment();
            int trk;
            int trkFrom = (chord->track() / VOICES) * VOICES;
            int trkTo   = trkFrom + VOICES;
            for(trk = trkFrom; trk < trkTo; ++trk) {
                  Element* ch = seg->elist().at(trk);
                  if (ch && ch->type() == Element::Type::CHORD)
                        sortChordNotes(sortedNotes, static_cast<Chord*>(ch), &count);
                  }
            }

      // scan chord notes from highest, matching with strings from the highest
      foreach(Note * note, sortedNotes) {
            nString     = nNewString    = note->string();
            nFret       = nNewFret      = note->fret();
            note->setFretConflict(false);       // assume no conflicts on this note
            // if no fretting yet or current fretting is no longer valid
            if (nString == STRING_NONE || nFret == FRET_NONE || getPitch(nString, nFret) != note->pitch()) {
                  // get a new fretting
                  if(!convertPitch(note->pitch(), &nNewString, &nNewFret) ) {
                        // no way to fit this note in this tab:
                        // mark as fretting conflict
                        note->setFretConflict(true);
                        // store fretting change without affecting chord context
                        if (nFret != nNewFret)
                              note->score()->undoChangeProperty(note, P_ID::FRET, nNewFret);
                        if (nString != nNewString)
                              note->score()->undoChangeProperty(note, P_ID::STRING, nNewString);
                        continue;
                        }

                  // check this note is not using the same string of another note of this chord
                  foreach(Note * note2, sortedNotes) {
                        // if same string...
                        if(note2 != note && note2->string() == nNewString) {
                              // ...attempt to fret this note on its old string
                              if( (nTempFret=fret(note->pitch(), nString)) != FRET_NONE) {
                                    nNewFret   = nTempFret;
                                    nNewString = nString;
                                    }
                              break;
                              }
                        }
                  }

            // check we are not reusing a string we already used
            if(bUsed[nNewString]) {
                  // ...try with each other string, from the highest
                  for(nTempString=0; nTempString < strings(); nTempString++) {
                        if(bUsed[nTempString])
                              continue;
                        if( (nTempFret=fret(note->pitch(), nTempString)) != FRET_NONE) {
                              // suitable string found
                              nNewFret    = nTempFret;
                              nNewString  = nTempString;
                              break;
                              }
                        }
                  // if we run out of strings
                  if(nTempString >= strings()) {
                        // no way to fit this chord in this tab:
                        // mark this note as fretting conflict
                        note->setFretConflict(true);
//                        continue;
                        }
                  }

            // if fretting did change, store as a fret change
            if (nFret != nNewFret)
                  note->score()->undoChangeProperty(note, P_ID::FRET, nNewFret);
            if (nString != nNewString)
                  note->score()->undoChangeProperty(note, P_ID::STRING, nNewString);

            bUsed[nNewString] = true;           // string is used
            }
Beispiel #2
0
void StringData::fretChords(Chord * chord) const
      {
      int   nFret, minFret, maxFret, nNewFret, nTempFret;
      int   nString, nNewString, nTempString;

      if(bFretting)
            return;
      bFretting = true;

      // we need to keep track of string allocation
      int bUsed[strings()];                    // initially all strings are available
      for(nString=0; nString<strings(); nString++)
            bUsed[nString] = 0;
      // we also need the notes sorted in order of string (from highest to lowest) and then pitch
      QMap<int, Note *> sortedNotes;
      int   count = 0;
      // store staff pitch offset at this tick, to speed up actual note pitch calculations
      // (ottavas not implemented yet)
      int transp = chord->staff() ? chord->part()->instrument()->transpose().chromatic : 0;     // TODO: tick?
      int pitchOffset = /*chord->staff()->pitchOffset(chord->segment()->tick())*/ - transp;
      // if chord parent is not a segment, the chord is special (usually a grace chord):
      // fret it by itself, ignoring the segment
      if (chord->parent()->type() != ElementType::SEGMENT)
            sortChordNotes(sortedNotes, chord, pitchOffset, &count);
      else {
            // scan each chord of seg from same staff as 'chord', inserting each of its notes in sortedNotes
            Segment* seg = chord->segment();
            int trk;
            int trkFrom = (chord->track() / VOICES) * VOICES;
            int trkTo   = trkFrom + VOICES;
            for(trk = trkFrom; trk < trkTo; ++trk) {
                  Element* ch = seg->elist().at(trk);
                  if (ch && ch->type() == ElementType::CHORD)
                        sortChordNotes(sortedNotes, toChord(ch), pitchOffset, &count);
                  }
            }
      // determine used range of frets
      minFret = INT32_MAX;
      maxFret = INT32_MIN;
      foreach(Note* note, sortedNotes) {
            if (note->string() != STRING_NONE)
                  bUsed[note->string()]++;
            if (note->fret() != FRET_NONE && note->fret() < minFret)
                  minFret = note->fret();
            if (note->fret() != FRET_NONE && note->fret() > maxFret)
                  maxFret = note->fret();
      }

      // scan chord notes from highest, matching with strings from the highest
      foreach(Note * note, sortedNotes) {
            nString     = nNewString    = note->string();
            nFret       = nNewFret      = note->fret();
            note->setFretConflict(false);       // assume no conflicts on this note
            // if no fretting (any invalid fretting has been erased by sortChordNotes() )
            if (nString == STRING_NONE /*|| nFret == FRET_NONE || getPitch(nString, nFret) != note->pitch()*/) {
                  // get a new fretting
                  if (!convertPitch(note->pitch(), pitchOffset, &nNewString, &nNewFret) ) {
                        // no way to fit this note in this tab:
                        // mark as fretting conflict
                        note->setFretConflict(true);
                        // store fretting change without affecting chord context
                        if (nFret != nNewFret)
                              note->undoChangeProperty(Pid::FRET, nNewFret);
                        if (nString != nNewString)
                              note->undoChangeProperty(Pid::STRING, nNewString);
                        continue;
                        }
                  // note can be fretted: use string
                  else {
                        bUsed[nNewString]++;
                        }
                  }

            // if the note string (either original or newly assigned) is also used by another note
            if (bUsed[nNewString] > 1) {
                  // attempt to find a suitable string, from topmost
                  for (nTempString=0; nTempString < strings(); nTempString++) {
                        if (bUsed[nTempString] < 1
                                    && (nTempFret=fret(note->pitch(), nTempString, pitchOffset)) != FRET_NONE) {
                              bUsed[nNewString]--;    // free previous string
                              bUsed[nTempString]++;   // and occupy new string
                              nNewFret   = nTempFret;
                              nNewString = nTempString;
                              break;
                              }
                        }
                  }

            // TODO : try to optimize used fret range, avoiding eccessively open positions

            // if fretting did change, store as a fret change
            if (nFret != nNewFret)
                  note->undoChangeProperty(Pid::FRET, nNewFret);
            if (nString != nNewString)
                  note->undoChangeProperty(Pid::STRING, nNewString);
            }