
    rhK                    4   S r SSKJr  SSKrSSKrSSKrSSKJr  SSKJ	r	  SSKJ
r
  SSKJr  \	R                  " S5      r " S	 S
\5      r " S S\
R                   5      r " S S5      r " S S5      r " S S5      r\S:X  a  SSKr\R,                  " 5         gg)a   
Attempts at reading pure .nwc files in music21

First will solve uncompressed .nwc then compressed .nwc

Thanks to Juria90 and the nwc2xml project for solving so many of the documentation problems.
No part of this code is taken from that project, but this project would have been impossible
without his work.

Translates .nwc into .nwctxt and then uses Jordi Guillen's .nwctxt translator to go from
there to music21.

BETA -- does not work for many file elements and is untested.

Demo, showing the extent of problems.  The measure numbers are not set.  Lyrics are missing.
Drum is still poorly handled.
This is very beta.  Much better would be to convert the file into .xml or .nwctxt first.

::

    >>> #_DOCS_SHOW c = converter.parse('/Users/Hildegard/Desktop/test1.nwc')
    >>> p = common.getSourceFilePath() / 'noteworthy' / 'cuthbert_test1_v175.nwc' #_DOCS_HIDE
    >>> c = converter.parse(p) #_DOCS_HIDE
    >>> c.show('text')
    {0.0} <music21.metadata.Metadata object at ...>
    {0.0} <music21.stream.Part ...>
        {0.0} <music21.instrument.Violin 'Violin'>
        {0.0} <music21.stream.Measure 0 offset=0.0>
            {0.0} <music21.clef.TrebleClef>
            {0.0} <music21.tempo.MetronomeMark animato Quarter=120>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.note.Note G>
            {1.0} <music21.note.Note C>
            {2.0} <music21.note.Note C>
            {3.0} <music21.note.Note B>
        {4.0} <music21.stream.Measure 0 offset=4.0>
            {0.0} <music21.note.Note C>
    {0.0} <music21.stream.Part ...>
        {0.0} <music21.instrument.Violin 'Violin'>
        {0.0} <music21.stream.Measure 0 offset=0.0>
            {0.0} <music21.clef.TrebleClef>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.note.Note G>
            {1.0} <music21.note.Note A>
            {2.0} <music21.note.Note A>
            {3.5} <music21.note.Note G>
        {4.0} <music21.stream.Measure 0 offset=4.0>
            {0.0} <music21.note.Note G>
    {0.0} <music21.stream.Part ...>
        {0.0} <music21.instrument.Viola 'Viola'>
        {0.0} <music21.stream.Measure 0 offset=0.0>
            {0.0} <music21.clef.AltoClef>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.note.Note D>
            {2.0} <music21.note.Note C#>
            {2.6667} <music21.note.Note D>
            {3.3333} <music21.note.Note E>
        {4.0} <music21.stream.Measure 0 offset=4.0>
            {0.0} <music21.note.Note E>
    {0.0} <music21.stream.Part ...>
        {0.0} <music21.instrument.Violoncello 'Violoncello'>
        {0.0} <music21.stream.Measure 0 offset=0.0>
            {0.0} <music21.clef.BassClef>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.note.Note G>
            {1.0} <music21.note.Note F>
            {2.0} <music21.note.Note E>
            {3.0} <music21.note.Note G>
        {4.0} <music21.stream.Measure 0 offset=4.0>
            {0.0} <music21.note.Note C>

    >>> #_DOCS_SHOW c = converter.parse('/Users/Hildegard/Desktop/jingle1.nwc')
    >>> p = common.getSourceFilePath() / 'noteworthy' / 'jingle_v175.nwc' #_DOCS_HIDE
    >>> c = converter.parse(p) #_DOCS_HIDE
    >>> c.show('text')
    {0.0} <music21.metadata.Metadata object at 0x7fe8c0a5ffa0>
    {0.0} <music21.stream.Part 0x7fe8c0920100>
        {0.0} <music21.instrument.Piano 'Piano'>
        {0.0} <music21.stream.Measure 0 offset=0.0>
            {0.0} <music21.expressions.TextExpression 'Lively'>
            {0.0} <music21.expressions.TextExpression 'F'>
            {0.0} <music21.clef.TrebleClef>
            {0.0} <music21.tempo.MetronomeMark animato Quarter=120>
            {0.0} <music21.key.KeySignature of 1 flat>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.note.Note A>
            {1.0} <music21.note.Note A>
            {2.0} <music21.note.Note A>
            {3.0} <music21.note.Rest quarter>
        {4.0} <music21.stream.Measure 0 offset=4.0>
            {0.0} <music21.note.Note A>
            {1.0} <music21.note.Note A>
            {2.0} <music21.note.Note A>
            {3.0} <music21.note.Rest quarter>
        {8.0} <music21.stream.Measure 1 offset=8.0>
            {0.0} <music21.note.Note A>
            {1.0} <music21.note.Note C>
            {2.0} <music21.note.Note F>
            {3.5} <music21.note.Note G>
        {12.0} <music21.stream.Measure 2 offset=12.0>
            {0.0} <music21.note.Note A>
            {3.0} <music21.note.Rest quarter>
        {16.0} <music21.stream.Measure 3 offset=16.0>
            {0.0} <music21.expressions.TextExpression 'Bb'>
            {0.0} <music21.note.Note B->
            {1.0} <music21.note.Note B->
            {2.0} <music21.note.Note B->
            {3.5} <music21.note.Note B->
        {20.0} <music21.stream.Measure 4 offset=20.0>
            {0.0} <music21.expressions.TextExpression 'F'>
            {0.0} <music21.note.Note B->
            {1.0} <music21.note.Note A>
            {2.0} <music21.note.Note A>
            {3.0} <music21.note.Note A>
            {3.5} <music21.note.Note A>
        {24.0} <music21.stream.Measure 5 offset=24.0>
            {0.0} <music21.expressions.TextExpression 'G'>
            {0.0} <music21.bar.Barline type=regular>
            {0.0} <music21.note.Note A>
            {1.0} <music21.note.Note G>
            {2.0} <music21.note.Note G>
            {3.0} <music21.note.Note A>
        {28.0} <music21.stream.Measure 6 offset=28.0>
            {0.0} <music21.expressions.TextExpression 'C7'>
            {0.0} <music21.note.Note G>
            {2.0} <music21.note.Note C>
            {4.0} <music21.bar.Repeat direction=end>
        {28.0} <music21.spanner.RepeatBracket 1
                <music21.stream.Measure 5 offset=24.0><music21.stream.Measure 6 offset=28.0>>
        {32.0} <music21.stream.Measure 7 offset=32.0>
            {0.0} <music21.expressions.TextExpression 'C7'>
            {0.0} <music21.bar.Barline type=regular>
            {0.0} <music21.note.Note C>
            {1.0} <music21.note.Note C>
            {2.0} <music21.note.Note B->
            {3.0} <music21.note.Note G>
        {36.0} <music21.stream.Measure 8 offset=36.0>
            {0.0} <music21.expressions.TextExpression 'F'>
            {0.0} <music21.note.Note F>
            {3.0} <music21.note.Rest quarter>
    {0.0} <music21.stream.Part 0x7fe8c0921660>
        {0.0} <music21.instrument.Piano 'Piano'>
        {0.0} <music21.stream.Measure 0 offset=0.0>
            {0.0} <music21.clef.BassClef>
            {0.0} <music21.key.KeySignature of 1 flat>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.chord.Chord F3 A3 C4>
        {4.0} <music21.stream.Measure 0 offset=4.0>
            {0.0} <music21.chord.Chord F3 A3 C4>
        {8.0} <music21.stream.Measure 1 offset=8.0>
            {0.0} <music21.chord.Chord F3 A3 C4>
        {12.0} <music21.stream.Measure 2 offset=12.0>
            {0.0} <music21.chord.Chord F3 A3 C4>
            {1.0} <music21.note.Rest quarter>
            {2.0} <music21.chord.Chord F3 A3 C4>
            {3.0} <music21.note.Rest quarter>
        {16.0} <music21.stream.Measure 3 offset=16.0>
            {0.0} <music21.chord.Chord F3 B-3 D4>
        {20.0} <music21.stream.Measure 4 offset=20.0>
            {0.0} <music21.chord.Chord F3 A3 C4>
            {1.0} <music21.note.Rest quarter>
            {2.0} <music21.note.Rest half>
        {24.0} <music21.stream.Measure 5 offset=24.0>
            {0.0} <music21.bar.Barline type=regular>
            {0.0} <music21.chord.Chord G3 B3>
            {2.0} <music21.note.Rest half>
        {28.0} <music21.stream.Measure 6 offset=28.0>
            {0.0} <music21.chord.Chord E3 B-3 C4>
            {4.0} <music21.bar.Repeat direction=end>
        {28.0} <music21.spanner.RepeatBracket 1
                 <music21.stream.Measure 5 offset=24.0><music21.stream.Measure 6 offset=28.0>>
        {32.0} <music21.stream.Measure 7 offset=32.0>
            {0.0} <music21.bar.Barline type=regular>
            {0.0} <music21.chord.Chord E3 B-3 C4>
            {1.0} <music21.note.Rest quarter>
            {2.0} <music21.note.Rest half>
        {36.0} <music21.stream.Measure 8 offset=36.0>
            {0.0} <music21.chord.Chord F3 A3 C4>
            {3.0} <music21.note.Rest quarter>


    )annotationsN)	TypedDict)environment)exceptions21)	constantsznoteworthy.translatec                  >    \ rS rSr% S\S'   S\S'   S\S'   S\S'   Srg	)
