Hello folks,

The recent posts on this subject show there is interest in the matter. Sorry for the length of this one...

My work was initially homed by Grame’s libmusicxml2 library as an example of what it could be used for, in the lilypond branch at https://github.com/grame-cncm/libmusicxml/tree/lilypond.

Dom Fober, the author and maintainer of libmusicxml2, and I decided some time ago to separate things for practical reasons, and I now push to the GitHub repository I created at https://github.com/jacques-menu/musicformats.
I’m currenly finalizing version 1.0.0, which explains why the test and master branches are not up to date - only the dev branch is currently.

The musicformats library is structured along the lines shown at page 16 in https://github.com/jacques-menu/musicformats/blob/dev/doc/maintainersGuideToMusicFormats/maintainersGuideToMusicformats.pdf (the users’s guide is not yet ‘usable’, sorry).

The central component of musicformats is MSR (Music Score Representation), from which various formats can be obtained.

In this picture, we see that we could create MusicXML output from within the LilyPond implementation going along the LilyPond - LPSR - MSR - MXSR  - MusicMXL path. The missing part would be the creation of an LPSR (LilyPond Score Representation), the others already exist.

As an example, the LPSR representation and LilyPond output produced by:

xml2ly basic/HelloWorld.xml -display-lpsr > LPSR_contents.txt 2>&1

are in the attached LPSR_contents.txt file. 

The resulting score is:


Jean and I have had discussions as to how the export to MusicXML could be tackled on the LilyPond side, but nothing concrete yet. Some of the information needed is readily accessible inside LilyPond, but grabbing the remaining part is not easy. 

The musicformats repository contains examples using the library to create scores in C++ applications, among them:

jacquesmenu@macmini: ~/musicformats-git-dev/files/musicxml > Mikrokosmos3Wandering -a
What Mikrokosmos3Wandering does:

    This multi-pass generator creates a textual representation
    of Zoltán Kodály's Mikrokosmos III Wandering score.
    It performs various passes depending on the output generated.

    Other passes are performed according to the options, such as
    displaying views of the internal data or printing a summary of the score.

    The activity log and warning/error messages go to standard error.

jacquesmenu@macmini: ~/musicformats-git-dev/files/musicxml > Mikrokosmos3Wandering -apropos generate
--- Help for atom "generate" in subgroup "Generated output"
    -generate, -gen GENERATED_OUTPUT_KIND
          Generate GENERATED_OUTPUT_KIND code to the output.
            The 5 generated output kinds available are:
            braille, guido, lilypond, midi and musicxml.
            The default is 'LilyPond output'.

(midi output is actually not yet available, though)

For example, one can run:

jacquesmenu@macmini: ~/musicformats-git-dev/files/musicxml > Mikrokosmos3Wandering -generate  musicxml  -o Mikrokosmos3Wandering.xml -trace=passes

%--------------------------------------------------------------
  Pass 1: Creating the MSR score with the functions
%--------------------------------------------------------------
*** MusicXML warning *** :91: The staffMeasuresSlicesSequence of staff "Part_OnlyPart_Staff_One" is null
*** MusicXML warning *** :91: The staffMeasuresSlicesSequence of staff "Part_OnlyPart_Staff_Two" is null

%--------------------------------------------------------------
  Pass 2: Convert the MSR score into a second MSR
%--------------------------------------------------------------

%--------------------------------------------------------------
  Pass 3: Translating the MSR into an MXSR
%--------------------------------------------------------------

%--------------------------------------------------------------
  Pass 4: Convert the MXSR into MusicXML text
%--------------------------------------------------------------

Opening file 'Mikrokosmos3Wandering.xml' for writing
Warning message(s) were issued for input line 91


This creates file Mikrokosmos3Wandering.xml, attached.


The functionality of musicformats is available as API C++ functions. For example, conversion from MusicXML data to LilyPond, as used by xml2ly and Grame’s experimental web site at https://libmusicxml.grame.fr, is available through these functions:

