Пример #1
0
//---------------------------------------------------------------------------------------
void ChordEngraver::add_note(ImoStaffObj* pSO, GmoShape* pStaffObjShape)
{
    m_numNotesMissing--;
    ImoNote* pNote = dynamic_cast<ImoNote*>(pSO);
    GmoShapeNote* pNoteShape = dynamic_cast<GmoShapeNote*>(pStaffObjShape);
    int posOnStaff = pNoteShape->get_pos_on_staff();

    if (m_notes.size() == 0)
    {
        ChordNoteData* pData = LOMSE_NEW ChordNoteData(pNote, pNoteShape, posOnStaff, m_iInstr);
	    m_notes.push_back(pData);
        m_pBaseNoteData = pData;
        m_stemWidth = tenths_to_logical(LOMSE_STEM_THICKNESS);
    }
    else
    {
        //keep notes sorted by pitch
        DiatonicPitch newPitch(pNote->get_step(), pNote->get_octave());
        std::list<ChordNoteData*>::iterator it;
        for (it = m_notes.begin(); it != m_notes.end(); ++it)
        {
            DiatonicPitch curPitch((*it)->pNote->get_step(), (*it)->pNote->get_octave());
            if (newPitch < curPitch)
            {
                ChordNoteData* pData =
                    LOMSE_NEW ChordNoteData(pNote, pNoteShape, posOnStaff, m_iInstr);
	            m_notes.insert(it, 1, pData);
                return;
            }
        }
        ChordNoteData* pData = LOMSE_NEW ChordNoteData(pNote, pNoteShape, posOnStaff, m_iInstr);
	    m_notes.push_back(pData);
    }
}
Пример #2
0
    TEST_FIXTURE(GmoShapeTestFixture, Composite_LockRecomputesBounds2)
    {
        Document doc(m_libraryScope);
        ImoNote* pNote = static_cast<ImoNote*>(ImFactory::inject(k_imo_note, &doc));
        pNote->set_step(0);
        pNote->set_octave(4);
        pNote->set_notated_accidentals(k_flat);
        pNote->set_note_type(k_whole);

        ScoreMeter meter(1, 1, 180.0f);
        ShapesStorage storage;
        NoteEngraver engraver(m_libraryScope, &meter, &storage, 0, 0);
        GmoShapeNote* pShape =
            dynamic_cast<GmoShapeNote*>(engraver.create_shape(pNote, k_clef_F4, UPoint(10.0f, 15.0f)) );

        pShape->unlock();
        CHECK( pShape->is_locked() == false );

        USize size = pShape->get_size();
        GmoShapeNotehead* pNH = pShape->get_notehead_shape();
        GmoShapeAccidentals* pAcc = pShape->get_accidentals_shape();
        USize shift(200.0f, 300.0f);
        pNH->shift_origin(shift);
        pShape->lock();

        CHECK( pShape->is_locked() == true );
        CHECK( pShape->get_size().width == size.width + shift.width );
        CHECK( pShape->get_origin().x == min(pAcc->get_origin().x, pNH->get_origin().x) );
        CHECK( pShape->get_origin().y == min(pAcc->get_origin().y, pNH->get_origin().y) );

        delete pNote;
        delete pShape;
    }
Пример #3
0
    TEST_FIXTURE(ScoreAlgorithmsTestFixture, find_and_classify_1)
    {
        //inserted note starts and ends at same time than existing note
        // 1 case: nrT == t (full)
        //  (clef G)(n e4 e v1)(n f4 e v1)(n g4 e v1)
        //          0--------32
        Document doc(m_libraryScope);
        doc.from_string("(score (vers 2.0)(instrument (musicData "
            "(clef G)(n e4 e v1)(n f4 e v1)(n g4 e v1)"
            ")))");
        ImoScore* pScore =
            static_cast<ImoScore*>( doc.get_imodoc()->get_content_item(0) );

        list<OverlappedNoteRest*> overlaps =
            ScoreAlgorithms::find_and_classify_overlapped_noterests_at(
                                                        pScore, 0, 1, 0.0, 32.0);

        OverlappedNoteRest* pOV = overlaps.front();
        ImoNote* pNote = static_cast<ImoNote*>(pOV->pNR);
        CHECK( overlaps.size() == 1 );
        CHECK( pNote != NULL );
        CHECK( pNote->get_fpitch() == FPitch("e4") );
        CHECK( pOV->type == k_overlap_full );
        CHECK( is_equal_time(pOV->overlap, 32.0) );

        delete_overlaps(overlaps);
    }