FontDict   bytesnameintsizestylecharset N)__name__
__module____qualname____firstlineno____annotations____static_attributes__r       \/home/james-whalen/.local/lib/python3.13/site-packages/music21/noteworthy/binaryTranslate.pyr	   r	      s    
K
IJLr   r	   c                      \ rS rSrSrg)"NoteworthyBinaryTranslateException   r   N)r   r   r   r   r   r   r   r   r   r      s    r   r   c            	          \ rS rSrSrSS jrSS jrS S!S jjrS"S jrS"S jr	S"S jr
S#S$S	 jjrS"S$S
 jjrS"S%S jjrSSSSSSSSS.rS"S jrS&S jrS'S(S jjrS rSS jrS)S jrS rSrg)*NWCConverter   ay  
A converter object for binary .nwc files.  Do not normally use directly; use converter.parse.

>>> nwcc = noteworthy.binaryTranslate.NWCConverter()
>>> nwcc
<music21.noteworthy.binaryTranslate.NWCConverter object at 0x...>
>>> nwcc.fileContents
b''
>>> nwcc.parsePosition
0
>>> nwcc.version  # version of nwc file to be parsed
200
>>> nwcc.numberOfStaves
0
>>> nwcc.staves
[]
c                   SU l         SU l        SU l        SU l        SU l        SU l        / U l        SU l        / U l        SU l	        SU l
        SU l        SU l        SU l        S U l        SU l        SU l        S U l        SU l        SU l        S U l        S U l        S U l        S U l        S U l        SU l        SU l        0 U l        g )Nr   r         s   Maestro)fileContentsparsePositionversionnumberOfStavestitlePageInfopageNumberStartstavescommentfontslyricistgroupVisibilityallowLayeringmarginsnotationTypefaceextendLastSystem