/*!
  \brief Converts a MusicXML representation to the LilyPond format.
  \param file a file name
  \param out the output stream
  \return an error code (\c musicFormatsError::k_NoError when success)
*/
EXP musicFormatsError musicxmlfile2lilypond (
  const char *file, const optionsVector& options, std::ostream& out, std::ostream& err);

/*!
  \brief Converts a MusicXML representation to the LilyPond format.
  \param fd a file descriptor
  \param out the output stream
  \return an error code (\c musicFormatsError::k_NoError when success)
*/
EXP musicFormatsError musicxmlfd2lilypond (
  FILE* fd, const optionsVector& options, std::ostream& out, std::ostream& err);

/*!
  \brief Converts a MusicXML representation to the LilyPond format.
  \param buffer a string containing MusicXML code
  \param out the output stream
  \return an error code (\c musicFormatsError::k_NoError when success)
*/
EXP musicFormatsError musicxmlstring2lilypond (
  const char *buffer, const optionsVector& options, std::ostream& out, std::ostream& err);


I’m no Python nor Scheme developper, but I guess this can be used with suitable interfaces from applications written in these languages.

I’ll be happy to collaborate to using musicformats to export from within LilyPond if such an attempt is done.

HTH!

JM

Attachment: Mikrokosmos3Wandering.xml
Description: XML document



%--------------------------------------------------------------
  Optional pass: displaying the LPSR as text
%--------------------------------------------------------------

LPSR Score

  MSR score summary
  
    partGroupsListSize                     : 1
    fScoreNumberOfMeasures                 : 0
    fScoreInstrumentNamesMaxLength         : 0
    fScoreInstrumentAbbreviationsMaxLength : 0
    fInhibitGraceNotesGroupsBeforeBrowsing : false
    fInhibitGraceNotesGroupsAfterBrowsing  : false
    fInhibitMeasureRepeatReplicasBrowsing  : false
    fInhibitFullMeasureRestsBrowsing       : false
    
    Part groups list:
      Part_POne (partID "P1", partName "Music")
    
    [Identification
      fIdentificationWorkTitle : "Hello World!"
    ]
    
    [PartGroup "PartGroup_1 ('0', fPartGroupName "Implicit")" (1 part)
      fPartGroupName           : "Implicit"
      fPartGroupAbbrevation    : "Impl."
      fPartGroupSymbolDefaultX : 0
      fPartGroupSymbolKind     : "kPartGroupSymbolNone"
      fPartGroupImplicit       : kPartGroupImplicitYes
      fPartGroupBarLine        : kPartGroupBarLineYes
      
        [Part Part_POne (1 staff, 1 measure)
          fPartID                      : "P1"
          fPartMsrName                 : "Part_POne"
          fPartName                    : "Music"
          fPartAbsoluteNumber          : 3
          fPartNameDisplayText         : ""
          fPartAbbrevation             : ""
          fPartAbbreviationDisplayText : ""
          fPartInstrumentName          : ""
          fPartInstrumentAbbreviation  : ""
          fPartNumberOfMeasures        : 1
          fPartContainsFullMeasureRests : false
          fPartCurrentPositionInMeasure : 0/1
          fPartAllStavesList           :
            [kStaffKindRegular staff "Part_POne_Staff_One", staff number '1', 
(1 voice)
              fStaffInstrumentName: ""
            ]
        ]
    ]
  TongueSchemeFunctionIsNeeded               : false
  EditorialAccidentalSchemeFunctionIsNeeded  : false
  
  Header
    HeaderIdentification:
      [Identification
        fIdentificationWorkTitle : "Hello World!"
      ]
    lilypondTitle    : Hello World!
  
  Paper
    indent                      : none
    shortIndent                 : none
    pageCount                   : -1
    systemCount                 : -1
  
  Layout
    layoutGlobalStaffSize : 20
  
  Voices & Stanzas
  
    [Regular voice "Part_POne_Staff_One_Voice_One", fVoiceNumber '1, line 34
      (0 harmony, 0 figured bass, 1 actual note, 0 rest, 0 skip, 0 stanza)
      fVoiceStaffUpLink                         : Part_POne_Staff_One
      fVoiceCurrentMeasureNumber                : ""
      fVoiceCurrentMeasureOrdinalNumber         : 1
      fVoiceCurrentMeasurePuristNumber          : 2
      fRegularVoiceStaffSequentialNumber        :
      fWholeNotesSinceLastRegularMeasureEnd     : 0/1
      fCurrentVoiceRepeatPhaseKind              : kVoiceRepeatPhaseNone
      fVoiceFirstClef                           : [Clef fClefKind: kClefTreble, 
fClefStaffNumber: 0, line 28]
      fVoiceCurrentClef                         : [Clef fClefKind: kClefTreble, 
fClefStaffNumber: 0, line 28]
      fVoiceCurrentKey                          : [Key, kKeyTraditional, c 
***k_NoMode***, line 21
      ]
        fVoiceCurrentTimeSignature                :
        [Time, line 24
          timeSignatureSymbolKind : kTimeSignatureSymbolNone
          timeIsCompound          : false
          timeSignatureItemsVector.size() : 1 item
          fTimeSignatureItemsVector :
            TimeSignatureItem 4/4, line 26
        ]
      fRegularVoiceHarmoniesVoiceForwardLink    : none
      fRegularVoiceFiguredBassVoiceForwardLink  : none
      fVoiceShortestNoteDuration                : 1/1
      fVoiceShortestNoteTupletFactor            :
        TupletFactor
          fTupletActualNotes : 1
          fTupletNormalNotes : 1
      fVoiceHasBeenFinalized                    : true
      fCurrentPositionInVoice                   : 0/1
      fCurrentMomentInVoice                     : Moment
        fWrittenPositionInMeseasure : 0/1
        fSoundingRelativeOffset    : 0/1
      fMusicHasBeenInsertedInVoice              : true
      fVoiceContainsFullMeasureRests            : false
      fVoiceContainsMeasureRepeats              : false
      fVoiceFirstSegment                        : '1'
      fVoiceLastAppendedMeasure                 : '[Measure 1, 
kMeasureKindRegular, Part_POne_Staff_One_Voice_One, 8 elements, line 17]'
      fVoiceFirstMeasure                        : '[Measure 1, 
