Began versioning from nwc2ly.py v0.9.0
authorW. Trevor King <wking@drexel.edu>
Thu, 25 Nov 2010 21:17:29 +0000 (16:17 -0500)
committerW. Trevor King <wking@drexel.edu>
Thu, 25 Nov 2010 21:17:35 +0000 (16:17 -0500)
Downloaded from
  http://lily4jedit.svn.sourceforge.net/viewvc/lily4jedit/trunk/LilyPondTool/otherpatches/nwc2ly.py?revision=410&view=markup&pathrev=476

nwc2ly.py [new file with mode: 0644]

diff --git a/nwc2ly.py b/nwc2ly.py
new file mode 100644 (file)
index 0000000..028cc45
--- /dev/null
+++ b/nwc2ly.py
@@ -0,0 +1,1061 @@
+import binascii, sys, zlib, traceback \r
+\r
+shortcopyleft = """\r
+nwc2ly - Converts NWC(v 1.75) to LY fileformat\r
+Copyright (C) 2005  Joshua Koo (joshuakoo @ myrealbox.com)\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+"""\r
+\r
+##\r
+# most infomation obtained about the nwc format \r
+# is by using noteworthycomposer and the somewhat like the french cafe method\r
+# (http://samba.org/ftp/tridge/misc/french_cafe.txt)\r
+#\r
+#\r
+## \r
+# Revisions\r
+# 0.1  07 april 2005 initial hex parsing;\r
+# 0.2  13 april 2005 added multiple staff, keysig, dots, durations\r
+# 0.3  14 april 2005 clef, key sig detection, absolute notes pitching\r
+# 0.4   15 April 2005 Relative Pitchs, Durations, Accidentals, Stem Up/Down, Beam, Tie\r
+# 0.5   16 April 2005 Bug fixes, Generate ly score , Write to file, Time Sig, Triplets, Experimental chords\r
+# 0.6  17 April 2005 Compressed NWC file Supported!\r
+# 0.7  19 April 2005 Version detection, Header \r
+#      20 April 2005 BUGS FiXes, small Syntax changes\r
+#      21 April 2005 Still fixing aimlessly \r
+#      23 April 2005 Chords Improvement\r
+#      24 April 2005 staccato, accent, tenuto. dynamics, midi detection (but unsupported)\r
+# 0.8  24 April 2005 Experimental Lyrics Support\r
+# 0.9  29 April 2005 Workround for \acciaccatura, simple Check full bar rest adjustment\r
+#      \r
+## \r
+# TODO\r
+# Proper syntax and structure for staffs, lyrics, layering\r
+# version 1.7 Support\r
+# nwc2ly in lilytool\r
+# \r
+# Piano Staff\r
+# Chords\r
+# Pedals\r
+# Midi Instruments\r
+# Visability\r
+# Lyrics\r
+# Context Staff\r
+# Staff layering / Merging\r
+##\r
+#\r
+# BUGS text markups, chords, fermata\r
+######\r
+# \r
+# cd /cygdrive/c/development/nwc2ly\r
+# $ python nwc2ly.py lvb7th1\ uncompressed.nwc test.ly > convert.log\r
+#######\r
+\r
+nwc2lyversion = '0.9.0'\r
+############\r
+# Options  #\r
+############\r
+debug = 0 \r
+       # You can use 0 for False and 1 for True\r
+relativePitch = 1\r
+relativeDuration = 1\r
+barLinesComments = 10 # Comments for every x lines     # section/line comment\r
+\r
+insertBeaming = 1\r
+insertSteming = 1\r
+#insertText = 0\r
+\r
+nwcversion = 1.75\r
+##############\r
+\r
+args =  len(sys.argv)\r
+if args<2:\r
+       print "Syntax: python nwc2ly.py nwcfile [lyfile]"\r
+       sys.exit()\r
+nwcfile = sys.argv[1] # 'simple1.nwc' #'simple2.nwc' 'simple3.nwc' 'bbc5-1-org.nwc' bbc5-1-nop.\r
+\r
+if args<3:\r
+       lyfile = ''  # 'test.ly'\r
+else:\r
+       lyfile = sys.argv[2]\r
+\r
+\r
+\r
+def getFileFormat(nwcData):\r
+       #'[NoteWorthy ArtWare]'\r
+       #'[NoteWorthy Composer]'\r
+       nwcData.seek(0)\r
+       company = readLn(nwcData)\r
+       nwcData.seek(2,1) # pad\r
+       product = readLn(nwcData)\r
+       version = readLn(nwcData)\r
+       version = ord(version[0]) * 0.01 + ord(version[1])\r
+       nwcversion = version\r
+       print 'NWC file version', nwcversion, 'detected!'\r
+       pad(nwcData,2) # times saved\r
+       name1 = readLn(nwcData)\r
+       name2 = readLn(nwcData)\r
+       \r
+       pad(nwcData,8)\r
+       huh = nwcData.read(1)\r
+       pad(nwcData,1)\r
+       \r
+def getFileInfo(nwcData):\r
+       title = readLn(nwcData)\r
+       author = readLn(nwcData)\r
+       copyright1 = readLn(nwcData)\r
+       copyright2 = readLn(nwcData)\r
+       comments = readLn(nwcData)\r
+       \r
+       header = "\\header {"\r
+       header += "\n\ttitle = \"%s\"" % title\r
+       header += "\n\tenteredby = \"%s\"" % author\r
+       header += "\n\tcopyright = \"%s\"" % copyright1\r
+       header += "\n\tfooter = \"%s\"" % copyright2\r
+       header += "\n\t%%{ %s %%}" % comments\r
+       header += "\n}"\r
+               \r
+       # TO ADD IN DEFAULT BLANK FEILDS TO KEY IN\r
+       print 'title,author,copyright1,copyright2,comments: ', (title,author,copyright1,copyright2,comments)\r
+       return header\r
+\r
+# Page Setup\r
+def getPageSetup(nwcData):\r
+       # ??\r
+       getMargins(nwcData)\r
+       #getContents(nwcData)\r
+       #getOptions(nwcData)\r
+       getFonts(nwcData)\r
+\r
+       \r
+def getMargins(nwcData):\r
+       readTill(nwcData,'\x01')\r
+       pad(nwcData,1)\r
+       # get string size 43\r
+       margins = readLn(nwcData)\r
+       print 'margins ', margins\r
+       #mirrorMargines\r
+       #UOM\r
+       return \r
+\r
+def getOptions(nwcData):\r
+       # page numbering, from\r
+       # title page info\r
+       # extend last system\r
+       # incrase note spacing for larger note duration\r
+       # staff size\r
+       # staff labels (none, first systems, top systems, all systems\r
+       # measure numbers none, plain, circled, boxed\r
+       # measure start\r
+       return\r
+\r
+def getFonts(nwcData):\r
+       # 12 Times\r
+       readTill(nwcData,'\xFF')\r
+       n = nwcData.read(1)\r
+       pad(nwcData,1)\r
+       for i in range (12):\r
+               # Font Name\r
+               font = readLn (nwcData)\r
+               \r
+               # 00\r
+               \r
+               # Style 'Regular' 'Italic' 'Bold' 'Bold Italic'\r
+               style = ord(nwcData.read(1)) & 3\r
+               \r
+               # Size\r
+               size = ord(nwcData.read(1))\r
+               \r
+               ## 00\r
+               nwcData.seek(1,1)\r
+               \r
+               # Typeface\r
+               # 00 Western, b1 Hebrew\r
+               typeface = nwcData.read(1)\r
+               \r
+               print 'Font detected' , font, 'size',size, 'style ', style, ' typeface',typeface\r
+               \r
+\r
+def findNoOfStaff(nwcData):\r
+       # Infomation on Staffs \x08 00 00 FF 00 00 n\r
+       data = 0;\r
+       \r
+       readTill(nwcData,'\xFF')\r
+       print "Where am I? ", nwcData.tell()\r
+       \r
+       \r
+       nwcData.read(2)\r
+       \r
+       layering = nwcData.read(1) # FF or 00\r
+       \r
+       noOfStaffs = ord(nwcData.read(1))\r
+       nwcData.read(1)\r
+       print noOfStaffs, " noOfStaffs found"\r
+       return noOfStaffs\r
+\r
+def findStaffInfo(nwcData):\r
+       # Properties for Staff\r
+               # General \r
+                       # Name.\r
+                       # Group\r
+                       # Ending Bar\r
+               # Visual\r
+                       # Verticle Upper Size\r
+                       # Verticle Lower Size\r
+                       # Style\r
+                       # Layer Next Staff\r
+                       # Color\r
+               # Midi\r
+                       # Part Volume\r
+                       # Stereo Pan\r
+                       # Transposition\r
+                       # Muted\r
+                       # PlayBack Device\r
+                       # Playback Channel\r
+               # Instrument\r
+                       # Patch Name\r
+                       # Patch List Type\r
+                       # Bank Select \r
+                       # Controller0\r
+                       # Controller32\r
+       # Staff Lyrics\r
+               # LineCount\r
+               # AlignSyllableRule\r
+               # StaffPlacementAligment\r
+               # StaffPlacementOffset\r
+               # StaffPropertiesVerticleSizeUpper\r
+               # StaffPropertiesVerticleSizeLower\r
+               \r
+       format = ''\r
+       staffName = readLn(nwcData)\r
+       format += "\\context Staff = %s " % staffName # or voice or lyrics \r
+       \r
+       groupName = readLn(nwcData) # HOW TO ORGANISE THEM??\r
+       \r
+       endbar = ord(nwcData.read(1)) # & (2^3-1)\r
+       #print 'end ',endbar\r
+       endingBar = ending[endbar] #  10 --> OC for lyrics?  10000 1100\r
+       \r
+       muted = ord(nwcData.read(1)) & 1\r
+       nwcData.read(1)\r
+       \r
+       channel = ord(nwcData.read(1)) + 1\r
+       nwcData.read(9)\r
+       \r
+       stafftype = staffType[ord(nwcData.read(1))&3]\r
+       nwcData.read(1)\r
+       \r
+       uppersize = 256 - ord(nwcData.read(1))  # - signed +1 )& 2^7-1 )\r
+       readTill(nwcData,'\xFF')\r
+       \r
+       lowersize = ord(nwcData.read(1))\r
+       ww = nwcData.read(1) \r
+       print '[uppersize,lowersize]',[uppersize,lowersize]\r
+       \r
+       noOfLines = ord(nwcData.read(1))\r
+       print '[staffName,groupName,endingBar,stafftype,noOfLines]', [staffName,groupName,endingBar,stafftype,noOfLines]\r
+       \r
+       layer = ord(nwcData.read(1)) & 1\r
+       \r
+       # signed transposition\r
+       # FF?\r
+       \r
+       partVolume = ord(nwcData.read(1))\r
+       ord(nwcData.read(1))\r
+       \r
+       stereoPan = ord(nwcData.read(1))\r
+       if nwcversion == 1.7:\r
+               nwcData.read(2)\r
+       else:\r
+               nwcData.read(3)\r
+       \r
+       nwcData.read(2)\r
+       #lyrics = ord(nwcData.read(1)) & 1\r
+       lyrics = readInt(nwcData)\r
+       noOfLyrics = readInt(nwcData)\r
+       \r
+       lyricsContent = ''\r
+       if lyrics:\r
+               lyricOptions = readInt(nwcData)\r
+               nwcData.read(3)\r
+               for i in range(noOfLyrics):\r
+                       print 'looping ',i, 'where', nwcData.tell()\r
+                       lyricsContent  += '\\ \lyricmode { ' # lyrics\r
+                       lyricsContent  += getLyrics(nwcData) #\r
+                       lyricsContent  += '}'\r
+               nwcData.read(1)\r
+       \r
+       nwcData.read(1)\r
+       color = ord(nwcData.read(1)) & 3 #12\r
+       \r
+       noOfTokens = readInt(nwcData)\r
+       print noOfTokens, " Tokens found", nwcData.tell()\r
+       return noOfTokens, format, lyricsContent\r
+       \r
+\r
+\r
+\r
+\r
+def pad(nwcData, length):\r
+       nwcData.seek(length,1)\r
+\r
+def readTill(nwcData, delimit):\r
+       data = ''\r
+       value = ''\r
+       while data!=delimit:\r
+               value += data\r
+               data = nwcData.read(1)\r
+               \r
+       return value\r
+       \r
+def readLn(nwcData):\r
+       return readTill (nwcData,'\x00')\r
+       # reads until 00 is hit\r
+       # od oa == \n\r
+\r
+def readInt(nwcData):\r
+       data = nwcData.read(2)\r
+       no = ord(data[0])\r
+       no += ord(data[1]) * 256\r
+       return no\r
+\r
+\r
+def getLyrics(nwcData):\r
+       \r
+       data = ''\r
+       print 'reach'\r
+       blocks = ord(nwcData.read(1))\r
+       if blocks==4: blocks = 1\r
+       if blocks==8: blocks = 2\r
+       if blocks == 0: return \r
+       \r
+       lyricsLen = readInt(nwcData)\r
+       \r
+       print 'blocks ',blocks, 'lyrics len', lyricsLen, 'at ', nwcData.tell()\r
+       \r
+       nwcData.read(1)\r
+       for i in range (blocks):\r
+               data += nwcData.read(1024)\r
+       \r
+       lyrics = data[1:lyricsLen-1]\r
+       print 'lyrics ', lyrics\r
+       return lyrics\r
+       \r
+def getDuration(data):\r
+       durationBit = ord(data[2]) & 7\r
+       durationDotBit = ord(data[6]) \r
+       \r
+       duration = durations[durationBit]\r
+       if (durationDotBit & 1<<2):\r
+               durationDot = '.'\r
+       elif (durationDotBit & 1):\r
+               durationDot = '..'\r
+       else :\r
+               durationDot = ''\r
+       return duration + durationDot\r
+\r
+def getKey(data):\r
+       data = binascii.hexlify(data)\r
+       \r
+       if (keysigs.has_key(data)):\r
+               return '\key ' + keysigs[data]\r
+       return '% unknown key'\r
+\r
+def getLocation(data):\r
+       offset = ord(data[8]);\r
+       if offset > 127 :\r
+               return 256-offset\r
+       if (ord(data[9])>>3 & 1):\r
+               return -offset\r
+       \r
+       return offset\r
+       #print 'offset ', offset\r
+       #print binascii.hexlify(data[8:9])\r
+\r
+def getAccidental(data):\r
+       data = ord(data)\r
+       data = (data & 7 )\r
+       return acdts[data]\r
+\r
+def getNote(data):\r
+       \r
+       # pitch\r
+       pitch = getLocation(data)\r
+       \r
+       # get Accidentals\r
+       accidental =  getAccidental(data[9])\r
+       \r
+       # get Relative Duration\r
+       duration = getDuration(data)\r
+       \r
+       # check stems\r
+       stem = ord(data[4])\r
+       stem = (stem >> 4) & 3\r
+       \r
+       # check beam\r
+       beam = ord(data[4]) & 3\r
+       \r
+       # triplets \r
+       triplet = triplets [ord(data[4])>>2 & 3 ]\r
+       \r
+       # check tie\r
+       tie = ''\r
+       if ord(data[6]) >> 4 & 1:\r
+               tie = '~'\r
+       \r
+       staccato = (ord(data[6]) >> 1) & 1\r
+       accent = (ord(data[6]) >> 5) & 1\r
+       \r
+       tenuto = (ord(data[7]) >> 2) & 1\r
+       slur = slurs[ord(data[7]) & 3 ]\r
+       grace = (ord(data[7]) >> 5) & 1\r
+       \r
+       # check slur\r
+       slur = slurs[ord(data[7]) & 3 ]\r
+       \r
+       \r
+       #TODO should use a dictionary\r
+       return (pitch, accidental, duration, stem, beam, triplet, slur, tie, grace, staccato, accent, tenuto)\r
+\r
+def getRelativePitch(lastPitch, pitch):\r
+       octave = ''\r
+       diff = pitch - lastPitch\r
+       if diff>3:\r
+               for i in range((diff-4 + 7)/7):\r
+                       octave += "'"\r
+               if octave == '':\r
+                       octave += "'"\r
+       elif diff<-3:\r
+               for i in range((-diff-4 + 7)/7):\r
+                       octave += ","\r
+               if octave == '':\r
+                       octave += ","\r
+       return octave\r
+       \r
+def durVal(duration):\r
+       where = duration.find('.')\r
+       \r
+       if where>-1:\r
+               durVal = 128/int (duration[:where])\r
+               nextVal = durVal\r
+               for i in range(len(duration)-where):\r
+                       nextVal = nextVal / 2\r
+                       durVal += nextVal\r
+               \r
+       else:\r
+               durVal = 128/int (duration)\r
+       return durVal\r
+       \r
+def processStaff(nwcData):\r
+       keysigCount =0\r
+       timesigCount=0\r
+       noteCount=0\r
+       restCount=0\r
+       staffCount=0\r
+       barlineCount=0\r
+       clefCount=0\r
+       textCount =0\r
+       dynamicCount = 0\r
+       \r
+       lastPitch = scale.index('c')\r
+       lastDuration = 0\r
+       lastClef = scale.index(clefs[0])  # index referenced to note of last clef\r
+       lastStem = 0\r
+       lastTimesig = 1\r
+       \r
+       lastKey = { 'c': '', #c \r
+       'd': '', 'e': '', 'f': '', 'g': '', 'a': '', 'b': '' }\r
+       currentKey = lastKey.copy()\r
+       \r
+       data = 0\r
+       token = 1\r
+       \r
+       result = ""\r
+       result += "\n\t\\new Staff {\n\t\t"\r
+       lastChord = 0\r
+       lastGrace = 0;\r
+       \r
+       (noOfTokens,format, lyrics) = findStaffInfo(nwcData);\r
+       if lyrics!='':\r
+               #result += '\\lyricmode { ' + lyrics + '}'\r
+               result += '%%Lyrics %%{ ' + lyrics + '%%}'\r
+       \r
+       if relativePitch: \r
+               result+="\\relative c {"\r
+       else :\r
+               result+=" {"\r
+       result+="\n\t\t\n\n\t\t"\r
+       result+= '\n\t %% Staff %s \n\t' % staff \r
+       \r
+       #print "00112233445566778899\n"\r
+       extra = ''\r
+       # the juice\r
+       \r
+       while data!="":\r
+               \r
+               token += 1\r
+               if token==noOfTokens:\r
+                       result += "\n\t\t}\n\t}\n\t"\r
+                       print "going next staff! %s" % nwcData.tell()\r
+                       break\r
+               \r
+               \r
+               if nwcversion==1.7:\r
+                       nwcData.seek(2,1)\r
+               \r
+               data = nwcData.read(1)\r
+               #print 'test', data\r
+               \r
+               # clef\r
+               if data=='\x00':\r
+                       data = nwcData.read(6)\r
+                       clefCount += 1\r
+                       \r
+                       key = ord(data[2]) & 3  \r
+                       octave = ord(data[4]) & 3\r
+                       # print binascii.hexlify(data) , "CLEF? "\r
+                       lastClef = scale.index(clefs[key]) + octaves[octave]\r
+                       #TODO check for octave shifts _8\r
+                       lastClef += clefShift[octave]  \r
+                       result += '\clef "' + clefNames[key] + clefOctave[octave]+ '"\n\t\t'\r
+                       \r
+               # key signature\r
+               elif data=='\x01':\r
+                       data = nwcData.read(12)\r
+                       keysigCount = keysigCount + 1\r
+                       \r
+                       #\r
+                       flatBits = ord(data[2])\r
+                       sharpBits = ord(data[4])\r
+                       \r
+                       for note in lastKey.keys():\r
+                               noteInd = ['a','b','c','d','e','f','g'].index(note)\r
+                               if (flatBits >> noteInd & 1):\r
+                                       lastKey[note] = 'es'\r
+                               elif (sharpBits >> noteInd & 1):\r
+                                       lastKey[note] = 'is'\r
+                               else:\r
+                                       lastKey[note] = ''\r
+                       \r
+                       currentKey = lastKey.copy()\r
+                       result = result + getKey(data[1:5]) + "\n\t\t"\r
+                       \r
+                       #print "data", binascii.hexlify(data)\r
+                       #print "flat", binascii.hexlify(flatBits)\r
+                       #print "sharp", binascii.hexlify(data[4])\r
+                       #print getKey(data[1:5])\r
+                       \r
+               \r
+               # barline\r
+               elif data=='\x02':\r
+                       data = nwcData.read(4)\r
+                       barlineCount += 1\r
+                       \r
+                       currentKey = lastKey.copy()\r
+                       \r
+                       result += "|\n\t\t"\r
+                       if (barlineCount % barLinesComments == 0):\r
+                               result += "\n\t\t% Bar " + str(barlineCount + 1) + "\n\t\t" \r
+                               #print '.',\r
+                               print "Bar ",barlineCount, " completed, "\r
+               \r
+               # timesig\r
+               elif data=='\x05':\r
+                       data = nwcData.read(8)\r
+                       timesigCount = timesigCount + 1 \r
+                       beats = ord(data[2])\r
+                       beatValues = [ 1, 2, 4, 8 ,6, 32 ]\r
+                       beatValue = beatValues[ord(data[4])]\r
+                       timesig = str(beats) + "/"  + str(beatValue)\r
+                       lastTimesig = timesigValues[timesig]\r
+                       result += "\\time " + timesig + " "\r
+               # Tempo\r
+               elif data=='\x06':\r
+                       print "Tempo"\r
+                       data = nwcData.read(7)\r
+                       tempo = readLn(nwcData)\r
+                       result += '\n\t\t%%tempo %s\n\t\t' % tempo\r
+                       #tempoCount = tempoCount + 1    \r
+                       \r
+               # note\r
+               elif data=='\x08':\r
+                       data = nwcData.read(10)\r
+                       noteCount = noteCount + 1\r
+                       \r
+                       if debug: print binascii.hexlify(data) , noteCount , nwcData.tell()\r
+                       (pitch, accidental, duration, stem, beam, triplet, slur, tie, grace, staccato, accent, tenuto) = getNote(data)\r
+                       \r
+                       \r
+                       articulate = ''\r
+                       if staccato: articulate+= '-.'\r
+                       if accent: articulate+= '->'\r
+                       if tenuto: articulate+= '--'\r
+                       \r
+                       beam = beams[beam]\r
+                       \r
+                       chordMatters = ''\r
+                       if lastChord>0 and beam==']' :\r
+                               chordMatters = ' } >> '\r
+                               lastChord = 0\r
+                       elif lastChord>0:\r
+                               \r
+                               print 'CHORd', durVal(duration), lastChord\r
+                               dur = durVal(duration)\r
+                               #lastChord = 1.0/((1.0 / lastChord) - (1.0/durVal(duration)))\r
+                               lastChord -= dur \r
+                               \r
+                               if lastChord <= 0 :\r
+                                       chordMatters = ' } >> '\r
+                                       lastChord = 0\r
+                                       \r
+                               \r
+                       \r
+                       if not insertBeaming: beam = ''\r
+                       \r
+                       # pitch\r
+                       pitch += lastClef\r
+                       note = scale[pitch]\r
+                       \r
+                       \r
+                       # get Accidentals\r
+                       #print 'accidental',accidental\r
+                       if (accidental!='auto'):\r
+                               currentKey[note[0]] = accidental\r
+                       accidental = currentKey[note[0]]\r
+                       \r
+                       if (relativePitch):\r
+                               octave = getRelativePitch(lastPitch, pitch)\r
+                               lastPitch = pitch\r
+                       else:\r
+                               octave = note[1:]\r
+                       pitch = note[0] + accidental + octave\r
+                       \r
+                       # get Relative Duration\r
+                       if (relativeDuration):\r
+                               if (lastDuration==duration):\r
+                                       duration = ''\r
+                               else:\r
+                                       lastDuration = duration\r
+                       \r
+                       # check stems\r
+                       if insertSteming and (stem!= lastStem) :\r
+                               lastStem = stem\r
+                               stem = stems[stem]\r
+                       else :\r
+                               stem = ''\r
+                       \r
+                       # normal note\r
+                       if extra!='':\r
+                               extra = '-"' + extra + '"'\r
+                       \r
+                       if grace and not lastGrace: result += "\\acciaccatura { "\r
+                       \r
+                       if not grace and lastGrace: result += " } "\r
+                       result += triplet[0] + stem + pitch + duration + articulate + extra \r
+                       result += slur + tie + beam  + triplet[1]  +chordMatters  +  " "\r
+                       \r
+                       \r
+                       # reset\r
+                       lastGrace = grace\r
+                       extra = ''\r
+               # rest\r
+               elif data=='\x09':\r
+                       data = nwcData.read(10)\r
+                       restCount = restCount + 1 \r
+                       \r
+                       # get Relative Duration\r
+                       duration = getDuration(data)\r
+                       if duration == '1':\r
+                               duration = lastTimesig\r
+                       if (relativeDuration):\r
+                               if (lastDuration==duration):\r
+                                       duration = ''\r
+                               else:\r
+                                       lastDuration = duration\r
+                                       \r
+                       result = result + 'r' + duration + " "\r
+\r
+               # text\r
+               elif data=='\x11':\r
+                       textCount = textCount + 1\r
+                       data = nwcData.read(2) #pad\r
+                       textpos = nwcData.read(1)\r
+                       data = nwcData.read(2) #pad\r
+                       text = ''\r
+                       data = nwcData.read(1)\r
+                       while data!='\x00':\r
+                               text += data\r
+                               data = nwcData.read(1)\r
+                       \r
+                       #if text.isdigit() : # check numbers\r
+                       #       text = "-\\markup -\\number "+ text \r
+                       #       #text = "-\\markup {\\number "+ text +"}"\r
+                       #else :\r
+                       #       text = '-"' + text + '"'\r
+                       \r
+                       extra += ' ' + text\r
+                       \r
+               # dynamics\r
+               elif data=='\x07':\r
+                       dynamicCount = dynamicCount + 1\r
+                       data = nwcData.read(9)\r
+               # chord\r
+               elif data=='\x0A' or data=='\x12':\r
+                       \r
+                       data = nwcData.read(12)\r
+                       \r
+                       chordAmt = ord(data[10])\r
+                       chords = []\r
+                       chordDur = getDuration(data)\r
+                       #print 'duration',chordDur\r
+                                               \r
+                       #print "WARNING Chord support is experimental", chordDur, chordAmt\r
+                       #print binascii.hexlify(data), 'barlines ', barlineCount\r
+                       #print 'no. of notes in chord' , chordAmt\r
+                       \r
+                       chord1 = []\r
+                       chord2 = []\r
+                       \r
+                       for i in range(chordAmt):\r
+                               # rest or note\r
+                               what = nwcData.read(1)\r
+                               \r
+                               data = nwcData.read(10)\r
+                               ha = getNote(data)\r
+                               #print 'data ', ha\r
+                               (pitch, accidental, duration, stem, beam, triplet, slur, tie, grace, staccato, accent, tenuto) = ha\r
+                               # add to list\r
+                               if ha[2] == chordDur:\r
+                                       chord1.append( (pitch,accidental ) )\r
+                                       if beam==0 or beam ==4 :\r
+                                               lastChord = 0\r
+                       \r
+                                       \r
+                               else : # 2 voices\r
+                                       chord2.append(  (pitch,accidental, duration) )\r
+                                       lastChord = durVal(duration)  \r
+                                       \r
+                       \r
+                       if len(chord2)==0: # block chord\r
+                               result += ' <'\r
+                               for i in range(len(chord1)):\r
+                                       (pitch,accidental ) = chord1[i]\r
+                                       pitch += lastClef\r
+                                       note = scale[pitch]\r
+                                       \r
+                                       if (accidental!='auto'):\r
+                                               currentKey[note[0]] = accidental\r
+                                       accidental = currentKey[note[0]]\r
+                                       \r
+                                       if (relativePitch):\r
+                                               octave = getRelativePitch(lastPitch, pitch)\r
+                                               lastPitch = pitch\r
+                                       else:\r
+                                               octave = note[1:]\r
+                                       result += note[0] + accidental + octave + ' '\r
+                               result += '>' +chordDur +' '\r
+                               lastPitch = chord1[0][0] + lastClef\r
+                       else: # 2 voices\r
+                               result += ' << ' \r
+                               for i in range(len(chord2)):\r
+                                       (pitch,accidental,duration ) = chord2[i]\r
+                                       pitch += lastClef\r
+                                       note = scale[pitch]\r
+                                       \r
+                                       if (accidental!='auto'):\r
+                                               currentKey[note[0]] = accidental\r
+                                       accidental = currentKey[note[0]]\r
+                                       \r
+                                       if (relativePitch):\r
+                                               octave = getRelativePitch(lastPitch, pitch)\r
+                                               lastPitch = pitch\r
+                                       else:\r
+                                               octave = note[1:]\r
+                                       result += note[0] + accidental + octave + duration + ' '\r
+                               \r
+                               result += " \\\\ {"\r
+                               \r
+                               for i in range(len(chord1)):\r
+                                       (pitch,accidental ) = chord1[i]\r
+                                       pitch += lastClef\r
+                                       note = scale[pitch]\r
+                                       \r
+                                       if (accidental!='auto'):\r
+                                               currentKey[note[0]] = accidental\r
+                                       accidental = currentKey[note[0]]\r
+                                       \r
+                                       if (relativePitch):\r
+                                               octave = getRelativePitch(lastPitch, pitch)\r
+                                               lastPitch = pitch\r
+                                       else:\r
+                                               octave = note[1:]\r
+                                       result += note[0] + accidental + octave +chordDur + ' '\r
+                               if lastChord >0 : lastChord = durVal(duration) - durVal(chordDur)\r
+                               if lastChord==0: result += ' } >> '\r
+                               # end 2 voices\r
+                       lastDuration = chordDur\r
+                       \r
+                       # check if duration / stem  / same \r
+                               # < >duration ties,beam, slurs\r
+               \r
+               # Pedal\r
+               elif data=='\x0b':\r
+                       print 'Ped      '\r
+                       data = data = nwcData.read(5)\r
+               # midi control instruction / MPC\r
+               elif data=='\x0d':\r
+                       print 'midi control instruction'\r
+                       data = data = nwcData.read(36)\r
+               # fermata / Breath mark\r
+               elif data=='\x0E':\r
+                       print "Fermata"\r
+                       data = nwcData.read(6)\r
+                       extra += "\\fermata" \r
+               \r
+               # Dynamics\r
+               elif data=='\x0f':\r
+                       print "Dynamics"\r
+                       data = nwcData.read(5)\r
+               \r
+               # Performance Style\r
+               elif data=='\x10':\r
+                       print "Performance Style"\r
+                       data = nwcData.read(5)\r
+               \r
+               # Instrument Patch\r
+               elif data=='\x04':\r
+                       print "Instrument Patch"\r
+                       data = nwcData.read(10)\r
+               \r
+               \r
+               # todo\r
+               else :\r
+                       print "WARNING: Unrecognised token ",binascii.hexlify(data), " at #", nwcData.tell(), " at Token",  token\r
+                       \r
+                       \r
+                       \r
+       # output converted file?\r
+       print "\nStats"\r
+       print keysigCount, " keysigCount found"\r
+       print noteCount, " notes found"\r
+       print staffCount, " staffCount found"\r
+       print clefCount, " clefCount found"\r
+       print barlineCount, " barlineCount found"\r
+       print timesigCount, " timesigCount found"\r
+       print textCount, " textCount found"\r
+       print dynamicCount, " dynamicCount found"\r
+       print restCount, " restCount found"\r
+       \r
+       #print "\nLilypond format:\n"\r
+       return result\r
+       \r
+# Variables\r
+keysigs = {\r
+'00000000' : 'c \major % or a \minor' ,\r
+'00000020' : 'g \major % or e \minor' ,\r
+'00000024': 'd \major % or b \minor' ,\r
+'00000064' : 'a \major % or fis \minor' ,\r
+'0000006c' : 'e \major % or cis \minor' ,\r
+'0000006d' : 'b \major % or gis \minor' ,\r
+'0000007d' : 'fis \major % or dis \minor' ,\r
+'0000007f' : 'cis \major % or ais \minor' ,\r
+'00020000' : 'f \major % or d \minor' ,\r
+'00120000' : 'bes \major % or g \minor' ,\r
+'00130000' : 'ees \major % or c \minor' ,\r
+'001b0000' : 'aes \major % or f \minor' ,\r
+'005b0000' : 'des \major % or bes \minor' ,\r
+'005f0000' : 'ges \major % or ees \minor' ,\r
+'007f0000' : 'ces \major % or a \minor'\r
+}\r
+\r
+acdts = ( 'is', 'es', '' ,'isis', 'eses', 'auto'  ) \r
+\r
+clefs = { 0 : "b'",\r
+          1 : "d",\r
+          2 : "c'",\r
+          3 : "a'",\r
+        }\r
+\r
+clefNames = { 0: 'treble',\r
+          1: 'bass',\r
+          2: 'alto',\r
+          3: 'tenor',\r
+        }\r
+octaves = { 0: 0, 1:7, 2:-7 }\r
+scale = [   # this list is taken from lilycomp\r
+        "c,,,","d,,,","e,,,","f,,,","g,,,","a,,,","b,,,",\r
+        "c,,","d,,","e,,","f,,","g,,","a,,","b,,",\r
+        "c,","d,","e,","f,","g,","a,","b,",\r
+        "c","d","e","f","g","a","b",\r
+        "c'","d'","e'","f'","g'","a'","b'",\r
+        "c''","d''","e''","f''","g''","a''","b''",\r
+        "c'''","d'''","e'''","f'''","g'''","a'''","b'''",\r
+        "c''''","d''''","e''''","f''''","g''''","a''''","b''''",\r
+        ]\r
+\r
+stems = [ '\stemNeutral ', '\stemUp ', '\stemDown ']\r
+\r
+slurs = [ '', '(' , ')', '' ]\r
+\r
+triplets = [ \r
+       ('' , '' ),\r
+       ( '\\times 2/3 { ', '') ,\r
+       ('' , '' ),\r
+       ('' , ' }' ),\r
+       ]\r
+\r
+durations = ( '1','2','4','8','16','32','64' ) \r
+\r
+barlines = (\r
+     '|', # 'Single'\r
+     '||', # 'Double'\r
+     '.|', # SectionOpen\r
+     '|.', # SectionClose\r
+     '|:', # MasterRepeatOpen\r
+     ':|', # MasterRepeatClose\r
+     '|:', # LocalRepeatOpen\r
+     ':|', # LocalRepeatClose\r
+)\r
+\r
+ending = (\r
+'|.', # SectionClose\r
+':|', # MasterRepeatClose\r
+'|', # 'Single'\r
+'||', # 'Double'\r
+'' # Open hidden\r
+)\r
+\r
+staffType = (\r
+'Standard' , # Standard\r
+'Upper Grand Staff' , # Upper Grand Staff\r
+'Lower Grand Staff' , # Lower Grand Staff\r
+'Orchestra' , # Orchestra\r
+)\r
+\r
+\r
+beams = [ '', '[', '',']' ]\r
+\r
+\r
+# end ' \bar "|."'\r
+\r
+# Notation Properties\r
+# extra accidental spacing\r
+# extra note spacing\r
+# muted\r
+# no ledger lines\r
+# slurdirection\r
+# tiedirection\r
+# lyricsyllable\r
+# visability \r
+# show printed\r
+# item color\r
+\r
+#dynamics\r
+# cmd = DynamicVariance\r
+# Decrescendo \setTextCresc \<\r
+# setTextCresc Crescendo \>  setHairpinCresc\r
+# Dynamics stop '\! '\r
+# style = ff pp\r
+\r
+clefOctave = [ '' , '^8', '_8' , '' ]\r
+clefShift = [0,7,-7, 0]\r
+\r
+\r
+# '#(set-accidental-style '#39'modern-cautionary)'\r
+#(ly:set-point-and-click 'line-column)\r
+#(set-global-staff-size 20)\r
+\r
+timesigValues = { \r
+       '4/4' : '1', '3/4' : '2.', '2/4' : '2', '1/4' : '1',\r
+       '1/8' : '8', '2/8' : '4', '3/8' : '4.', '6/8' : '2.',\r
+       '4/8' : '2', '9/8' : '12', '12/8' : '1',\r
+       '2/2' : '1', '4/2' : '0', '1/2' : '2', \r
+        }\r
+\r
+print "python nwc2ly is running..."\r
+try:\r
+\r
+       nwcData = open( nwcfile,'rb')\r
+       \r
+       # check if its a readable nwc format\r
+       # compressed - [NWZ]\r
+       # uncompressed - [NoteWorthy ArtWare] [NoteWorthy Composer]\r
+       format = nwcData.read(5)\r
+       if format== '[NWZ]':\r
+               nwcData.seek(1,1)\r
+               print 'Compressed NWC detected!'\r
+               print 'Dumping to uncompressed NWC format and attemping conversion soon...'\r
+               uncompress = open ('uncompressed.nwc','wb')\r
+               uncompress.write(zlib.decompress(nwcData.read()))\r
+               uncompress.close()\r
+               print 'Inflating done. Now opening new file...'\r
+               nwcData.close()\r
+               nwcData = open( 'uncompressed.nwc','rb')\r
+               nwcData.seek(6)\r
+       elif format!= '[Note':\r
+               print 'Unknown format, please use an uncompress NWC format and try again.'  \r
+               sys.exit()\r
+       \r
+       \r
+       \r
+       resultFile = '%% Generated from python nwc2ly converter v%s by Joshua Koo (joshuakoo@myrealbox.com)' % nwc2lyversion\r
+       resultFile += '\n\n\\version "2.4.0"'\r
+       resultFile += "\n"\r
+       \r
+       \r
+       # START WORK\r
+       getFileFormat(nwcData)\r
+       resultFile+=getFileInfo(nwcData)\r
+       resultFile+= "\n\n\\score {"\r
+       resultFile+= "\n\t<<\n\t\t"\r
+       \r
+       getPageSetup(nwcData)\r
+       \r
+       noOfStaffs = findNoOfStaff(nwcData);\r
+       \r
+       for staff in range(1,noOfStaffs+1):\r
+               print "\n\nWorking on Staff", staff\r
+               result = processStaff(nwcData)\r
+               #print result\r
+               resultFile += result\r
+       \r
+       resultFile+= "\n\t>>"\r
+       resultFile+= "\n\t\layout {}"\r
+       resultFile+= "\n\t\midi {}"\r
+       resultFile+= "\n}"\r
+       nwcData.close()\r
+       \r
+       if lyfile=='':\r
+               print 'Dumping output file to screen'\r
+               print resultFile\r
+       else :\r
+               write = open( lyfile ,'w')\r
+               write.write (resultFile)\r
+               write.close()\r
+\r
+except IOError:\r
+       print 'File does not exist or an IO error occurred'\r
+except Exception, e: #KeyError\r
+       print "Error while reading data at ", nwcData.tell() ,"\n"\r
+       print 'Dumping whatever result first'\r
+       print resultFile\r
+       print result\r
+       print\r
+       traceback.print_exc()\r
+\r
+print\r
+print\r
+print "Please send all bugs and requests to joshuakoo@myrealbox.com"\r