copyright1
copyright2increaseNoteSpacingauthortitlemeasureStartmeasureNumbersmirrorMarginsstaffLabelssinsuserstaffHeightcurrentAlterations)selfkeywordss     r   __init__NWCConverter.__init__   s    #& &(!%'
"&)"#!'1 $!$!$#'  
 "!		24r   c                    [        US5       nUR                  5       U l        SSS5        U R                  5         U R	                  5       $ ! , (       d  f       N.= f)a"  
Parse a file (calls .toStream)

>>> #_DOCS_SHOW fp = '/Users/cuthbert/desktop/cuthbert_test1.nwc'
>>> fp = str(common.getSourceFilePath()/'noteworthy'/'cuthbert_test1.nwc') #_DOCS_HIDE
>>> nwcc = noteworthy.binaryTranslate.NWCConverter()
>>> nwcc.fileContents
b''
>>> streamObj = nwcc.parseFile(fp)
>>> len(nwcc.fileContents)  # binary
1139
>>> nwcc.fileContents[0:80]
b'[NoteWorthy ArtWare]\x00\x00\x00[NoteWorthy
         Composer]\x00\x01\x02\x02\x00\x00\x00N/A\x000_JldRQMSKq6M5a3FQqK_g\x00\x00\x00'
>>> streamObj
<music21.stream.Score ...>
rbN)openreadr#   parsetoStream)r?   fpfs      r   	parseFileNWCConverter.parseFile  s?    & "d^q !D 

}} ^s   A
Ac                N    Xl         U R                  5         U R                  5       $ )zN
same as parseFile but takes a string (in Py3, bytes) of binary data instead.
)r#   rG   rH   )r?   bytesIns     r   parseStringNWCConverter.parseString$  s     $

}}r   c                    U R                   nU R                  n[        R                  " SX#US-    5      S   nUSL a
  US-   U l        U$ )a  
Helper module: read a little-endian short value to an integer

>>> nwcc = noteworthy.binaryTranslate.NWCConverter()
>>> nwcc.fileContents = b''
>>> nwcc.parsePosition
0
>>> nwcc.readLEShort()
258
>>> nwcc.parsePosition
2
>>> nwcc.readLEShort()
259
>>> nwcc.parsePosition
4

