lenmus / lomse

A C++ library for rendering, editing and playing back music scores.
MIT License
117 stars 28 forks source link

How to fetch note information from internal model? #349

Closed AndreasKoettl95 closed 2 years ago

AndreasKoettl95 commented 2 years ago

Dear Devs,

I'm trying to fetch information about each note in a score. I want to know the step, the octave, and any other information that is provided in the score. But I can't figure out how to do it.

I'm new to this library, and I know there is this ImoNote class, there are enums for steps and octave, so I assume the information is somewhere in the internal model, but I don't know how to fetch it.

Background if it does matter: I want to analyze, what a musician has to do, to play a certain note. For example on a guitar, what fret needs to be pressed, how many strings are involved, how long is the duration of this note, etc. And according to this information, I want to modify the document, e.g. remove the next note etc. and update the render output.

Hope you can help me out.

Thanks!

cecilios commented 2 years ago

I have not published much information about the internal model because it should remain internal and user applications should not directly access to it, as this will create problems for future changes. Instead, user applications should access to it indirectly, through stable API classes and methods.

Unfortunately, I didn't have use cases and much time to think on this and develop this API so, currently the only option is to access directly to the internal model.

As to your question, my first impression is that for traversing the score you should use an instance of class StaffObjsCursor. This class is a kind of iterator for traversing the score as a musician does, by time position. As an example, look at the code in method PitchAssigner::assign_pitch() (in src/internal_model/lomse_model_builder.cpp). StaffObjsCursor is more flexible than other alternatives and it also collects information as the score is being traversed and can provide additional information, e.g. which key signature or clef is applicable to current pointed note.

Once you have access to the desired note, you can directly access the note and get the information of interest, e.g. its pitch or its duration:

ImoStaffObj* pSO = cursor.get_staffobj();
if (pSO->is_note())
{
    ImoNote* pNote = static_cast<ImoNote*>(pSO);
    pNote->get_voice();
    pNote->get_step();
    pNote->get_octave();
    pNote->get_fpitch();                //FPitch. Ignores fractional part of actual accidentals
    pNote->get_midi_pitch();            //MidiPitch
    pNote->get_playback_duration();     //playback duration: nominal duration for playback
    pNote->get_event_duration();        //event duration: real duration for playback
    pNote->get_playback_time();         //playback time: on-set time for playback
}

If you are going to use Lomse, I'll be glad to help you and get your feedback to develop a better API instead of having to access the internal model.

cecilios commented 2 years ago

This is an example for traversing all notes in the order they will be played an accessing notes information:

    Presenter* m_presenter = m_lomse.open_document(...):
    ADocument doc = m_presenter->get_document();
    AScore score = doc.first_score();
    ImoScore* pScore = score.internal_object();

    StaffObjsCursor cursor(pScore);
    while(!cursor.is_end())
    {
        ImoStaffObj* pSO = cursor.get_staffobj();
        if (pSO->is_note())
        {
            ImoNote* pNote = static_cast<ImoNote*>(pSO);
            pNote->get_voice();
            pNote->get_step();
            pNote->get_octave();
            pNote->get_fpitch();                //FPitch. Ignores fractional part of actual accidentals
            pNote->get_midi_pitch();            //MidiPitch
            pNote->get_playback_duration();     //playback duration: nominal duration for playback
            pNote->get_event_duration();        //event duration: real duration for playback
            pNote->get_playback_time();         //playback time: on-set time for playback
        }

        cursor.move_next();
    }
AndreasKoettl95 commented 2 years ago

Sorry, for not letting you know by now, but this is exactly what I need.
Thank you for your help and fast response!

I will continue using this library for my project. It seems to already provide most of the things that I need, at least in some way. I just have to figure out how to use it.

From my perspective, this issue can be closed, thank you.