Пример #4
0
    TEST_FIXTURE(ScoreAlgorithmsTestFixture, find_and_classify_5)
    {
        //inserted note starts before and ends at same time than existing note
        //  (clef G)(n e4 e v1)(n f4 e v1)(n g4 e v1)
        //               24----------56
        Document doc(m_libraryScope);
        doc.from_string("(score (vers 2.0)(instrument (musicData "
            "(clef G)(n e4 e v1)(n f4 e v1)(n g4 e v1)"
            ")))");
        ImoScore* pScore =
            static_cast<ImoScore*>( doc.get_imodoc()->get_content_item(0) );

        list<OverlappedNoteRest*> overlaps =
            ScoreAlgorithms::find_and_classify_overlapped_noterests_at(
                                                        pScore, 0, 1, 24.0, 32.0);

        CHECK( overlaps.size() == 2 );
        list<OverlappedNoteRest*>::const_iterator it = overlaps.begin();
        OverlappedNoteRest* pOV = *it;
        ImoNote* pNote = static_cast<ImoNote*>(pOV->pNR);
        CHECK( pNote != NULL );
        CHECK( pNote->get_fpitch() == FPitch("e4") );
        CHECK( pOV->type == k_overlap_at_end );
        CHECK( is_equal_time(pOV->overlap, 8.0) );

        ++it;
        pOV = *it;
        pNote = static_cast<ImoNote*>(pOV->pNR);
        CHECK( pNote != NULL );
        CHECK( pNote->get_fpitch() == FPitch("f4") );
        CHECK( pOV->type == k_overlap_at_start );
        CHECK( is_equal_time(pOV->overlap, 24.0) );

        delete_overlaps(overlaps);
    }
Пример #5
0
    TEST_FIXTURE(NoteEngraverTestFixture, NoteEngraver_HeadStemFlagTwoDots)
    {
        Document doc(m_libraryScope);
        ImoNote* pNote = static_cast<ImoNote*>(ImFactory::inject(k_imo_note, &doc));
        pNote->set_notated_pitch(k_step_C, k_octave_4, k_no_accidentals);
        pNote->set_note_type(k_eighth);
        pNote->set_dots(2);

        ScoreMeter meter(nullptr, 1, 1, 180.0f);
        ShapesStorage storage;
        NoteEngraver engraver(m_libraryScope, &meter, &storage, 0, 0);
        GmoShapeNote* pShape =
            dynamic_cast<GmoShapeNote*>(engraver.create_shape(pNote, k_clef_F4, UPoint(10.0f, 15.0f)) );
        CHECK( pShape != nullptr );
        CHECK( pShape->is_shape_note() == true );
        std::list<GmoShape*>& components = pShape->get_components();
        std::list<GmoShape*>::iterator it = components.begin();
        CHECK( components.size() == 5 );
        CHECK( (*it)->is_shape_notehead() );
        ++it;
        CHECK( (*it)->is_shape_dot() );
        ++it;
        CHECK( (*it)->is_shape_dot() );
        ++it;
        CHECK( (*it)->is_shape_stem() );
        ++it;
        CHECK( (*it)->is_shape_flag() );

        delete pNote;
        delete pShape;
    }