Or to not update the parsePosition, send False:
>>> nwcc.parsePosition = 0
>>> nwcc.readLEShort(False)
258
>>> nwcc.readLEShort(False)
258
>>> nwcc.parsePosition
0
z<h   r   T)r#   r$   structunpackr?   updateParsePositionfcppvalues        r   readLEShortNWCConverter.readLEShort,  sP    4 dB"q&M215$&!#aDr   c                t    U R                   nU R                  n[        X#US-    5      nUSL a
  US-   U l        U$ )z`
changes a byte into an unsigned int
(i.e., if the byte is > 127 then it's subtracted from 256)
r"   T)r#   r$   ordrU   s        r   	byteToIntNWCConverter.byteToIntN  sE    
 B"q&M"$&!#aDr   c                >    U R                  U5      nUS:  a  US-
  nU$ )z]
changes a byte into a signed int
(i.e., if the byte is > 127 then it's subtracted from 256)
      )r^   )r?   rV   vals      r   byteToSignedIntNWCConverter.byteToSignedInt[  s(    
 nn019)C
r   c                ^    U R                   nU R                  nX4XA-    nUSL a	  XA-   U l        U$ )zS
reads the next bytesToRead bytes and then (optionally) updates self.parsePosition
T)r#   r$   )r?   bytesToReadrV   rW   rX   rY   s         r   	readBytesNWCConverter.readBytese  s?     b&'$&!#!1Dr   c                    U R                   n UR                  SU R                  5      nUS:X  a  X R                  S nOX R                  U nUSL a
  US-   U l        U$ ! [         a    Sn NBf = f)z
reads self.fileContents up to, but not including, the next position of \x00.

updates the parsePosition unless updateParsePosition is False
r   NTr"   )r#   indexr$   
ValueError)r?   rV   rW   nulPositionrets        r   	readToNULNWCConverter.readToNULp  s     	((1d&8&89K "''()C''4C$&!,qD
  	K	s   A A-,A-c                    U R                   nSU l         U R                  5       nUS:w  a  gU R                  5       nU R                  5       nU R                  5       nUS:w  a  gUSL a  US:w  a  X l         g)Nr   s   [NoteWorthy ArtWare]Fz[NoteWorthy Composer]T)r$   rp   )r?   rV   storedPPheader1junkheader2s         r   isValidNWCFileNWCConverter.isValidNWCFile  st    %%.."--~~~~.."--%'HM!)r   x                  r!      )i  i  i2  i7  iF  iK  i   i  c                    U R                   nSU l         U R                  U5      nUSL a  X l         X0R                  ;   a   U R                  U   U l        U R                  $ [	        S5        SU l        U R                  $ )N-   Fz:No Version Found! Most likely a newer version.  Using 2.01r   )r$   rZ   versionFromHexr%   print)r?   rV   rs   fileVersionRaws       r   fileVersionNWCConverter.fileVersion  sz    %%))*=>%'!)000..~>DL
 || NODL||r   c                .    U =R                   U-  sl         g N)r$   )r?   numBytess     r   	skipBytesNWCConverter.skipBytes  s    h&r   c                z    U R                   nU R                  nX2US-    U:X  a  US-  nX2US-    U:X  a  M  X l         g )Nr"   )r$   r#   )r?   nulrX   rW   s       r   advanceToNotNULNWCConverter.advanceToNotNUL  sI    BFms"!GB BFms"r   c                V   U R                   SS S:X  a(  SSKnUR                  U R                   SS 5      nX l         SU l        U R	                  5         / U l        [        U R                  5       H7  n[        U S9nUR                  5         U R
                  R                  U5        M9     g)z?
the main parse routine called by parseFile() or parseString()
r      s   [NWZ] N)parent)r#   zlib
decompressr$   parseHeaderr)   ranger&   NWCStaffrG   append)r?   r   fcNewi	thisStaffs        r   rG   NWCConverter.parse  s     Qq!\1OOD$5$5ab$9:E % t**+A -IOOKKy) ,r   c                F   U R                  5         U R                  5         U R                  S5        U R                  5       U l        U R                  5       nU R                  S5        U R                  5       U l        U R                  5       U l        U R                  S:  a  U R                  5       U l        U R                  5       U l	        U R                  5       U l
        U R                  5       U l        U R                  5       U l        U R                  5       U l        U R                  S5      nU R                  5       U l        U R                  S5      nU R#                  5       U l        U R                  S:  a  U R                  5       U l        OSU l        U R                  5       nU R                  S5      nU R                  S:  a+  U R                  S	5      U l        U R                  5       U l        U R                  S:  a  U R                  5       U l        U R#                  5       U l        U R                  S
:  a  SnOU R                  S:  a  SnOSnU R1                  5         U R                  S5        / U l        [5        U5       H  nU R                  5       U R                  5       U R                  5       SS.nU R                  5       nU R                  5       US'   US   S:X  a  SUS'   US   S:X  a  SUS'   U R2                  R7                  U5        M     U R                  5       U l        U R                  5       U l        U R#                  5       U l        U R                  S:  a  U R                  S5        U R                  5       U l        U R                  S5        g)zM
Sets a ton of information from the header, and advances the parse position.
   
   r!      r"   rz   s   0.0 0.0 0.0 0.0rR       r}      r   )r   r   r   r   r   r   r   s   Times New Romanr   N) rw   r   r   rp   r<   r6   r5   r%   r,   r2   r3   r*   r^   r1   r4   rh   r8   rZ   r7   r/   r-   r.   r0   r=   r   r+   r   r   r'   r:   r(   r&   )r?   unused_unknownunused	fontCountr   fontDicts         r   r   NWCConverter.parseHeader  s    	 	qNN$	)r^^%
nn&<<3 NN,DM..*..*~~' $ 0#'>>#3 ""nn." ,,.<<3>>+DL-DL!"<<3#'>>"#5D !%!1D<<3$(NN$4D!++-<<#I\\CIIq
y!A()(	"H ^^%F"&.."2HY3&#5 1$#% JJh' "  "^^-  >>+#//1<<3NN1"nn.qr   c                R   SnU R                   (       a!  USU R                   R                  S5      -   -  nU R                  (       a!  USU R                  R                  S5      -   -  nU/nU R                   H-  nUR	                  5       nU H  nUR                  U5        M     M/     U$ )N z|SongInfo|Title:latin_1z|Author:)r6   decoder5   r)   dumpr   )r?   infosdumpObjectssstaffDumpObjectssdos         r   dumpToNWCTextNWCConverter.dumpToNWCText  s    ::'$***;*;I*FFFE;;Z$++"4"4Y"???EgA vvx'""3' ( 
 r   c                p    SSK Jn  UR                  5       nUR                  U R	                  5       5      nU$ )Nr   )	translate)music21.noteworthyr   NoteworthyTranslator	parseListr   )r?   r   nwtr   s       r   rH   NWCConverter.toStream-  s/    0,,.MM$,,./r   )r.   r5   r*   r2   r3   r>   r1   r#   r+   r-   r4   r,   r/   r8   r7   r9   r0   r&   r(   r$   r;   r=   r:   r)   r6   r'   r<   r%   N)returnNone)rI   zpathlib.Path | str)r   )rN   r   )T)r"   T)r   r   )r   bool)r"   )    )r   r   r   z	list[str])r   r   r   r   __doc__rA   rK   rO   rZ   r^   rd   rh   rp   rw   r   r   r   r   rG   r   r   rH   r   r   r   r   r   r      s{    "5>0 D	.  "!!!!!!!N' *&Pdr   r   c                  D    \ rS rSrSrSS jrS rSS jrS rS r	S r
S	rg
)r   i4  a/  
A NWCStaff is a list of NWCObjects (see :meth:`parseObjects`) associated to metadata
(see :meth:`parseHeader`). It may also contain some lyrics (see :meth:`parseLyrics`).
It defines a :meth:`dump` method that return a list of string containing the
nwctxt-formatted content of each object of the staff.
c                    Xl         / U l        / U l        SU l        S U l        S U l        S U l        S U l        S U l        SU l	        S U l
        SU l        SU l        SU l        S U l        SU l        SU l        SU l        g )Nr   r   )r   lyricsobjectsinstrumentNamegrouplayerWithNextStafftransposition
partVolume	stereoPancoloralignSyllablenumberOfLyricsnumberOfObjectslinesr   staffOffsetlabellyricAlignment)r?   r   s     r   rA   NWCStaff.__init__;  s    $*)+(*%(
"&!
! 
	
r   c                d    U R                  5         U R                  5         U R                  5         g r   )r   parseLyricsparseObjects)r?   s    r   rG   NWCStaff.parseO  s&    r   c                X   / nU R                   (       a  U R                   R                  S5      OSnU R                  (       a  U R                  R                  S5      OUnSU-   nUR                  U5        SU-   nU[        R
                  ;   a0  US-  nU[        [        R
                  R                  U5      5      -  nUS[        U R                  5      -   -  nUR                  U5        U R                   H0  nUR                  nU" U5      nUS:w  d  M  UR                  U5        M2     U$ )Nr   zAcoustic Grand Pianoz|AddStaff|Name:z|StaffInstrument|Name:z|Patch:z|Trans:r   )r   r   r   r   r   MidiInstrumentsstrrl   r   r   
dumpMethod)	r?   r   
instruNamer   staffStringstaffInstruStringodmds	            r   r   NWCStaff.dumpX  s    ,, ))00;1 	 15



!!),
'%/;'4zA222*Y%>%>%D%DZ%P!QQYT-?-?)@@@,-AB1ABw""1%	  r   c                   U R                   nUR                  5       U l        UR                  S:  a*  UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  S:  a  UR                  S5        UR                  5       U l	        UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        OUR                  S:X  a  UR                  S5        UR                  5       nSUs=:  a  [%        [&        R(                  5      :  a  O  OUS-
  OSn[&        R(                  U   R+                  S5      U l        UR                  S5        UR-                  5       U l        UR                  S	5        UR                  5       U l        UR                  5       U l        U R"                  S:  a+  UR                  5       U l        UR                  5       U l        g SU l        SU l        g )
Nr!      r~      r   r"   r   r   r   )r   rp   r   r%   r   r   r   r   r^   r   rZ   r   r   r   r   r   r   r   lenr   r   encoderd   r   r   )r?   pinstruPatchrl   s       r   r   NWCStaff.parseHeaderu  s   KKKKM	99DJ"#++-D[[]
 99" KKODJ '(mmoD#!"DmmoDO]]_DNDJ!"D"#--/DYY#KKO++-K'(;'WY=V=V9W'WK!O]^E"+";";E"B"I"I)"TDKKO!"!2!2!4DKKN!"D"#--/D""#--/D }}D"#D Dr   c                   U R                   n/ n[        U R                  5       H  n/ n UR                  5       nUS:  d  M  UR                  5       nUR                  nUR                  5       nSn	Sn
U	SL aB  U
S:  a<  UR                  5       nU
S-  n
US:X  a  Sn	OUR                  U5        U	SL a  U
S:  a  M<  Xu-   Ul        UR                  U5        M     U R                  S:  a  UR                  5       nUR                  5       nX l        U$ ! [        R
                   a    Sn[        R                  S5         GNf = f)Nr   z/Could not read lyrics. Trying with zero length.Ti  r"   r   F)r   r   r   rZ   rS   errorenvironLocalwarnr$   rp   r   r   )r?   r   r   r   	syllableslyricBlockSizeunused_lyricSizeparsePositionStartru   
continueItmaxReadsyllablejunk_2s                r   r   NWCStaff.parseLyrics  s1   KKt**+AIU!" !#$==? %&__" }}!
 D(Wq[ {{}HqLG3%*
!((2 !D(Wq[ #5"Ei(7 ,< "==?D? << U!"!!"STUs   D+D>=D>c                .   U R                   n/ nUR                  5       U l        UR                  S:  a  U =R                  S-  sl        [	        U R                  5       H-  n[        XS9nUR                  5         UR                  U5        M/     X l        U$ )Nr{   rR   staffParentparserParent)	r   rZ   r   r%   r   	NWCObjectrG   r   r   )r?   r   r   r   
thisObjects        r   r   NWCStaff.parseObjects  s    KK }}99s?  A%  t++,A"tDJNN:& - r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   N)r   r   r   r   r   )r   r   r   r   r   rA   rG   r   r   r   r   r   r   r   r   r   r   4  s'     (::!z(Tr   r   c                      \ rS rSrSrSS jrS rS rS rS r	S r
S	 rS
 rS rS rS rS rS rS rS rS rS rS rS rS rS rS r\\\	\
\\\\\\\\\\\\\\\/rSrg)r   i  a>  
NWCObject class is a union that can be used for each type of object contained in a staff.

An object binary blob starts with its type.
The parse() method calls the appropriate method depending on the object type.
Each parsing method should set up the 'dumpMethod' method that return the nwctxt version
of the object.
c                T   Xl         X l        S U l        SU l        SU l        SU l        SU l        SU l        S U l        S U l	        S U l
        SU l        SU l        SU l        SU l        SU l        S U l        SU l        SU l        SU l        S U l        S U l        S U l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l         S U l!        SU l"        SU l#        SU l$        SU l%        SU l&        S U l'        S U l(        SS jnX0l)        g )Nr   r   c                    g)Nr   r   
inner_selfs    r   genericDumpMethod-NWCObject.__init__.<locals>.genericDumpMethod!  s    r   )r   r   )*r   r   type	placementposr   localRepeatCountdatadata1data2data3delayclefTypeoffsetvisibledurationdurationStrfontsharpsoctaveShiftoctaveShiftNameclefName
attribute1
attribute2
stemLengthdotsbitsdenominatortieInfovolumebasevelocitycountr   rY   flats	keyString	numeratoralterationStrdotAttributetextr   )r?   r   r   r  s       r   rA   NWCObject.__init__  s2   %0*6	
 !	



	#			
	

 		 ,r   c                J   U R                   nUR                  5       nU[        U R                  5      :  d  US:  a$  [	        SU S[        U R                  5       35      eUR
                  S:  a  UR                  5       U l        OSU l        U R                  U   nU" U 5        g)z@
determine what type of object I am, and set things accordingly
r   zCannot translate objectType: z	; max is r}   N)r   rZ   r   
objMethodsr   r%   r^   r  )r?   r   
objectTypeobjectMethods       r   rG   NWCObject.parse&  s     ]]_
T__--a4/
|9SEYDZ[] ]99;;=DLDLz2Tr   c                   U R                   nSU l        UR                  5       U l        UR                  5       U l        U R                  [        [        R                  5      :  a"  [        R                  U R                     U l        U R                  [        [        R                  5      :  a"  [        R                  U R                     U l
        S nX l        g)z
clef info,
4 bytes
Clefc                    SnU R                   (       a  USU R                   -   S-   -  nU R                  (       a  USU R                  -   S-   -  nU$ )Nz|Clef|zType:|zOctaveShift:)r  r  r  builds     r   r   NWCObject.clef.<locals>.dumpL  sR    E"":#6#66<<))**D*DDsJJLr   N)r   r  rZ   r  r  r   r   	ClefNamesr  OctaveShiftNamesr  r   r?   r   r   s      r   clefNWCObject.clef;  s    
 	==?==3y2233%//>DMc)"<"<==#,#=#=d>N>N#OD 	 r   c                &   U R                   nSU l        UR                  5       U l        UR	                  S5        UR                  5       U l        UR	                  S5        U R                  S:  aA  U R                  [        R                  ;   a#  [        R                  U R                     U l        OXU R
                  S:  aA  U R
                  [        R                  ;   a#  [        R                  U R
                     U l        OSU l        S nX l
        g)z
Key signature
10 bytes
KeySigr"      r   r   c                $    SU R                   -   nU$ )Nz|Key|Signature:)r%  r4  s     r   r   NWCObject.keySig.<locals>.dumpn  s    %
(<(<<ELr   N)r   r  r^   r$  r   r  r   FlatMaskr%  	SharpMaskr   r9  s      r   keySigNWCObject.keySigV  s    
 	[[]
	Akkm	A ::>djjI,>,>>&//

;DN[[1_	0C0C!C&00=DNDN	 r   c                    U R                   nSU l        UR                  5       U l        UR                  5       U l        0 U R                   l        S nX l        g)z
Bar line
2 bytes
Barlinec                    SnSU R                   s=:  a  [        [        R                  5      :  a)  O  U$ [        R                  U R                      nUSU-   -  nU$ )Nz|Bar|r   z|Style:)r   r   r   	BarStyles)r  r5  styleStrings      r   r   NWCObject.barline.<locals>.dump  sX    E:##>c)*=*=&>> L (11*2B2BC[00Lr   N)r   r  r^   r   r	  r>   r   r9  s      r   barlineNWCObject.barlinet  sK    
 	[[]
 !/1,	 r   c                    U R                   nSU l        UR                  5       U l        UR	                  S5        S nX l        g)z
Endings
2 bytes
Endingr"   c                2    S[        U R                  5      -   $ )Nz|Ending|Endings:)r   r   r  s    r   r   NWCObject.ending.<locals>.dump  s    %J,<,<(===r   N)r   r  r^   r   r   r   r9  s      r   endingNWCObject.ending  s:    
 	[[]
	A	> r   c                L    U R                   nSU l        UR                  S5        g)z
Instrument
8 bytes

Instrument   N)r   r  r   r?   r   s     r   
instrumentNWCObject.instrument  s#    
  	 	
Ar   c                    U R                   nSU l        UR                  5       U l        UR                  5       U l        SU R                  -  U l        UR                  5       U l        S nX l        g)z
Time signature
6 bytes
TimeSigr"   c                >    SU R                    SU R                   3nU$ )Nz|TimeSig|Signature:/)r&  r  r4  s     r   r   NWCObject.timeSig.<locals>.dump  s'    )**>*>)?qAWAW@XYELr   N)r   r  rZ   r&  r  r  r   r   r9  s      r   timeSigNWCObject.timeSig  sY    
 	MMO			>]]_
	 r   c                N   U R                   nSU l        UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  S:  a  UR                  5       nUR                  5       U l
        S nX0l        g)z4
Tempo indications
5 bytes + null terminated string
Tempor}   c                     SU R                    3$ )Nz|Tempo|Tempo:)rY   r  s    r   r   NWCObject.tempo.<locals>.dump  s    ":#3#3"455r   N)r   r  r^   r  r  rZ   rY   r!  r%   rp   r)  r   )r?   r   ru   r   s       r   tempoNWCObject.tempo  sy    
 	;;=]]_
KKM	99s?==?DKKM		6 r   c                4   U R                   nSU l        UR                  S:  a  [        S5        gUR	                  5       U l        UR	                  5       U l        UR	                  5       U l        UR                  5       U l	        UR                  5       U l
        g)z
dynamics
7 bytes
Dynamicr}   z3Dynamics on version below 1.70 is not supported yetN)r   r  r%   r   r^   r  r  r   rZ   r"  r   rV  s     r   dynamicNWCObject.dynamic  sk    
 	99s?GH{{}DH[[]DNDJMMODM--/DKr   c                   [         R                  U R                     nSnSnU R                  S:X  a'  U R                  S   U l        U R                  S   S-  nOU R                  S   U l        U R                  S   S-  nU R
                  nUS-  S:  a  SU l        OUS	-  S:  a  SU l        OSU l        U R                  S:X  a  US
-  nOU R                  S:X  a  US-  nUS:  a  US-  nU(       a  US-  nU$ )z&
get duration string for note or rest
r   FNoter"   r      r   rR   r   z,Dottedz
,DblDottedz,Gracez,Triplet)r   DurationValuesr  r  r  r(  r  r  )r?   durStrgracetripletordDots        r   setDurationForObjectNWCObject.setDurationForObject  s    
 ))$--899 $ 2DOOA&-E $

1D **Q-$&""TMQDItmq DIDI99>iFYY!^l"F19hFj Fr   c                   U R                   nSU l        UR                  S:  a  [        S5        OUR	                  5       U l        UR                  S5      U l        UR                  S5      U l        UR                  5       U l
        SU R                  -  U l
        UR	                  5       U l        UR                  S::  a  UR                  S5      U l        OSU l        UR                  S:  a1  U R                  S	-  S
:w  a  UR	                  5       U l        OSU l        OSU l        U R                  5       U l        U R                  S-  nU[!        ["        R$                  5      :  a  ["        R$                  U   U l        OSU l        U R&                  S:X  a8  U R                   R(                  R+                  U R                  S-  S5      U l        U R&                  c  SU l        U R&                  U R                   R(                  U R                  S-  '   SU l        U R                  S
   nUS-  S
:  a  SU l        S nX@l        g)z
Note
8 bytes
rk  r}   z%Cannot yet handle versions before 170rl  rR   rk   Nr!   @   r   r>  r      ^c                    SU R                   -   S-   nUSU R                  -   [        U R                  5      -   U R                  -   S-   -  nU$ )Nz
|Note|Dur:r3  zPos:)r  r'  r   r  r  r4  s     r   r   NWCObject.note.<locals>.dumpD  sc     :#9#99C?Ef"001JNN+, #**+ .11 2E Lr   )r   r  r%   r   r^   r  rh   r  r  rd   r  r  r  r  rr  r  r   r   AlterationTextsr'  r>   getr  r   )r?   r   alterationIndexordAtt1r   s        r   noteNWCObject.note  s   
 	99s?9:KKMDMQDJkk!nDO((*DHDHH}DHkkmDOyyC[[^
!
yyCOOd*q0&'kkmDO '(DO"#  446//D0S!:!:;;!*!:!:?!KD!#D #!%!2!2!E!E!I!I$((UV,XZ![D%!#D=A=O=O,,TXX\://!$dNaDL	 r   c                   U R                   nSU l        UR                  S::  a  [        S5        O@UR	                  5       U l        UR                  S5      U l        UR                  5       U l	        U R                  5       U l        S nX l        g)z
Rest
8 bytes
Restr{   z Does not work under version 1.50r   c                *    SU R                   -   S-   nU$ )Nz
|Rest|Dur:r3  )r  r4  s     r   r   NWCObject.rest.<locals>.dump_  s     :#9#99C?ELr   N)r   r  r%   r   r^   r  rh   r  rZ   r  rr  r  r   r9  s      r   restNWCObject.restO  sq    
 	9945KKMDMQDJ--/DK446	 r   c                   U R                   nSU l        SnUR                  S::  a  UR                  S5      U l        OLUR                  S:X  a&  UR                  S5      U l        U R                  S   nOUR                  S5      U l        UR                  S:  a?  U R                  S	   S
-  S:w  a!  [        S5        UR                  5       U l        OS	U l        OS	U l        / U l        [        R                  (       a  [        U [        5      (       d   e[        U5       H7  n[        XS9nUR                  5         U R                  R!                  U5        M9     S nXPl        g)z'
Chord member
8 bytes + n Note objects
NoteChordMemberr   r}   r   r~   r   rU  r!   r>  ru  zhave stemLength info!r   c                l   Sn0 nU R                    Hw  nUR                  UR                  5      c  / X#R                  '   X#R                     R                  UR                  [        UR                  5      -   UR                  -   5        My     U H"  nUSU-   S-   SR                  X$   5      -   -  nM$     U$ )N|Chord|Dur:|Pos:,)	r  r{  r  r   r'  r   r  r  join)r  r5  notesr   ns        r   r   'NWCObject.noteChordMember.<locals>.dump  s    EE%%99Q]]+3+-E--(mm$++AOOc!%%j,H199,TU	 & 1w.%(1CCC  Lr   N)r   r  r%   rh   r  r   r^   r  r  tTYPE_CHECKING
isinstancer   r   r   rG   r   r   )r?   r   numberOfNotesr   	chordNoter   s         r   noteChordMemberNWCObject.noteChordMembere  s   
 %	99RDJYY#RDJ JJqMMQDJ99

1$*-."#++- #$DO
??dH----}%A!dCIOOJJi( &
	 r   c                    U R                   nSU l        UR                  S:  a  [        S5        gUR	                  5       U l        UR	                  5       U l        UR	                  5       U l        g)z
Pedal
3 bytes
Pedalr}   z/Pedal on version below 170 is not yet supportedN)r   r  r%   r   r^   r  r  r   rV  s     r   pedalNWCObject.pedal  sQ    
 	99s?CD{{}DH[[]DNDJr   c                    U R                   nSU l        UR                  S:  a+  UR                  5       U l        UR                  5       U l        OSU l        SU l        UR                  5       U l        g)z
Flow
4 bytes
FlowDirr}   ir"   N)r   r  r%   r^   r  r  rZ   r   rV  s     r   flowDirNWCObject.flowDir  sW    
 	99{{}DH[[]DNDH!DN]]_
r   c                F   U R                   nSU l        UR                  5       U l        UR                  5       U l        UR
                  S:X  a  UR                  S5      U l        gUR
                  S:  a  UR                  S5      U l        gUR                  S5      U l        g)z
Midi Instructions
34 bytes
MPCr~   r   r|      N)r   r  r^   r  r  r%   rh   r  rV  s     r   mpcNWCObject.mpc  st    
 	;;=99RDJYY_RDJRDJr   c                   U R                   nSU l        UR                  S:  aU  UR                  5       U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        gUR                  5       U l        U R                  S-  U l        UR                  5       U l        UR                  5       U l        UR                  5       U l        g)z
Tempo variation
4 bytes
TempoVariationr}      N)r   r  r%   r^   r  r  r   r  rV  s     r   tempoVariationNWCObject.tempoVariation  s    
 $	99{{}DH[[]DNDJDJDJd*DJ{{}DH[[]DNDJr   c                    U R                   nSU l        UR                  5       U l        UR                  S:  a  UR                  5       U l        OSU l        UR                  5       U l        g)z
Dynamic variation
3 bytes
DynamicVariationr}   r   Nr   r  r^   r  r%   r  r   rV  s     r   dynamicVariationNWCObject.dynamicVariation  sP    
 &	;;=99[[]DNDN[[]
r   c                    U R                   nSU l        UR                  5       U l        UR                  S:  a  UR                  5       U l        OSU l        UR                  5       U l        g)z
Performance
3 bytes
Performancer}   r   Nr  rV  s     r   performanceNWCObject.performance  sP    
 !	;;=99[[]DNDN[[]
r   c                
  ^  T R                   nST l        UR                  5       T l        UR	                  5       T l        UR	                  5       T l        UR                  5       T l        U 4S jnT R                  b  UT l	        gg)z'
Text
3 bytes + null terminated string
Textc                v   > SU R                   R                  S5      -   S-   [        TR                  5      -   nU$ )Nz|Text|Text:r   r  )r)  r   r   r  )r  r5  r?   s     r   r   NWCObject.textObj.<locals>.dump  s8    !JOO$:$:9$EEORUVZV^V^R__ELr   N)
r   r  rd   r  r^   r
  r  rp   r)  r   r9  s   `  r   textObjNWCObject.textObj  sk    
 	$$&KKM	KKM	KKM		 99 "DO !r   c                l   U R                  5         SU l        [        R                  (       a  [	        U [
        5      (       d   e[        X R                  S9nU R                  S   Ul	        U R                  Ul
        UR                  5       Ul        U R                  R                  U5        S nX l        g)z
Rest chord
10 bytes
RestChordMemberr   r   c                   Sn0 nU R                    Hw  nUR                  UR                  5      c  / X#R                  '   X#R                     R                  UR                  [        UR                  5      -   UR                  -   5        My     SnU HY  nU[        U5      S-
  :X  a   USU-   S-   SR                  X%   5      -   -  nOUSU-   S-   SR                  X%   5      -   -  nUS-  nM[     U$ )	Nr  r   r"   z|Dur2:z|Pos2:r  r  r  )
r  r{  r  r   r'  r   r  r  r   r  )r  r5  r  r   r   r  s         r   r   'NWCObject.restChordMember.<locals>.dump  s    EE%%99Q]]+3+-E--(mm$++AOOc!%%j,H199,TU	 & AE
Q&X\H4sxx7IIIEWq[72SXXeh5GGGEQ  Lr   N)r  r  r  r  r  r   r   r   r  r  r  rr  r  r   r   )r?   r  r   s      r   restChordMemberNWCObject.restChordMember
  s    
 	%	??dH----T8I8IJ

1ZZ
446

$	& r   )*r'  r  r  r!  r  r  r  r#  r
  r  r  r  r  r  r(  r  r   r  r  r$  r  r%  r	  r   r&  r  r  r  r   r  r  r  r   r  r   r)  r  r  rY   r"  r  r   N)r   r   r   r   )r   r   r   r   r   rA   rG   r:  rC  rK  rQ  rW  r^  rd  rh  rr  r~  r  r  r  r  r  r  r  r  r  r  r,  r   r   r   r   r   r     s    .,`*6<,	$** &PJX,/f'% ) '&###*"N ! "!%Jr   r   __main__)r   
__future__r   pathlibrS   typingr  r   music21r   r   r   r   Environmentr   r	   Music21Exceptionr   r   r   r   r   mainTestr   r   r   <module>r     s   ul #        (&&'=>y 	)F)F 	V Vr
v vrW	 W	t z r   