Skip to content
Snippets Groups Projects
tmeasureobject.cpp 24.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • /***************************************************************************
    
     *   Copyright (C) 2017-2021 by Tomasz Bojczuk                             *
    
     *   seelook@gmail.com                                                     *
     *                                                                         *
     *   This program is free software; you can redistribute it and/or modify  *
     *   it under the terms of the GNU General Public License as published by  *
     *   the Free Software Foundation; either version 3 of the License, or     *
     *   (at your option) any later version.                                   *
     *                                                                         *
     *   This program is distributed in the hope that it will be useful,       *
     *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
     *   GNU General Public License for more details.                          *
     *                                                                         *
     *  You should have received a copy of the GNU General Public License      *
     *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
     ***************************************************************************/
    
    #include "tmeasureobject.h"
    
    #include "music/tmeter.h"
    #include "music/tnote.h"
    
    #include "tbeamobject.h"
    #include "tnoteitem.h"
    #include "tnotepair.h"
    #include "tscoreobject.h"
    #include "tstaffitem.h"
    
    #include <QtCore/qdebug.h>
    
    #include <QtGui/qguiapplication.h>
    #include <QtGui/qpalette.h>
    
    void content(TmeasureObject *m)
    {
        QString c = QStringLiteral("| ");
        for (int n = 0; n < m->noteCount(); ++n)
            c += QString("(%1)").arg(m->note(n)->index()) + QLatin1String("<") + m->note(n)->note()->toText() + QLatin1String(">")
                + m->note(n)->note()->rtm.string() + QLatin1String(" ");
        c += QStringLiteral("|");
        qDebug() << m->debug() << c;
    }
    
    TmeasureObject::TmeasureObject(int nr, TscoreObject *parent)
        : QObject(parent)
        , m_number(nr)
        , m_score(parent)
        , m_staff(nullptr)
        , m_firstInGr(new qint8[1])
        , m_barLine(nullptr)
    {
        clearAccidState();
        m_duration = m_score->meter()->duration();
        m_free = m_duration;
    
        qApp->installEventFilter(this);
    
    TmeasureObject::~TmeasureObject()
    
            delete m_barLine;
        delete[] m_firstInGr;
        //   qDebug() << debug() << "is going delete";
    
    void TmeasureObject::setNumber(int nr)
    
    void TmeasureObject::setStaff(TstaffItem *st)
    {
        if (m_staff != st) {
            m_staff = st;
    
            for (TnotePair *np : std::as_const(m_notes))
    
                np->item()->setStaff(m_staff);
        }
    
    int TmeasureObject::durationFrom(int id)
    {
        int dur = m_free;
        if (id < noteCount()) {
            for (int n = id; n < noteCount(); ++n)
                dur += note(n)->note()->duration();
        } else // TODO It should never occur, delete if so
            qDebug() << debug() << "FIXME! This note doesn't belong to this measure or doesn't exist at all!" << id;
        return dur;
    
    int TmeasureObject::durationBefore(TnoteItem *it)
    {
        int dur = 0;
        bool found = false;
        for (int n = 0; n < noteCount(); ++n) {
            if (note(n)->item() != it)
                dur += note(n)->note()->duration();
            else {
                found = true;
                break;
            }
        }
        return found ? dur : 0;
    
    void TmeasureObject::appendNewNotes(int segmentId, int count)
    {
        // so far we are sure there is enough space for whole note list in this measure
        //   qDebug() << debug() << "append" << count << "note(s) from" << segmentId << "measure duration" << duration();
        for (int n = segmentId; n < segmentId + count; ++n)
            m_notes.append(m_score->noteSegment(n));
        updateRhythmicGroups();
    
        const int grWithBeam = beamGroup(segmentId);
    
        for (int n = segmentId; n < segmentId + count; ++n) {
            auto np = m_score->noteSegment(n);
            if (np->item() == nullptr)
                np->setNoteItem(new TnoteItem(m_staff, np));
            else
                np->item()->setStaff(m_staff);
            np->item()->setMeasure(this);
            checkAccidentals();
            np->item()->setNote(*np->note());
            if (m_score->showNoteNames())
                np->item()->setNoteNameVisible(true);
        }
        if (grWithBeam > -1) {
            auto firstInGrId = m_score->noteSegment(firstNoteId() + m_firstInGr[grWithBeam])->index();
            TbeamObject *curBeam = nullptr;
            while (firstInGrId < m_score->notesCount()) {
                auto ns = m_score->noteSegment(firstInGrId);
                if (ns->beam()) {
                    if (ns->beam() != curBeam) {
                        ns->beam()->prepareBeam();
                        curBeam = ns->beam();
                    }
                }
                ++firstInGrId;
            }
    
        refresh();
        m_staff->refresh();
        checkBarLine();
    
    void TmeasureObject::insertNotes(Tpairs &nList, int startId)
    {
        int listDur = TnotePair::pairsDuration(nList);
        Tpairs outNotes;
        if (listDur > m_score->meter()->duration())
            qDebug() << debug() << "FIXME! Ooh, notes to insert are longer than entire measure can contain!" << listDur;
    
        if (listDur > m_free) {
            int leftDur = releaseAtEnd(listDur - m_free, outNotes, startId);
            if (leftDur) // TODO it should never happen - DELETE IT!
                qDebug() << debug() << "FIXME! Can't insert" << listDur << leftDur << listDur - m_free;
        }
        for (int n = 0; n < nList.count(); ++n) {
            auto noteIn = nList[n];
            m_notes.insert(startId, noteIn);
            if (noteIn->item() == nullptr)
                noteIn->setNoteItem(new TnoteItem(m_staff, noteIn));
            else if (m_staff != noteIn->item()->staff())
                noteIn->item()->setStaff(m_staff);
            noteIn->item()->setMeasure(this);
        }
        update(m_notes[startId]->rhythmGroup()); // nList.first()->rhythmGroup()
        shiftReleased(outNotes);
    }
    
    void TmeasureObject::insertNote(TnoteItem *afterItem)
    {
        if (afterItem) {
            int afterIdInBar = afterItem->index() - afterItem->measure()->firstNoteId();
            int possibleDur = afterItem->measure()->durationFrom(afterIdInBar);
            int workDur = m_score->workRhythm().duration();
            // cut note duration if it is longer than possible measure duration starting from the item
            auto newRtmList = Trhythm::resolve(workDur > possibleDur ? possibleDur : workDur);
            Tpairs nl;
    
            for (Trhythm rtm : std::as_const(newRtmList)) {
    
                Tnote newNote(0, 0, 0, Trhythm(rtm.rhythm(), true));
                auto np = m_score->insertSilently(afterItem->index(), newNote, this);
                m_notes.removeAt(afterIdInBar);
                nl << np;
    
            insertNotes(nl, afterIdInBar);
    
    }
    
    void TmeasureObject::removeNote(TnotePair *n)
    {
        m_free += n->item()->note()->duration(); // n->note() is already null here
        m_notes.takeAt(n->index() - firstNoteId());
        fill();
    }
    
    void TmeasureObject::removeLastNote()
    {
        if (m_free == 0 && m_barLine) {
            m_barLine->setVisible(false);
            m_barLine->setParentItem(nullptr);
    
        auto noteToRemove = m_notes.takeLast();
        updateRhythmicGroups();
        // TODO Try to use resolveBeaming here
        if (noteToRemove->beam()) {
            if (noteToRemove->beam()->count() < 3)
                noteToRemove->beam()->deleteBeam();
            else
                noteToRemove->beam()->removeNote(noteToRemove);
            int segId = m_firstInGr[noteToRemove->rhythmGroup()];
            while (segId < m_notes.count()) { // update notes of entire rhythm group
                m_notes[segId]->approve();
                segId++;
            }
    
    void TmeasureObject::keySignatureChanged()
    {
        for (int n = 0; n < m_notes.size(); ++n) {
            m_notes[n]->item()->keySignatureChanged();
        }
        refresh();
    }
    
    int TmeasureObject::firstNoteId() const
    {
        return m_notes.isEmpty() ? 0 : m_notes.first()->index();
    
    int TmeasureObject::lastNoteId() const
    {
        return m_notes.isEmpty() ? 0 : m_notes.last()->index();
    }
    
    char TmeasureObject::debug()
    {
        QTextStream o(stdout);
        o << " \033[01;33m[" << QString("%1/%2").arg(number() + 1).arg(m_staff ? m_staff->number() + 1 : -1) << " MEASURE]\033[01;00m";
        return 32; // fake
    
    // #################################################################################################
    // ###################              PROTECTED           ############################################
    // #################################################################################################
    
    void TmeasureObject::flush()
    {
        if (m_barLine)
            m_barLine->setVisible(false);
        m_notes.clear();
        setStaff(nullptr);
        m_allNotesWidth = 0.0;
        m_gapsSum = 0.0;
        delete[] m_firstInGr;
        m_firstInGr = new qint8[1];
    
    void TmeasureObject::updateRhythmicGroups()
    {
        if (duration() == 0)
            return;
    
        int notePos = 0, grNr = 0, currGr = 0;
        delete[] m_firstInGr;
        m_firstInGr = new qint8[m_score->groupCount()];
        m_firstInGr[0] = 0; // first note in measure also begins first rhythmic group
        for (int i = 0; i < m_notes.size(); ++i) {
            if (currGr != grNr) {
                m_firstInGr[grNr] = i;
                currGr = grNr;
            }
            m_notes[i]->setRhythmGroup(grNr);
            /** We are cheating here: no-rhythm-note gets duration of 1 - such a rhythm doesn't exists */
            notePos += m_notes[i]->note()->rhythm() == Trhythm::NoRhythm ? 1 : m_notes[i]->note()->duration();
            while (grNr < m_score->groupCount() && notePos >= m_score->groupPos(grNr))
                grNr++;
        }
        if (currGr < m_score->groupCount() - 1) { // fill the rest of the array
            for (int gr = currGr + 1; gr < m_score->groupCount(); ++gr)
                m_firstInGr[gr] = -1; // with '-1' - means no notes yet
        }
        m_free = m_duration - notePos;
    
    void TmeasureObject::checkBarLine()
    {
        if (m_free == 0 && m_score->meter()->meter() != Tmeter::NoMeter) {
            //     qDebug() << debug() << "check bar line";
            auto lastNote = last()->item();
            if (!m_barLine) {
                m_staff->score()->component()->setData("import QtQuick 2.9; Rectangle { width: 0.3 }", QUrl());
                m_barLine = qobject_cast<QQuickItem *>(m_staff->score()->component()->create());
                m_barLine->setProperty("color", qApp->palette().text().color());
                m_barLine->setParentItem(lastNote);
            }
            m_barLine->setParentItem(lastNote);
            m_barLine->setVisible(true);
            qreal xOff = lastNote == m_staff->lastMeasure()->last()->item() ? 0.2 : 0.0; // fit line at the staff end
            m_barLine->setX(lastNote->rightX() - lastNote->x() + xOff);
            m_barLine->setY(m_staff->upperLine());
            m_barLine->setHeight(m_score->isPianoStaff() ? 30.0 : 8.0);
        }
    }
    
    void TmeasureObject::meterChanged()
    {
        m_duration = m_score->meter()->duration();
        updateRhythmicGroups();
    
    void TmeasureObject::refresh()
    {
        m_gapsSum = 0.0;
        m_allNotesWidth = 0.0;
        for (int n = 0; n < m_notes.size(); ++n) {
            auto noteObj = note(n)->item();
            m_gapsSum += noteObj->rhythmFactor();
            m_allNotesWidth += noteObj->width();
        }
    }
    
    void TmeasureObject::checkAccidentals()
    {
        clearAccidState();
        for (int n = 0; n < m_notes.size(); ++n) {
            auto np = note(n);
            if (np->note()->isValid() && !np->note()->isRest())
                m_accidsState[np->note()->note() - 1] = np->note()->alter(); // register accidental of a note
        }
    }
    
    int TmeasureObject::beamGroup(int segmentId)
    {
        int currGr = m_score->noteSegment(segmentId)->rhythmGroup();
        int segId = m_firstInGr[currGr] + 1;
        if (segId < 0) { // TODO it should never happen - DELETE IT!
            qDebug() << debug() << "FIXME! beamGroup()";
            return -1;
    
        int grWithBeam = -1;
        while (segId < m_notes.count() && m_notes[segId]->rhythmGroup() == currGr) {
            auto noteSeg = m_notes[segId];
            auto prevSeg = m_notes[segId - 1];
            if (!noteSeg->note()->isRest() && !prevSeg->note()->isRest() // not a rest
                && noteSeg->note()->rhythm() > Trhythm::Quarter // sixteenth or eighth
                && prevSeg->note()->rhythm() > Trhythm::Quarter
                && (!m_score->isPianoStaff() || noteSeg->note()->onUpperStaff() == prevSeg->note()->onUpperStaff())) {
                if (prevSeg->note()->rtm.beam() == Trhythm::e_noBeam) // start beam group
                    prevSeg->setBeam(m_score->getBeam(prevSeg, this));
                auto beam = prevSeg->beam();
                if (noteSeg->beam() == nullptr)
                    beam->addNote(noteSeg);
                grWithBeam = currGr;
            }
            segId++;
    
        return grWithBeam;
    }
    
    void TmeasureObject::noteGoingRest(TnotePair *np)
    {
        if (np->beam()) {
            if (np->beam()->count() > 2) {
                if (np->beam()->removeNote(np))
                    np->beam()->deleteBeam();
            } else
                np->beam()->deleteBeam();
            int segId = m_firstInGr[np->rhythmGroup()];
            while (segId < m_notes.count() && m_notes[segId]->rhythmGroup() == np->rhythmGroup()) { // update notes of entire rhythm group
                m_notes[segId]->approve();
                segId++;
            }
    
    }
    
    void TmeasureObject::restGoingNote(TnotePair *np)
    {
        QList<QList<int>> beamLists;
        QList<int> l1;
        beamLists << l1;
        for (int bb = m_firstInGr[np->rhythmGroup()]; bb < m_notes.count() && m_notes[bb]->rhythmGroup() == np->rhythmGroup(); ++bb) {
            auto prevSeg = m_notes[bb];
            if (!prevSeg->note()->isRest() && prevSeg->note()->rhythm() > Trhythm::Quarter) {
                auto lastBeam = beamLists.last();
                if (!lastBeam.isEmpty()) {
                    if (lastBeam.last() < bb - 1) { // a new beam if there was a rest in between notes in current rhythm group
                        QList<int> newBeam;
                        beamLists << newBeam;
                    }
                }
                beamLists.last() << bb;
            }
    
        int noteId = np->index() - firstNoteId();
        for (int bl = 0; bl < beamLists.size(); ++bl) {
            QList<int> &beam = beamLists[bl];
            if (beam.size() > 1 && noteId >= beam.first() && noteId <= beam.last()) {
                TbeamObject *newBeam = nullptr;
                for (int b = beam.first(); b <= beam.last(); ++b) {
                    auto noteInBeam = m_notes[b];
                    if (noteInBeam->beam())
                        delete noteInBeam->beam();
                    if (newBeam)
                        newBeam->addNote(noteInBeam);
                    else
                        newBeam = m_score->getBeam(noteInBeam, this);
                }
                newBeam->prepareBeam();
                newBeam->drawBeam();
    
    }
    
    void TmeasureObject::changeNoteDuration(TnotePair *np, const Tnote &newNote)
    {
        int prevDur = np->note()->duration();
        int newDur = newNote.duration();
        if (prevDur == newDur) {
            qDebug() << debug() << "FIXME! calling changeNoteDuration() when duration doesn't changed";
            return;
    
        Tnote nn = newNote;
        Tpairs notesToOut;
        if (m_free - (newDur - prevDur) < 0) { // There is not enough space for new note - its duration is longer than possible free space in the measure
            /** 1. Try to release measure (move notes after this @p np one to the next measure) */
            int leftDur = releaseAtEnd(newDur - prevDur - m_free, notesToOut, np->index() - firstNoteId() + 1);
            if (leftDur) {
                /** 2. There is still not enough space for new duration - so cut duration of this @p np note */
                auto thisBarRtms = Trhythm::resolve(m_free + prevDur);
                nn.setRhythm(thisBarRtms.first());
                for (int r = 1; r < thisBarRtms.count(); ++r) {
                    if (!newNote.isRest())
                        thisBarRtms[r].setTie(Trhythm::e_tieCont);
                    m_score->insertSilently(np->index() + r, Tnote(newNote, thisBarRtms[r]), this);
                }
    
            np->setPairNotes(nn);
    
            score()->updateNoteInList(np, nn);
    
    
            update(np->rhythmGroup());
            checkBarLine();
        } else { // measure duration is less than meter - take notes from the next measure
            m_free += prevDur - newDur;
    
            np->setPairNotes(nn);
    
            score()->updateNoteInList(np, nn);
    
            fill(); // it updates measure
        }
        shiftReleased(notesToOut);
    }
    
    void TmeasureObject::resolveBeaming(int firstGroup, int endGroup)
    {
        if (noteCount() < 2)
            return;
    
        if (endGroup == -1)
            endGroup = m_score->groupCount() - 1;
    
        // delete beams in group range of [firstGroup to endGroup]
        int noteId = m_firstInGr[firstGroup];
        if (noteId < 0) { // TODO it should never happen - DELETE IT!
            qDebug() << debug() << "FIXME! wrong grouping";
            return;
        }
        int grId = firstGroup;
        while (noteId < noteCount() && grId <= endGroup) {
            if (m_notes[noteId]->beam())
                m_notes[noteId]->beam()->deleteBeam();
            noteId++;
            if (noteId < noteCount())
                grId = m_notes[noteId]->rhythmGroup();
        }
    
        for (int g = firstGroup; g <= endGroup; ++g) {
            if (m_firstInGr[g] < 0 || m_firstInGr[g] > noteCount() - 1)
                break;
            int gr = beamGroup(m_firstInGr[g] + firstNoteId());
            if (gr > -1 && gr < m_score->groupCount()) {
                TbeamObject *beam = nullptr;
                TbeamObject *prevBeam = nullptr;
                for (int n = m_firstInGr[gr]; n < noteCount(); ++n) {
                    if (m_notes[n]->rhythmGroup() != gr)
                        break;
                    beam = m_notes[n]->beam();
                    if (beam && beam != prevBeam) {
                        beam->prepareBeam();
                        prevBeam = beam;
                    }
                }
    
        // approve beam changes for all eighths and sixteenths that have no beam just flag - to revert the flag
        if (m_firstInGr[firstGroup] >= 0 && m_firstInGr[firstGroup] < noteCount()) {
            for (int n = m_firstInGr[firstGroup]; n < noteCount(); ++n) {
                auto note = m_notes[n];
                if (!note->beam() && !note->note()->isRest() && note->note()->rhythm() > Trhythm::Quarter)
                    note->approve();
            }
    
        }
    }
    
    /**
     *  - iterate through notes in backward order (right to left), take note by note to release required duration
     *  - create a list from taken notes to send it to the next measure
     *  - split the latest note (the most right one in the measure) if necessary
     *  - half of the duration remains in current measure at the end tied with
     *    a new note that has to be created and push to the beginning of the next measure
     */
    
    int TmeasureObject::releaseAtEnd(int dur, Tpairs &notesToOut, int endNote)
    {
        int noteNr = m_notes.count() - 1;
        while (noteNr >= endNote && dur > 0) {
            auto lastNote = last();
            int lastDur = lastNote->note()->duration();
            if (lastDur > dur) { // last note is longer than required space - split it and create and move the rest of its duration to the next measure
                auto rList = Trhythm::resolve(lastDur - dur);
                auto lastTie = lastNote->note()->rtm.tie();
                if (!lastNote->note()->isRest()) {
                    rList.first().setTie(lastTie > Trhythm::e_tieStart ? Trhythm::e_tieCont : Trhythm::e_tieStart);
                }
                for (int r = 1; r < rList.count(); ++r) {
                    if (!lastNote->note()->isRest())
                        rList[r].setTie(Trhythm::e_tieCont);
                    m_score->insertSilently(lastNote->index() + r, Tnote(*lastNote->note(), rList[r]), this);
                }
    
                Tnote n(Tnote(*lastNote->note(), rList.first()));
                lastNote->setPairNotes(n);
                score()->updateNoteInList(lastNote, n);
    
                // remaining part of the note that goes to next measure
                auto rtmToNext = Trhythm::resolve(dur);
                int indexToInsert = rtmToNext.count() > 1 ? 0 : notesToOut.count();
                for (int r = 0; r < rtmToNext.count(); ++r) {
                    if (!lastNote->note()->isRest()) {
                        if (r < rtmToNext.count() - 1)
                            rtmToNext[r].setTie(Trhythm::e_tieCont);
                        else
                            rtmToNext[r].setTie(lastTie == Trhythm::e_tieCont ? lastTie : Trhythm::e_tieEnd);
                    }
                    m_score->insertSilently(last()->index() + r + 1, Tnote(*lastNote->note(), rtmToNext[r]), this);
                    notesToOut.insert(indexToInsert, m_notes.takeLast());
                }
                lastDur = dur; // instead of: dur = 0; m_free += lastDur; lastDur = 0;
            } else { // last note is the same long or smaller than required space - so move it to the next measure
                notesToOut << m_notes.takeLast();
                // TODO maybe clear beams here
    
            dur -= lastDur;
            m_free += lastDur; // note was taken out so there is more free space in the measure
            noteNr--;
    
    void TmeasureObject::releaseAtStart(int dur, Tpairs &notesToOut)
    {
        int retDur = 0;
        TnotePair *firstNote;
        Trhythm::Etie firstTie;
        while (!m_notes.isEmpty() && dur > 0) {
            firstNote = first();
            int firstDur = firstNote->note()->duration();
            if (firstDur > dur) { // first measure note is longer than required duration - shrink it and create new one
                auto rList = Trhythm::resolve(firstDur - dur);
                firstTie = firstNote->note()->rtm.tie();
                if (!firstNote->note()->isRest())
                    rList.first().setTie(firstTie > Trhythm::e_tieStart ? Trhythm::e_tieCont : Trhythm::e_tieEnd);
    
                Tnote n(Tnote(*firstNote->note(), rList.first()));
                firstNote->setPairNotes(n);
                score()->updateNoteInList(firstNote, n);
    
                for (int r = 1; r < rList.count(); ++r) {
                    if (!firstNote->note()->isRest())
                        rList[r].setTie(Trhythm::e_tieCont);
                    m_score->insertSilently(firstNoteId(), Tnote(*firstNote->note(), rList[r]), this);
                }
                firstDur = dur;
                retDur = dur;
                dur = 0;
            } else { // first note is the same long or smaller than required space - so move it to the next measure
                notesToOut << m_notes.takeFirst();
                dur -= firstDur;
                // TODO maybe clear beams here
            }
            m_free += firstDur;
        }
    
        if (m_free)
            fill();
    
        if (retDur) {
            // remaining part of the note that goes to previous measure
            auto rtmToPrev = Trhythm::resolve(retDur);
            for (int r = 0; r < rtmToPrev.count(); ++r) {
                if (!firstNote->note()->isRest()) {
                    if (r < rtmToPrev.count() - 1)
                        rtmToPrev[r].setTie(Trhythm::e_tieCont);
                    else
                        rtmToPrev[r].setTie(firstTie == Trhythm::e_tieCont ? firstTie : Trhythm::e_tieStart);
                }
                m_score->insertSilently(firstNoteId(), Tnote(*firstNote->note(), rtmToPrev[r]), this);
                notesToOut.append(m_notes.takeFirst());
            }
    
        if (m_free && m_barLine) {
            m_barLine->setVisible(false);
            m_barLine->setParentItem(nullptr);
        }
    
    void TmeasureObject::insertSilently(int id, TnotePair *np)
    {
    
        m_notes.insert(qBound(0, id, m_notes.size()), np);
    
        if (np->item() == nullptr)
            np->setNoteItem(new TnoteItem(m_staff, np));
        else if (m_staff != np->item()->staff())
            np->item()->setStaff(m_staff);
        np->item()->setMeasure(this);
        np->item()->setNote(*np->note());
        if (m_score->showNoteNames())
            np->item()->setNoteNameVisible(true);
    
    bool TmeasureObject::eventFilter(QObject *obj, QEvent *event)
    {
        if (obj == qApp && event->type() == QEvent::ApplicationPaletteChange) {
            if (m_barLine)
                m_barLine->setProperty("color", qApp->palette().text().color());
        }
        return QObject::eventFilter(obj, event);
    }
    
    // #################################################################################################
    // ###################              PRIVATE             ############################################
    // #################################################################################################
    
    void TmeasureObject::clearAccidState()
    {
        for (int i = 0; i < 7; ++i)
            m_accidsState[i] = 100; // note doesn't occur in a measure
    
    void TmeasureObject::shiftReleased(Tpairs &notesToOut)
    {
        if (!notesToOut.isEmpty())
            m_staff->shiftToMeasure(m_number + 1, notesToOut);
    
    void TmeasureObject::fill()
    {
        Tpairs notesToShift;
        m_staff->shiftFromMeasure(m_number + 1, m_free, notesToShift);
        int lastId = lastNoteId() + 1;
    
        for (int i = 0; i < notesToShift.count(); ++i)
            insertSilently(lastId + i, notesToShift[i]);
    
        update();
        if (m_free && m_barLine) {
            m_barLine->setVisible(false);
            m_barLine->setParentItem(nullptr);
        }
    
    void TmeasureObject::update(int beamGrToResolve)
    {
        updateRhythmicGroups();
        checkAccidentals();
        resolveBeaming(beamGrToResolve);
        refresh();