Пример #6
0
//=======================================================================================
// SelectionValidator implementation
//=======================================================================================
bool SelectionValidator::is_valid_to_add_tie(SelectionSet* pSelection,
                                           ImoNote** ppStartNote,
                                           ImoNote** ppEndNote)
{
    //Returns TRUE if current selection is valid for adding a tie.
    //If valid, returns pointers to start and end notes, if not NULL parameters received


    //Conditions to be valid:
    //   1. The first note found can be tied to next one
    //   2. If condition 1 is true, the next note must also be in the selection

    bool fValid = false;
    ImoNote* pStart = NULL;
    ImoNote* pEnd = NULL;

    ColStaffObjs* pCollection = pSelection->get_staffobjs_collection();
    if (pCollection == NULL)
        return false;

    ColStaffObjsIterator it;
    for (it = pCollection->begin(); it != pCollection->end(); ++it)
    {
        ImoObj* pImo = (*it)->imo_object();
        if (pImo->is_note())
        {
            if (!pStart)
            {
                //first note found. Verify if it can be tied to next
                pStart = static_cast<ImoNote*>(pImo);
                if (!pStart->is_tied_next())
                {
                    ImoScore* pScore = pStart->get_score();
                    ColStaffObjs* pCol = pScore->get_staffobjs_table();
                    pEnd = ScoreAlgorithms::find_possible_end_of_tie(pCol, pStart);
                }
            }
            else
            {
                //Start note processed. verify if end note is also in the selection
                if (pEnd && pEnd->get_id() == pImo->get_id())
                {
                    fValid = true;      //ok. End note is in the selection
                    break;
                }
            }
        }
    }

    if (fValid)
    {
        if (ppStartNote)
            *ppStartNote = pStart;
        if (ppEndNote)
            *ppEndNote = pEnd;
        return true;
    }
    else
        return false;
}
Пример #7
0
    TEST_FIXTURE(ScoreAlgorithmsTestFixture, find_noterest_1)
    {
        //note exists and starts at same timepos
        Document doc(m_libraryScope);
        doc.from_string("(score (vers 2.0)(instrument (musicData "
            "(clef G)(n e4 e v1)(n f4 e v1)(n g4 e v1)"
            ")))");
        ImoScore* pScore =
            static_cast<ImoScore*>( doc.get_imodoc()->get_content_item(0) );

        ImoNote* pNote = static_cast<ImoNote*>(
                            ScoreAlgorithms::find_noterest_at(pScore, 0, 1, 0.0) );

        CHECK( pNote != NULL );
        CHECK( pNote->get_fpitch() == FPitch("e4") );
    }
Пример #8
0
//---------------------------------------------------------------------------------------
ImoObj* Linker::add_staffobj(ImoStaffObj* pSO)
{
    if (m_pParent)
    {
        if (m_pParent->is_music_data())
            m_pParent->append_child_imo(pSO);
        else if (m_pParent->is_chord() && pSO->is_note())
        {
            ImoChord* pChord = static_cast<ImoChord*>(m_pParent);
            ImoNote* pNote = static_cast<ImoNote*>(pSO);
            pNote->include_in_relation(m_pDoc, pChord);
            return NULL;
        }
    }
    return pSO;
}
Пример #9
0
    TEST_FIXTURE(GmoShapeTestFixture, Composite_IsLocked)
    {
        Document doc(m_libraryScope);
        ImoNote* pNote = static_cast<ImoNote*>(ImFactory::inject(k_imo_note, &doc));
        pNote->set_step(0);
        pNote->set_octave(4);
        pNote->set_notated_accidentals(k_no_accidentals);
        pNote->set_note_type(k_whole);

        ScoreMeter meter(1, 1, 180.0f);
        ShapesStorage storage;
        NoteEngraver engraver(m_libraryScope, &meter, &storage, 0, 0);
        GmoShapeNote* pShape =
            dynamic_cast<GmoShapeNote*>(engraver.create_shape(pNote, k_clef_F4, UPoint(10.0f, 15.0f)) );

        CHECK( pShape != NULL );
        CHECK( pShape->is_locked() == true );

        delete pNote;
        delete pShape;
    }