kMeasureKindRegular, Part_POne_Staff_One_Voice_One, 8 elements, line 17]'
      fVoiceFirstNonGraceNote                   : [kNoteRegularInMeasure c1, 
o4, voice: 1, staff: 1, line 34]
      fVoiceLastAppendedNote                    :   [kNoteRegularInMeasure c1, 
o4, voice: 1, staff: 1, line 34]
      fVoiceMeasuresFlatList                    : empty
      
      fVoiceInitialElementsList                 : 1 elements
        [Segment '1, fSegmentDebugNumber: '3', 1 measure, line 34
          fSegmentVoiceUpLink  : "Part_POne_Staff_One_Voice_One"
          
          [Measure '1', kMeasureKindRegular, 8 elements, line 17
            fCurrentMeasureWholeNotesDuration             : 1/1
            fullMeasureWholeNotesDuration                 : 1/1
            fMeasureOrdinalNumberInVoice                  : 1
            fMeasurePuristNumber                          : 1
            fMeasureDebugNumber                           : 3
            fMeasureEndRegularKind                        : 
kMeasureEndRegularYes
            fMeasureRepeatContextKind                     : 
kMeasureRepeatContextNone
            fMeasureFirstInVoice                          : true
            fMeasureFirstInSegmentKind                    : 
kMeasureFirstInSegmentKindYes
            segmentUpLink                                 : [Segment '1, 
fSegmentDebugNumber: '3', voice: "Part_POne_Staff_One_Voice_One"]
            voiceCurrentClef                              : [Clef fClefKind: 
kClefTreble, fClefStaffNumber: 0, line 28]
            voiceCurrentKey                               : [Key, 
kKeyTraditional, c ***k_NoMode***, line 21
            ]
            voiceCurrentTimeSignature                     : [Time, line 24
              timeSignatureSymbolKind : kTimeSignatureSymbolNone
              timeIsCompound          : false
              timeSignatureItemsVector.size() : 1 item
              fTimeSignatureItemsVector :
                TimeSignatureItem 4/4, line 26
            ]
            fMeasureLongestNote                           : none
            fMeasureContainsMusic                         : true
            fMeasureKindAndPuristNumberHaveBeenDetermined : true
            fMeasurePositionInVoice                       : 0/1
            fMeasureMomentInVoice                         : [Moment 
writtenPositionInMeseasure: 0/1, soundingRelativeOffset: 0/1]
            fMeasureHasBeenFinalized                      : true
            fMeasureFinalizationContext                   : 
finalizeMeasureClone()
            fMeasureIsAFullMeasureRest                    : false
            nextMeasureNumber                             : ""
            fMeasureElementsList                          : 8 elements
            
              [Key, kKeyTraditional, c ***k_NoMode***, line 21
              ]
              
              [Time, line 24
                timeSignatureSymbolKind : kTimeSignatureSymbolNone
                timeIsCompound          : false
                timeSignatureItemsVector.size() : 1 item
                fTimeSignatureItemsVector :
                  TimeSignatureItem 4/4, line 26
              ]
              
              [Clef fClefKind: kClefTreble, fClefStaffNumber: 0, line 28]
              
              [kNoteRegularInMeasure c1, o4, voice: 1, staff: 1, line 34]
                fMeasureElementMeasureNumber       : 1
                measureElementPositionInMeasure    : 0/1
                measureElementPositionInVoice      : -987/1
                measureElementMomentInVoice        :
                  Moment
                    fWrittenPositionInMeseasure : -987/1
                    fSoundingRelativeOffset    : -987/1
                fNoteDirectMeasureUpLink           :
                  [Measure 1, kMeasureKindRegular, 
Part_POne_Staff_One_Voice_One, 8 elements, line 17]
                
                fNoteDirectChordUpLink             :  : none
                fNoteDirectGraceNotesGroupUpLink   :  : none
                fNoteDirectTupletUpLink            :  : none
                fMeasureElementSoundingWholeNotes  : 1/1
                fNoteDisplayWholeNotes             : 1/1
                measureFullLength                  : 1/1
                fNoteBelongsToAChord               : false
                fNoteBelongsToATuplet              : false
                fNoteOccupiesAFullMeasure          : true
                fNoteBelongsToAFullMeasureRests    : false
                fNoteFullMeasureRestsSequenceNumber : -1
                fNotePrintObjectKind               : ***kPrintObjectNone***
                fNoteHeadKind                      : kNoteHeadNormal
                fNoteHeadFilledKind                : kNoteHeadFilledYes
                fNoteHeadParenthesesKind           : kNoteHeadParenthesesNo
                fNoteAccidentalKind                : accidentalNone
                fNoteEditorialAccidentalKind       : kEditorialAccidentalNo
                fNoteCautionaryAccidentalKind      : kCautionaryAccidentalNo
                fNoteIsACueNoteKind                : kNoteIsACueNoteNo
                getNoteIsAGraceNote                : false
                fNoteIsStemless                    : false
                fNoteIsAChordsFirstMemberNote      : false
                fNoteIsFirstNoteInADoubleTremolo   : false
                fNoteIsSecondNoteInADoubleTremolo  : false
                noteSoundingWholeNotesAsMsrString  : "1"
                noteDisplayWholeNotesAsMsrString   : "1"
                noteGraphicDurationAsMsrString     : "kWhole"
                fNoteAlphaRGBColor                 : color: colorRGB = "", 
colorAlpha = ""
                fNoteAlphaRGBColorHasBenSet        : false
                fNoteSoloNoteOrRestInVoiceKind     : kSoloNoteOrRestInVoiceNo
                fNoteSoloNoteOrRestInStaffKind     : kSoloNoteOrRestInStaffNo
                fNoteBeams                         : none
                fNoteArticulations                 : none
                fNoteSpanners                      : none
                fNoteTechnicals                    : none
                fNoteTechnicalWithIntegers         : none
                fNoteTechnicalWithFloats           : none
                fNoteTechnicalWithStrings          : none
                fNoteOrnaments                     : none
                fNoteGlissandos                    : none
                fNoteSlides                        : none
                fNoteSingleTremolo                 : none
                fNoteDynamics                      : none
                fNoteOtherDynamics                 : none
                fNoteWords                         : none
                fNoteSlurs                         : none
                fNoteLigatures                     : none
                fNotePedals                        : none
                fNoteSlashes                       : none
                fNoteWedges                        : none
                fNoteSegnos                        : none
                fNoteDalSegnos                     : none
                fNoteCodas                         : none
                fNoteEyeGlasses                    : none
                fNoteDamps                         : none
                fNoteDampAlls                      : none
                fNoteScordaturas                   : none
                fNoteHarmoniesList                 : none
                fNoteFiguredBassElementsList       : none
                fNoteSyllables                     : none
                fNoteGraceNotesGroupAfter          : none
              
              BarCheck, nextBarOriginalNumber = "", nextBarPuristNumber = "2", 
line 17
              
              BarNumberCheck, nextBarOriginalNumber = "", nextBarPuristNumber = 
"2"
              
              BarCheck, nextBarOriginalNumber = "", nextBarPuristNumber = "2", 
line 17
              
              BarNumberCheck, nextBarOriginalNumber = "", nextBarPuristNumber = 
"2"
            
            fMeasureNotesFlatList: 0 note
          ]
        ]
      
      fVoiceLastSegment                         : null
      
      fVoiceStanzasMap                          : empty
    ]
  Book blocks
  
    BookBlock
    
      BookBlockElements
        ScoreBlock
        
          ParallelMusicBLock, 1 part group
            
            PartGroupBlock for partGroup "PartGroup_1 ('0', fPartGroupName 
