singing.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. # converts XML files from Milan Zamazal's Singing Computer to UTAU format
  2. import sys
  3. from xml.dom.minidom import parse
  4. from xml.dom import minidom
  5. def splitNote(n,sep):
  6. a = ""
  7. b = ""
  8. l = []
  9. for c in n:
  10. if c in sep:
  11. a += c
  12. l += [b]
  13. b = ""
  14. else:
  15. b += c
  16. l += [b]
  17. return a,l
  18. def convertPitch(pitch):
  19. pitch = pitch.lower()
  20. octave = ""
  21. step = ""
  22. steps = {"c": 0, "c#": 1, "d": 2, "d#": 3, "e": 4,
  23. "f": 5, "f#": 6, "g": 7, "g#": 8, "a": 9,"a#": 10, "b": 11}
  24. for p in pitch:
  25. if p in "1234567890":
  26. octave += p
  27. if p in "abcdefg#":
  28. step += p
  29. pitch = steps[step]+12*int(octave)
  30. return str(pitch)
  31. class Note:
  32. def __init__(self,lyric,length,pitch):
  33. self.lyric = lyric
  34. self.length = length
  35. self.pitch = pitch
  36. class Score:
  37. def __init__(self,filename):
  38. self.notes = []
  39. self.bpm = 120.0
  40. self.utau = "DEFAULT"
  41. self.pos = 0
  42. dom = parse(filename)
  43. singing = dom.getElementsByTagName('SINGING')[0]
  44. utau = singing.getAttribute("UTAU")
  45. bpm = singing.getAttribute("BPM")
  46. if(len(bpm)):
  47. self.bpm = float(bpm)
  48. if(len(utau)):
  49. self.utau = utau
  50. nodes = singing.childNodes
  51. #filter nodes
  52. nodes = [item for item in nodes if
  53. item.nodeType == minidom.Node.ELEMENT_NODE]
  54. for element in nodes:
  55. self.addElement(element)
  56. def addElement(self,element):
  57. if(element.localName=="REST"):
  58. self.addRest(element)
  59. else:
  60. self.addNote(element)
  61. def addRest(self,element):
  62. beats = element.getAttribute("BEATS")
  63. beats = float(beats)
  64. self.notes += [Note("R",beats,"")]
  65. length = beats*60/self.bpm
  66. self.pos += length
  67. def addNote3(self,lyric,dur,pit):
  68. beats = float(dur)
  69. self.notes += [Note(lyric,beats,pit)]
  70. length = beats*60/self.bpm
  71. self.pos += length
  72. def addNote(self,element):
  73. pitch_note = None
  74. duration_beats = None
  75. lyric = None
  76. if(element.localName=="DURATION"):
  77. inner = element.getElementsByTagName('PITCH')[0]
  78. pitch_note = inner.getAttribute("NOTE")
  79. duration_beats = element.getAttribute("BEATS")
  80. lyric = inner.firstChild.data
  81. elif(element.localName=="PITCH"):
  82. inner = element.getElementsByTagName('DURATION')[0]
  83. pitch_note = element.getAttribute("NOTE")
  84. duration_beats = inner.getAttribute("BEATS")
  85. lyric = inner.firstChild.data
  86. sep1, pit = splitNote(pitch_note,",+")
  87. sep2, dur = splitNote(duration_beats,",+")
  88. assert(sep1==sep1)
  89. lyrics = [lyric]
  90. for c in sep1:
  91. lyrics += [c]
  92. assert(len(lyrics)==len(pit))
  93. assert(len(lyrics)==len(dur))
  94. for i in range(len(lyrics)):
  95. self.addNote3(lyrics[i],dur[i],pit[i])
  96. def toUST(self):
  97. ust = []
  98. ust += ["[#SETTING]"]
  99. ust += ["Tempo="+str(self.bpm)]
  100. for i in range(len(self.notes)):
  101. s = str(i)
  102. fill = "0"*(4-len(s))
  103. ust += ["[#"+fill+s+"]"]
  104. n = self.notes[i]
  105. ust += ["Lyric="+n.lyric]
  106. ust += ["Length="+str(int(n.length*480))]
  107. ust += ["NoteNum="+convertPitch(n.pitch)]
  108. ust += ["[#TRACKEND]"]
  109. return ust