Пример #10
0
//---------------------------------------------------------------------------------------
void ChordEngraver::add_stem_and_flag()
{
    //  Rules (taken from ref. [1] Music Publishers' Association)
    //
    //  p.3, b) ... When there is more than one note head on a stem,as in a chord, the
    //          stem length is calculated from the note closest to the end of the stem.

    if (!has_stem())
        return;

    //the stem length must be increased with the distance from min note to max note.
    GmoShapeNote* pMinNoteShape = m_notes.front()->pNoteShape;
    GmoShapeNote* pMaxNoteShape = m_notes.back()->pNoteShape;
    GmoShapeNotehead* pMinHeadShape = pMinNoteShape->get_notehead_shape();
    GmoShapeNotehead* pMaxHeadShape = pMaxNoteShape->get_notehead_shape();
    LUnits uExtraLenght = pMinHeadShape->get_top() - pMaxHeadShape->get_top();

    //stem and the flag will computed for max/min note, depending on stem direction
    ChordNoteData* pData = (is_stem_down() ? m_notes.front() : m_notes.back());
    ImoNote* pNote = pData->pNote;
    GmoShapeNote* pNoteShape = pData->pNoteShape;
    int instr = pData->iInstr;
    int staff = pNote->get_staff();
    int nPosOnStaff = pData->posOnStaff;

    //but the stem is added to base note shape
    GmoShapeNote* pBaseNoteShape = m_pBaseNoteData->pNoteShape;
    Tenths length = NoteEngraver::get_standard_stem_length(nPosOnStaff, is_stem_down());
    if (!is_chord_beamed() && length < 35.0f && m_noteType > k_eighth)
        length = 35.0f;     // 3.5 spaces
    bool fShortFlag = (length < 35.0f);
    LUnits stemLength = tenths_to_logical(length) + uExtraLenght;
    StemFlagEngraver engrv(m_libraryScope, m_pMeter, pNote, instr, staff);

    pNoteShape = (is_stem_down() ? pMaxNoteShape : pMinNoteShape);
    engrv.add_stem_flag(pNoteShape, pBaseNoteShape, m_noteType, is_stem_down(),
                        has_flag(), fShortFlag, stemLength, m_color);
}
Пример #11
0
//---------------------------------------------------------------------------------------
bool SelectionValidator::is_valid_for_toggle_stem(SelectionSet* pSelection)
{
    //Returns TRUE if current selection is valid to toggle stems.
    //It is valid if there is at least a note with stem

    ColStaffObjs* pCollection = pSelection->get_staffobjs_collection();
    if (pCollection == NULL)
        return false;

    ColStaffObjsIterator it;
    for (it = pCollection->begin(); it != pCollection->end(); ++it)
    {
        ImoObj* pImo = (*it)->imo_object();
        if (pImo->is_note())
        {
            ImoNote* pNote = static_cast<ImoNote*>(pImo);
            if (pNote->get_note_type() > k_whole && !pNote->is_in_chord()
                && pNote->get_stem_direction() != k_stem_none)
                return true;
        }
    }

    return false;
}
Пример #12
0
//---------------------------------------------------------------------------------------
void AutoClef::find_staves_needing_clef()
{
    //An staff needs clef if it has pitched notes before finding a clef.
    //This method saves data for each staff in vectors m_fNeedsClef, m_pAt,
    //m_maxPitch, m_minPitch

    int staves = m_pCursor->get_num_staves();
    int stavesWithNotes = 0;

    m_fNeedsClef.assign(staves, false);
    m_pAt.assign(staves, (ImoStaffObj*)nullptr);
    m_maxPitch.assign(staves, k_undefined_fpitch);
    m_minPitch.assign(staves, k_undefined_fpitch);
    m_numNotes.assign(staves, 0);

    vector<bool> fHasNotes;         //true if staff i has pitched notes
    fHasNotes.assign(staves, false);

    while(!m_pCursor->is_end())
    {
        ImoStaffObj* pSO = m_pCursor->get_staffobj();
        int iStaff = m_pCursor->staff_index();

        if (m_pAt[iStaff] == nullptr)
            m_pAt[iStaff] = pSO;

        if (pSO->is_note())
        {
            ImoNote* pN = static_cast<ImoNote*>(pSO);
            if (!m_fNeedsClef[iStaff] && !fHasNotes[iStaff])
            {
                if (pN->is_pitch_defined())
                {
                    int clefType = m_pCursor->get_applicable_clef_type();
                    if (clefType == k_clef_undefined)
                        m_fNeedsClef[iStaff] = true;
                    fHasNotes[iStaff] = true;
                }
            }

            if (m_fNeedsClef[iStaff])
            {
                if (pN->is_pitch_defined())
                {
                    FPitch fp = pN->get_fpitch();
                    if (m_maxPitch[iStaff] == k_undefined_fpitch || m_maxPitch[iStaff] < fp)
                        m_maxPitch[iStaff] = fp;
                    if (m_minPitch[iStaff] == k_undefined_fpitch || m_minPitch[iStaff] > fp)
                        m_minPitch[iStaff] = fp;
                    ++m_numNotes[iStaff];

                     if (m_numNotes[iStaff] == 10)
                        ++stavesWithNotes;
                     if (stavesWithNotes == staves)
                        break;
               }
            }
        }
        m_pCursor->move_next();
    }
}
Пример #13
0
//---------------------------------------------------------------------------------------
void SystemLayouter::engrave_attached_objects(ImoStaffObj* pSO, GmoShape* pMainShape,
                                              int iInstr, int iStaff, int iSystem,
                                              int iCol, int iLine,
                                              ImoInstrument* pInstr)
{
    //rel objs
    if (pSO->get_num_relations() > 0)
    {
        ImoRelations* pRelObjs = pSO->get_relations();
        int size = pRelObjs->get_num_items();
	    for (int i=0; i < size; ++i)
	    {
            ImoRelObj* pRO = pRelObjs->get_item(i);

            if (!pRO->is_chord())
            {
		        if (pSO == pRO->get_start_object())
                    m_pShapesCreator->start_engraving_relobj(pRO, pSO, pMainShape,
                                                            iInstr, iStaff, iSystem, iCol,
                                                            iLine, pInstr);
		        else if (pSO == pRO->get_end_object())
		        {
                    SystemLayouter* pSysLyt = m_pScoreLyt->get_system_layouter(iSystem);
                    LUnits prologWidth( pSysLyt->get_prolog_width() );

                    m_pShapesCreator->finish_engraving_relobj(pRO, pSO, pMainShape,
                                                            iInstr, iStaff, iSystem, iCol,
                                                            iLine, prologWidth, pInstr);
                    add_relobjs_shapes_to_model(pRO, GmoShape::k_layer_aux_objs);
		        }
                else
                    m_pShapesCreator->continue_engraving_relobj(pRO, pSO, pMainShape,
                                                                iInstr, iStaff, iSystem,
                                                                iCol, iLine, pInstr);
            }
        }
    }

    //aux objs
    if (pSO->get_num_attachments() > 0)
    {
        ImoAttachments* pAuxObjs = pSO->get_attachments();
        int size = pAuxObjs->get_num_items();
	    for (int i=0; i < size; ++i)
	    {
            ImoAuxObj* pAO = static_cast<ImoAuxObj*>( pAuxObjs->get_item(i) );
            if (pAO->is_lyric())
            {
                if (pSO->is_note())
                {
                    ImoLyric* pLyric = static_cast<ImoLyric*>(pAO);
                    ImoNote* pNote = static_cast<ImoNote*>(pSO);

                    //build hash code from instrument, number & voice.
                    stringstream tag;
                    tag << iInstr << "-" << pLyric->get_number()
                        << "-" << pNote->get_voice();

                    GmoShapeNote* pNoteShape = static_cast<GmoShapeNote*>(pMainShape);
                    if (pLyric->is_start_of_relation())
                        m_pShapesCreator->start_engraving_auxrelobj(pLyric, pSO, tag.str(),
                                                    pNoteShape, iInstr, iStaff, iSystem,
                                                    iCol, iLine, pInstr);
                    else if (pLyric->is_end_of_relation())
                    {
                        SystemLayouter* pSysLyt = m_pScoreLyt->get_system_layouter(iSystem);
                        LUnits prologWidth( pSysLyt->get_prolog_width() );

                        m_pShapesCreator->finish_engraving_auxrelobj(pLyric, pSO, tag.str(),
                                                    pNoteShape, iInstr, iStaff, iSystem,
                                                    iCol, iLine, prologWidth, pInstr);
                        add_relauxobjs_shapes_to_model(tag.str(), GmoShape::k_layer_aux_objs);
                    }
                    else
                        m_pShapesCreator->continue_engraving_auxrelobj(pLyric, pSO, tag.str(),
                                                    pNoteShape, iInstr, iStaff, iSystem,
                                                    iCol, iLine, pInstr);
                }
            }
            else
            {
                GmoShape* pAuxShape =
                            m_pShapesCreator->create_auxobj_shape(pAO, iInstr, iStaff,
                                                                  pMainShape);
    //            pMainShape->accept_link_from(pAuxShape);
                add_aux_shape_to_model(pAuxShape, GmoShape::k_layer_aux_objs, iSystem,
                                       iCol, iInstr);
                m_yMax = max(m_yMax, pAuxShape->get_bottom());
            }
        }
    }
}
Пример #14
0
//---------------------------------------------------------------------------------------
void ChordEngraver::decide_on_stem_direction()
{
    //  Rules (taken from ref. [2] www.coloradocollege.edu)
    //
    //  a) Two notes in chord:
    //    a1. If the interval above the middle line is greater than the interval below
    //      the middle line: downward stems. i.e. (a4,d5) (f4,f5) (a4,g5)
    //      ==>   (MaxNotePos + MinNotePos)/2 > MiddleLinePos
    //
    //    a2. If the interval below the middle line is greater than the interval above
    //      the middle line: upward stems. i.e. (e4,c5)(g4,c5)(d4,e5)
    //
    //    a3. If the two notes are at the same distance from the middle line: stem can
    //      go in either direction, but most engravers prefer downward stems.
    //      i.e. (g4.d5)(a4,c5)
    //
    //
    //  b) More than two notes in chord:
    //
    //    b1. If the interval of the highest note above the middle line is greater than
    //      the interval of the lowest note below the middle line: downward stems.
    //      ==>   same than a1
    //
    //    b2. If the interval of the lowest note below the middle line is greater than
    //      the interval of the highest note above the middle line: upward stems.
    //      ==>   same than a2
    //
    //    b3. If the highest and the lowest notes are the same distance from the middle
    //      line use the majority rule to determine stem direction: If the majority of
    //      the notes are above the middle: downward stems. Else: upward stems.
    //      ==>   Mean(NotePos) > MiddleLinePos -> downward
    //
    //  Additional rules (mine):
    //  c) chords without stem (notes longer than half notes):
    //    c1. layout as if stem was up

    ImoNote* pBaseNote = get_base_note();
    m_noteType = pBaseNote->get_note_type();
    int stemType = pBaseNote->get_stem_direction();

    m_fHasStem = m_noteType >= k_half
                 && stemType != k_stem_none;
    m_fHasFlag = m_fHasStem && m_noteType > k_quarter
                 && !is_chord_beamed();


    if (m_noteType < k_half)
        m_fStemDown = false;                    //c1. layout as if stem up

    else if (stemType == k_stem_up)
        m_fStemDown = false;                    //force stem up

    else if (stemType == k_stem_down)
        m_fStemDown = true;                     //force stem down

    else if (stemType == k_stem_none)
        m_fStemDown = false;                    //c1. layout as if stem up

    else if (stemType == k_stem_default)     //as decided by program
    {
        //majority rule
        int weight = 0;
        std::list<ChordNoteData*>::iterator it;
        for(it=m_notes.begin(); it != m_notes.end(); ++it)
            weight += (*it)->posOnStaff;

        m_fStemDown = ( weight >= 6 * int(m_notes.size()) );
    }
}