"Implicit")", kPartGroupSymbolNone, 1 element
            
              PartBlock for part Part_POne (partID "P1", partName "Music"), 1 
element
                partName                     = "Music"
                partAbbreviation             = ""
                partBlockInstrumentName      = "Music"
                partBlockShortInstrumentName = ""
                
                StaffBlock for staff "Part_POne_Staff_One" (kStaffKindRegular), 
1 element
                  (StaffBlockInstrumentName       = "")
                  (StaffBlockShortInstrumentName  = "")
                  
                  UseVoiceCommand "Part_POne_Staff_One_Voice_One", 0 stanza
          
          Layout
            layoutGlobalStaffSize : 20
          
          [MidiTempo
            midiTempoDuration  = 16
            midiTempoPerSecond = 360
            
          ]
          
%--------------------------------------------------------------

\version "2.22.0"

% Pick your choice from the next two lines as needed
%myBreak = { \break }
myBreak = {}

% Pick your choice from the next two lines as needed
%myPageBreak = { \break }
myPageBreak = {}

\header {
    title                = "Hello World!"
    workTitle            = "Hello World!"
    title                = "Hello World!"
}

\paper {
}

\layout {
    \context {
      \Score
      autoBeaming = ##f % to display tuplets brackets
    }
    \context {
      \Voice
    }
}

Part_POne_Staff_One_Voice_One = \absolute {
    \language "nederlands"
    \key c \major
    \numericTimeSignature \time 4/4
    
    \clef "treble"
    c'1 | % 2
    \barNumberCheck #2
    | % 2
    \barNumberCheck #2
}

\book {
    \score {
        <<
            
            \new Staff = "Part_POne_Staff_One"
            \with {
            }
            <<
                \context Voice = "Part_POne_Staff_One_Voice_One" <<
                    \Part_POne_Staff_One_Voice_One
                >>
            >>
            
        >>
        
        \layout {
            \context {
              \Score
              autoBeaming = ##f % to display tuplets brackets
            }
            \context {
              \Voice
            }
        }
        
        \midi {
            \tempo 16 = 360
        }
    }
    
}




Reply via email to