lenmus / lomse

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

I use JUCE to render the score rendered by lomse, but it doesn't work #348

Closed ayyb1988 closed 2 years ago

ayyb1988 commented 2 years ago

Reference:https://gist.github.com/ffAudio/a51e5f660f362035566e09fb4e629446#comments

 class MainWindow    : public juce::DocumentWindow
    {
    public:
        LomseComponent *pComponent;
        lomse::LomseDoorway lomse;
        lomse::Presenter *pPresenter;

        MainWindow (juce::String name)
            : DocumentWindow (name,
                              juce::Desktop::getInstance().getDefaultLookAndFeel()
                                                          .findColour (juce::ResizableWindow::backgroundColourId),
                              DocumentWindow::allButtons)
        {
            setUsingNativeTitleBar (true);
//            setContentOwned (new MainComponent(), true);
            pComponent = new LomseComponent();
            pComponent->setSize(360,720);
            setContentOwned (pComponent, true);
            //initialize the Lomse library
            lomse.init_library (lomse::k_pix_format_rgba32, 96, false);

            pPresenter = lomse.new_document(lomse::k_view_vertical_book,
                                                              "(lenmusdoc (vers 0.0)"
                                                              "(content "
                                                              "(para (txt \"Hello world!\"))"
                                                              "(score (vers 1.6) "
                                                              "(instrument (musicData (clef G)(key C)(time 2 4)(n c4 q) )))"
                                                              ")"
                                                              ")",
                                                              lomse::Document::k_format_ldp);
            pComponent->setPresenter(std::unique_ptr<lomse::Presenter>(pPresenter));
/**
 \file LomseComponent.h
 \author Daniel Walz - Foleys Finest Audio (ffAudio)
 This uses JUCE     www.juce.com
 and lenmus         https://github.com/lenmus/lomse
 */

#pragma once

//lomse headers
#include <lomse_doorway.h>
#include <lomse_presenter.h>
#include <lomse_interactor.h>
#include <lomse_graphic_view.h>
#include <lomse_document.h>
#include <lomse_events.h>

/**
 A Component to display a score using the lomse library.
 */
class LomseComponent : public juce::Component
{
public:

    /**
     A Component to display a score using the lomse library.
     To use it create a doorway and use it to create a presenter
     \code{.cpp}
        // add a member
        lomse::LomseDoorway lomse;
        //initialize the Lomse library
        lomse.init_library (lomse::k_pix_format_rgba32, 96, false);
     \endcode
     */
    LomseComponent() = default;

    /**
     Set a presenter to be displayed
     \param[in] newPresenter a presenter object to be used
     */
    void setPresenter (std::unique_ptr<lomse::Presenter> newPresenter)
    {
        presenter = std::move (newPresenter);

        if (presenter.get() == nullptr)
            return;

        if (auto interactor = presenter->get_interactor(0).lock())
        {
            interactor->add_event_handler (lomse::k_update_window_event, this, wrapper_update_window);
        }
    }

    /**
     Grant access to the lomse::Presenter
     */
    lomse::Presenter* getPresenter()
    {
        return presenter.get();
    }

    /**
     Draw the score
     */
    void paint (juce::Graphics& g) override
    {
        if (auto interactor = (presenter.get() != nullptr) ? presenter->get_interactor(0).lock() : nullptr)
        {
            //connect the View with the window buffer
            juce::Image::BitmapData data (image, 0, 0, image.getWidth(), image.getHeight(), juce::Image::BitmapData::writeOnly);
            buffer.attach (data.data, static_cast<unsigned int> (image.getWidth()), static_cast<unsigned int> (image.getHeight()), 4 * image.getWidth());

            interactor->set_rendering_buffer (&buffer);
            interactor->redraw_bitmap();

            g.drawImageAt (image, 0, 0);
        }
    }

    /**
     Called when the component is resized to recreate the backing image
     */
    void resized() override
    {
        image = juce::Image (juce::Image::ARGB, getWidth(), getHeight(), false);
    }

    /**
     Callback from lomse when the score needs to be drawn
     */
    static void wrapper_update_window (void* pThis, lomse::SpEventInfo pEvent)
    {
        juce::ignoreUnused (pEvent);

        static_cast<LomseComponent*>(pThis)->repaint();
    }

private:
    juce::Image                       image;
    lomse::RenderingBuffer            buffer;
    std::unique_ptr<lomse::Presenter> presenter;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LomseComponent)
};
cecilios commented 2 years ago

I never used JUCE but the code in class LomseComponent looks right to me.

The only problem I see is that in class MainWindow there is no code to invoke LomseComponent::paint(), that is responsible for painting the score in the juce::Graphics device. Probably you should place this invocation in the MainWindow paint event handler, or just after the line

pComponent->setPresenter(std::unique_ptr<lomse::Presenter>(pPresenter));

but depends on your app. logic.

cecilios commented 2 years ago

Project https://github.com/hugbug/conpianist uses Lomse with JUCE. Perhaps you can get inspiration in its code.

ayyb1988 commented 2 years ago

Thanks, I'll take a look at the conpianist, LomseComponent::paint() will be called back by the jUCE framework

ayyb1988 commented 2 years ago

solved this problem:

change interactor->set_rendering_buffer (&buffer); to spInteractor->set_rendering_buffer(bitmap.data,getWidth(),getHeight());